gameboy-perfect-core Mirror

./build/CMakeCache.txt

# This is the CMakeCache file.
# For build in directory: /home/ubuntu/Desktop/gameboy-perfect-core/build
# It was generated by CMake: /usr/bin/cmake
# You can edit this file to change values found and used by cmake.
# If you do not want to change any of the values, simply exit the editor.
# If you do want to change a value, simply edit, save, and exit the editor.
# The syntax for the file is as follows:
# KEY:TYPE=VALUE
# KEY is the name of a variable in the cache.
# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
# VALUE is the current value for the KEY.

########################
# EXTERNAL cache entries
########################

//Path to a program.
CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line

//Path to a program.
CMAKE_AR:FILEPATH=/usr/bin/ar

//Choose the type of build, options are: None Debug Release RelWithDebInfo
// MinSizeRel ...
CMAKE_BUILD_TYPE:STRING=

//Enable/Disable color output during build.
CMAKE_COLOR_MAKEFILE:BOOL=ON

//C compiler
CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-12

//A wrapper around 'ar' adding the appropriate '--plugin' option
// for the GCC compiler
CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-12

//A wrapper around 'ranlib' adding the appropriate '--plugin' option
// for the GCC compiler
CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-12

//Flags used by the C compiler during all build types.
CMAKE_C_FLAGS:STRING=

//Flags used by the C compiler during DEBUG builds.
CMAKE_C_FLAGS_DEBUG:STRING=-g

//Flags used by the C compiler during MINSIZEREL builds.
CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG

//Flags used by the C compiler during RELEASE builds.
CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG

//Flags used by the C compiler during RELWITHDEBINFO builds.
CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG

//Path to a program.
CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND

//Flags used by the linker during all build types.
CMAKE_EXE_LINKER_FLAGS:STRING=

//Flags used by the linker during DEBUG builds.
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during MINSIZEREL builds.
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during RELEASE builds.
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during RELWITHDEBINFO builds.
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//Enable/Disable output of compile commands during generation.
CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=

//Value Computed by CMake.
CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/pkgRedirects

//Install path prefix, prepended onto install directories.
CMAKE_INSTALL_PREFIX:PATH=/usr/local

//Path to a program.
CMAKE_LINKER:FILEPATH=/usr/bin/ld

//Path to a program.
CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/gmake

//Flags used by the linker during the creation of modules during
// all build types.
CMAKE_MODULE_LINKER_FLAGS:STRING=

//Flags used by the linker during the creation of modules during
// DEBUG builds.
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during the creation of modules during
// MINSIZEREL builds.
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during the creation of modules during
// RELEASE builds.
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during the creation of modules during
// RELWITHDEBINFO builds.
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//Path to a program.
CMAKE_NM:FILEPATH=/usr/bin/nm

//Path to a program.
CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy

//Path to a program.
CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump

//Value Computed by CMake
CMAKE_PROJECT_DESCRIPTION:STATIC=

//Value Computed by CMake
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=

//Value Computed by CMake
CMAKE_PROJECT_NAME:STATIC=gameboy_perfect_core

//Path to a program.
CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib

//Path to a program.
CMAKE_READELF:FILEPATH=/usr/bin/readelf

//Flags used by the linker during the creation of shared libraries
// during all build types.
CMAKE_SHARED_LINKER_FLAGS:STRING=

//Flags used by the linker during the creation of shared libraries
// during DEBUG builds.
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during the creation of shared libraries
// during MINSIZEREL builds.
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during the creation of shared libraries
// during RELEASE builds.
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during the creation of shared libraries
// during RELWITHDEBINFO builds.
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//If set, runtime paths are not added when installing shared libraries,
// but are added when building.
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO

//If set, runtime paths are not added when using shared libraries.
CMAKE_SKIP_RPATH:BOOL=NO

//Flags used by the linker during the creation of static libraries
// during all build types.
CMAKE_STATIC_LINKER_FLAGS:STRING=

//Flags used by the linker during the creation of static libraries
// during DEBUG builds.
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during the creation of static libraries
// during MINSIZEREL builds.
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during the creation of static libraries
// during RELEASE builds.
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during the creation of static libraries
// during RELWITHDEBINFO builds.
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//Path to a program.
CMAKE_STRIP:FILEPATH=/usr/bin/strip

//Path to a program.
CMAKE_TAPI:FILEPATH=CMAKE_TAPI-NOTFOUND

//If this value is on, makefiles will be generated without the
// .SILENT directive, and all commands will be echoed to the console
// during the make.  This is useful for debugging only. With Visual
// Studio IDE projects all commands are done without /nologo.
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE

//Value Computed by CMake
gameboy_perfect_core_BINARY_DIR:STATIC=/home/ubuntu/Desktop/gameboy-perfect-core/build

//Value Computed by CMake
gameboy_perfect_core_IS_TOP_LEVEL:STATIC=ON

//Value Computed by CMake
gameboy_perfect_core_SOURCE_DIR:STATIC=/home/ubuntu/Desktop/gameboy-perfect-core


########################
# INTERNAL cache entries
########################

//ADVANCED property for variable: CMAKE_ADDR2LINE
CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_AR
CMAKE_AR-ADVANCED:INTERNAL=1
//This is the directory where this CMakeCache.txt was created
CMAKE_CACHEFILE_DIR:INTERNAL=/home/ubuntu/Desktop/gameboy-perfect-core/build
//Major version of cmake used to create the current loaded cache
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
//Minor version of cmake used to create the current loaded cache
CMAKE_CACHE_MINOR_VERSION:INTERNAL=28
//Patch version of cmake used to create the current loaded cache
CMAKE_CACHE_PATCH_VERSION:INTERNAL=3
//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE
CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1
//Path to CMake executable.
CMAKE_COMMAND:INTERNAL=/usr/bin/cmake
//Path to cpack program executable.
CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack
//Path to ctest program executable.
CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest
//ADVANCED property for variable: CMAKE_C_COMPILER
CMAKE_C_COMPILER-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_COMPILER_AR
CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB
CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS
CMAKE_C_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_DLLTOOL
CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
//Executable file format
CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS
CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1
//Name of external makefile project generator.
CMAKE_EXTRA_GENERATOR:INTERNAL=
//Name of generator.
CMAKE_GENERATOR:INTERNAL=Unix Makefiles
//Generator instance identifier.
CMAKE_GENERATOR_INSTANCE:INTERNAL=
//Name of generator platform.
CMAKE_GENERATOR_PLATFORM:INTERNAL=
//Name of generator toolset.
CMAKE_GENERATOR_TOOLSET:INTERNAL=
//Source directory with the top level CMakeLists.txt file for this
// project
CMAKE_HOME_DIRECTORY:INTERNAL=/home/ubuntu/Desktop/gameboy-perfect-core
//Install .so files without execute permission.
CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1
//ADVANCED property for variable: CMAKE_LINKER
CMAKE_LINKER-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MAKE_PROGRAM
CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_NM
CMAKE_NM-ADVANCED:INTERNAL=1
//number of local generators
CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
//ADVANCED property for variable: CMAKE_OBJCOPY
CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_OBJDUMP
CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
//Platform information initialized
CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
//ADVANCED property for variable: CMAKE_RANLIB
CMAKE_RANLIB-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_READELF
CMAKE_READELF-ADVANCED:INTERNAL=1
//Path to CMake installation.
CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.28
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SKIP_RPATH
CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STRIP
CMAKE_STRIP-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_TAPI
CMAKE_TAPI-ADVANCED:INTERNAL=1
//uname command
CMAKE_UNAME:INTERNAL=/usr/bin/uname
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
//linker supports push/pop state
_CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED:INTERNAL=TRUE

./build/CMakeFiles/3.28.3/CMakeCCompiler.cmake

set(CMAKE_C_COMPILER "/usr/bin/gcc-12")
set(CMAKE_C_COMPILER_ARG1 "")
set(CMAKE_C_COMPILER_ID "GNU")
set(CMAKE_C_COMPILER_VERSION "12.3.0")
set(CMAKE_C_COMPILER_VERSION_INTERNAL "")
set(CMAKE_C_COMPILER_WRAPPER "")
set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "17")
set(CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT "ON")
set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert;c_std_17;c_std_23")
set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes")
set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros")
set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert")
set(CMAKE_C17_COMPILE_FEATURES "c_std_17")
set(CMAKE_C23_COMPILE_FEATURES "c_std_23")

set(CMAKE_C_PLATFORM_ID "Linux")
set(CMAKE_C_SIMULATE_ID "")
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
set(CMAKE_C_SIMULATE_VERSION "")




set(CMAKE_AR "/usr/bin/ar")
set(CMAKE_C_COMPILER_AR "/usr/bin/gcc-ar-12")
set(CMAKE_RANLIB "/usr/bin/ranlib")
set(CMAKE_C_COMPILER_RANLIB "/usr/bin/gcc-ranlib-12")
set(CMAKE_LINKER "/usr/bin/ld")
set(CMAKE_MT "")
set(CMAKE_TAPI "CMAKE_TAPI-NOTFOUND")
set(CMAKE_COMPILER_IS_GNUCC 1)
set(CMAKE_C_COMPILER_LOADED 1)
set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_C_ABI_COMPILED TRUE)

set(CMAKE_C_COMPILER_ENV_VAR "CC")

set(CMAKE_C_COMPILER_ID_RUN 1)
set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m)
set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
set(CMAKE_C_LINKER_PREFERENCE 10)
set(CMAKE_C_LINKER_DEPFILE_SUPPORTED TRUE)

# Save compiler ABI information.
set(CMAKE_C_SIZEOF_DATA_PTR "8")
set(CMAKE_C_COMPILER_ABI "ELF")
set(CMAKE_C_BYTE_ORDER "LITTLE_ENDIAN")
set(CMAKE_C_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")

if(CMAKE_C_SIZEOF_DATA_PTR)
  set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}")
endif()

if(CMAKE_C_COMPILER_ABI)
  set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}")
endif()

if(CMAKE_C_LIBRARY_ARCHITECTURE)
  set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")
endif()

set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "")
if(CMAKE_C_CL_SHOWINCLUDES_PREFIX)
  set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}")
endif()





set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/12/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include")
set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "gcc;gcc_s;c;gcc;gcc_s")
set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/12;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib")
set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")

./build/CMakeFiles/3.28.3/CMakeDetermineCompilerABI_C.bin

ELF>@@7@8
@@@@   TT-== (.>>88800hhhDDStd88800Ptd   ,,QtdRtd-==/lib64/ld-linux-x86-64.so.2 GNUGNU{$$/zcQlGNUemC _ n "__libc_start_main__cxa_finalizelibc.so.6GLIBC_2.2.5GLIBC_2.34_ITM_deregisterTMCloneTable__gmon_start___ITM_registerTMCloneTable"ui	,8= =@@?????HH/HtH5/%/@%/fD1I^HHPTE11H=s/f.H=/H/H9tHV/Ht	H=i/H5b/H)HH?HHHtH%/HtfD=%/u+UH=/HtH=/)d.]wUH}HuEEHHEEHHHEEHHHEEHHEE]HHINFO:sizeof_dptr[08]NIOFb:ty_eroed[rIB_GNEIDNA]INFO:byte_order[LITTLE_ENDIAN]INFO:abi[ELF];,`HzRx`&D$4(FJw?9*3$"\t{EC
r "
==oh
?0	ooooo>@GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0	 p 3I@U=| =@ `   P!> '?=Z  @v  @@ @ @@&@){@ "#Scrt1.o__abi_tagcrtstuff.cderegister_tm_clones__do_global_dtors_auxcompleted.0__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entryCMakeCCompilerABI.cinfo_byte_order_big_endianinfo_byte_order_little_endianinfo_abi__FRAME_END___DYNAMIC__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_start_main@GLIBC_2.34_ITM_deregisterTMCloneTableinfo_sizeof_dptr_edata_fini__data_start__gmon_start____dso_handle_IO_stdin_used_end__bss_startmain__TMC_END___ITM_registerTMCloneTable__cxa_finalize@GLIBC_2.2.5_init.symtab.strtab.shstrtab.interp.note.gnu.property.note.gnu.build-id.note.ABI-tag.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.init.plt.plt.got.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.dynamic.data.bss.comment#8806hh$I Wo$aihhqo~o000  00@@d
     ,  =-=->.?/@@0@000&80	3)	6

./build/CMakeFiles/3.28.3/CMakeSystem.cmake

set(CMAKE_HOST_SYSTEM "Linux-6.14.0-29-generic")
set(CMAKE_HOST_SYSTEM_NAME "Linux")
set(CMAKE_HOST_SYSTEM_VERSION "6.14.0-29-generic")
set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64")



set(CMAKE_SYSTEM "Linux-6.14.0-29-generic")
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_VERSION "6.14.0-29-generic")
set(CMAKE_SYSTEM_PROCESSOR "x86_64")

set(CMAKE_CROSSCOMPILING "FALSE")

set(CMAKE_SYSTEM_LOADED 1)

./build/CMakeFiles/3.28.3/CompilerIdC/a.out

ELF>@@7@8
@@@@hh   -==HP.>>88800hhhDDStd88800Ptd   ,,QtdRtd-==/lib64/ld-linux-x86-64.so.2 GNUGNUV =F&}7GNUemC _ n "__libc_start_main__cxa_finalizelibc.so.6GLIBC_2.2.5GLIBC_2.34_ITM_deregisterTMCloneTable__gmon_start___ITM_registerTMCloneTable"ui	,8= =@@@  @r  @ (@ 0@ ?????HH/HtH5/%/@%/fD1I^HHPTE11H=s/f.H=/H/H9tHV/Ht	H=/H5/H)HH?HHHtH%/HtfD=M/u+UH=/HtH=/)d%/]wUH}HuEH.EHHEH.EHHEH.EHHEEHHEH.EHHEHt.EHHEE]HHINFO:compiler[GNU]INFO:compiler_version[00000012.00000003.00000000]INFO:platform[Linux]INFO:arch[]INFO:standard_default[17]INFO:extensions_default[ON];(T\dtD]zRx(&D$4FJw?9*3$"\tEC
 "
==oh
?08	ooooo>@  r    GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0	 p 3I8@U=| =!> ? B @38@:@@M \@i x@0@@@F@&@8@)8@(@ "+1@ 2> @Scrt1.o__abi_tagcrtstuff.cderegister_tm_clones__do_global_dtors_auxcompleted.0__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entryCMakeCCompilerId.c__FRAME_END___DYNAMIC__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_start_main@GLIBC_2.34_ITM_deregisterTMCloneTable_edata_fini__data_start__gmon_start____dso_handle_IO_stdin_usedinfo_platforminfo_language_extensions_default_endinfo_compiler__bss_startmain__TMC_END__info_language_standard_default_ITM_registerTMCloneTable__cxa_finalize@GLIBC_2.2.5_initinfo_versioninfo_arch.symtab.strtab.shstrtab.interp.note.gnu.property.note.gnu.build-id.note.ABI-tag.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.init.plt.plt.got.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.dynamic.data.bss.comment#8806hh$I Wo$aihhqo~o0008  00@@
     ,  =-=->.?/@@088@80080&`0	84H6

./build/CMakeFiles/3.28.3/CompilerIdC/CMakeCCompilerId.c

#ifdef __cplusplus
# error "A C++ compiler has been selected for C."
#endif

#if defined(__18CXX)
# define ID_VOID_MAIN
#endif
#if defined(__CLASSIC_C__)
/* cv-qualifiers did not exist in K&R C */
# define const
# define volatile
#endif

#if !defined(__has_include)
/* If the compiler does not have __has_include, pretend the answer is
   always no.  */
#  define __has_include(x) 0
#endif


/* Version number components: V=Version, R=Revision, P=Patch
   Version date components:   YYYY=Year, MM=Month,   DD=Day  */

#if defined(__INTEL_COMPILER) || defined(__ICC)
# define COMPILER_ID "Intel"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# if defined(__GNUC__)
#  define SIMULATE_ID "GNU"
# endif
  /* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,
     except that a few beta releases use the old format with V=2021.  */
# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111
#  define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
#  define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
#  if defined(__INTEL_COMPILER_UPDATE)
#   define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
#  else
#   define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER   % 10)
#  endif
# else
#  define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)
#  define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)
   /* The third version component from --version is an update index,
      but no macro is provided for it.  */
#  define COMPILER_VERSION_PATCH DEC(0)
# endif
# if defined(__INTEL_COMPILER_BUILD_DATE)
   /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
#  define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
# endif
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# if defined(__GNUC__)
#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
# elif defined(__GNUG__)
#  define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
# endif
# if defined(__GNUC_MINOR__)
#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
#  define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif

#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)
# define COMPILER_ID "IntelLLVM"
#if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
#endif
#if defined(__GNUC__)
# define SIMULATE_ID "GNU"
#endif
/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
 * later.  Look for 6 digit vs. 8 digit version number to decide encoding.
 * VVVV is no smaller than the current year when a version is released.
 */
#if __INTEL_LLVM_COMPILER < 1000000L
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER    % 10)
#else
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER     % 100)
#endif
#if defined(_MSC_VER)
  /* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
#endif
#if defined(__GNUC__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
#elif defined(__GNUG__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
#endif
#if defined(__GNUC_MINOR__)
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
#endif
#if defined(__GNUC_PATCHLEVEL__)
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
#endif

#elif defined(__PATHCC__)
# define COMPILER_ID "PathScale"
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
# if defined(__PATHCC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
# endif

#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
# define COMPILER_ID "Embarcadero"
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__     & 0xFFFF)

#elif defined(__BORLANDC__)
# define COMPILER_ID "Borland"
  /* __BORLANDC__ = 0xVRR */
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)

#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
# define COMPILER_ID "Watcom"
   /* __WATCOMC__ = VVRR */
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif

#elif defined(__WATCOMC__)
# define COMPILER_ID "OpenWatcom"
   /* __WATCOMC__ = VVRP + 1100 */
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif

#elif defined(__SUNPRO_C)
# define COMPILER_ID "SunPro"
# if __SUNPRO_C >= 0x5100
   /* __SUNPRO_C = 0xVRRP */
#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12)
#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF)
#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_C    & 0xF)
# else
   /* __SUNPRO_CC = 0xVRP */
#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8)
#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF)
#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_C    & 0xF)
# endif

#elif defined(__HP_cc)
# define COMPILER_ID "HP"
  /* __HP_cc = VVRRPP */
# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000)
# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__HP_cc     % 100)

#elif defined(__DECC)
# define COMPILER_ID "Compaq"
  /* __DECC_VER = VVRRTPPPP */
# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000)
# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000  % 100)
# define COMPILER_VERSION_PATCH DEC(__DECC_VER         % 10000)

#elif defined(__IBMC__) && defined(__COMPILER_VER__)
# define COMPILER_ID "zOS"
  /* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)

#elif defined(__open_xl__) && defined(__clang__)
# define COMPILER_ID "IBMClang"
# define COMPILER_VERSION_MAJOR DEC(__open_xl_version__)
# define COMPILER_VERSION_MINOR DEC(__open_xl_release__)
# define COMPILER_VERSION_PATCH DEC(__open_xl_modification__)
# define COMPILER_VERSION_TWEAK DEC(__open_xl_ptf_fix_level__)


#elif defined(__ibmxl__) && defined(__clang__)
# define COMPILER_ID "XLClang"
# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)


#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800
# define COMPILER_ID "XL"
  /* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)

#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800
# define COMPILER_ID "VisualAge"
  /* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)

#elif defined(__NVCOMPILER)
# define COMPILER_ID "NVHPC"
# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
# if defined(__NVCOMPILER_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
# endif

#elif defined(__PGI)
# define COMPILER_ID "PGI"
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
# if defined(__PGIC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
# endif

#elif defined(__clang__) && defined(__cray__)
# define COMPILER_ID "CrayClang"
# define COMPILER_VERSION_MAJOR DEC(__cray_major__)
# define COMPILER_VERSION_MINOR DEC(__cray_minor__)
# define COMPILER_VERSION_PATCH DEC(__cray_patchlevel__)
# define COMPILER_VERSION_INTERNAL_STR __clang_version__


#elif defined(_CRAYC)
# define COMPILER_ID "Cray"
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)

#elif defined(__TI_COMPILER_VERSION__)
# define COMPILER_ID "TI"
  /* __TI_COMPILER_VERSION__ = VVVRRRPPP */
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000   % 1000)
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__        % 1000)

#elif defined(__CLANG_FUJITSU)
# define COMPILER_ID "FujitsuClang"
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# define COMPILER_VERSION_INTERNAL_STR __clang_version__


#elif defined(__FUJITSU)
# define COMPILER_ID "Fujitsu"
# if defined(__FCC_version__)
#   define COMPILER_VERSION __FCC_version__
# elif defined(__FCC_major__)
#   define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
#   define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
#   define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# endif
# if defined(__fcc_version)
#   define COMPILER_VERSION_INTERNAL DEC(__fcc_version)
# elif defined(__FCC_VERSION)
#   define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)
# endif


#elif defined(__ghs__)
# define COMPILER_ID "GHS"
/* __GHS_VERSION_NUMBER = VVVVRP */
# ifdef __GHS_VERSION_NUMBER
# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER      % 10)
# endif

#elif defined(__TASKING__)
# define COMPILER_ID "Tasking"
  # define COMPILER_VERSION_MAJOR DEC(__VERSION__/1000)
  # define COMPILER_VERSION_MINOR DEC(__VERSION__ % 100)
# define COMPILER_VERSION_INTERNAL DEC(__VERSION__)

#elif defined(__ORANGEC__)
# define COMPILER_ID "OrangeC"
# define COMPILER_VERSION_MAJOR DEC(__ORANGEC_MAJOR__)
# define COMPILER_VERSION_MINOR DEC(__ORANGEC_MINOR__)
# define COMPILER_VERSION_PATCH DEC(__ORANGEC_PATCHLEVEL__)

#elif defined(__TINYC__)
# define COMPILER_ID "TinyCC"

#elif defined(__BCC__)
# define COMPILER_ID "Bruce"

#elif defined(__SCO_VERSION__)
# define COMPILER_ID "SCO"

#elif defined(__ARMCC_VERSION) && !defined(__clang__)
# define COMPILER_ID "ARMCC"
#if __ARMCC_VERSION >= 1000000
  /* __ARMCC_VERSION = VRRPPPP */
  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION     % 10000)
#else
  /* __ARMCC_VERSION = VRPPPP */
  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION    % 10000)
#endif


#elif defined(__clang__) && defined(__apple_build_version__)
# define COMPILER_ID "AppleClang"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)

#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
# define COMPILER_ID "ARMClang"
  # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
  # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION/100   % 100)
# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)

#elif defined(__clang__)
# define COMPILER_ID "Clang"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif

#elif defined(__LCC__) && (defined(__GNUC__) || defined(__GNUG__) || defined(__MCST__))
# define COMPILER_ID "LCC"
# define COMPILER_VERSION_MAJOR DEC(__LCC__ / 100)
# define COMPILER_VERSION_MINOR DEC(__LCC__ % 100)
# if defined(__LCC_MINOR__)
#  define COMPILER_VERSION_PATCH DEC(__LCC_MINOR__)
# endif
# if defined(__GNUC__) && defined(__GNUC_MINOR__)
#  define SIMULATE_ID "GNU"
#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
#  if defined(__GNUC_PATCHLEVEL__)
#   define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
#  endif
# endif

#elif defined(__GNUC__)
# define COMPILER_ID "GNU"
# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
# if defined(__GNUC_MINOR__)
#  define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif

#elif defined(_MSC_VER)
# define COMPILER_ID "MSVC"
  /* _MSC_VER = VVRR */
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
# if defined(_MSC_FULL_VER)
#  if _MSC_VER >= 1400
    /* _MSC_FULL_VER = VVRRPPPPP */
#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
#  else
    /* _MSC_FULL_VER = VVRRPPPP */
#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
#  endif
# endif
# if defined(_MSC_BUILD)
#  define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
# endif

#elif defined(_ADI_COMPILER)
# define COMPILER_ID "ADSP"
#if defined(__VERSIONNUM__)
  /* __VERSIONNUM__ = 0xVVRRPPTT */
#  define COMPILER_VERSION_MAJOR DEC(__VERSIONNUM__ >> 24 & 0xFF)
#  define COMPILER_VERSION_MINOR DEC(__VERSIONNUM__ >> 16 & 0xFF)
#  define COMPILER_VERSION_PATCH DEC(__VERSIONNUM__ >> 8 & 0xFF)
#  define COMPILER_VERSION_TWEAK DEC(__VERSIONNUM__ & 0xFF)
#endif

#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# define COMPILER_ID "IAR"
# if defined(__VER__) && defined(__ICCARM__)
#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
#  define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
#  define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
#  define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
#  define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# endif

#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC)
# define COMPILER_ID "SDCC"
# if defined(__SDCC_VERSION_MAJOR)
#  define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR)
#  define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR)
#  define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH)
# else
  /* SDCC = VRP */
#  define COMPILER_VERSION_MAJOR DEC(SDCC/100)
#  define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10)
#  define COMPILER_VERSION_PATCH DEC(SDCC    % 10)
# endif


/* These compilers are either not known or too old to define an
  identification macro.  Try to identify the platform and guess that
  it is the native compiler.  */
#elif defined(__hpux) || defined(__hpua)
# define COMPILER_ID "HP"

#else /* unknown compiler */
# define COMPILER_ID ""
#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
#ifdef SIMULATE_ID
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
#endif

#ifdef __QNXNTO__
char const* qnxnto = "INFO" ":" "qnxnto[]";
#endif

#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
#endif

#define STRINGIFY_HELPER(X) #X
#define STRINGIFY(X) STRINGIFY_HELPER(X)

/* Identify known platforms by name.  */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"

#elif defined(__MSYS__)
# define PLATFORM_ID "MSYS"

#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"

#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"

#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"

#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"

#elif defined(__FreeBSD__) || defined(__FreeBSD)
# define PLATFORM_ID "FreeBSD"

#elif defined(__NetBSD__) || defined(__NetBSD)
# define PLATFORM_ID "NetBSD"

#elif defined(__OpenBSD__) || defined(__OPENBSD)
# define PLATFORM_ID "OpenBSD"

#elif defined(__sun) || defined(sun)
# define PLATFORM_ID "SunOS"

#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
# define PLATFORM_ID "AIX"

#elif defined(__hpux) || defined(__hpux__)
# define PLATFORM_ID "HP-UX"

#elif defined(__HAIKU__)
# define PLATFORM_ID "Haiku"

#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
# define PLATFORM_ID "BeOS"

#elif defined(__QNX__) || defined(__QNXNTO__)
# define PLATFORM_ID "QNX"

#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
# define PLATFORM_ID "Tru64"

#elif defined(__riscos) || defined(__riscos__)
# define PLATFORM_ID "RISCos"

#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
# define PLATFORM_ID "SINIX"

#elif defined(__UNIX_SV__)
# define PLATFORM_ID "UNIX_SV"

#elif defined(__bsdos__)
# define PLATFORM_ID "BSDOS"

#elif defined(_MPRAS) || defined(MPRAS)
# define PLATFORM_ID "MP-RAS"

#elif defined(__osf) || defined(__osf__)
# define PLATFORM_ID "OSF1"

#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
# define PLATFORM_ID "SCO_SV"

#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
# define PLATFORM_ID "ULTRIX"

#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
# define PLATFORM_ID "Xenix"

#elif defined(__WATCOMC__)
# if defined(__LINUX__)
#  define PLATFORM_ID "Linux"

# elif defined(__DOS__)
#  define PLATFORM_ID "DOS"

# elif defined(__OS2__)
#  define PLATFORM_ID "OS2"

# elif defined(__WINDOWS__)
#  define PLATFORM_ID "Windows3x"

# elif defined(__VXWORKS__)
#  define PLATFORM_ID "VxWorks"

# else /* unknown platform */
#  define PLATFORM_ID
# endif

#elif defined(__INTEGRITY)
# if defined(INT_178B)
#  define PLATFORM_ID "Integrity178"

# else /* regular Integrity */
#  define PLATFORM_ID "Integrity"
# endif

# elif defined(_ADI_COMPILER)
#  define PLATFORM_ID "ADSP"

#else /* unknown platform */
# define PLATFORM_ID

#endif

/* For windows compilers MSVC and Intel we can determine
   the architecture of the compiler being used.  This is because
   the compilers do not have flags that can change the architecture,
   but rather depend on which compiler is being used
*/
#if defined(_WIN32) && defined(_MSC_VER)
# if defined(_M_IA64)
#  define ARCHITECTURE_ID "IA64"

# elif defined(_M_ARM64EC)
#  define ARCHITECTURE_ID "ARM64EC"

# elif defined(_M_X64) || defined(_M_AMD64)
#  define ARCHITECTURE_ID "x64"

# elif defined(_M_IX86)
#  define ARCHITECTURE_ID "X86"

# elif defined(_M_ARM64)
#  define ARCHITECTURE_ID "ARM64"

# elif defined(_M_ARM)
#  if _M_ARM == 4
#   define ARCHITECTURE_ID "ARMV4I"
#  elif _M_ARM == 5
#   define ARCHITECTURE_ID "ARMV5I"
#  else
#   define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
#  endif

# elif defined(_M_MIPS)
#  define ARCHITECTURE_ID "MIPS"

# elif defined(_M_SH)
#  define ARCHITECTURE_ID "SHx"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__WATCOMC__)
# if defined(_M_I86)
#  define ARCHITECTURE_ID "I86"

# elif defined(_M_IX86)
#  define ARCHITECTURE_ID "X86"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# if defined(__ICCARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__ICCRX__)
#  define ARCHITECTURE_ID "RX"

# elif defined(__ICCRH850__)
#  define ARCHITECTURE_ID "RH850"

# elif defined(__ICCRL78__)
#  define ARCHITECTURE_ID "RL78"

# elif defined(__ICCRISCV__)
#  define ARCHITECTURE_ID "RISCV"

# elif defined(__ICCAVR__)
#  define ARCHITECTURE_ID "AVR"

# elif defined(__ICC430__)
#  define ARCHITECTURE_ID "MSP430"

# elif defined(__ICCV850__)
#  define ARCHITECTURE_ID "V850"

# elif defined(__ICC8051__)
#  define ARCHITECTURE_ID "8051"

# elif defined(__ICCSTM8__)
#  define ARCHITECTURE_ID "STM8"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__ghs__)
# if defined(__PPC64__)
#  define ARCHITECTURE_ID "PPC64"

# elif defined(__ppc__)
#  define ARCHITECTURE_ID "PPC"

# elif defined(__ARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__x86_64__)
#  define ARCHITECTURE_ID "x64"

# elif defined(__i386__)
#  define ARCHITECTURE_ID "X86"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__TI_COMPILER_VERSION__)
# if defined(__TI_ARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__MSP430__)
#  define ARCHITECTURE_ID "MSP430"

# elif defined(__TMS320C28XX__)
#  define ARCHITECTURE_ID "TMS320C28x"

# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
#  define ARCHITECTURE_ID "TMS320C6x"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

# elif defined(__ADSPSHARC__)
#  define ARCHITECTURE_ID "SHARC"

# elif defined(__ADSPBLACKFIN__)
#  define ARCHITECTURE_ID "Blackfin"

#elif defined(__TASKING__)

# if defined(__CTC__) || defined(__CPTC__)
#  define ARCHITECTURE_ID "TriCore"

# elif defined(__CMCS__)
#  define ARCHITECTURE_ID "MCS"

# elif defined(__CARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__CARC__)
#  define ARCHITECTURE_ID "ARC"

# elif defined(__C51__)
#  define ARCHITECTURE_ID "8051"

# elif defined(__CPCP__)
#  define ARCHITECTURE_ID "PCP"

# else
#  define ARCHITECTURE_ID ""
# endif

#else
#  define ARCHITECTURE_ID
#endif

/* Convert integer to decimal digit literals.  */
#define DEC(n)                   \
  ('0' + (((n) / 10000000)%10)), \
  ('0' + (((n) / 1000000)%10)),  \
  ('0' + (((n) / 100000)%10)),   \
  ('0' + (((n) / 10000)%10)),    \
  ('0' + (((n) / 1000)%10)),     \
  ('0' + (((n) / 100)%10)),      \
  ('0' + (((n) / 10)%10)),       \
  ('0' +  ((n) % 10))

/* Convert integer to hex digit literals.  */
#define HEX(n)             \
  ('0' + ((n)>>28 & 0xF)), \
  ('0' + ((n)>>24 & 0xF)), \
  ('0' + ((n)>>20 & 0xF)), \
  ('0' + ((n)>>16 & 0xF)), \
  ('0' + ((n)>>12 & 0xF)), \
  ('0' + ((n)>>8  & 0xF)), \
  ('0' + ((n)>>4  & 0xF)), \
  ('0' + ((n)     & 0xF))

/* Construct a string literal encoding the version number. */
#ifdef COMPILER_VERSION
char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";

/* Construct a string literal encoding the version number components. */
#elif defined(COMPILER_VERSION_MAJOR)
char const info_version[] = {
  'I', 'N', 'F', 'O', ':',
  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
  COMPILER_VERSION_MAJOR,
# ifdef COMPILER_VERSION_MINOR
  '.', COMPILER_VERSION_MINOR,
#  ifdef COMPILER_VERSION_PATCH
   '.', COMPILER_VERSION_PATCH,
#   ifdef COMPILER_VERSION_TWEAK
    '.', COMPILER_VERSION_TWEAK,
#   endif
#  endif
# endif
  ']','\0'};
#endif

/* Construct a string literal encoding the internal version number. */
#ifdef COMPILER_VERSION_INTERNAL
char const info_version_internal[] = {
  'I', 'N', 'F', 'O', ':',
  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
  'i','n','t','e','r','n','a','l','[',
  COMPILER_VERSION_INTERNAL,']','\0'};
#elif defined(COMPILER_VERSION_INTERNAL_STR)
char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
#endif

/* Construct a string literal encoding the version number components. */
#ifdef SIMULATE_VERSION_MAJOR
char const info_simulate_version[] = {
  'I', 'N', 'F', 'O', ':',
  's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
  SIMULATE_VERSION_MAJOR,
# ifdef SIMULATE_VERSION_MINOR
  '.', SIMULATE_VERSION_MINOR,
#  ifdef SIMULATE_VERSION_PATCH
   '.', SIMULATE_VERSION_PATCH,
#   ifdef SIMULATE_VERSION_TWEAK
    '.', SIMULATE_VERSION_TWEAK,
#   endif
#  endif
# endif
  ']','\0'};
#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";



#if !defined(__STDC__) && !defined(__clang__)
# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__)
#  define C_VERSION "90"
# else
#  define C_VERSION
# endif
#elif __STDC_VERSION__ > 201710L
# define C_VERSION "23"
#elif __STDC_VERSION__ >= 201710L
# define C_VERSION "17"
#elif __STDC_VERSION__ >= 201000L
# define C_VERSION "11"
#elif __STDC_VERSION__ >= 199901L
# define C_VERSION "99"
#else
# define C_VERSION "90"
#endif
const char* info_language_standard_default =
  "INFO" ":" "standard_default[" C_VERSION "]";

const char* info_language_extensions_default = "INFO" ":" "extensions_default["
#if (defined(__clang__) || defined(__GNUC__) || defined(__xlC__) ||           \
     defined(__TI_COMPILER_VERSION__)) &&                                     \
  !defined(__STRICT_ANSI__)
  "ON"
#else
  "OFF"
#endif
"]";

/*--------------------------------------------------------------------------*/

#ifdef ID_VOID_MAIN
void main() {}
#else
# if defined(__CLASSIC_C__)
int main(argc, argv) int argc; char *argv[];
# else
int main(int argc, char* argv[])
# endif
{
  int require = 0;
  require += info_compiler[argc];
  require += info_platform[argc];
  require += info_arch[argc];
#ifdef COMPILER_VERSION_MAJOR
  require += info_version[argc];
#endif
#ifdef COMPILER_VERSION_INTERNAL
  require += info_version_internal[argc];
#endif
#ifdef SIMULATE_ID
  require += info_simulate[argc];
#endif
#ifdef SIMULATE_VERSION_MAJOR
  require += info_simulate_version[argc];
#endif
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
  require += info_cray[argc];
#endif
  require += info_language_standard_default[argc];
  require += info_language_extensions_default[argc];
  (void)argv;
  return require;
}
#endif

./build/CMakeFiles/cmake.check_cache

# This file is generated by cmake for dependency checking of the CMakeCache.txt file

./build/CMakeFiles/CMakeConfigureLog.yaml

---
events:
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake:233 (message)"
      - "CMakeLists.txt:2 (project)"
    message: |
      The system is: Linux - 6.14.0-29-generic - x86_64
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:17 (message)"
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:64 (__determine_compiler_id_test)"
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCCompiler.cmake:123 (CMAKE_DETERMINE_COMPILER_ID)"
      - "CMakeLists.txt:2 (project)"
    message: |
      Compiling the C compiler identification source file "CMakeCCompilerId.c" succeeded.
      Compiler: /usr/bin/gcc-12 
      Build flags: 
      Id flags:  
      
      The output was:
      0
      
      
      Compilation of the C compiler identification source "CMakeCCompilerId.c" produced "a.out"
      
      The C compiler identification is GNU, found in:
        /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/3.28.3/CompilerIdC/a.out
      
  -
    kind: "try_compile-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:57 (try_compile)"
      - "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
      - "CMakeLists.txt:2 (project)"
    checks:
      - "Detecting C compiler ABI info"
    directories:
      source: "/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau"
      binary: "/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau"
    cmakeVariables:
      CMAKE_C_FLAGS: ""
      CMAKE_C_FLAGS_DEBUG: "-g"
      CMAKE_EXE_LINKER_FLAGS: ""
    buildResult:
      variable: "CMAKE_C_ABI_COMPILED"
      cached: true
      stdout: |
        Change Dir: '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau'
        
        Run Build Command(s): /usr/bin/cmake -E env VERBOSE=1 /usr/bin/gmake -f Makefile cmTC_964bd/fast
        /usr/bin/gmake  -f CMakeFiles/cmTC_964bd.dir/build.make CMakeFiles/cmTC_964bd.dir/build
        gmake[1]: Entering directory '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau'
        Building C object CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o
        /usr/bin/gcc-12   -v -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -c /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c
        Using built-in specs.
        COLLECT_GCC=/usr/bin/gcc-12
        OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
        OFFLOAD_TARGET_DEFAULT=1
        Target: x86_64-linux-gnu
        Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
        Thread model: posix
        Supported LTO compression algorithms: zlib zstd
        gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) 
        COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/'
         /usr/lib/gcc/x86_64-linux-gnu/12/cc1 -quiet -v -imultiarch x86_64-linux-gnu /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c -quiet -dumpdir CMakeFiles/cmTC_964bd.dir/ -dumpbase CMakeCCompilerABI.c.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/cc3SVGrU.s
        GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)
        	compiled by GNU C version 12.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP
        
        GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
        ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
        ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/include-fixed"
        ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include"
        #include "..." search starts here:
        #include <...> search starts here:
         /usr/lib/gcc/x86_64-linux-gnu/12/include
         /usr/local/include
         /usr/include/x86_64-linux-gnu
         /usr/include
        End of search list.
        GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)
        	compiled by GNU C version 12.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP
        
        GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
        Compiler executable checksum: 80b6e71efd51e0718437238f59d9f3d5
        COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/'
         as -v --64 -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o /tmp/cc3SVGrU.s
        GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42
        COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/
        LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/
        COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.'
        Linking C executable cmTC_964bd
        /usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_964bd.dir/link.txt --verbose=1
        /usr/bin/gcc-12  -v CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -o cmTC_964bd 
        Using built-in specs.
        COLLECT_GCC=/usr/bin/gcc-12
        COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper
        OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
        OFFLOAD_TARGET_DEFAULT=1
        Target: x86_64-linux-gnu
        Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
        Thread model: posix
        Supported LTO compression algorithms: zlib zstd
        gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) 
        COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/
        LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/
        COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_964bd' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_964bd.'
         /usr/lib/gcc/x86_64-linux-gnu/12/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/12/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper -plugin-opt=-fresolution=/tmp/ccWyJEFN.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_964bd /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/12 -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/12/../../.. CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o
        COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_964bd' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_964bd.'
        gmake[1]: Leaving directory '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau'
        
      exitCode: 0
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:127 (message)"
      - "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
      - "CMakeLists.txt:2 (project)"
    message: |
      Parsed C implicit include dir info: rv=done
        found start of include info
        found start of implicit include info
          add: [/usr/lib/gcc/x86_64-linux-gnu/12/include]
          add: [/usr/local/include]
          add: [/usr/include/x86_64-linux-gnu]
          add: [/usr/include]
        end of search list found
        collapse include dir [/usr/lib/gcc/x86_64-linux-gnu/12/include] ==> [/usr/lib/gcc/x86_64-linux-gnu/12/include]
        collapse include dir [/usr/local/include] ==> [/usr/local/include]
        collapse include dir [/usr/include/x86_64-linux-gnu] ==> [/usr/include/x86_64-linux-gnu]
        collapse include dir [/usr/include] ==> [/usr/include]
        implicit include dirs: [/usr/lib/gcc/x86_64-linux-gnu/12/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include]
      
      
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:159 (message)"
      - "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
      - "CMakeLists.txt:2 (project)"
    message: |
      Parsed C implicit link information:
        link line regex: [^( *|.*[/\\])(ld|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\\]+-)?ld|collect2)[^/\\]*( |$)]
        ignore line: [Change Dir: '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau']
        ignore line: []
        ignore line: [Run Build Command(s): /usr/bin/cmake -E env VERBOSE=1 /usr/bin/gmake -f Makefile cmTC_964bd/fast]
        ignore line: [/usr/bin/gmake  -f CMakeFiles/cmTC_964bd.dir/build.make CMakeFiles/cmTC_964bd.dir/build]
        ignore line: [gmake[1]: Entering directory '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau']
        ignore line: [Building C object CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o]
        ignore line: [/usr/bin/gcc-12   -v -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -c /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c]
        ignore line: [Using built-in specs.]
        ignore line: [COLLECT_GCC=/usr/bin/gcc-12]
        ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa]
        ignore line: [OFFLOAD_TARGET_DEFAULT=1]
        ignore line: [Target: x86_64-linux-gnu]
        ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
        ignore line: [Thread model: posix]
        ignore line: [Supported LTO compression algorithms: zlib zstd]
        ignore line: [gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) ]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/']
        ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/12/cc1 -quiet -v -imultiarch x86_64-linux-gnu /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c -quiet -dumpdir CMakeFiles/cmTC_964bd.dir/ -dumpbase CMakeCCompilerABI.c.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/cc3SVGrU.s]
        ignore line: [GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)]
        ignore line: [	compiled by GNU C version 12.3.0  GMP version 6.3.0  MPFR version 4.2.1  MPC version 1.3.1  isl version isl-0.26-GMP]
        ignore line: []
        ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
        ignore line: [ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"]
        ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/include-fixed"]
        ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include"]
        ignore line: [#include "..." search starts here:]
        ignore line: [#include <...> search starts here:]
        ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/12/include]
        ignore line: [ /usr/local/include]
        ignore line: [ /usr/include/x86_64-linux-gnu]
        ignore line: [ /usr/include]
        ignore line: [End of search list.]
        ignore line: [GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)]
        ignore line: [	compiled by GNU C version 12.3.0  GMP version 6.3.0  MPFR version 4.2.1  MPC version 1.3.1  isl version isl-0.26-GMP]
        ignore line: []
        ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
        ignore line: [Compiler executable checksum: 80b6e71efd51e0718437238f59d9f3d5]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/']
        ignore line: [ as -v --64 -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o /tmp/cc3SVGrU.s]
        ignore line: [GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42]
        ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/]
        ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.']
        ignore line: [Linking C executable cmTC_964bd]
        ignore line: [/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_964bd.dir/link.txt --verbose=1]
        ignore line: [/usr/bin/gcc-12  -v CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -o cmTC_964bd ]
        ignore line: [Using built-in specs.]
        ignore line: [COLLECT_GCC=/usr/bin/gcc-12]
        ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper]
        ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa]
        ignore line: [OFFLOAD_TARGET_DEFAULT=1]
        ignore line: [Target: x86_64-linux-gnu]
        ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
        ignore line: [Thread model: posix]
        ignore line: [Supported LTO compression algorithms: zlib zstd]
        ignore line: [gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) ]
        ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/]
        ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_964bd' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_964bd.']
        link line: [ /usr/lib/gcc/x86_64-linux-gnu/12/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/12/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper -plugin-opt=-fresolution=/tmp/ccWyJEFN.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_964bd /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/12 -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/12/../../.. CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/collect2] ==> ignore
          arg [-plugin] ==> ignore
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/liblto_plugin.so] ==> ignore
          arg [-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper] ==> ignore
          arg [-plugin-opt=-fresolution=/tmp/ccWyJEFN.res] ==> ignore
          arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
          arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore
          arg [-plugin-opt=-pass-through=-lc] ==> ignore
          arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
          arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore
          arg [--build-id] ==> ignore
          arg [--eh-frame-hdr] ==> ignore
          arg [-m] ==> ignore
          arg [elf_x86_64] ==> ignore
          arg [--hash-style=gnu] ==> ignore
          arg [--as-needed] ==> ignore
          arg [-dynamic-linker] ==> ignore
          arg [/lib64/ld-linux-x86-64.so.2] ==> ignore
          arg [-pie] ==> ignore
          arg [-znow] ==> ignore
          arg [-zrelro] ==> ignore
          arg [-o] ==> ignore
          arg [cmTC_964bd] ==> ignore
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/12]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib]
          arg [-L/lib/x86_64-linux-gnu] ==> dir [/lib/x86_64-linux-gnu]
          arg [-L/lib/../lib] ==> dir [/lib/../lib]
          arg [-L/usr/lib/x86_64-linux-gnu] ==> dir [/usr/lib/x86_64-linux-gnu]
          arg [-L/usr/lib/../lib] ==> dir [/usr/lib/../lib]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12/../../..] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../..]
          arg [CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o] ==> ignore
          arg [-lgcc] ==> lib [gcc]
          arg [--push-state] ==> ignore
          arg [--as-needed] ==> ignore
          arg [-lgcc_s] ==> lib [gcc_s]
          arg [--pop-state] ==> ignore
          arg [-lc] ==> lib [c]
          arg [-lgcc] ==> lib [gcc]
          arg [--push-state] ==> ignore
          arg [--as-needed] ==> ignore
          arg [-lgcc_s] ==> lib [gcc_s]
          arg [--pop-state] ==> ignore
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o]
        collapse obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o] ==> [/usr/lib/x86_64-linux-gnu/Scrt1.o]
        collapse obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o] ==> [/usr/lib/x86_64-linux-gnu/crti.o]
        collapse obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o] ==> [/usr/lib/x86_64-linux-gnu/crtn.o]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12] ==> [/usr/lib/gcc/x86_64-linux-gnu/12]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib] ==> [/usr/lib]
        collapse library dir [/lib/x86_64-linux-gnu] ==> [/lib/x86_64-linux-gnu]
        collapse library dir [/lib/../lib] ==> [/lib]
        collapse library dir [/usr/lib/x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
        collapse library dir [/usr/lib/../lib] ==> [/usr/lib]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../..] ==> [/usr/lib]
        implicit libs: [gcc;gcc_s;c;gcc;gcc_s]
        implicit objs: [/usr/lib/x86_64-linux-gnu/Scrt1.o;/usr/lib/x86_64-linux-gnu/crti.o;/usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o;/usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o;/usr/lib/x86_64-linux-gnu/crtn.o]
        implicit dirs: [/usr/lib/gcc/x86_64-linux-gnu/12;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib]
        implicit fwks: []
      
      
...

./build/CMakeFiles/CMakeDirectoryInformation.cmake

# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Relative path conversion top directories.
set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/ubuntu/Desktop/gameboy-perfect-core")
set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/ubuntu/Desktop/gameboy-perfect-core/build")

# Force unix paths in dependencies.
set(CMAKE_FORCE_UNIX_PATHS 1)


# The C and CXX include file regular expressions for this directory.
set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$")
set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$")
set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})
set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN})

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/build.make

# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Delete rule output on recipe failure.
.DELETE_ON_ERROR:

#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:

# Disable VCS-based implicit rules.
% : %,v

# Disable VCS-based implicit rules.
% : RCS/%

# Disable VCS-based implicit rules.
% : RCS/%,v

# Disable VCS-based implicit rules.
% : SCCS/s.%

# Disable VCS-based implicit rules.
% : s.%

.SUFFIXES: .hpux_make_needs_suffix_list

# Command-line flag to silence nested $(MAKE).
$(VERBOSE)MAKESILENT = -s

#Suppress display of executed commands.
$(VERBOSE).SILENT:

# A target that is always out of date.
cmake_force:
.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake

# The command to remove a file.
RM = /usr/bin/cmake -E rm -f

# Escaping for special characters.
EQUALS = =

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/ubuntu/Desktop/gameboy-perfect-core

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/ubuntu/Desktop/gameboy-perfect-core/build

# Include any dependencies generated for this target.
include CMakeFiles/gameboy_perfect_core_libretro.dir/depend.make
# Include any dependencies generated by the compiler for this target.
include CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.make

# Include the progress variables for this target.
include CMakeFiles/gameboy_perfect_core_libretro.dir/progress.make

# Include the compile flags for this target's objects.
include CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_5) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_6) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_7) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_8) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c > CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s

# Object files for target gameboy_perfect_core_libretro
gameboy_perfect_core_libretro_OBJECTS = \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o"

# External object files for target gameboy_perfect_core_libretro
gameboy_perfect_core_libretro_EXTERNAL_OBJECTS =

gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/build.make
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/link.txt
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --bold --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_9) "Linking C shared library gameboy_perfect_core_libretro.so"
	$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/gameboy_perfect_core_libretro.dir/link.txt --verbose=$(VERBOSE)

# Rule to build all files generated by this target.
CMakeFiles/gameboy_perfect_core_libretro.dir/build: gameboy_perfect_core_libretro.so
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/build

CMakeFiles/gameboy_perfect_core_libretro.dir/clean:
	$(CMAKE_COMMAND) -P CMakeFiles/gameboy_perfect_core_libretro.dir/cmake_clean.cmake
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/clean

CMakeFiles/gameboy_perfect_core_libretro.dir/depend:
	cd /home/ubuntu/Desktop/gameboy-perfect-core/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Desktop/gameboy-perfect-core /home/ubuntu/Desktop/gameboy-perfect-core /home/ubuntu/Desktop/gameboy-perfect-core/build /home/ubuntu/Desktop/gameboy-perfect-core/build /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/gameboy_perfect_core_libretro.dir/DependInfo.cmake "--color=$(COLOR)"
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/depend

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/cmake_clean.cmake

file(REMOVE_RECURSE
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o.d"
  "gameboy_perfect_core_libretro.pdb"
  "gameboy_perfect_core_libretro.so"
)

# Per-language clean rules from dependency scanning.
foreach(lang C)
  include(CMakeFiles/gameboy_perfect_core_libretro.dir/cmake_clean_${lang}.cmake OPTIONAL)
endforeach()

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.make

# Empty compiler generated dependencies file for gameboy_perfect_core_libretro.
# This may be replaced when dependencies are built.

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts

# CMAKE generated file: DO NOT EDIT!
# Timestamp file for compiler generated dependencies management for gameboy_perfect_core_libretro.

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/DependInfo.cmake

# Consider dependencies only in project.
set(CMAKE_DEPENDS_IN_PROJECT_ONLY OFF)

# The set of languages for which implicit dependencies are needed:
set(CMAKE_DEPENDS_LANGUAGES
  )

# The set of dependency files which are needed:
set(CMAKE_DEPENDS_DEPENDENCY_FILES
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o.d"
  )

# Targets to which this target links which contain Fortran sources.
set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES
  )

# Targets to which this target links which contain Fortran sources.
set(CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES
  )

# Fortran module output directory.
set(CMAKE_Fortran_TARGET_MODULE_DIR "")

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/depend.make

# Empty dependencies file for gameboy_perfect_core_libretro.
# This may be replaced when dependencies are built.

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make

# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# compile C with /usr/bin/gcc-12
C_DEFINES = -Dgameboy_perfect_core_libretro_EXPORTS

C_INCLUDES = -I/home/ubuntu/Desktop/gameboy-perfect-core/include -I/home/ubuntu/Desktop/gameboy-perfect-core/include/libretro-common/include

C_FLAGS = -std=gnu99 -fPIC

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/link.txt

/usr/bin/gcc-12 -fPIC -shared -Wl,-soname,gameboy_perfect_core_libretro.so -o gameboy_perfect_core_libretro.so CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o 

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/progress.make

CMAKE_PROGRESS_1 = 1
CMAKE_PROGRESS_2 = 2
CMAKE_PROGRESS_3 = 3
CMAKE_PROGRESS_4 = 4
CMAKE_PROGRESS_5 = 5
CMAKE_PROGRESS_6 = 6
CMAKE_PROGRESS_7 = 7
CMAKE_PROGRESS_8 = 8
CMAKE_PROGRESS_9 = 9

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o

ELF>	@@
UHHEHEf(fHn
f/v
UHH}HEHEf1ЃfEHEfE	ЉHEfHEt
]UHHH}HEXHHE@<HEf@8HE@D_UHHH}HEHUHH H}uHEPHEHEPHHEPHHE@D9HEPHHE@D)HEPHfEHEt>HEHXHE@HEH@fHnMMXEHE@t>HEH XHE@ HEH@ fHnMXEHE@tkHEH(XHE@(HEH@(f(fHn
YfZf~fnMXEHE@tHEH8HMXEHEH<YMYEHEE@LHEE@PUHH}HE@L]UHH}HE@P]???>kJn?C|?kJn?-DT!@>GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0GNUzRxIAC
D<eAC
`\OEC
F|EC
VEC
EC
NEC
NIIe %O18EQViapu.csquare_wavenoise_samplefmodgb_apu_initmemsetgb_apu_resetgb_apu_stepsinfgb_apu_sample_leftgb_apu_sample_right#+9C$$,AOW4p< @I`.symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.note.gnu.property.rela.eh_frame @@&^,^1`D90'BR je@h	P	8}	t

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdbool.h /usr/include/math.h \
 /usr/include/x86_64-linux-gnu/bits/math-vector.h \
 /usr/include/x86_64-linux-gnu/bits/libm-simd-decl-stubs.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/include/x86_64-linux-gnu/bits/flt-eval-method.h \
 /usr/include/x86_64-linux-gnu/bits/fp-logb.h \
 /usr/include/x86_64-linux-gnu/bits/fp-fast.h \
 /usr/include/x86_64-linux-gnu/bits/mathcalls-helper-functions.h \
 /usr/include/x86_64-linux-gnu/bits/mathcalls.h /usr/include/string.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \
 /usr/include/strings.h

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o

ELF>@@UH]UHfUfE]UH]GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0GNUzRxEC
B<EC
N\EC
B	!"audio.caudio_initaudio_sampleaudio_update @`".symtab.strtab.shstrtab.text.data.bss.comment.note.GNU-stack.note.gnu.property.rela.eh_frame@-!m'm,0m'5E ]xX@H	0
	.8g

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h /usr/include/stdlib.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/waitflags.h \
 /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/include/x86_64-linux-gnu/sys/types.h \
 /usr/include/x86_64-linux-gnu/bits/types/clock_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/clockid_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/time_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/timer_t.h /usr/include/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endianness.h \
 /usr/include/x86_64-linux-gnu/bits/byteswap.h \
 /usr/include/x86_64-linux-gnu/bits/uintn-identity.h \
 /usr/include/x86_64-linux-gnu/sys/select.h \
 /usr/include/x86_64-linux-gnu/bits/select.h \
 /usr/include/x86_64-linux-gnu/bits/types/sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
 /usr/include/x86_64-linux-gnu/bits/thread-shared-types.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes-arch.h \
 /usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h \
 /usr/include/x86_64-linux-gnu/bits/struct_mutex.h \
 /usr/include/x86_64-linux-gnu/bits/struct_rwlock.h /usr/include/alloca.h \
 /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdbool.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h \
 /usr/include/string.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \
 /usr/include/strings.h

./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdbool.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h \
 /usr/include/stdlib.h /usr/lib/gcc/x86_64-linux-gnu/12/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/waitflags.h \
 /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/include/x86_64-linux-gnu/sys/types.h \
 /usr/include/x86_64-linux-gnu/bits/types/clock_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/clockid_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/time_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/timer_t.h /usr/include/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endianness.h \
 /usr/include/x86_64-linux-gnu/bits/byteswap.h \
 /usr/include/x86_64-linux-gnu/bits/uintn-identity.h \
 /usr/include/x86_64-linux-gnu/sys/select.h \
 /usr/include/x86_64-linux-gnu/bits/select.h \
 /usr/include/x86_64-linux-gnu/bits/types/sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
 /usr/include/x86_64-linux-gnu/bits/thread-shared-types.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes-arch.h \
 /usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h \
 /usr/include/x86_64-linux-gnu/bits/struct_mutex.h \
 /usr/include/x86_64-linux-gnu/bits/struct_rwlock.h /usr/include/alloca.h \
 /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h \
 /usr/include/string.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \
 /usr/include/strings.h

./build/CMakeFiles/Makefile2

# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target

#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:

# Disable VCS-based implicit rules.
% : %,v

# Disable VCS-based implicit rules.
% : RCS/%

# Disable VCS-based implicit rules.
% : RCS/%,v

# Disable VCS-based implicit rules.
% : SCCS/s.%

# Disable VCS-based implicit rules.
% : s.%

.SUFFIXES: .hpux_make_needs_suffix_list

# Command-line flag to silence nested $(MAKE).
$(VERBOSE)MAKESILENT = -s

#Suppress display of executed commands.
$(VERBOSE).SILENT:

# A target that is always out of date.
cmake_force:
.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake

# The command to remove a file.
RM = /usr/bin/cmake -E rm -f

# Escaping for special characters.
EQUALS = =

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/ubuntu/Desktop/gameboy-perfect-core

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/ubuntu/Desktop/gameboy-perfect-core/build

#=============================================================================
# Directory level rules for the build root directory

# The main recursive "all" target.
all: CMakeFiles/gameboy_perfect_core_libretro.dir/all
.PHONY : all

# The main recursive "preinstall" target.
preinstall:
.PHONY : preinstall

# The main recursive "clean" target.
clean: CMakeFiles/gameboy_perfect_core_libretro.dir/clean
.PHONY : clean

#=============================================================================
# Target rules for target CMakeFiles/gameboy_perfect_core_libretro.dir

# All Build rule for target.
CMakeFiles/gameboy_perfect_core_libretro.dir/all:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/depend
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/build
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=1,2,3,4,5,6,7,8,9 "Built target gameboy_perfect_core_libretro"
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/all

# Build rule for subdir invocation for target.
CMakeFiles/gameboy_perfect_core_libretro.dir/rule: cmake_check_build_system
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles 9
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 CMakeFiles/gameboy_perfect_core_libretro.dir/all
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles 0
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/rule

# Convenience name for target.
gameboy_perfect_core_libretro: CMakeFiles/gameboy_perfect_core_libretro.dir/rule
.PHONY : gameboy_perfect_core_libretro

# clean rule for target.
CMakeFiles/gameboy_perfect_core_libretro.dir/clean:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/clean
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/clean

#=============================================================================
# Special targets to cleanup operation of make.

# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system

./build/CMakeFiles/Makefile.cmake

# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# The generator used is:
set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles")

# The top level Makefile was generated from the following files:
set(CMAKE_MAKEFILE_DEPENDS
  "CMakeCache.txt"
  "/home/ubuntu/Desktop/gameboy-perfect-core/CMakeLists.txt"
  "CMakeFiles/3.28.3/CMakeCCompiler.cmake"
  "CMakeFiles/3.28.3/CMakeSystem.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeCCompiler.cmake.in"
  "/usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c"
  "/usr/share/cmake-3.28/Modules/CMakeCInformation.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeCommonLanguageInclude.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeCompilerIdDetection.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompileFeatures.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeFindBinUtils.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeGenericSystem.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeInitializeConfigs.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeLanguageInformation.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeParseImplicitIncludeInfo.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeParseImplicitLinkInfo.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeParseLibraryArchitecture.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeSystem.cmake.in"
  "/usr/share/cmake-3.28/Modules/CMakeSystemSpecificInformation.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeSystemSpecificInitialize.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeTestCompilerCommon.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeUnixFindMake.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/ADSP-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/ARMCC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/ARMClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/AppleClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Borland-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Bruce-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Clang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Compaq-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Cray-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/CrayClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Embarcadero-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Fujitsu-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GHS-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU-C.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU-FindBinUtils.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/HP-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IAR-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IBMClang-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Intel-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/LCC-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/MSVC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/NVHPC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/NVIDIA-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/OrangeC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/PGI-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/PathScale-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/SCO-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/SDCC-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/SunPro-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/TI-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Tasking-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Watcom-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/XL-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/XLClang-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/zOS-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Internal/FeatureTesting.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux-GNU-C.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux-GNU.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux-Initialize.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/UnixPaths.cmake"
  )

# The corresponding makefile is:
set(CMAKE_MAKEFILE_OUTPUTS
  "Makefile"
  "CMakeFiles/cmake.check_cache"
  )

# Byproducts of CMake generate step:
set(CMAKE_MAKEFILE_PRODUCTS
  "CMakeFiles/3.28.3/CMakeSystem.cmake"
  "CMakeFiles/3.28.3/CMakeCCompiler.cmake"
  "CMakeFiles/3.28.3/CMakeCCompiler.cmake"
  "CMakeFiles/CMakeDirectoryInformation.cmake"
  )

# Dependency information for all targets:
set(CMAKE_DEPEND_INFO_FILES
  "CMakeFiles/gameboy_perfect_core_libretro.dir/DependInfo.cmake"
  )

./build/CMakeFiles/Progress/1

empty

./build/CMakeFiles/Progress/2

empty

./build/CMakeFiles/Progress/3

empty

./build/CMakeFiles/Progress/4

empty

./build/CMakeFiles/Progress/count.txt

9

./build/CMakeFiles/progress.marks

9

./build/CMakeFiles/TargetDirectories.txt

/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/gameboy_perfect_core_libretro.dir
/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/edit_cache.dir
/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/rebuild_cache.dir

./build/cmake_install.cmake

# Install script for directory: /home/ubuntu/Desktop/gameboy-perfect-core

# Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
  set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")

# Set the install configuration name.
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
  if(BUILD_TYPE)
    string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
           CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
  else()
    set(CMAKE_INSTALL_CONFIG_NAME "")
  endif()
  message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
endif()

# Set the component getting installed.
if(NOT CMAKE_INSTALL_COMPONENT)
  if(COMPONENT)
    message(STATUS "Install component: \"${COMPONENT}\"")
    set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
  else()
    set(CMAKE_INSTALL_COMPONENT)
  endif()
endif()

# Install shared libraries without execute permission?
if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
  set(CMAKE_INSTALL_SO_NO_EXE "1")
endif()

# Is this installation the result of a crosscompile?
if(NOT DEFINED CMAKE_CROSSCOMPILING)
  set(CMAKE_CROSSCOMPILING "FALSE")
endif()

# Set default install directory permissions.
if(NOT DEFINED CMAKE_OBJDUMP)
  set(CMAKE_OBJDUMP "/usr/bin/objdump")
endif()

if(CMAKE_INSTALL_COMPONENT)
  set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
else()
  set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
endif()

string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
       "${CMAKE_INSTALL_MANIFEST_FILES}")
file(WRITE "/home/ubuntu/Desktop/gameboy-perfect-core/build/${CMAKE_INSTALL_MANIFEST}"
     "${CMAKE_INSTALL_MANIFEST_CONTENT}")

./build_log.txt

[*] Cleaning old build...
[*] Configuring with CMake...
-- The C compiler identification is GNU 12.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/gcc-12 - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /home/ubuntu/Desktop/gameboy-perfect-core/build
[*] Building...
[ 11%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
[ 22%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘->’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘->’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:35: error: unknown type name ‘uint8_t’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                   ^~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:1: note: ‘uint8_t’ is defined in header ‘<stdint.h>’; did you forget to ‘#include <stdint.h>’?
  +++ |+#include <stdint.h>
    1 |       |                                                    ^~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘->’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘->’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘->’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘->’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘->’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
[ 33%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘->’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘->’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:8,
                 from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘->’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘->’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘->’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:2:
/usr/include/string.h:44:22: error: unknown type name ‘size_t’
   44 |                      size_t __n) __THROW __nonnull ((1, 2));
      |                      ^~~~~~
/usr/include/string.h:34:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
   33 | #include <stddef.h>
  +++ |+#include <stddef.h>
   34 | 
/usr/include/string.h:47:56: error: unknown type name ‘size_t’
   47 | extern void *memmove (void *__dest, const void *__src, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:47:56: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:55:32: error: unknown type name ‘size_t’
   55 |                       int __c, size_t __n)
      |                                ^~~~~~
/usr/include/string.h:55:32: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:61:42: error: unknown type name ‘size_t’
   61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
      |                                          ^~~~~~
/usr/include/string.h:61:42: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:64:56: error: unknown type name ‘size_t’
   64 | extern int memcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:64:56: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:80:60: error: unknown type name ‘size_t’
   80 | extern int __memcmpeq (const void *__s1, const void *__s2, size_t __n)
      |                                                            ^~~~~~
/usr/include/string.h:80:60: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:107:48: error: unknown type name ‘size_t’
  107 | extern void *memchr (const void *__s, int __c, size_t __n)
      |                                                ^~~~~~
/usr/include/string.h:107:48: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:145:53: error: unknown type name ‘size_t’
  145 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:145:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:153:23: error: unknown type name ‘size_t’
  153 |                       size_t __n) __THROW __nonnull ((1, 2));
      |                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘->’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:153:23: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:159:57: error: unknown type name ‘size_t’
  159 | extern int strncmp (const char *__s1, const char *__s2, size_t __n)
      |                                                         ^~~~~~
/usr/include/string.h:159:57: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/usr/include/string.h:166:8: error: unknown type name ‘size_t’
  166 | extern size_t strxfrm (char *__restrict __dest,
      |        ^~~~~~
/usr/include/string.h:167:54: error: unknown type name ‘size_t’
  167 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:167:54: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:179:8: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |        ^~~~~~
/usr/include/string.h:179:59: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |                                                           ^~~~~~
/usr/include/string.h:179:59: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:195:45: error: unknown type name ‘size_t’
  195 | extern char *strndup (const char *__string, size_t __n)
      |                                             ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:195:45: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/usr/include/string.h:293:8: error: unknown type name ‘size_t’
  293 | extern size_t strcspn (const char *__s, const char *__reject)
      |        ^~~~~~
/usr/include/string.h:297:8: error: unknown type name ‘size_t’
  297 | extern size_t strspn (const char *__s, const char *__accept)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/usr/include/string.h:389:46: error: unknown type name ‘size_t’
  389 | extern void *memmem (const void *__haystack, size_t __haystacklen,
      |                                              ^~~~~~
/usr/include/string.h:389:46: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:390:44: error: unknown type name ‘size_t’
  390 |                      const void *__needle, size_t __needlelen)
      |                                            ^~~~~~
/usr/include/string.h:390:44: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:398:55: error: unknown type name ‘size_t’
  398 |                         const void *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/usr/include/string.h:398:55: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/usr/include/string.h:401:53: error: unknown type name ‘size_t’
  401 |                       const void *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:401:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:407:8: error: unknown type name ‘size_t’
  407 | extern size_t strlen (const char *__s)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/usr/include/string.h:413:8: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |        ^~~~~~
/usr/include/string.h:413:46: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:413:46: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘->’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
In file included from /usr/include/features.h:502,
                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
                 from /usr/include/string.h:26:
/usr/include/string.h:432:12: error: unknown type name ‘size_t’
  432 | extern int __REDIRECT_NTH (strerror_r,
      |            ^~~~~~~~~~~~~~
/usr/include/string.h:432:12: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
In file included from /usr/include/string.h:462:
/usr/include/strings.h:34:54: error: unknown type name ‘size_t’
   34 | extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                      ^~~~~~
/usr/include/strings.h:24:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
   23 | #include <stddef.h>
  +++ |+#include <stddef.h>
   24 | 
/usr/include/strings.h:38:53: error: unknown type name ‘size_t’
   38 | extern void bcopy (const void *__src, void *__dest, size_t __n)
      |                                                     ^~~~~~
/usr/include/strings.h:38:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/strings.h:42:31: error: unknown type name ‘size_t’
   42 | extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
      |                               ^~~~~~
/usr/include/strings.h:42:31: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/usr/include/strings.h:120:61: error: unknown type name ‘size_t’
  120 | extern int strncasecmp (const char *__s1, const char *__s2, size_t __n)
      |                                                             ^~~~~~
/usr/include/strings.h:120:61: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/strings.h:134:27: error: unknown type name ‘size_t’
  134 |                           size_t __n, locale_t __loc)
      |                           ^~~~~~
/usr/include/strings.h:134:27: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:466:40: error: unknown type name ‘size_t’
  466 | extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1))
      |                                        ^~~~~~
/usr/include/string.h:466:40: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:497:55: error: unknown type name ‘size_t’
  497 |                         const char *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘->’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/string.h:497:55: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:500:53: error: unknown type name ‘size_t’
  500 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:500:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:506:8: error: unknown type name ‘size_t’
  506 | extern size_t strlcpy (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:507:54: error: unknown type name ‘size_t’
  507 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:507:54: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:512:8: error: unknown type name ‘size_t’
  512 | extern size_t strlcat (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:513:54: error: unknown type name ‘size_t’
  513 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:513:54: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:5:19: error: unknown type name ‘gb_apu_t’
    5 | void gb_apu_reset(gb_apu_t *apu) {
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:11:18: error: unknown type name ‘gb_apu_t’
   11 | void gb_apu_step(gb_apu_t *apu, int cycles) {
      |                  ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:90: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘->’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘->’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘->’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: data definition has no type or storage class
   17 | } core_state_t;
      |   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: type defaults to ‘int’ in declaration of ‘core_state_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:19:1: error: unknown type name ‘core_state_t’
   19 | core_state_t* gb_core_create(void);
      | ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:20:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   20 | void gb_core_destroy(core_state_t* state);
      |                      ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_init(core_state_t* state, const uint8_t* rom_data, size_t rom_size);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:22:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   22 | void gb_core_step(core_state_t* state);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:23:25: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   23 | int gb_core_frame_ready(core_state_t* state);
      |                         ^~~~~~~~~~~~
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:4:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘->’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘->’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: error: redefinition of ‘val’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘->’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘->’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘->’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘->’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘->’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘->’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘->’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:5:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: data definition has no type or storage class
   25 | } gb_mmu_t;
      |   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: type defaults to ‘int’ in declaration of ‘gb_mmu_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:28:19: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   28 | void gb_mmu_reset(gb_mmu_t *mmu);
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:31:26: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   31 | uint8_t gb_mmu_read_byte(gb_mmu_t *mmu, uint16_t addr);
      |                          ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:34:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   34 | void gb_mmu_write_byte(gb_mmu_t *mmu, uint16_t addr, uint8_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:37:27: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   37 | uint16_t gb_mmu_read_word(gb_mmu_t *mmu, uint16_t addr);
      |                           ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:40:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   40 | void gb_mmu_write_word(gb_mmu_t *mmu, uint16_t addr, uint16_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:9:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
    9 | void gb_core_init(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_step(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:28:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   28 | void gb_core_destroy(core_state_t *state) {
      |                      ^~~~~~~~~~~~
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:104: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/gameboy_perfect_core_libretro.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

./build/Makefile

# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target

# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:

#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:

# Disable VCS-based implicit rules.
% : %,v

# Disable VCS-based implicit rules.
% : RCS/%

# Disable VCS-based implicit rules.
% : RCS/%,v

# Disable VCS-based implicit rules.
% : SCCS/s.%

# Disable VCS-based implicit rules.
% : s.%

.SUFFIXES: .hpux_make_needs_suffix_list

# Command-line flag to silence nested $(MAKE).
$(VERBOSE)MAKESILENT = -s

#Suppress display of executed commands.
$(VERBOSE).SILENT:

# A target that is always out of date.
cmake_force:
.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake

# The command to remove a file.
RM = /usr/bin/cmake -E rm -f

# Escaping for special characters.
EQUALS = =

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/ubuntu/Desktop/gameboy-perfect-core

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/ubuntu/Desktop/gameboy-perfect-core/build

#=============================================================================
# Targets provided globally by CMake.

# Special rule for the target edit_cache
edit_cache:
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "No interactive CMake dialog available..."
	/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
.PHONY : edit_cache

# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast

# Special rule for the target rebuild_cache
rebuild_cache:
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..."
	/usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache

# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast

# The main all target
all: cmake_check_build_system
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles /home/ubuntu/Desktop/gameboy-perfect-core/build//CMakeFiles/progress.marks
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles 0
.PHONY : all

# The main clean target
clean:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean
.PHONY : clean

# The main clean target
clean/fast: clean
.PHONY : clean/fast

# Prepare targets for installation.
preinstall: all
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall

# Prepare targets for installation.
preinstall/fast:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall/fast

# clear depends
depend:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
.PHONY : depend

#=============================================================================
# Target rules for targets named gameboy_perfect_core_libretro

# Build rule for target.
gameboy_perfect_core_libretro: cmake_check_build_system
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 gameboy_perfect_core_libretro
.PHONY : gameboy_perfect_core_libretro

# fast build rule for target.
gameboy_perfect_core_libretro/fast:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/build
.PHONY : gameboy_perfect_core_libretro/fast

src/common/apu.o: src/common/apu.c.o
.PHONY : src/common/apu.o

# target to build an object file
src/common/apu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
.PHONY : src/common/apu.c.o

src/common/apu.i: src/common/apu.c.i
.PHONY : src/common/apu.i

# target to preprocess a source file
src/common/apu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i
.PHONY : src/common/apu.c.i

src/common/apu.s: src/common/apu.c.s
.PHONY : src/common/apu.s

# target to generate assembly for a file
src/common/apu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s
.PHONY : src/common/apu.c.s

src/common/audio.o: src/common/audio.c.o
.PHONY : src/common/audio.o

# target to build an object file
src/common/audio.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
.PHONY : src/common/audio.c.o

src/common/audio.i: src/common/audio.c.i
.PHONY : src/common/audio.i

# target to preprocess a source file
src/common/audio.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i
.PHONY : src/common/audio.c.i

src/common/audio.s: src/common/audio.c.s
.PHONY : src/common/audio.s

# target to generate assembly for a file
src/common/audio.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s
.PHONY : src/common/audio.c.s

src/common/core_state.o: src/common/core_state.c.o
.PHONY : src/common/core_state.o

# target to build an object file
src/common/core_state.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
.PHONY : src/common/core_state.c.o

src/common/core_state.i: src/common/core_state.c.i
.PHONY : src/common/core_state.i

# target to preprocess a source file
src/common/core_state.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i
.PHONY : src/common/core_state.c.i

src/common/core_state.s: src/common/core_state.c.s
.PHONY : src/common/core_state.s

# target to generate assembly for a file
src/common/core_state.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s
.PHONY : src/common/core_state.c.s

src/common/cpu.o: src/common/cpu.c.o
.PHONY : src/common/cpu.o

# target to build an object file
src/common/cpu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o
.PHONY : src/common/cpu.c.o

src/common/cpu.i: src/common/cpu.c.i
.PHONY : src/common/cpu.i

# target to preprocess a source file
src/common/cpu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i
.PHONY : src/common/cpu.c.i

src/common/cpu.s: src/common/cpu.c.s
.PHONY : src/common/cpu.s

# target to generate assembly for a file
src/common/cpu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s
.PHONY : src/common/cpu.c.s

src/common/gba_cpu.o: src/common/gba_cpu.c.o
.PHONY : src/common/gba_cpu.o

# target to build an object file
src/common/gba_cpu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o
.PHONY : src/common/gba_cpu.c.o

src/common/gba_cpu.i: src/common/gba_cpu.c.i
.PHONY : src/common/gba_cpu.i

# target to preprocess a source file
src/common/gba_cpu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i
.PHONY : src/common/gba_cpu.c.i

src/common/gba_cpu.s: src/common/gba_cpu.c.s
.PHONY : src/common/gba_cpu.s

# target to generate assembly for a file
src/common/gba_cpu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s
.PHONY : src/common/gba_cpu.c.s

src/common/gba_mmu.o: src/common/gba_mmu.c.o
.PHONY : src/common/gba_mmu.o

# target to build an object file
src/common/gba_mmu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o
.PHONY : src/common/gba_mmu.c.o

src/common/gba_mmu.i: src/common/gba_mmu.c.i
.PHONY : src/common/gba_mmu.i

# target to preprocess a source file
src/common/gba_mmu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i
.PHONY : src/common/gba_mmu.c.i

src/common/gba_mmu.s: src/common/gba_mmu.c.s
.PHONY : src/common/gba_mmu.s

# target to generate assembly for a file
src/common/gba_mmu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s
.PHONY : src/common/gba_mmu.c.s

src/common/libretro.o: src/common/libretro.c.o
.PHONY : src/common/libretro.o

# target to build an object file
src/common/libretro.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o
.PHONY : src/common/libretro.c.o

src/common/libretro.i: src/common/libretro.c.i
.PHONY : src/common/libretro.i

# target to preprocess a source file
src/common/libretro.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i
.PHONY : src/common/libretro.c.i

src/common/libretro.s: src/common/libretro.c.s
.PHONY : src/common/libretro.s

# target to generate assembly for a file
src/common/libretro.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s
.PHONY : src/common/libretro.c.s

src/common/ppu.o: src/common/ppu.c.o
.PHONY : src/common/ppu.o

# target to build an object file
src/common/ppu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o
.PHONY : src/common/ppu.c.o

src/common/ppu.i: src/common/ppu.c.i
.PHONY : src/common/ppu.i

# target to preprocess a source file
src/common/ppu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i
.PHONY : src/common/ppu.c.i

src/common/ppu.s: src/common/ppu.c.s
.PHONY : src/common/ppu.s

# target to generate assembly for a file
src/common/ppu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s
.PHONY : src/common/ppu.c.s

# Help Target
help:
	@echo "The following are some of the valid targets for this Makefile:"
	@echo "... all (the default if no target is provided)"
	@echo "... clean"
	@echo "... depend"
	@echo "... edit_cache"
	@echo "... rebuild_cache"
	@echo "... gameboy_perfect_core_libretro"
	@echo "... src/common/apu.o"
	@echo "... src/common/apu.i"
	@echo "... src/common/apu.s"
	@echo "... src/common/audio.o"
	@echo "... src/common/audio.i"
	@echo "... src/common/audio.s"
	@echo "... src/common/core_state.o"
	@echo "... src/common/core_state.i"
	@echo "... src/common/core_state.s"
	@echo "... src/common/cpu.o"
	@echo "... src/common/cpu.i"
	@echo "... src/common/cpu.s"
	@echo "... src/common/gba_cpu.o"
	@echo "... src/common/gba_cpu.i"
	@echo "... src/common/gba_cpu.s"
	@echo "... src/common/gba_mmu.o"
	@echo "... src/common/gba_mmu.i"
	@echo "... src/common/gba_mmu.s"
	@echo "... src/common/libretro.o"
	@echo "... src/common/libretro.i"
	@echo "... src/common/libretro.s"
	@echo "... src/common/ppu.o"
	@echo "... src/common/ppu.i"
	@echo "... src/common/ppu.s"
.PHONY : help



#=============================================================================
# Special targets to cleanup operation of make.

# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system

./build.sh

#!/bin/bash
set -e

echo "[*] Cleaning old build..."
rm -rf build
mkdir -p build
cd build

echo "[*] Configuring with CMake..."
cmake ..

echo "[*] Building..."
make -j$(nproc)

echo "[*] Done!"
echo "Output core: $(realpath gameboy_perfect_core_libretro.so)"

./CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(gameboy_perfect_core C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

set(SRC
    src/common/audio.c
    src/common/apu.c
    src/common/core_state.c
    src/common/cpu.c
    src/common/gba_cpu.c
    src/common/gba_mmu.c
    src/common/libretro.c
    src/common/ppu.c
)

include_directories(
    include
    include/libretro-common/include
)

add_library(gameboy_perfect_core_libretro SHARED ${SRC})

set_target_properties(gameboy_perfect_core_libretro PROPERTIES
    PREFIX ""
    OUTPUT_NAME "gameboy_perfect_core_libretro"
)

./errors_only.txt

-- Build files have been written to: /home/ubuntu/Desktop/gameboy-perfect-core/build
[*] Building...
[ 11%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
[ 22%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘->’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘->’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:35: error: unknown type name ‘uint8_t’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                   ^~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:1: note: ‘uint8_t’ is defined in header ‘<stdint.h>’; did you forget to ‘#include <stdint.h>’?
  +++ |+#include <stdint.h>
    1 |       |                                                    ^~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘->’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘->’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘->’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘->’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘->’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
[ 33%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘->’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘->’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:8,
                 from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘->’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘->’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘->’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:2:
/usr/include/string.h:44:22: error: unknown type name ‘size_t’
   44 |                      size_t __n) __THROW __nonnull ((1, 2));
      |                      ^~~~~~
/usr/include/string.h:34:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
   33 | #include <stddef.h>
  +++ |+#include <stddef.h>
   34 | 
/usr/include/string.h:47:56: error: unknown type name ‘size_t’
   47 | extern void *memmove (void *__dest, const void *__src, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:47:56: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:55:32: error: unknown type name ‘size_t’
   55 |                       int __c, size_t __n)
      |                                ^~~~~~
/usr/include/string.h:55:32: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:61:42: error: unknown type name ‘size_t’
   61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
      |                                          ^~~~~~
/usr/include/string.h:61:42: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:64:56: error: unknown type name ‘size_t’
   64 | extern int memcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:64:56: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:80:60: error: unknown type name ‘size_t’
   80 | extern int __memcmpeq (const void *__s1, const void *__s2, size_t __n)
      |                                                            ^~~~~~
/usr/include/string.h:80:60: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:107:48: error: unknown type name ‘size_t’
  107 | extern void *memchr (const void *__s, int __c, size_t __n)
      |                                                ^~~~~~
/usr/include/string.h:107:48: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:145:53: error: unknown type name ‘size_t’
  145 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:145:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:153:23: error: unknown type name ‘size_t’
  153 |                       size_t __n) __THROW __nonnull ((1, 2));
      |                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘->’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:153:23: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:159:57: error: unknown type name ‘size_t’
  159 | extern int strncmp (const char *__s1, const char *__s2, size_t __n)
      |                                                         ^~~~~~
/usr/include/string.h:159:57: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/usr/include/string.h:166:8: error: unknown type name ‘size_t’
  166 | extern size_t strxfrm (char *__restrict __dest,
      |        ^~~~~~
/usr/include/string.h:167:54: error: unknown type name ‘size_t’
  167 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:167:54: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:179:8: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |        ^~~~~~
/usr/include/string.h:179:59: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |                                                           ^~~~~~
/usr/include/string.h:179:59: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:195:45: error: unknown type name ‘size_t’
  195 | extern char *strndup (const char *__string, size_t __n)
      |                                             ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:195:45: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/usr/include/string.h:293:8: error: unknown type name ‘size_t’
  293 | extern size_t strcspn (const char *__s, const char *__reject)
      |        ^~~~~~
/usr/include/string.h:297:8: error: unknown type name ‘size_t’
  297 | extern size_t strspn (const char *__s, const char *__accept)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/usr/include/string.h:389:46: error: unknown type name ‘size_t’
  389 | extern void *memmem (const void *__haystack, size_t __haystacklen,
      |                                              ^~~~~~
/usr/include/string.h:389:46: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:390:44: error: unknown type name ‘size_t’
  390 |                      const void *__needle, size_t __needlelen)
      |                                            ^~~~~~
/usr/include/string.h:390:44: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:398:55: error: unknown type name ‘size_t’
  398 |                         const void *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/usr/include/string.h:398:55: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/usr/include/string.h:401:53: error: unknown type name ‘size_t’
  401 |                       const void *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:401:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:407:8: error: unknown type name ‘size_t’
  407 | extern size_t strlen (const char *__s)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/usr/include/string.h:413:8: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |        ^~~~~~
/usr/include/string.h:413:46: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:413:46: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘->’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
In file included from /usr/include/features.h:502,
                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
                 from /usr/include/string.h:26:
/usr/include/string.h:432:12: error: unknown type name ‘size_t’
  432 | extern int __REDIRECT_NTH (strerror_r,
      |            ^~~~~~~~~~~~~~
/usr/include/string.h:432:12: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
In file included from /usr/include/string.h:462:
/usr/include/strings.h:34:54: error: unknown type name ‘size_t’
   34 | extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                      ^~~~~~
/usr/include/strings.h:24:1: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
   23 | #include <stddef.h>
  +++ |+#include <stddef.h>
   24 | 
/usr/include/strings.h:38:53: error: unknown type name ‘size_t’
   38 | extern void bcopy (const void *__src, void *__dest, size_t __n)
      |                                                     ^~~~~~
/usr/include/strings.h:38:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/strings.h:42:31: error: unknown type name ‘size_t’
   42 | extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
      |                               ^~~~~~
/usr/include/strings.h:42:31: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/usr/include/strings.h:120:61: error: unknown type name ‘size_t’
  120 | extern int strncasecmp (const char *__s1, const char *__s2, size_t __n)
      |                                                             ^~~~~~
/usr/include/strings.h:120:61: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/strings.h:134:27: error: unknown type name ‘size_t’
  134 |                           size_t __n, locale_t __loc)
      |                           ^~~~~~
/usr/include/strings.h:134:27: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:466:40: error: unknown type name ‘size_t’
  466 | extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1))
      |                                        ^~~~~~
/usr/include/string.h:466:40: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:497:55: error: unknown type name ‘size_t’
  497 |                         const char *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘->’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/string.h:497:55: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:500:53: error: unknown type name ‘size_t’
  500 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:500:53: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/usr/include/string.h:506:8: error: unknown type name ‘size_t’
  506 | extern size_t strlcpy (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:507:54: error: unknown type name ‘size_t’
  507 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:507:54: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:512:8: error: unknown type name ‘size_t’
  512 | extern size_t strlcat (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:513:54: error: unknown type name ‘size_t’
  513 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:513:54: note: ‘size_t’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:5:19: error: unknown type name ‘gb_apu_t’
    5 | void gb_apu_reset(gb_apu_t *apu) {
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:11:18: error: unknown type name ‘gb_apu_t’
   11 | void gb_apu_step(gb_apu_t *apu, int cycles) {
      |                  ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:90: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘->’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘->’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘->’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: data definition has no type or storage class
   17 | } core_state_t;
      |   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: type defaults to ‘int’ in declaration of ‘core_state_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:19:1: error: unknown type name ‘core_state_t’
   19 | core_state_t* gb_core_create(void);
      | ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:20:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   20 | void gb_core_destroy(core_state_t* state);
      |                      ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_init(core_state_t* state, const uint8_t* rom_data, size_t rom_size);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:22:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   22 | void gb_core_step(core_state_t* state);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:23:25: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   23 | int gb_core_frame_ready(core_state_t* state);
      |                         ^~~~~~~~~~~~
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:4:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘->’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘->’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: error: redefinition of ‘val’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘->’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘->’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘->’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘->’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘->’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘->’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘->’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:5:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: data definition has no type or storage class
   25 | } gb_mmu_t;
      |   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: type defaults to ‘int’ in declaration of ‘gb_mmu_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:28:19: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   28 | void gb_mmu_reset(gb_mmu_t *mmu);
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:31:26: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   31 | uint8_t gb_mmu_read_byte(gb_mmu_t *mmu, uint16_t addr);
      |                          ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:34:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   34 | void gb_mmu_write_byte(gb_mmu_t *mmu, uint16_t addr, uint8_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:37:27: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   37 | uint16_t gb_mmu_read_word(gb_mmu_t *mmu, uint16_t addr);
      |                           ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:40:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   40 | void gb_mmu_write_word(gb_mmu_t *mmu, uint16_t addr, uint16_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:9:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
    9 | void gb_core_init(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_step(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:28:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   28 | void gb_core_destroy(core_state_t *state) {
      |                      ^~~~~~~~~~~~
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:104: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/gameboy_perfect_core_libretro.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

./gameboy_perfect_core_libretro.info

display_name = "Game Boy Perfect"
authors = "CanC-Code"
supported_extensions = "gb|gbc|gba"
corename = "Game Boy Perfect Core"
manufacturer = "Nintendo"
categories = "Emulator"
systemname = "Game Boy / Color / Advance"
license = "GPLv3"
permissions = ""
display_version = "0.1.0"
library_name = "Game Boy Perfect"
library_version = "0.1.0"
datasource = "libretro"
supports_no_game = "false"
firmware_count = "0"

./.gitignore

# Build artifacts
/build/
/bin/
/obj/
/*.o
/*.so
*.apk
*.log

# IDE files
*.idea/
*.vscode/
*.iml

./.gitmodules

[submodule "include/libretro-common"]
	path = include/libretro-common
	url = https://github.com/libretro/libretro-common.git

./include/libretro-common/audio/audio_mix.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mix.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>
#include <memalign.h>

#include <retro_environment.h>

#if defined(__SSE2__)
#include <emmintrin.h>
#elif defined(__ALTIVEC__)
#include <altivec.h>
#endif

#include <retro_miscellaneous.h>
#include <audio/audio_mix.h>
#include <streams/file_stream.h>
#include <audio/conversion/float_to_s16.h>
#include <audio/conversion/s16_to_float.h>

void audio_mix_volume_C(float *s, const float *in, float vol, size_t len)
{
   size_t i;
   for (i = 0; i < len; i++)
      s[i] += in[i] * vol;
}

#ifdef __SSE2__
void audio_mix_volume_SSE2(float *s, const float *in, float vol, size_t len)
{
   size_t i, remaining_samples;
   __m128 volume = _mm_set1_ps(vol);

   for (i = 0; i + 16 <= len; i += 16, s += 16, in += 16)
   {
      unsigned j;
      __m128 input[4];
      __m128 additive[4];

      input[0]    = _mm_loadu_ps(s +  0);
      input[1]    = _mm_loadu_ps(s +  4);
      input[2]    = _mm_loadu_ps(s +  8);
      input[3]    = _mm_loadu_ps(s + 12);

      additive[0] = _mm_mul_ps(volume, _mm_loadu_ps(in +  0));
      additive[1] = _mm_mul_ps(volume, _mm_loadu_ps(in +  4));
      additive[2] = _mm_mul_ps(volume, _mm_loadu_ps(in +  8));
      additive[3] = _mm_mul_ps(volume, _mm_loadu_ps(in + 12));

      for (j = 0; j < 4; j++)
         _mm_storeu_ps(s + 4 * j, _mm_add_ps(input[j], additive[j]));
   }

   remaining_samples = len - i;

   for (i = 0; i < remaining_samples; i++)
      s[i] += in[i] * vol;
}
#endif

void audio_mix_free_chunk(audio_chunk_t *chunk)
{
   if (!chunk)
      return;

#ifdef HAVE_RWAV
   if (chunk->rwav && chunk->rwav->samples)
   {
      /* rwav_free only frees the samples */
      rwav_free(chunk->rwav);
      free(chunk->rwav);
   }
#endif

   if (chunk->buf)
      free(chunk->buf);

   if (chunk->upsample_buf)
      memalign_free(chunk->upsample_buf);

   if (chunk->float_buf)
      memalign_free(chunk->float_buf);

   if (chunk->float_resample_buf)
      memalign_free(chunk->float_resample_buf);

   if (chunk->resample_buf)
      memalign_free(chunk->resample_buf);

   if (chunk->resampler && chunk->resampler_data)
      chunk->resampler->free(chunk->resampler_data);

   free(chunk);
}

audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,
      const char *resampler_ident, enum resampler_quality quality)
{
#ifdef HAVE_RWAV
   int sample_size;
   int64_t len                = 0;
   void *buf                  = NULL;
   audio_chunk_t *chunk       = (audio_chunk_t*)malloc(sizeof(*chunk));

   if (!chunk)
      return NULL;

   chunk->buf                 = NULL;
   chunk->upsample_buf        = NULL;
   chunk->float_buf           = NULL;
   chunk->float_resample_buf  = NULL;
   chunk->resample_buf        = NULL;
   chunk->len                 = 0;
   chunk->resample_len        = 0;
   chunk->sample_rate         = sample_rate;
   chunk->resample            = false;
   chunk->resampler           = NULL;
   chunk->resampler_data      = NULL;
   chunk->ratio               = 0.00f;
   chunk->rwav                = (rwav_t*)malloc(sizeof(rwav_t));

   if (!chunk->rwav)
      goto error;

   chunk->rwav->bitspersample = 0;
   chunk->rwav->numchannels   = 0;
   chunk->rwav->samplerate    = 0;
   chunk->rwav->numsamples    = 0;
   chunk->rwav->subchunk2size = 0;
   chunk->rwav->samples       = NULL;

   if (!filestream_read_file(path, &buf, &len))
      goto error;

   chunk->buf                 = buf;
   chunk->len                 = len;

   if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR)
      goto error;

   /* numsamples does not know or care about
    * multiple channels, but we need space for 2 */
   chunk->upsample_buf        = (int16_t*)memalign_alloc(128,
         chunk->rwav->numsamples * 2 * sizeof(int16_t));

   sample_size                = chunk->rwav->bitspersample / 8;

   if (sample_size == 1)
   {
      unsigned i;

      if (chunk->rwav->numchannels == 1)
      {
         for (i = 0; i < chunk->rwav->numsamples; i++)
         {
            uint8_t *sample                  = (
                  (uint8_t*)chunk->rwav->samples) + i;

            chunk->upsample_buf[i * 2]       =
               (int16_t)((sample[0] - 128) << 8);
            chunk->upsample_buf[(i * 2) + 1] =
               (int16_t)((sample[0] - 128) << 8);
         }
      }
      else if (chunk->rwav->numchannels == 2)
      {
         for (i = 0; i < chunk->rwav->numsamples; i++)
         {
            uint8_t *sample                  = (
                  (uint8_t*)chunk->rwav->samples) +
               (i * 2);

            chunk->upsample_buf[i * 2]       =
               (int16_t)((sample[0] - 128) << 8);
            chunk->upsample_buf[(i * 2) + 1] =
               (int16_t)((sample[1] - 128) << 8);
         }
      }
   }
   else if (sample_size == 2)
   {
      if (chunk->rwav->numchannels == 1)
      {
         unsigned i;

         for (i = 0; i < chunk->rwav->numsamples; i++)
         {
            int16_t sample                   = ((int16_t*)
                  chunk->rwav->samples)[i];

            chunk->upsample_buf[i * 2]       = sample;
            chunk->upsample_buf[(i * 2) + 1] = sample;
         }
      }
      else if (chunk->rwav->numchannels == 2)
         memcpy(chunk->upsample_buf, chunk->rwav->samples,
               chunk->rwav->subchunk2size);
   }
   else if (sample_size != 2)
   {
      /* we don't support any other sample size besides 8 and 16-bit yet */
      goto error;
   }

   if (sample_rate != (int)chunk->rwav->samplerate)
   {
      chunk->resample = true;
      chunk->ratio    = (double)sample_rate / chunk->rwav->samplerate;

      retro_resampler_realloc(&chunk->resampler_data,
            &chunk->resampler,
            resampler_ident,
            quality,
            chunk->ratio);

      if (chunk->resampler && chunk->resampler_data)
      {
         struct resampler_data info;

         chunk->float_buf          = (float*)memalign_alloc(128,
               chunk->rwav->numsamples * 2 *
               chunk->ratio * sizeof(float));

         /* why is *3 needed instead of just *2? Does the
          * sinc driver require more space than we know about? */
         chunk->float_resample_buf = (float*)memalign_alloc(128,
               chunk->rwav->numsamples * 3 *
               chunk->ratio * sizeof(float));

         convert_s16_to_float(chunk->float_buf,
               chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0);

         info.data_in       = (const float*)chunk->float_buf;
         info.data_out      = chunk->float_resample_buf;
         /* a 'frame' consists of two channels, so we set this
          * to the number of samples irrespective of channel count */
         info.input_frames  = chunk->rwav->numsamples;
         info.output_frames = 0;
         info.ratio         = chunk->ratio;

         chunk->resampler->process(chunk->resampler_data, &info);

         /* number of output_frames does not increase with
          * multiple channels, but assume we need space for 2 */
         chunk->resample_buf = (int16_t*)memalign_alloc(128,
               info.output_frames * 2 * sizeof(int16_t));
         chunk->resample_len = info.output_frames;
         convert_float_to_s16(chunk->resample_buf,
               chunk->float_resample_buf, info.output_frames * 2);
      }
   }

   return chunk;

error:
   audio_mix_free_chunk(chunk);
#endif
   return NULL;
}

size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk->rwav)
   {
      if (chunk->resample)
         return chunk->resample_len;
      return chunk->rwav->numsamples;
   }
#endif

   /* no other filetypes supported yet */
   return 0;
}

/**
 * audio_mix_get_chunk_sample:
 * @chunk              : audio chunk instance
 * @channel            : channel of the sample (0=left, 1=right)
 * @index              : index of the sample
 *
 * Get a sample from an audio chunk.
 *
 * Returns: A signed 16-bit audio sample.
 **/
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk,
      unsigned channel, size_t index)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk->rwav)
   {
      int sample_size    = chunk->rwav->bitspersample / 8;
      int16_t sample_out = 0;

      /* 0 is the first/left channel */
      uint8_t *sample    = NULL;

      if (chunk->resample)
         sample = (uint8_t*)chunk->resample_buf +
            (sample_size * index * chunk->rwav->numchannels)
            + (channel * sample_size);
      else
         sample = (uint8_t*)chunk->upsample_buf +
            (sample_size * index * chunk->rwav->numchannels)
            + (channel * sample_size);

      sample_out = (int16_t)*sample;

      return sample_out;
   }
#endif

   /* no other filetypes supported yet */
   return 0;
}

int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk->rwav)
   {
      int16_t *sample;

      if (chunk->resample)
         sample = chunk->resample_buf;
      else
         sample = chunk->upsample_buf;

      return sample;
   }
#endif

   return NULL;
}

int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk->rwav)
      return chunk->rwav->numchannels;
#endif

   /* don't support other formats yet */
   return 0;
}

./include/libretro-common/audio/audio_mixer.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mixer.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif

#include <audio/audio_mixer.h>
#include <audio/audio_resampler.h>

#ifdef HAVE_RWAV
#include <formats/rwav.h>
#endif
#include <memalign.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#ifdef HAVE_STB_VORBIS
#define STB_VORBIS_NO_PUSHDATA_API
#define STB_VORBIS_NO_STDIO
#define STB_VORBIS_NO_CRT

#include <stb/stb_vorbis.h>
#endif

#ifdef HAVE_DR_FLAC
#include <retro_inline.h>
#define DR_FLAC_IMPLEMENTATION
#define DRFLAC_API static INLINE
#include <dr/dr_flac.h>
#endif

#ifdef HAVE_DR_MP3
#define DR_MP3_IMPLEMENTATION
#include <retro_assert.h>
#define DRMP3_ASSERT(expression) retro_assert(expression)
#include <dr/dr_mp3.h>
#endif

#ifdef HAVE_IBXM
#include <ibxm/ibxm.h>
#endif

#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#define AUDIO_MIXER_LOCK(voice)   slock_lock(voice->lock)
#define AUDIO_MIXER_UNLOCK(voice) slock_unlock(voice->lock)
#else
#define AUDIO_MIXER_LOCK(voice)   do {} while(0)
#define AUDIO_MIXER_UNLOCK(voice) do {} while(0)
#endif

#define AUDIO_MIXER_MAX_VOICES      8
#define AUDIO_MIXER_TEMP_BUFFER 8192

struct audio_mixer_sound
{
   enum audio_mixer_type type;
   void* user_data;

   union
   {
      struct
      {
         /* wav */
         const float* pcm;
         unsigned frames;
      } wav;

#ifdef HAVE_STB_VORBIS
      struct
      {
         /* ogg */
         const void* data;
         unsigned size;
      } ogg;
#endif

#ifdef HAVE_DR_FLAC
      struct
      {
          /* flac */
         const void* data;
         unsigned size;
      } flac;
#endif

#ifdef HAVE_DR_MP3
      struct
      {
          /* mp */
         const void* data;
         unsigned size;
      } mp3;
#endif

#ifdef HAVE_IBXM
      struct
      {
         /* mod/s3m/xm */
         const void* data;
         unsigned size;
      } mod;
#endif
   } types;
};

struct audio_mixer_voice
{
   struct
   {
      struct
      {
         unsigned position;
      } wav;

#ifdef HAVE_STB_VORBIS
      struct
      {
         stb_vorbis *stream;
         void       *resampler_data;
         const retro_resampler_t *resampler;
         float      *buffer;
         unsigned    position;
         unsigned    samples;
         unsigned    buf_samples;
         float       ratio;
      } ogg;
#endif

#ifdef HAVE_DR_FLAC
      struct
      {
         float*      buffer;
         drflac      *stream;
         void        *resampler_data;
         const retro_resampler_t *resampler;
         unsigned    position;
         unsigned    samples;
         unsigned    buf_samples;
         float       ratio;
      } flac;
#endif

#ifdef HAVE_DR_MP3
      struct
      {
         drmp3       stream;
         void        *resampler_data;
         const retro_resampler_t *resampler;
         float*      buffer;
         unsigned    position;
         unsigned    samples;
         unsigned    buf_samples;
         float       ratio;
      } mp3;
#endif

#ifdef HAVE_IBXM
      struct
      {
         int*              buffer;
         struct replay*    stream;
         struct module*    module;
         unsigned          position;
         unsigned          samples;
         unsigned          buf_samples;
      } mod;
#endif
   } types;
   audio_mixer_sound_t *sound;
   audio_mixer_stop_cb_t stop_cb;
   unsigned type;
   float    volume;
   bool     repeat;
#ifdef HAVE_THREADS
   slock_t *lock;
#endif
};

/* TODO/FIXME - static globals */
static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0};
static unsigned s_rate = 0;

static void audio_mixer_release(audio_mixer_voice_t* voice);

#ifdef HAVE_RWAV
static bool wav_to_float(const rwav_t* wav, float** pcm, size_t len)
{
   size_t i;
   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
   float *f           = (float*)memalign_alloc(16,
         ((len + 15) & ~15) * sizeof(float));

   if (!f)
      return false;

   *pcm = f;

   if (wav->bitspersample == 8)
   {
      float sample      = 0.0f;
      const uint8_t *u8 = (const uint8_t*)wav->samples;

      if (wav->numchannels == 1)
      {
         for (i = wav->numsamples; i != 0; i--)
         {
            sample = (float)*u8++ / 255.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            *f++   = sample;
         }
      }
      else if (wav->numchannels == 2)
      {
         for (i = wav->numsamples; i != 0; i--)
         {
            sample = (float)*u8++ / 255.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            sample = (float)*u8++ / 255.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
         }
      }
   }
   else
   {
      /* TODO/FIXME note to leiradel - can we use audio/conversion/s16_to_float
       * functions here? */

      float sample       = 0.0f;
      const int16_t *s16 = (const int16_t*)wav->samples;

      if (wav->numchannels == 1)
      {
         for (i = wav->numsamples; i != 0; i--)
         {
            sample = (float)((int)*s16++ + 32768) / 65535.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            *f++   = sample;
         }
      }
      else if (wav->numchannels == 2)
      {
         for (i = wav->numsamples; i != 0; i--)
         {
            sample = (float)((int)*s16++ + 32768) / 65535.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            sample = (float)((int)*s16++ + 32768) / 65535.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
         }
      }
   }

   return true;
}

static bool one_shot_resample(const float* in, size_t samples_in,
      unsigned rate, const char *resampler_ident, enum resampler_quality quality,
      float** out, size_t* samples_out)
{
   struct resampler_data info;
   void* data                         = NULL;
   const retro_resampler_t* resampler = NULL;
   float ratio                        = (double)s_rate / (double)rate;

   if (!retro_resampler_realloc(&data, &resampler,
         resampler_ident, quality, ratio))
      return false;

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler->process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   *samples_out                       = (size_t)(samples_in * ratio);
   *out                               = (float*)memalign_alloc(16,
         (((*samples_out + 16) + 15) & ~15) * sizeof(float));

   if (*out == NULL)
      return false;

   info.data_in                       = in;
   info.data_out                      = *out;
   info.input_frames                  = samples_in / 2;
   info.output_frames                 = 0;
   info.ratio                         = ratio;

   resampler->process(data, &info);
   resampler->free(data);
   return true;
}
#endif

void audio_mixer_init(unsigned rate)
{
   unsigned i;

   s_rate = rate;

   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)
   {
      audio_mixer_voice_t *voice = &s_voices[i];

      voice->type = AUDIO_MIXER_TYPE_NONE;
#ifdef HAVE_THREADS
      if (!voice->lock)
         voice->lock = slock_new();
#endif
   }
}

void audio_mixer_done(void)
{
   unsigned i;

   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)
   {
      audio_mixer_voice_t *voice = &s_voices[i];

      AUDIO_MIXER_LOCK(voice);
      audio_mixer_release(voice);
      AUDIO_MIXER_UNLOCK(voice);
#ifdef HAVE_THREADS
      slock_free(voice->lock);
      voice->lock = NULL;
#endif
   }
}

audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,
      const char *resampler_ident, enum resampler_quality quality)
{
#ifdef HAVE_RWAV
   /* WAV data */
   rwav_t wav;
   /* WAV samples converted to float */
   float* pcm                 = NULL;
   size_t samples             = 0;
   /* Result */
   audio_mixer_sound_t* sound = NULL;

   wav.bitspersample          = 0;
   wav.numchannels            = 0;
   wav.samplerate             = 0;
   wav.numsamples             = 0;
   wav.subchunk2size          = 0;
   wav.samples                = NULL;

   if ((rwav_load(&wav, buffer, size)) != RWAV_ITERATE_DONE)
      return NULL;

   samples       = wav.numsamples * 2;

   if (!wav_to_float(&wav, &pcm, samples))
      return NULL;

   if (wav.samplerate != s_rate)
   {
      float* resampled           = NULL;

      if (!one_shot_resample(pcm, samples, wav.samplerate,
            resampler_ident, quality,
            &resampled, &samples))
         return NULL;

      memalign_free((void*)pcm);
      pcm = resampled;
   }

   sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
   {
      memalign_free((void*)pcm);
      return NULL;
   }

   sound->type             = AUDIO_MIXER_TYPE_WAV;
   sound->types.wav.frames = (unsigned)(samples / 2);
   sound->types.wav.pcm    = pcm;

   rwav_free(&wav);

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size)
{
#ifdef HAVE_STB_VORBIS
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound->type           = AUDIO_MIXER_TYPE_OGG;
   sound->types.ogg.size = size;
   sound->types.ogg.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size)
{
#ifdef HAVE_DR_FLAC
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound->type           = AUDIO_MIXER_TYPE_FLAC;
   sound->types.flac.size = size;
   sound->types.flac.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size)
{
#ifdef HAVE_DR_MP3
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound->type           = AUDIO_MIXER_TYPE_MP3;
   sound->types.mp3.size = size;
   sound->types.mp3.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size)
{
#ifdef HAVE_IBXM
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound->type           = AUDIO_MIXER_TYPE_MOD;
   sound->types.mod.size = size;
   sound->types.mod.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

void audio_mixer_destroy(audio_mixer_sound_t* sound)
{
   void *handle = NULL;
   if (!sound)
      return;

   switch (sound->type)
   {
      case AUDIO_MIXER_TYPE_WAV:
         handle = (void*)sound->types.wav.pcm;
         if (handle)
            memalign_free(handle);
         break;
      case AUDIO_MIXER_TYPE_OGG:
#ifdef HAVE_STB_VORBIS
         handle = (void*)sound->types.ogg.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_MOD:
#ifdef HAVE_IBXM
         handle = (void*)sound->types.mod.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_FLAC:
#ifdef HAVE_DR_FLAC
         handle = (void*)sound->types.flac.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_MP3:
#ifdef HAVE_DR_MP3
         handle = (void*)sound->types.mp3.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_NONE:
         break;
   }

   free(sound);
}

static bool audio_mixer_play_wav(audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice, bool repeat, float volume,
      audio_mixer_stop_cb_t stop_cb)
{
   voice->types.wav.position = 0;
   return true;
}

#ifdef HAVE_STB_VORBIS
static bool audio_mixer_play_ogg(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   stb_vorbis_info info;
   int res                         = 0;
   float ratio                     = 1.0f;
   unsigned samples                = 0;
   void *ogg_buffer                = NULL;
   void *resampler_data            = NULL;
   const retro_resampler_t* resamp = NULL;
   stb_vorbis *stb_vorbis          = stb_vorbis_open_memory(
         (const unsigned char*)sound->types.ogg.data,
         sound->types.ogg.size, &res, NULL);

   if (!stb_vorbis)
      return false;

   info                    = stb_vorbis_get_info(stb_vorbis);

   if (info.sample_rate != s_rate)
   {
      ratio = (double)s_rate / (double)info.sample_rate;

      if (!retro_resampler_realloc(&resampler_data,
               &resamp, resampler_ident, quality,
               ratio))
         goto error;
   }

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler->process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
   ogg_buffer                      = (float*)memalign_alloc(16,
         (((samples + 16) + 15) & ~15) * sizeof(float));

   if (!ogg_buffer)
   {
      if (resamp && resampler_data)
         resamp->free(resampler_data);
      goto error;
   }

   voice->types.ogg.resampler      = resamp;
   voice->types.ogg.resampler_data = resampler_data;
   voice->types.ogg.buffer         = (float*)ogg_buffer;
   voice->types.ogg.buf_samples    = samples;
   voice->types.ogg.ratio          = ratio;
   voice->types.ogg.stream         = stb_vorbis;
   voice->types.ogg.position       = 0;
   voice->types.ogg.samples        = 0;

   return true;

error:
   stb_vorbis_close(stb_vorbis);
   return false;
}

static void audio_mixer_release_ogg(audio_mixer_voice_t* voice)
{
   if (voice->types.ogg.stream)
      stb_vorbis_close(voice->types.ogg.stream);
   if (voice->types.ogg.resampler && voice->types.ogg.resampler_data)
      voice->types.ogg.resampler->free(voice->types.ogg.resampler_data);
   if (voice->types.ogg.buffer)
      memalign_free(voice->types.ogg.buffer);
}

#endif

#ifdef HAVE_IBXM
static bool audio_mixer_play_mod(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      audio_mixer_stop_cb_t stop_cb)
{
   struct data data;
   char message[64];
   int buf_samples               = 0;
   int samples                   = 0;
   void *mod_buffer              = NULL;
   struct module* module         = NULL;
   struct replay* replay         = NULL;

   data.buffer                   = (char*)sound->types.mod.data;
   data.length                   = sound->types.mod.size;
   module                        = module_load(&data, message);

   if (!module)
   {
      printf("audio_mixer_play_mod module_load() failed with error: %s\n", message);
      goto error;
   }

   if (voice->types.mod.module)
      dispose_module(voice->types.mod.module);

   voice->types.mod.module = module;

   replay = new_replay(module, s_rate, 1);

   if (!replay)
   {
      printf("audio_mixer_play_mod new_replay() failed\n");
      goto error;
   }

   buf_samples = calculate_mix_buf_len(s_rate);
   mod_buffer  = memalign_alloc(16, ((buf_samples + 15) & ~15) * sizeof(int));

   if (!mod_buffer)
   {
      printf("audio_mixer_play_mod cannot allocate mod_buffer !\n");
      goto error;
   }

   samples = replay_calculate_duration(replay);

   if (!samples)
   {
      printf("audio_mixer_play_mod cannot retrieve duration !\n");
      goto error;
   }

   voice->types.mod.buffer         = (int*)mod_buffer;
   voice->types.mod.buf_samples    = buf_samples;
   voice->types.mod.stream         = replay;
   voice->types.mod.position       = 0;
   voice->types.mod.samples        = 0; /* samples; */

   return true;

error:
   if (mod_buffer)
      memalign_free(mod_buffer);
   if (module)
      dispose_module(module);
   return false;

}

static void audio_mixer_release_mod(audio_mixer_voice_t* voice)
{
   if (voice->types.mod.stream)
      dispose_replay(voice->types.mod.stream);
   if (voice->types.mod.buffer)
      memalign_free(voice->types.mod.buffer);
}
#endif

#ifdef HAVE_DR_FLAC
static bool audio_mixer_play_flac(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   float ratio                     = 1.0f;
   unsigned samples                = 0;
   void *flac_buffer                = NULL;
   void *resampler_data            = NULL;
   const retro_resampler_t* resamp = NULL;
   drflac *dr_flac          = drflac_open_memory((const unsigned char*)sound->types.flac.data, sound->types.flac.size, NULL);

   if (!dr_flac)
      return false;
   if (dr_flac->sampleRate != s_rate)
   {
      ratio = (double)s_rate / (double)(dr_flac->sampleRate);

      if (!retro_resampler_realloc(&resampler_data,
               &resamp, resampler_ident, quality,
               ratio))
         goto error;
   }

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler->process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
   flac_buffer                     = (float*)memalign_alloc(16,
         (((samples + 16) + 15) & ~15) * sizeof(float));

   if (!flac_buffer)
   {
      if (resamp && resamp->free)
         resamp->free(resampler_data);
      goto error;
   }

   voice->types.flac.resampler      = resamp;
   voice->types.flac.resampler_data = resampler_data;
   voice->types.flac.buffer         = (float*)flac_buffer;
   voice->types.flac.buf_samples    = samples;
   voice->types.flac.ratio          = ratio;
   voice->types.flac.stream         = dr_flac;
   voice->types.flac.position       = 0;
   voice->types.flac.samples        = 0;

   return true;

error:
   drflac_close(dr_flac);
   return false;
}

static void audio_mixer_release_flac(audio_mixer_voice_t* voice)
{
   if (voice->types.flac.stream)
      drflac_close(voice->types.flac.stream);
   if (voice->types.flac.resampler && voice->types.flac.resampler_data)
      voice->types.flac.resampler->free(voice->types.flac.resampler_data);
   if (voice->types.flac.buffer)
      memalign_free(voice->types.flac.buffer);
}
#endif

#ifdef HAVE_DR_MP3
static bool audio_mixer_play_mp3(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   float ratio                     = 1.0f;
   unsigned samples                = 0;
   void *mp3_buffer                = NULL;
   void *resampler_data            = NULL;
   const retro_resampler_t* resamp = NULL;
   bool res;

   res = drmp3_init_memory(&voice->types.mp3.stream, (const unsigned char*)sound->types.mp3.data, sound->types.mp3.size, NULL);

   if (!res)
      return false;

   if (voice->types.mp3.stream.sampleRate != s_rate)
   {
      ratio = (double)s_rate / (double)(voice->types.mp3.stream.sampleRate);

      if (!retro_resampler_realloc(&resampler_data,
               &resamp, resampler_ident, quality,
               ratio))
         goto error;
   }

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler->process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
   mp3_buffer                      = (float*)memalign_alloc(16,
         (((samples + 16) + 15) & ~15) * sizeof(float));

   if (!mp3_buffer)
   {
      if (resamp && resampler_data)
         resamp->free(resampler_data);
      goto error;
   }

   voice->types.mp3.resampler      = resamp;
   voice->types.mp3.resampler_data = resampler_data;
   voice->types.mp3.buffer         = (float*)mp3_buffer;
   voice->types.mp3.buf_samples    = samples;
   voice->types.mp3.ratio          = ratio;
   voice->types.mp3.position       = 0;
   voice->types.mp3.samples        = 0;

   return true;

error:
   drmp3_uninit(&voice->types.mp3.stream);
   return false;
}

static void audio_mixer_release_mp3(audio_mixer_voice_t* voice)
{
   if (voice->types.mp3.resampler && voice->types.mp3.resampler_data)
      voice->types.mp3.resampler->free(voice->types.mp3.resampler_data);
   if (voice->types.mp3.buffer)
      memalign_free(voice->types.mp3.buffer);
   if (voice->types.mp3.stream.pData)
      drmp3_uninit(&voice->types.mp3.stream);
}

#endif

audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   unsigned i;
   bool res                   = false;
   audio_mixer_voice_t* voice = s_voices;

   if (!sound)
      return NULL;

   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
   {
      if (voice->type != AUDIO_MIXER_TYPE_NONE)
         continue;

      AUDIO_MIXER_LOCK(voice);

      if (voice->type != AUDIO_MIXER_TYPE_NONE)
      {
         AUDIO_MIXER_UNLOCK(voice);
         continue;
      }

      /* claim the voice, also helps with cleanup on error */
      voice->type = sound->type;

      switch (sound->type)
      {
         case AUDIO_MIXER_TYPE_WAV:
            res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb);
            break;
         case AUDIO_MIXER_TYPE_OGG:
#ifdef HAVE_STB_VORBIS
            res = audio_mixer_play_ogg(sound, voice, repeat, volume,
                  resampler_ident, quality, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_MOD:
#ifdef HAVE_IBXM
            res = audio_mixer_play_mod(sound, voice, repeat, volume, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_FLAC:
#ifdef HAVE_DR_FLAC
            res = audio_mixer_play_flac(sound, voice, repeat, volume,
                  resampler_ident, quality, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_MP3:
#ifdef HAVE_DR_MP3
            res = audio_mixer_play_mp3(sound, voice, repeat, volume,
                  resampler_ident, quality, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_NONE:
            break;
      }

      break;
   }

   if (res)
   {
      voice->repeat   = repeat;
      voice->volume   = volume;
      voice->sound    = sound;
      voice->stop_cb  = stop_cb;
      AUDIO_MIXER_UNLOCK(voice);
   }
   else
   {
      if (i < AUDIO_MIXER_MAX_VOICES)
      {
         audio_mixer_release(voice);
         AUDIO_MIXER_UNLOCK(voice);
      }
      voice = NULL;
   }

   return voice;
}

/* Need to hold lock for voice.  */
static void audio_mixer_release(audio_mixer_voice_t* voice)
{
   if (!voice)
      return;

   switch (voice->type)
   {
#ifdef HAVE_STB_VORBIS
      case AUDIO_MIXER_TYPE_OGG:
         audio_mixer_release_ogg(voice);
         break;
#endif
#ifdef HAVE_IBXM
      case AUDIO_MIXER_TYPE_MOD:
         audio_mixer_release_mod(voice);
         break;
#endif
#ifdef HAVE_DR_FLAC
      case AUDIO_MIXER_TYPE_FLAC:
         audio_mixer_release_flac(voice);
         break;
#endif
#ifdef HAVE_DR_MP3
      case AUDIO_MIXER_TYPE_MP3:
         audio_mixer_release_mp3(voice);
         break;
#endif
      default:
         break;
   }

   memset(&voice->types, 0, sizeof(voice->types));
   voice->type = AUDIO_MIXER_TYPE_NONE;
}

void audio_mixer_stop(audio_mixer_voice_t* voice)
{
   audio_mixer_stop_cb_t stop_cb = NULL;
   audio_mixer_sound_t* sound    = NULL;

   if (voice)
   {
      AUDIO_MIXER_LOCK(voice);
      stop_cb     = voice->stop_cb;
      sound       = voice->sound;

      audio_mixer_release(voice);

      AUDIO_MIXER_UNLOCK(voice);

      if (stop_cb)
         stop_cb(sound, AUDIO_MIXER_SOUND_STOPPED);
   }
}

static void audio_mixer_mix_wav(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   unsigned buf_free                = (unsigned)(num_frames * 2);
   const audio_mixer_sound_t* sound = voice->sound;
   unsigned pcm_available           = sound->types.wav.frames
      * 2 - voice->types.wav.position;
   const float* pcm                 = sound->types.wav.pcm +
      voice->types.wav.position;

again:
   if (pcm_available < buf_free)
   {
      for (i = pcm_available; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      if (voice->repeat)
      {
         if (voice->stop_cb)
            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);

         buf_free                  -= pcm_available;
         pcm_available              = sound->types.wav.frames * 2;
         pcm                        = sound->types.wav.pcm;
         voice->types.wav.position  = 0;
         goto again;
      }

      if (voice->stop_cb)
         voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);

      audio_mixer_release(voice);
   }
   else
   {
      for (i = buf_free; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      voice->types.wav.position += buf_free;
   }
}

#ifdef HAVE_STB_VORBIS
static void audio_mixer_mix_ogg(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   float* temp_buffer = NULL;
   unsigned buf_free                = (unsigned)(num_frames * 2);
   unsigned temp_samples            = 0;
   float* pcm                       = NULL;

   if (!voice->types.ogg.stream)
      return;

   if (voice->types.ogg.position == voice->types.ogg.samples)
   {
again:
      if (temp_buffer == NULL)
         temp_buffer = (float*)malloc(AUDIO_MIXER_TEMP_BUFFER * sizeof(float));

      temp_samples = stb_vorbis_get_samples_float_interleaved(
            voice->types.ogg.stream, 2, temp_buffer,
            AUDIO_MIXER_TEMP_BUFFER) * 2;

      if (temp_samples == 0)
      {
         if (voice->repeat)
         {
            if (voice->stop_cb)
               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);

            stb_vorbis_seek_start(voice->types.ogg.stream);
            goto again;
         }

         if (voice->stop_cb)
            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         goto cleanup;
      }

      if (voice->types.ogg.resampler)
      {
         struct resampler_data info;
         info.data_in = temp_buffer;
         info.data_out = voice->types.ogg.buffer;
         info.input_frames = temp_samples / 2;
         info.output_frames = 0;
         info.ratio = voice->types.ogg.ratio;

         voice->types.ogg.resampler->process(
               voice->types.ogg.resampler_data, &info);
      }
      else
         memcpy(voice->types.ogg.buffer, temp_buffer,
               temp_samples * sizeof(float));

      voice->types.ogg.position = 0;
      voice->types.ogg.samples  = voice->types.ogg.buf_samples;
   }

   pcm = voice->types.ogg.buffer + voice->types.ogg.position;

   if (voice->types.ogg.samples < buf_free)
   {
      for (i = voice->types.ogg.samples; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      buf_free -= voice->types.ogg.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
      *buffer++ += *pcm++ * volume;

   voice->types.ogg.position += buf_free;
   voice->types.ogg.samples  -= buf_free;

cleanup:
   if (temp_buffer != NULL)
      free(temp_buffer);
}
#endif

#ifdef HAVE_IBXM
static void audio_mixer_mix_mod(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   float samplef                    = 0.0f;
   unsigned temp_samples            = 0;
   unsigned buf_free                = (unsigned)(num_frames * 2);
   int* pcm                         = NULL;

   if (voice->types.mod.samples == 0)
   {
again:
      temp_samples = replay_get_audio(
            voice->types.mod.stream, voice->types.mod.buffer, 0 ) * 2;

      if (temp_samples == 0)
      {
         if (voice->repeat)
         {
            if (voice->stop_cb)
               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);

            replay_seek( voice->types.mod.stream, 0);
            goto again;
         }

         if (voice->stop_cb)
            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         return;
      }

      voice->types.mod.position = 0;
      voice->types.mod.samples  = temp_samples;
   }
   pcm = voice->types.mod.buffer + voice->types.mod.position;

   if (voice->types.mod.samples < buf_free)
   {
      for (i = voice->types.mod.samples; i != 0; i--)
      {
         samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;
         samplef     = samplef * 2.0f - 1.0f;
         *buffer++  += samplef * volume;
      }

      buf_free -= voice->types.mod.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
   {
      samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;
      samplef     = samplef * 2.0f - 1.0f;
      *buffer++  += samplef * volume;
   }

   voice->types.mod.position += buf_free;
   voice->types.mod.samples  -= buf_free;
}
#endif

#ifdef HAVE_DR_FLAC
static void audio_mixer_mix_flac(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   struct resampler_data info;
   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
   unsigned buf_free                = (unsigned)(num_frames * 2);
   unsigned temp_samples            = 0;
   float *pcm                       = NULL;

   if (voice->types.flac.position == voice->types.flac.samples)
   {
again:
      temp_samples = (unsigned)drflac_read_pcm_frames_f32( voice->types.flac.stream, AUDIO_MIXER_TEMP_BUFFER, temp_buffer);
      if (temp_samples == 0)
      {
         if (voice->repeat)
         {
            if (voice->stop_cb)
               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);

            drflac_seek_to_pcm_frame(voice->types.flac.stream,0);
            goto again;
         }

         if (voice->stop_cb)
            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         return;
      }

      info.data_in              = temp_buffer;
      info.data_out             = voice->types.flac.buffer;
      info.input_frames         = temp_samples / 2;
      info.output_frames        = 0;
      info.ratio                = voice->types.flac.ratio;

      if (voice->types.flac.resampler)
         voice->types.flac.resampler->process(
               voice->types.flac.resampler_data, &info);
      else
         memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float));
      voice->types.flac.position = 0;
      voice->types.flac.samples  = voice->types.flac.buf_samples;
   }

   pcm = voice->types.flac.buffer + voice->types.flac.position;

   if (voice->types.flac.samples < buf_free)
   {
      for (i = voice->types.flac.samples; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      buf_free -= voice->types.flac.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
      *buffer++ += *pcm++ * volume;

   voice->types.flac.position += buf_free;
   voice->types.flac.samples  -= buf_free;
}
#endif

#ifdef HAVE_DR_MP3
static void audio_mixer_mix_mp3(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   struct resampler_data info;
   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
   unsigned buf_free                = (unsigned)(num_frames * 2);
   unsigned temp_samples            = 0;
   float* pcm                       = NULL;

   if (voice->types.mp3.position == voice->types.mp3.samples)
   {
again:
      temp_samples = (unsigned)drmp3_read_f32(
            &voice->types.mp3.stream,
            AUDIO_MIXER_TEMP_BUFFER / 2, temp_buffer) * 2;

      if (temp_samples == 0)
      {
         if (voice->repeat)
         {
            if (voice->stop_cb)
               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);

            drmp3_seek_to_frame(&voice->types.mp3.stream,0);
            goto again;
         }

         if (voice->stop_cb)
            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         return;
      }

      info.data_in              = temp_buffer;
      info.data_out             = voice->types.mp3.buffer;
      info.input_frames         = temp_samples / 2;
      info.output_frames        = 0;
      info.ratio                = voice->types.mp3.ratio;

      if (voice->types.mp3.resampler)
         voice->types.mp3.resampler->process(
               voice->types.mp3.resampler_data, &info);
      else
         memcpy(voice->types.mp3.buffer, temp_buffer,
               temp_samples * sizeof(float));
      voice->types.mp3.position = 0;
      voice->types.mp3.samples  = voice->types.mp3.buf_samples;
   }

   pcm = voice->types.mp3.buffer + voice->types.mp3.position;

   if (voice->types.mp3.samples < buf_free)
   {
      for (i = voice->types.mp3.samples; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      buf_free -= voice->types.mp3.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
      *buffer++ += *pcm++ * volume;

   voice->types.mp3.position += buf_free;
   voice->types.mp3.samples  -= buf_free;
}
#endif

void audio_mixer_mix(float* buffer, size_t num_frames,
      float volume_override, bool override)
{
   unsigned i;
   size_t j                   = 0;
   float* sample              = NULL;
   audio_mixer_voice_t* voice = s_voices;

   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
   {
      float volume;

      AUDIO_MIXER_LOCK(voice);

      volume = (override) ? volume_override : voice->volume;

      switch (voice->type)
      {
         case AUDIO_MIXER_TYPE_WAV:
            audio_mixer_mix_wav(buffer, num_frames, voice, volume);
            break;
         case AUDIO_MIXER_TYPE_OGG:
#ifdef HAVE_STB_VORBIS
            audio_mixer_mix_ogg(buffer, num_frames, voice, volume);
#endif
            break;
         case AUDIO_MIXER_TYPE_MOD:
#ifdef HAVE_IBXM
            audio_mixer_mix_mod(buffer, num_frames, voice, volume);
#endif
            break;
         case AUDIO_MIXER_TYPE_FLAC:
#ifdef HAVE_DR_FLAC
            audio_mixer_mix_flac(buffer, num_frames, voice, volume);
#endif
            break;
            case AUDIO_MIXER_TYPE_MP3:
#ifdef HAVE_DR_MP3
            audio_mixer_mix_mp3(buffer, num_frames, voice, volume);
#endif
            break;
         case AUDIO_MIXER_TYPE_NONE:
            break;
      }

      AUDIO_MIXER_UNLOCK(voice);
   }

   for (j = 0, sample = buffer; j < num_frames * 2; j++, sample++)
   {
      if (*sample < -1.0f)
         *sample = -1.0f;
      else if (*sample > 1.0f)
         *sample = 1.0f;
   }
}

float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice)
{
   if (!voice)
      return 0.0f;

   return voice->volume;
}

void audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val)
{
   if (!voice)
      return;

   AUDIO_MIXER_LOCK(voice);
   voice->volume = val;
   AUDIO_MIXER_UNLOCK(voice);
}

./include/libretro-common/audio/conversion/float_to_s16.c

/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <stdint.h>
#include <stddef.h>

#if defined(__SSE2__)
#include <emmintrin.h>
#elif defined(__ALTIVEC__)
#include <altivec.h>
#endif

#include <features/features_cpu.h>
#include <audio/conversion/float_to_s16.h>

#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
static bool float_to_s16_neon_enabled = false;
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
void convert_float_s16_asm(int16_t *s, const float *in, size_t len);
#else
#include <arm_neon.h>
#endif

void convert_float_to_s16(int16_t *s, const float *in, size_t len)
{
   size_t i           = 0;
   if (float_to_s16_neon_enabled)
   {
      float        gf = (1<<15);
      float32x4_t vgf = {gf, gf, gf, gf};
      while (len >= 8)
      {
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
         size_t aligned_samples = len & ~7;
         if (aligned_samples)
            convert_float_s16_asm(s, in, aligned_samples);

         s        += aligned_samples;
         in       += aligned_samples;
         samples  -= aligned_samples;
         i         = 0;
#else
         int16x4x2_t oreg;
         int32x4x2_t creg;
         float32x4x2_t inreg = vld2q_f32(in);
         creg.val[0]         = vcvtq_s32_f32(vmulq_f32(inreg.val[0], vgf));
         creg.val[1]         = vcvtq_s32_f32(vmulq_f32(inreg.val[1], vgf));
         oreg.val[0]         = vqmovn_s32(creg.val[0]);
         oreg.val[1]         = vqmovn_s32(creg.val[1]);
         vst2_s16(s, oreg);
         in      += 8;
         s       += 8;
         len     -= 8;
#endif
      }
   }

   for (; i < len; i++)
   {
      int32_t val = (int32_t)(in[i] * 0x8000);
      s[i]        = (val > 0x7FFF) ? 0x7FFF :
         (val < -0x8000 ? -0x8000 : (int16_t)val);
   }
}

void convert_float_to_s16_init_simd(void)
{
   uint64_t cpu = cpu_features_get();

   if (cpu & RETRO_SIMD_NEON)
      float_to_s16_neon_enabled = true;
}
#else
void convert_float_to_s16(int16_t *s, const float *in, size_t len)
{
   size_t i          = 0;
#if defined(__SSE2__)
   __m128 factor     = _mm_set1_ps((float)0x8000);
   /* Initialize a 4D vector with 32768.0 for its elements */

   for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)
   { /* Skip forward 8 samples at a time... */
      __m128 input_a = _mm_loadu_ps(in + 0); /* Create a 4-float vector from the next four samples... */
      __m128 input_b = _mm_loadu_ps(in + 4); /* ...and another from the *next* next four. */
      __m128 res_a   = _mm_mul_ps(input_a, factor);
      __m128 res_b   = _mm_mul_ps(input_b, factor); /* Multiply these samples by 32768 */
      __m128i ints_a = _mm_cvtps_epi32(res_a);
      __m128i ints_b = _mm_cvtps_epi32(res_b); /* Convert the samples to 32-bit integers */
      __m128i packed = _mm_packs_epi32(ints_a, ints_b); /* Then convert them to 16-bit ints, clamping to [-32768, 32767] */

      _mm_storeu_si128((__m128i *)s, packed); /* Then put the result in the output array */
   }

   len               = len - i;
   i                 = 0;
   /* If there are any stray samples at the end, we need to convert them
    * (maybe the original array didn't contain a multiple of 8 samples) */
#elif defined(__ALTIVEC__)
   int samples_in    = len;

   /* Unaligned loads/store is a bit expensive,
    * so we optimize for the good path (very likely). */
   if (((uintptr_t)s & 15) + ((uintptr_t)in & 15) == 0)
   {
      size_t i;
      for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)
      {
         vector float       input0 = vec_ld( 0, in);
         vector float       input1 = vec_ld(16, in);
         vector signed int result0 = vec_cts(input0, 15);
         vector signed int result1 = vec_cts(input1, 15);
         vec_st(vec_packs(result0, result1), 0, s);
      }

      samples_in    -= i;
   }

   len               = samples_in;
   i                 = 0;
#elif defined(_MIPS_ARCH_ALLEGREX)
#ifdef DEBUG
   /* Make sure the buffers are 16 byte aligned, this should be
    * the default behaviour of malloc in the PSPSDK.
    * Assume alignment. */
   retro_assert(((uintptr_t)in  & 0xf) == 0);
   retro_assert(((uintptr_t)s & 0xf) == 0);
#endif

   for (i = 0; i + 8 <= len; i += 8)
   {
      __asm__ (
            ".set    push                 \n"
            ".set    noreorder            \n"

            "lv.q    c100,  0(%0)         \n"
            "lv.q    c110,  16(%0)        \n"

            "vf2in.q c100, c100, 31       \n"
            "vf2in.q c110, c110, 31       \n"
            "vi2s.q  c100, c100           \n"
            "vi2s.q  c102, c110           \n"

            "sv.q    c100,  0(%1)         \n"

            ".set    pop                  \n"
            :: "r"(in + i), "r"(s + i));
   }
#endif

   /* This loop converts stray samples to the right format,
    * but it's also a fallback in case no SIMD instructions are available. */
   for (; i < len; i++)
   {
      int32_t val    = (int32_t)(in[i] * 0x8000);
      s[i]           = (val > 0x7FFF)
         ? 0x7FFF
         : (val < -0x8000 ? -0x8000 : (int16_t)val);
   }
}

void convert_float_to_s16_init_simd(void) { }
#endif

./include/libretro-common/audio/conversion/float_to_s16_neon.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#if defined(__thumb__)
#define DECL_ARMMODE(x) "  .align 2\n" "  .global " x "\n" "  .thumb\n" "  .thumb_func\n" "  .type " x ", %function\n" x ":\n"
#else
#define DECL_ARMMODE(x) "  .align 4\n" "  .global " x "\n" "  .arm\n" x ":\n"
#endif

asm(
    DECL_ARMMODE("convert_float_s16_asm")
    DECL_ARMMODE("_convert_float_s16_asm")
    "# convert_float_s16_asm(int16_t *s, const float *in, size_t len)\n"
    "   # Hacky way to get a constant of 2^15.\n"
    "   # ((2^4)^2)^2 * 0.5 = 2^15\n"
    "   vmov.f32 q8, #16.0\n"
    "   vmov.f32 q9, #0.5\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q9\n"
    "\n"
    "1:\n"
    "   # Preload here?\n"
    "   vld1.f32 {q0-q1}, [r1]!\n"
    "\n"
    "   vmul.f32 q0, q0, q8\n"
    "   vmul.f32 q1, q1, q8\n"
    "\n"
    "   vcvt.s32.f32 q0, q0\n"
    "   vcvt.s32.f32 q1, q1\n"
    "\n"
    "   vqmovn.s32 d4, q0\n"
    "   vqmovn.s32 d5, q1\n"
    "\n"
    "   vst1.f32 {d4-d5}, [r0]!\n"
    "\n"
    "   # Guaranteed to get samples in multiples of 8.\n"
    "   subs r2, r2, #8\n"
    "   bne 1b\n"
    "\n"
    "   bx lr\n"
    "\n"
    );
#endif

./include/libretro-common/audio/conversion/float_to_s16_neon.S

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#ifndef __MACH__
.arm
#endif

.align 4
.globl convert_float_s16_asm
#ifndef __MACH__
.type convert_float_s16_asm, %function
#endif
.globl _convert_float_s16_asm
#ifndef __MACH__
.type _convert_float_s16_asm, %function
#endif
# convert_float_s16_asm(int16_t *out, const float *in, size_t samples)
convert_float_s16_asm:
_convert_float_s16_asm:
   # Hacky way to get a constant of 2^15.
   # ((2^4)^2)^2 * 0.5 = 2^15
   vmov.f32 q8, #16.0
   vmov.f32 q9, #0.5
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q9

1:
   # Preload here?
   vld1.f32 {q0-q1}, [r1]!

   vmul.f32 q0, q0, q8
   vmul.f32 q1, q1, q8

   vcvt.s32.f32 q0, q0
   vcvt.s32.f32 q1, q1

   vqmovn.s32 d4, q0
   vqmovn.s32 d5, q1

   vst1.f32 {d4-d5}, [r0]!

   # Guaranteed to get samples in multiples of 8.
   subs r2, r2, #8
   bne 1b

   bx lr

#endif

./include/libretro-common/audio/conversion/mono_to_stereo_float.c

/* Copyright  (C) 2010-2023 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (mono_to_stereo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <stdint.h>
#include <stddef.h>

#include <audio/conversion/dual_mono.h>

/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */
void convert_to_dual_mono_float(float *s, const float *in, size_t len)
{
   unsigned i = 0;

   if (!s || !in || !len)
      return;

   for (; i < len; i++)
   {
      s[i * 2]     = in[i];
      s[i * 2 + 1] = in[i];
   }
}

/* Why is there no equivalent for int16_t samples?
 * No inherent reason, I just didn't need one.
 * If you do, open a pull request. */

./include/libretro-common/audio/conversion/s16_to_float.c

/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__SSE2__)
#include <emmintrin.h>
#elif defined(__ALTIVEC__)
#include <altivec.h>
#endif

#include <boolean.h>
#include <features/features_cpu.h>
#include <audio/conversion/s16_to_float.h>

#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
static bool s16_to_float_neon_enabled = false;

#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
/* Avoid potential hard-float/soft-float ABI issues. */
void convert_s16_float_asm(float *s, const int16_t *in,
      size_t len, const float *gain);
#else
#include <arm_neon.h>
#endif

void convert_s16_to_float(float *s,
      const int16_t *in, size_t len, float gain)
{
   unsigned i      = 0;

   if (s16_to_float_neon_enabled)
   {
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
      size_t aligned_samples = len & ~7;
      if (aligned_samples)
         convert_s16_float_asm(s, in, aligned_samples, &gain);

      /* Could do all conversion in ASM, but keep it simple for now. */
      s                 += aligned_samples;
      in                += aligned_samples;
      len               -= aligned_samples;
      i                  = 0;
#else
      float        gf    = gain / (1 << 15);
      float32x4_t vgf    = {gf, gf, gf, gf};
      while (len >= 8)
      {
         float32x4x2_t oreg;
         int16x4x2_t inreg   = vld2_s16(in);
         int32x4_t      p1   = vmovl_s16(inreg.val[0]);
         int32x4_t      p2   = vmovl_s16(inreg.val[1]);
         oreg.val[0]         = vmulq_f32(vcvtq_f32_s32(p1), vgf);
         oreg.val[1]         = vmulq_f32(vcvtq_f32_s32(p2), vgf);
         vst2q_f32(s, oreg);
         in                 += 8;
         s                  += 8;
         len                -= 8;
      }
#endif
   }

   gain /= 0x8000;

   for (; i < len; i++)
      s[i] = (float)in[i] * gain;
}

void convert_s16_to_float_init_simd(void)
{
   uint64_t cpu = cpu_features_get();

   if (cpu & RETRO_SIMD_NEON)
      s16_to_float_neon_enabled = true;
}
#else
void convert_s16_to_float(float *s,
      const int16_t *in, size_t len, float gain)
{
   unsigned i      = 0;

#if defined(__SSE2__)
   float fgain   = gain / UINT32_C(0x80000000);
   __m128 factor = _mm_set1_ps(fgain);

   for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)
   {
      __m128i input    = _mm_loadu_si128((const __m128i *)in);
      __m128i regs_l   = _mm_unpacklo_epi16(_mm_setzero_si128(), input);
      __m128i regs_r   = _mm_unpackhi_epi16(_mm_setzero_si128(), input);
      __m128 output_l  = _mm_mul_ps(_mm_cvtepi32_ps(regs_l), factor);
      __m128 output_r  = _mm_mul_ps(_mm_cvtepi32_ps(regs_r), factor);

      _mm_storeu_ps(s + 0, output_l);
      _mm_storeu_ps(s + 4, output_r);
   }

   len     = len - i;
   i       = 0;
#elif defined(__ALTIVEC__)
   size_t samples_in = len;

   /* Unaligned loads/store is a bit expensive, so we
    * optimize for the good path (very likely). */
   if (((uintptr_t)s & 15) + ((uintptr_t)in & 15) == 0)
   {
      const vector float gain_vec = { gain, gain , gain, gain };
      const vector float zero_vec = { 0.0f, 0.0f, 0.0f, 0.0f};

      for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)
      {
         vector signed short input = vec_ld(0, in);
         vector signed int hi      = vec_unpackh(input);
         vector signed int lo      = vec_unpackl(input);
         vector float out_hi       = vec_madd(vec_ctf(hi, 15), gain_vec, zero_vec);
         vector float out_lo       = vec_madd(vec_ctf(lo, 15), gain_vec, zero_vec);

         vec_st(out_hi,  0, s);
         vec_st(out_lo, 16, s);
      }

      samples_in -= i;
   }

   len     = samples_in;
   i       = 0;
#endif

   gain   /= 0x8000;

#if defined(_MIPS_ARCH_ALLEGREX)
#ifdef DEBUG
   /* Make sure the buffer is 16 byte aligned, this should be the
    * default behaviour of malloc in the PSPSDK.
    * Only the output buffer can be assumed to be 16-byte aligned. */
   retro_assert(((uintptr_t)s & 0xf) == 0);
#endif

   __asm__ (
         ".set    push                    \n"
         ".set    noreorder               \n"
         "mtv     %0, s200                \n"
         ".set    pop                     \n"
         ::"r"(gain));

   for (i = 0; i + 16 <= len; i += 16)
   {
      __asm__ (
            ".set    push                 \n"
            ".set    noreorder            \n"

            "lv.s    s100,  0(%0)         \n"
            "lv.s    s101,  4(%0)         \n"
            "lv.s    s110,  8(%0)         \n"
            "lv.s    s111, 12(%0)         \n"
            "lv.s    s120, 16(%0)         \n"
            "lv.s    s121, 20(%0)         \n"
            "lv.s    s130, 24(%0)         \n"
            "lv.s    s131, 28(%0)         \n"

            "vs2i.p  c100, c100           \n"
            "vs2i.p  c110, c110           \n"
            "vs2i.p  c120, c120           \n"
            "vs2i.p  c130, c130           \n"

            "vi2f.q  c100, c100, 16       \n"
            "vi2f.q  c110, c110, 16       \n"
            "vi2f.q  c120, c120, 16       \n"
            "vi2f.q  c130, c130, 16       \n"

            "vmscl.q e100, e100, s200     \n"

            "sv.q    c100,  0(%1)         \n"
            "sv.q    c110, 16(%1)         \n"
            "sv.q    c120, 32(%1)         \n"
            "sv.q    c130, 48(%1)         \n"

            ".set    pop                  \n"
            :: "r"(in + i), "r"(s + i));
   }
#endif

   for (; i < len; i++)
      s[i] = (float)in[i] * gain;
}

void convert_s16_to_float_init_simd(void) { }
#endif

./include/libretro-common/audio/conversion/s16_to_float_neon.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#if defined(__thumb__)
#define DECL_ARMMODE(x) "  .align 2\n" "  .global " x "\n" "  .thumb\n" "  .thumb_func\n" "  .type " x ", %function\n" x ":\n"
#else
#define DECL_ARMMODE(x) "  .align 4\n" "  .global " x "\n" "  .arm\n" x ":\n"
#endif

asm(
    DECL_ARMMODE("convert_s16_float_asm")
    DECL_ARMMODE("_convert_s16_float_asm")
    "# convert_s16_float_asm(float *s, const int16_t *in, size_t len, const float *gain)\n"
    "   # Hacky way to get a constant of 2^-15.\n"
    "   # Might be faster to just load a constant from memory.\n"
    "   # It's just done once however ...\n"
    "   vmov.f32 q8, #0.25\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vadd.f32 q8, q8, q8\n"
    "\n"
    "   # Apply gain\n"
    "   vld1.f32 {d6[0]}, [r3]\n"
    "   vmul.f32 q8, q8, d6[0]\n"
    "\n"
    "1:\n"
    "   # Preload here?\n"
    "   vld1.s16 {q0}, [r1]!\n"
    "\n"
    "   # Widen to 32-bit\n"
    "   vmovl.s16 q1, d0\n"
    "   vmovl.s16 q2, d1\n"
    "\n"
    "   # Convert to float\n"
    "   vcvt.f32.s32 q1, q1\n"
    "   vcvt.f32.s32 q2, q2\n"
    "\n"
    "   vmul.f32 q1, q1, q8\n"
    "   vmul.f32 q2, q2, q8\n"
    "\n"
    "   vst1.f32 {q1-q2}, [r0]!\n"
    "\n"
    "   # Guaranteed to get samples in multiples of 8.\n"
    "   subs r2, r2, #8\n"
    "   bne 1b\n"
    "\n"
    "   bx lr\n"
    "\n"
    );
#endif

./include/libretro-common/audio/conversion/s16_to_float_neon.S

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#ifndef __MACH__
.arm
#endif

.align 4
.globl convert_s16_float_asm
#ifndef __MACH__
.type convert_s16_float_asm, %function
#endif
.globl _convert_s16_float_asm
#ifndef __MACH__
.type _convert_s16_float_asm, %function
#endif
# convert_s16_float_asm(float *out, const int16_t *in, size_t samples, const float *gain)
convert_s16_float_asm:
_convert_s16_float_asm:
   # Hacky way to get a constant of 2^-15.
   # Might be faster to just load a constant from memory.
   # It's just done once however ...
   vmov.f32 q8, #0.25
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q8
   vadd.f32 q8, q8, q8

   # Apply gain
   vld1.f32 {d6[0]}, [r3]
   vmul.f32 q8, q8, d6[0]

1:
   # Preload here?
   vld1.s16 {q0}, [r1]!

   # Widen to 32-bit
   vmovl.s16 q1, d0
   vmovl.s16 q2, d1

   # Convert to float
   vcvt.f32.s32 q1, q1
   vcvt.f32.s32 q2, q2

   vmul.f32 q1, q1, q8
   vmul.f32 q2, q2, q8

   vst1.f32 {q1-q2}, [r0]!

   # Guaranteed to get samples in multiples of 8.
   subs r2, r2, #8
   bne 1b

   bx lr

#endif

./include/libretro-common/audio/conversion/stereo_to_mono_float.c

/* Copyright  (C) 2010-2023 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (mono_to_stereo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <stdint.h>
#include <stddef.h>

#include <audio/conversion/dual_mono.h>

/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */
void convert_to_mono_float_left(float *out, const float *in, size_t frames)
{
   unsigned i = 0;

   if (!out || !in || !frames)
      return;

   for (; i < frames; i++)
   {
      out[i] = in[i * 2];
   }
}

/* Why is there no equivalent for int16_t samples?
 * No inherent reason, I just didn't need one.
 * If you do, open a pull request.
 * Same goes for the lack of a convert_to_mono_float_right;
 * I didn't need one, so I didn't write one. */

./include/libretro-common/audio/dsp_filter.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dsp_filter.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>

#include <retro_miscellaneous.h>

#include <compat/posix_string.h>
#include <dynamic/dylib.h>

#include <file/file_path.h>
#include <file/config_file_userdata.h>
#include <features/features_cpu.h>
#include <lists/string_list.h>
#include <string/stdstring.h>
#include <libretro_dspfilter.h>

#include <audio/dsp_filter.h>

struct retro_dsp_plug
{
#ifdef HAVE_DYLIB
   dylib_t lib;
#endif
   const struct dspfilter_implementation *impl;
};

struct retro_dsp_instance
{
   const struct dspfilter_implementation *impl;
   void *impl_data;
};

struct retro_dsp_filter
{
   config_file_t *conf;

   struct retro_dsp_plug *plugs;
   unsigned num_plugs;

   struct retro_dsp_instance *instances;
   unsigned num_instances;
};

static const struct dspfilter_implementation *find_implementation(
      retro_dsp_filter_t *dsp, const char *ident)
{
   unsigned i;
   for (i = 0; i < dsp->num_plugs; i++)
   {
      if (string_is_equal(dsp->plugs[i].impl->short_ident, ident))
         return dsp->plugs[i].impl;
   }

   return NULL;
}

static const struct dspfilter_config dspfilter_config = {
   config_userdata_get_float,
   config_userdata_get_int,
   config_userdata_get_float_array,
   config_userdata_get_int_array,
   config_userdata_get_string,
   config_userdata_free,
};

static bool create_filter_graph(retro_dsp_filter_t *dsp, float sample_rate)
{
   unsigned i;
   struct retro_dsp_instance *instances = NULL;
   unsigned filters                     = 0;

   if (!config_get_uint(dsp->conf, "filters", &filters))
      return false;

   instances = (struct retro_dsp_instance*)calloc(filters, sizeof(*instances));
   if (!instances)
      return false;

   dsp->instances     = instances;
   dsp->num_instances = filters;

   for (i = 0; i < filters; i++)
   {
      struct config_file_userdata userdata;
      struct dspfilter_info info;
      char key[64];
      char name[64];

      key[0] = name[0] = '\0';

      info.input_rate  = sample_rate;

      snprintf(key, sizeof(key), "filter%u", i);

      if (!config_get_array(dsp->conf, key, name, sizeof(name)))
         return false;

      dsp->instances[i].impl = find_implementation(dsp, name);
      if (!dsp->instances[i].impl)
         return false;

      userdata.conf = dsp->conf;
      /* Index-specific configs take priority over ident-specific. */
      userdata.prefix[0] = key;
      userdata.prefix[1] = dsp->instances[i].impl->short_ident;

      dsp->instances[i].impl_data = dsp->instances[i].impl->init(&info,
            &dspfilter_config, &userdata);
      if (!dsp->instances[i].impl_data)
         return false;
   }

   return true;
}

#if defined(HAVE_FILTERS_BUILTIN)
extern const struct dspfilter_implementation *chorus_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *delta_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *echo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *eq_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *iir_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *panning_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *phaser_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *reverb_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *tremolo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *vibrato_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *wahwah_dspfilter_get_implementation(dspfilter_simd_mask_t mask);

static const dspfilter_get_implementation_t dsp_plugs_builtin[] = {
   chorus_dspfilter_get_implementation,
   delta_dspfilter_get_implementation,
   echo_dspfilter_get_implementation,
   eq_dspfilter_get_implementation,
   iir_dspfilter_get_implementation,
   panning_dspfilter_get_implementation,
   phaser_dspfilter_get_implementation,
   reverb_dspfilter_get_implementation,
   tremolo_dspfilter_get_implementation,
   vibrato_dspfilter_get_implementation,
   wahwah_dspfilter_get_implementation,
};

static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
{
   unsigned i;
   dspfilter_simd_mask_t mask   = (dspfilter_simd_mask_t)cpu_features_get();
   struct retro_dsp_plug *plugs = (struct retro_dsp_plug*)
      calloc(ARRAY_SIZE(dsp_plugs_builtin), sizeof(*plugs));

   if (!plugs)
      return false;

   dsp->plugs     = plugs;
   dsp->num_plugs = ARRAY_SIZE(dsp_plugs_builtin);

   for (i = 0; i < ARRAY_SIZE(dsp_plugs_builtin); i++)
   {
      dsp->plugs[i].impl = dsp_plugs_builtin[i](mask);
      if (!dsp->plugs[i].impl)
         return false;
   }

   return true;
}
#elif defined(HAVE_DYLIB)
static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
{
   unsigned i;
   dspfilter_simd_mask_t mask = (dspfilter_simd_mask_t)cpu_features_get();
   unsigned list_size         = list ? (unsigned)list->size : 0;

   for (i = 0; i < list_size; i++)
   {
      dspfilter_get_implementation_t cb;
      const struct dspfilter_implementation *impl = NULL;
      struct retro_dsp_plug *new_plugs            = NULL;
      dylib_t lib                                 =
         dylib_load(list->elems[i].data);

      if (!lib)
         continue;

      cb = (dspfilter_get_implementation_t)dylib_proc(lib, "dspfilter_get_implementation");
      if (!cb)
      {
         dylib_close(lib);
         continue;
      }

      impl = cb(mask);
      if (!impl)
      {
         dylib_close(lib);
         continue;
      }

      if (impl->api_version != DSPFILTER_API_VERSION)
      {
         dylib_close(lib);
         continue;
      }

      new_plugs = (struct retro_dsp_plug*)
         realloc(dsp->plugs, sizeof(*dsp->plugs) * (dsp->num_plugs + 1));
      if (!new_plugs)
      {
         dylib_close(lib);
         return false;
      }

      /* Found plug. */

      dsp->plugs = new_plugs;
      dsp->plugs[dsp->num_plugs].lib = lib;
      dsp->plugs[dsp->num_plugs].impl = impl;
      dsp->num_plugs++;
   }

   return true;
}
#endif

retro_dsp_filter_t *retro_dsp_filter_new(
      const char *filter_config,
      void *string_data,
      float sample_rate)
{
   config_file_t *conf           = NULL;
   struct string_list *plugs     = NULL;
   retro_dsp_filter_t *dsp       = (retro_dsp_filter_t*)calloc(1, sizeof(*dsp));

   if (!dsp)
      return NULL;

   if (!(conf = config_file_new_from_path_to_string(filter_config)))
      goto error;

   dsp->conf = conf;

   if (string_data)
      plugs = (struct string_list*)string_data;

#if defined(HAVE_DYLIB) || defined(HAVE_FILTERS_BUILTIN)
   if (!append_plugs(dsp, plugs))
      goto error;
#endif

   if (plugs)
      string_list_free(plugs);
   plugs = NULL;

   if (!create_filter_graph(dsp, sample_rate))
      goto error;

   return dsp;

error:
   if (plugs)
      string_list_free(plugs);
   retro_dsp_filter_free(dsp);
   return NULL;
}

void retro_dsp_filter_free(retro_dsp_filter_t *dsp)
{
   unsigned i;
   if (!dsp)
      return;

   for (i = 0; i < dsp->num_instances; i++)
   {
      if (dsp->instances[i].impl_data && dsp->instances[i].impl)
         dsp->instances[i].impl->free(dsp->instances[i].impl_data);
   }
   free(dsp->instances);

#ifdef HAVE_DYLIB
   for (i = 0; i < dsp->num_plugs; i++)
   {
      if (dsp->plugs[i].lib)
         dylib_close(dsp->plugs[i].lib);
   }
   free(dsp->plugs);
#endif

   if (dsp->conf)
      config_file_free(dsp->conf);

   free(dsp);
}

void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
      struct retro_dsp_data *data)
{
   unsigned i;
   struct dspfilter_output output = {0};
   struct dspfilter_input input   = {0};

   output.samples = data->input;
   output.frames  = data->input_frames;

   for (i = 0; i < dsp->num_instances; i++)
   {
      input.samples = output.samples;
      input.frames  = output.frames;
      dsp->instances[i].impl->process(
            dsp->instances[i].impl_data, &output, &input);
   }

   data->output        = output.samples;
   data->output_frames = output.frames;
}

./include/libretro-common/audio/dsp_filters/BassBoost.dsp

filters = 2
filter0 = iir
filter1 = panning

iir_gain = 10.0
iir_type = BBOOST
iir_frequency = 200.0

# Avoids clipping.
panning_left_mix = "0.3 0.0"
panning_right_mix = "0.0 0.3"

./include/libretro-common/audio/dsp_filters/ChipTuneEnhance.dsp

filters = 4
filter0 = eq
filter1 = reverb
filter2 = iir
filter3 = panning

eq_frequencies = "32 64 125 250 500 1000 2000 4000 8000 16000 20000"
eq_gains = "6 9 12 7 6 5 7 9 11 6 0"

# Reverb - slight reverb
 reverb_drytime = 0.5
 reverb_wettime = 0.15
 reverb_damping = 0.8
 reverb_roomwidth = 0.25
 reverb_roomsize = 0.25

# IIR - filters out some harsh sounds on the upper end
iir_type = RIAA_CD

# Panning - cut the volume a bit
panning_left_mix = "0.75 0.0"
panning_right_mix = "0.0 0.75"

./include/libretro-common/audio/dsp_filters/ChipTune-Lowpass.dsp

filters = 1
filter0 = iir

iir_frequency = 8600.0
iir_quality = 0.707
iir_gain = 6.0
iir_type = LPF

./include/libretro-common/audio/dsp_filters/chorus.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (chorus.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>

#define CHORUS_MAX_DELAY 4096
#define CHORUS_DELAY_MASK (CHORUS_MAX_DELAY - 1)

struct chorus_data
{
   float old[2][CHORUS_MAX_DELAY];
   float delay;
   float depth;
   float input_rate;
   float mix_dry;
   float mix_wet;
   unsigned old_ptr;
   unsigned lfo_ptr;
   unsigned lfo_period;
};

static void chorus_free(void *data)
{
   if (data)
      free(data);
}

static void chorus_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out             = NULL;
   struct chorus_data *ch = (struct chorus_data*)data;

   output->samples        = input->samples;
   output->frames         = input->frames;
   out                    = output->samples;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      unsigned delay_int;
      float delay_frac, l_a, l_b, r_a, r_b;
      float chorus_l, chorus_r;
      float in[2]             = { out[0], out[1] };
      float delay             = ch->delay + ch->depth * sin((2.0 * M_PI * ch->lfo_ptr++) / ch->lfo_period);

      delay                  *= ch->input_rate;
      if (ch->lfo_ptr >= ch->lfo_period)
         ch->lfo_ptr          = 0;

      delay_int               = (unsigned)delay;

      if (delay_int >= CHORUS_MAX_DELAY - 1)
         delay_int            = CHORUS_MAX_DELAY - 2;

      delay_frac              = delay - delay_int;

      ch->old[0][ch->old_ptr] = in[0];
      ch->old[1][ch->old_ptr] = in[1];

      l_a                     = ch->old[0][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];
      l_b                     = ch->old[0][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];
      r_a                     = ch->old[1][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];
      r_b                     = ch->old[1][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];

      /* Lerp introduces aliasing of the chorus component,
       * but doing full polyphase here is probably overkill. */
      chorus_l                = l_a * (1.0f - delay_frac) + l_b * delay_frac;
      chorus_r                = r_a * (1.0f - delay_frac) + r_b * delay_frac;

      out[0]                  = ch->mix_dry * in[0] + ch->mix_wet * chorus_l;
      out[1]                  = ch->mix_dry * in[1] + ch->mix_wet * chorus_r;

      ch->old_ptr             = (ch->old_ptr + 1) & CHORUS_DELAY_MASK;
   }
}

static void *chorus_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float delay, depth, lfo_freq, drywet;
   struct chorus_data *ch = (struct chorus_data*)calloc(1, sizeof(*ch));
   if (!ch)
      return NULL;

   config->get_float(userdata, "delay_ms", &delay, 25.0f);
   config->get_float(userdata, "depth_ms", &depth, 1.0f);
   config->get_float(userdata, "lfo_freq", &lfo_freq, 0.5f);
   config->get_float(userdata, "drywet", &drywet, 0.8f);

   delay            /= 1000.0f;
   depth            /= 1000.0f;

   if (depth > delay)
      depth          = delay;

   if (drywet < 0.0f)
      drywet         = 0.0f;
   else if (drywet > 1.0f)
      drywet         = 1.0f;

   ch->mix_dry       = 1.0f - 0.5f * drywet;
   ch->mix_wet       = 0.5f * drywet;

   ch->delay         = delay;
   ch->depth         = depth;
   ch->lfo_period    = (1.0f / lfo_freq) * info->input_rate;
   ch->input_rate    = info->input_rate;
   if (!ch->lfo_period)
      ch->lfo_period = 1;
   return ch;
}

static const struct dspfilter_implementation chorus_plug = {
   chorus_init,
   chorus_process,
   chorus_free,

   DSPFILTER_API_VERSION,
   "Chorus",
   "chorus",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation chorus_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *
dspfilter_get_implementation(dspfilter_simd_mask_t mask) { return &chorus_plug; }

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Chorus.dsp

filters = 1
filter0 = chorus

# Controls the base delay of the chorus (milliseconds).
# chorus_delay_ms = 25.0
#
# Controls the depth of the delay. The delay will vary between delay_ms +/- depth_ms.
# chorus_depth_ms = 1.0
#
# Frequency of LFO which controls delay.
# chorus_lfo_freq = 0.5
#
# Controls dry/wet-ness of effect. 1.0 = full chorus, 0.0 = no chorus.
# chorus_drywet = 0.8

./include/libretro-common/audio/dsp_filters/configure

#!/bin/sh

PACKAGE_NAME=retroarch-filters-audio

./include/libretro-common/audio/dsp_filters/crystalizer.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (echo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>

struct delta_data
{
   float intensity;
   float old[2];
};

static void delta_free(void *data)
{
   free(data);
}

static void delta_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i, c;
   struct delta_data *d   = (struct delta_data*)data;
   float *out             = output->samples;
   output->samples        = input->samples;
   output->frames         = input->frames;

   for (i = 0; i < input->frames; i++)
   {
      for (c = 0; c < 2; c++)
      {
           float current  = *out;
           *out++         = current + (current - d->old[c]) * d->intensity;
           d->old[c]      = current;
      }
   }
}

static void *delta_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   struct delta_data *d = (struct delta_data*)calloc(1, sizeof(*d));
   if (!d)
      return NULL;
   config->get_float(userdata, "intensity", &d->intensity, 5.0f);
   return d;
}

static const struct dspfilter_implementation delta_plug = {
   delta_init,
   delta_process,
   delta_free,
   DSPFILTER_API_VERSION,
   "Delta Sharpening",
   "crystalizer",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation delta_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &delta_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Crystalizer.dsp

filters = 1
filter0 = crystalizer
# Controls dry/wet-ness of effect. 0.0 = none, 10.0 = max.
crystalizer_intensity = 5.0

./include/libretro-common/audio/dsp_filters/echo.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (echo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>

struct echo_channel
{
   float *buffer;
   unsigned ptr;
   unsigned frames;
   float feedback;
};

struct echo_data
{
   struct echo_channel *channels;
   unsigned num_channels;
   float amp;
};

static void echo_free(void *data)
{
   unsigned i;
   struct echo_data *echo = (struct echo_data*)data;

   for (i = 0; i < echo->num_channels; i++)
      free(echo->channels[i].buffer);
   free(echo->channels);
   free(echo);
}

static void echo_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i, c;
   float *out             = NULL;
   struct echo_data *echo = (struct echo_data*)data;

   output->samples        = input->samples;
   output->frames         = input->frames;

   out                    = output->samples;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float left, right;
      float echo_left  = 0.0f;
      float echo_right = 0.0f;

      for (c = 0; c < echo->num_channels; c++)
      {
         echo_left  += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0];
         echo_right += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1];
      }

      echo_left     *= echo->amp;
      echo_right    *= echo->amp;

      left           = out[0] + echo_left;
      right          = out[1] + echo_right;

      for (c = 0; c < echo->num_channels; c++)
      {
         float feedback_left  = out[0] + echo->channels[c].feedback * echo_left;
         float feedback_right = out[1] + echo->channels[c].feedback * echo_right;

         echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0] = feedback_left;
         echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1] = feedback_right;

         echo->channels[c].ptr = (echo->channels[c].ptr + 1) % echo->channels[c].frames;
      }

      out[0] = left;
      out[1] = right;
   }
}

static void *echo_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   unsigned i, channels;
   struct echo_channel *echo_channels    = NULL;
   float *delay                          = NULL;
   float *feedback                       = NULL;
   unsigned num_delay                    = 0;
   unsigned num_feedback                 = 0;

   static const float default_delay[]    = { 200.0f };
   static const float default_feedback[] = { 0.5f };
   struct echo_data *echo                = (struct echo_data*)
      calloc(1, sizeof(*echo));

   if (!echo)
      return NULL;

   config->get_float_array(userdata, "delay", &delay,
         &num_delay, default_delay, 1);
   config->get_float_array(userdata, "feedback", &feedback,
         &num_feedback, default_feedback, 1);
   config->get_float(userdata, "amp", &echo->amp, 0.2f);

   channels            = num_feedback = num_delay = MIN(num_delay, num_feedback);

   if (!(echo_channels = (struct echo_channel*)calloc(channels,
         sizeof(*echo_channels))))
      goto error;

   echo->channels      = echo_channels;
   echo->num_channels  = channels;

   for (i = 0; i < channels; i++)
   {
      unsigned frames  = (unsigned)(delay[i] * info->input_rate / 1000.0f + 0.5f);
      if (!frames)
         goto error;

      if (!(echo->channels[i].buffer = (float*)calloc(frames, 2 * sizeof(float))))
         goto error;

      echo->channels[i].frames   = frames;
      echo->channels[i].feedback = feedback[i];
   }

   config->free(delay);
   config->free(feedback);
   return echo;

error:
   config->free(delay);
   config->free(feedback);
   echo_free(echo);
   return NULL;
}

static const struct dspfilter_implementation echo_plug = {
   echo_init,
   echo_process,
   echo_free,

   DSPFILTER_API_VERSION,
   "Multi-Echo",
   "echo",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation echo_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &echo_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Echo.dsp

filters = 1
filter0 = echo

# Somewhat fancy Echo filter. Can take any number of echo channels with varying delays (ms) and feedback factors.
# Echo output from all channels can be fed back into each other to create a somewhat reverb-like effect if desired.

# Defaults, 200 ms delay echo with feedback:
# Delay in ms. Takes an array with multiple channels.
# echo_delay = "200"
# Feedback factor for echo.
# echo_feedback = "0.5"
# Overall echo amplification. If too high, the echo becomes unstable due to feedback.
# echo_amp = "0.2"

# Reverby preset.
# echo_delay    = " 60  80 120 172 200 320 380"
# echo_feedback = "0.5 0.5 0.4 0.3 0.5 0.3 0.2"

# echo_amp = "0.12"

./include/libretro-common/audio/dsp_filters/EchoReverb.dsp

filters = 2
filter0 = echo
filter1 = reverb

echo_delay = "200"
echo_feedback = "0.6"
echo_amp = "0.25"

reverb_roomwidth = 0.75
reverb_roomsize = 0.75
reverb_damping = 1.0
reverb_wettime = 0.3

./include/libretro-common/audio/dsp_filters/eq.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (eq.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <retro_inline.h>
#include <retro_miscellaneous.h>
#include <filters.h>
#include <libretro_dspfilter.h>

#include "fft/fft.c"

struct eq_data
{
   fft_t *fft;
   float *save;
   float *block;
   fft_complex_t *filter;
   fft_complex_t *fftblock;
   float buffer[8 * 1024];
   unsigned block_size;
   unsigned block_ptr;
};

struct eq_gain
{
   float freq;
   float gain; /* Linear. */
};

static void eq_free(void *data)
{
   struct eq_data *eq = (struct eq_data*)data;
   if (!eq)
      return;

   fft_free(eq->fft);
   free(eq->save);
   free(eq->block);
   free(eq->fftblock);
   free(eq->filter);
   free(eq);
}

static void eq_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   float *out;
   const float *in;
   unsigned input_frames;
   struct eq_data *eq = (struct eq_data*)data;

   output->samples    = eq->buffer;
   output->frames     = 0;

   out                = eq->buffer;
   in                 = input->samples;
   input_frames       = input->frames;

   while (input_frames)
   {
      unsigned write_avail = eq->block_size - eq->block_ptr;

      if (input_frames < write_avail)
         write_avail = input_frames;

      memcpy(eq->block + eq->block_ptr * 2, in, write_avail * 2 * sizeof(float));

      in            += write_avail * 2;
      input_frames  -= write_avail;
      eq->block_ptr += write_avail;

      /* Convolve a new block. */
      if (eq->block_ptr == eq->block_size)
      {
         unsigned i, c;

         for (c = 0; c < 2; c++)
         {
            fft_process_forward(eq->fft, eq->fftblock, eq->block + c, 2);
            for (i = 0; i < 2 * eq->block_size; i++)
               eq->fftblock[i] = fft_complex_mul(eq->fftblock[i], eq->filter[i]);
            fft_process_inverse(eq->fft, out + c, eq->fftblock, 2);
         }

         /* Overlap add method, so add in saved block now. */
         for (i = 0; i < 2 * eq->block_size; i++)
            out[i]      += eq->save[i];

         /* Save block for later. */
         memcpy(eq->save, out + 2 * eq->block_size, 2 * eq->block_size * sizeof(float));

         out            += eq->block_size * 2;
         output->frames += eq->block_size;
         eq->block_ptr   = 0;
      }
   }
}

static int gains_cmp(const void *a_, const void *b_)
{
   const struct eq_gain *a = (const struct eq_gain*)a_;
   const struct eq_gain *b = (const struct eq_gain*)b_;
   if (a->freq < b->freq)
      return -1;
   if (a->freq > b->freq)
      return 1;
   return 0;
}

static void generate_response(fft_complex_t *response,
      const struct eq_gain *gains, unsigned num_gains, unsigned samples)
{
   unsigned i;

   float start_freq = 0.0f;
   float start_gain = 1.0f;

   float end_freq   = 1.0f;
   float end_gain   = 1.0f;

   if (num_gains)
   {
      end_freq = gains->freq;
      end_gain = gains->gain;
      num_gains--;
      gains++;
   }

   /* Create a response by linear interpolation between
    * known frequency sample points. */
   for (i = 0; i <= samples; i++)
   {
      float gain;
      float lerp = 0.5f;
      float freq = (float)i / samples;

      while (freq >= end_freq)
      {
         if (num_gains)
         {
            start_freq = end_freq;
            start_gain = end_gain;
            end_freq = gains->freq;
            end_gain = gains->gain;

            gains++;
            num_gains--;
         }
         else
         {
            start_freq = end_freq;
            start_gain = end_gain;
            end_freq = 1.0f;
            end_gain = 1.0f;
            break;
         }
      }

      /* Edge case where i == samples. */
      if (end_freq > start_freq)
         lerp = (freq - start_freq) / (end_freq - start_freq);
      gain = (1.0f - lerp) * start_gain + lerp * end_gain;

      response[i].real               = gain;
      response[i].imag               = 0.0f;
      response[2 * samples - i].real = gain;
      response[2 * samples - i].imag = 0.0f;
   }
}

static void create_filter(struct eq_data *eq, unsigned size_log2,
      struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)
{
   int i;
   int half_block_size = eq->block_size >> 1;
   double window_mod   = 1.0 / kaiser_window_function(0.0, beta);
   fft_t *fft          = fft_new(size_log2);
   float *time_filter  = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter));
   if (!fft || !time_filter)
      goto end;

   /* Make sure bands are in correct order. */
   qsort(gains, num_gains, sizeof(*gains), gains_cmp);

   /* Compute desired filter response. */
   generate_response(eq->filter, gains, num_gains, half_block_size);

   /* Get equivalent time-domain filter. */
   fft_process_inverse(fft, time_filter, eq->filter, 1);

   /* ifftshift() to create the correct linear phase filter.
    * The filter response was designed with zero phase, which
    * won't work unless we compensate
    * for the repeating property of the FFT here
    * by flipping left and right blocks. */
   for (i = 0; i < half_block_size; i++)
   {
      float tmp = time_filter[i + half_block_size];
      time_filter[i + half_block_size] = time_filter[i];
      time_filter[i] = tmp;
   }

   /* Apply a window to smooth out the frequency response. */
   for (i = 0; i < (int)eq->block_size; i++)
   {
      /* Kaiser window. */
      double phase    = (double)i / eq->block_size;
      phase           = 2.0 * (phase - 0.5);
      time_filter[i] *= window_mod * kaiser_window_function(phase, beta);
   }

#ifdef DEBUG
   /* Debugging. */
   if (filter_path)
   {
      FILE *file = fopen(filter_path, "w");
      if (file)
      {
         for (i = 0; i < (int)eq->block_size - 1; i++)
            fprintf(file, "%.8f\n", time_filter[i + 1]);
         fclose(file);
      }
   }
#endif

   /* Padded FFT to create our FFT filter.
    * Make our even-length filter odd by discarding the first coefficient.
    * For some interesting reason, this allows us to design an odd-length linear phase filter.
    */
   fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1);

end:
   fft_free(fft);
   free(time_filter);
}

static void *eq_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   int size_log2;
   float beta;
   float *frequencies, *gain;
   unsigned num_freq, num_gain, i, size;
   struct eq_gain *gains      = NULL;
   char *filter_path          = NULL;
   const float default_freq[] = { 0.0f, info->input_rate };
   const float default_gain[] = { 0.0f, 0.0f };
   struct eq_data *eq         = (struct eq_data*)calloc(1, sizeof(*eq));
   if (!eq)
      return NULL;

   config->get_float(userdata, "window_beta", &beta, 4.0f);

   config->get_int(userdata, "block_size_log2", &size_log2, 8);
   size = 1 << size_log2;

   config->get_float_array(userdata, "frequencies", &frequencies, &num_freq, default_freq, 2);
   config->get_float_array(userdata, "gains", &gain, &num_gain, default_gain, 2);

   if (!config->get_string(userdata, "impulse_response_output", &filter_path, ""))
   {
      config->free(filter_path);
      filter_path = NULL;
   }

   num_gain = num_freq = MIN(num_gain, num_freq);

   if (!(gains = (struct eq_gain*)calloc(num_gain, sizeof(*gains))))
      goto error;

   for (i = 0; i < num_gain; i++)
   {
      gains[i].freq = frequencies[i] / (0.5f * info->input_rate);
      gains[i].gain = pow(10.0, gain[i] / 20.0);
   }
   config->free(frequencies);
   config->free(gain);

   eq->block_size = size;

   eq->save       = (float*)calloc(    size, 2 * sizeof(*eq->save));
   eq->block      = (float*)calloc(2 * size, 2 * sizeof(*eq->block));
   eq->fftblock   = (fft_complex_t*)calloc(2 * size, sizeof(*eq->fftblock));
   eq->filter     = (fft_complex_t*)calloc(2 * size, sizeof(*eq->filter));

   /* Use an FFT which is twice the block size with zero-padding
    * to make circular convolution => proper convolution.
    */
   eq->fft        = fft_new(size_log2 + 1);

   if (!eq->fft || !eq->fftblock || !eq->save || !eq->block || !eq->filter)
      goto error;

   create_filter(eq, size_log2, gains, num_gain, beta, filter_path);
   config->free(filter_path);
   filter_path = NULL;

   free(gains);
   return eq;

error:
   free(gains);
   eq_free(eq);
   return NULL;
}

static const struct dspfilter_implementation eq_plug = {
   eq_init,
   eq_process,
   eq_free,

   DSPFILTER_API_VERSION,
   "Linear-Phase FFT Equalizer",
   "eq",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation eq_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &eq_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/EQ.dsp

filters = 1
filter0 = eq

# Defaults

# Beta factor for Kaiser window.
# Lower values will allow better frequency resolution, but more ripple.
# eq_window_beta = 4.0

# The block size on which FFT is done.
# Too high value requires more processing as well as longer latency but
# allows finer-grained control over the spectrum.
# eq_block_size_log2 = 8

# An array of which frequencies to control.
# You can create an arbitrary amount of these sampling points.
# The EQ will try to create a frequency response which fits well to these points.
# The filter response is linearly interpolated between sampling points here.
#
# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
#
# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
# eq_frequencies = "500 1000 2000"
# eq_gains = "0 3 0"
# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.

# By default, this filter has a flat frequency response.

# Dumps the impulse response generated by the EQ as a plain-text file
# with one coefficient per line.
# eq_impulse_response_output = "eq_impulse.txt"
#
# Using GNU Octave or Matlab, you can plot the response with:
#
# f = fopen('/path/to/eq_impulse.txt');
# l = textscan(f, '%f');
# res = l{1};
# freqz(res, 1, 4096, 48000);
#
# It will give the response in Hz; 48000 is the default Output Rate of RetroArch

./include/libretro-common/audio/dsp_filters/fft/fft.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fft.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>

#include "fft.h"

#include <retro_miscellaneous.h>

struct fft
{
   fft_complex_t *interleave_buffer;
   fft_complex_t *phase_lut;
   unsigned *bitinverse_buffer;
   unsigned size;
};

static unsigned bitswap(unsigned x, unsigned size_log2)
{
   unsigned i;
   unsigned ret = 0;
   for (i = 0; i < size_log2; i++)
      ret |= ((x >> i) & 1) << (size_log2 - i - 1);
   return ret;
}

static void build_bitinverse(unsigned *bitinverse, unsigned size_log2)
{
   unsigned i;
   unsigned size = 1 << size_log2;
   for (i = 0; i < size; i++)
      bitinverse[i] = bitswap(i, size_log2);
}

static fft_complex_t exp_imag(double phase)
{
   fft_complex_t out = { cos(phase), sin(phase) };
   return out;
}

static void build_phase_lut(fft_complex_t *out, int size)
{
   int i;
   out += size;
   for (i = -size; i <= size; i++)
      out[i] = exp_imag((M_PI * i) / size);
}

static void interleave_complex(const unsigned *bitinverse,
      fft_complex_t *out, const fft_complex_t *in,
      unsigned samples, unsigned step)
{
   unsigned i;
   for (i = 0; i < samples; i++, in += step)
      out[bitinverse[i]] = *in;
}

static void interleave_float(const unsigned *bitinverse,
      fft_complex_t *out, const float *in,
      unsigned samples, unsigned step)
{
   unsigned i;
   for (i = 0; i < samples; i++, in += step)
   {
      unsigned inv_i = bitinverse[i];
      out[inv_i].real = *in;
      out[inv_i].imag = 0.0f;
   }
}

static void resolve_float(float *out, const fft_complex_t *in, unsigned samples,
      float gain, unsigned step)
{
   unsigned i;
   for (i = 0; i < samples; i++, in++, out += step)
      *out = gain * in->real;
}

fft_t *fft_new(unsigned block_size_log2)
{
   unsigned size;
   fft_t *fft = (fft_t*)calloc(1, sizeof(*fft));
   if (!fft)
      return NULL;

   size                   = 1 << block_size_log2;
   fft->interleave_buffer = (fft_complex_t*)calloc(size, sizeof(*fft->interleave_buffer));
   fft->bitinverse_buffer = (unsigned*)calloc(size, sizeof(*fft->bitinverse_buffer));
   fft->phase_lut         = (fft_complex_t*)calloc(2 * size + 1, sizeof(*fft->phase_lut));

   if (!fft->interleave_buffer || !fft->bitinverse_buffer || !fft->phase_lut)
      goto error;

   fft->size = size;

   build_bitinverse(fft->bitinverse_buffer, block_size_log2);
   build_phase_lut(fft->phase_lut, size);
   return fft;

error:
   fft_free(fft);
   return NULL;
}

void fft_free(fft_t *fft)
{
   if (!fft)
      return;

   free(fft->interleave_buffer);
   free(fft->bitinverse_buffer);
   free(fft->phase_lut);
   free(fft);
}

static void butterfly(fft_complex_t *a, fft_complex_t *b, fft_complex_t mod)
{
   mod = fft_complex_mul(mod, *b);
   *b  = fft_complex_sub(*a, mod);
   *a  = fft_complex_add(*a, mod);
}

static void butterflies(fft_complex_t *butterfly_buf,
      const fft_complex_t *phase_lut,
      int phase_dir, unsigned step_size, unsigned samples)
{
   unsigned i, j;
   for (i = 0; i < samples; i += step_size << 1)
   {
      int phase_step = (int)samples * phase_dir / (int)step_size;
      for (j = i; j < i + step_size; j++)
         butterfly(&butterfly_buf[j], &butterfly_buf[j + step_size],
               phase_lut[phase_step * (int)(j - i)]);
   }
}

void fft_process_forward_complex(fft_t *fft,
      fft_complex_t *out, const fft_complex_t *in, unsigned step)
{
   unsigned step_size;
   unsigned samples = fft->size;
   interleave_complex(fft->bitinverse_buffer, out, in, samples, step);

   for (step_size = 1; step_size < samples; step_size <<= 1)
   {
      butterflies(out,
            fft->phase_lut + samples,
            -1, step_size, samples);
   }
}

void fft_process_forward(fft_t *fft,
      fft_complex_t *out, const float *in, unsigned step)
{
   unsigned step_size;
   unsigned samples = fft->size;
   interleave_float(fft->bitinverse_buffer, out, in, samples, step);

   for (step_size = 1; step_size < fft->size; step_size <<= 1)
   {
      butterflies(out,
            fft->phase_lut + samples,
            -1, step_size, samples);
   }
}

void fft_process_inverse(fft_t *fft,
      float *out, const fft_complex_t *in, unsigned step)
{
   unsigned step_size;
   unsigned samples = fft->size;

   interleave_complex(fft->bitinverse_buffer, fft->interleave_buffer,
         in, samples, 1);

   for (step_size = 1; step_size < samples; step_size <<= 1)
   {
      butterflies(fft->interleave_buffer,
            fft->phase_lut + samples,
            1, step_size, samples);
   }

   resolve_float(out, fft->interleave_buffer, samples, 1.0f / samples, step);
}

./include/libretro-common/audio/dsp_filters/fft/fft.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fft.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RARCH_FFT_H__
#define RARCH_FFT_H__

#include <retro_inline.h>
#include <math/complex.h>

typedef struct fft fft_t;

fft_t *fft_new(unsigned block_size_log2);

void fft_free(fft_t *fft);

void fft_process_forward_complex(fft_t *fft,
      fft_complex_t *out, const fft_complex_t *in, unsigned step);

void fft_process_forward(fft_t *fft,
      fft_complex_t *out, const float *in, unsigned step);

void fft_process_inverse(fft_t *fft,
      float *out, const fft_complex_t *in, unsigned step);

#endif

./include/libretro-common/audio/dsp_filters/HighShelfDampen.dsp

filters = 1
filter0 = iir

iir_gain = -12.0
iir_type = HSH
iir_frequency = 8000.0

./include/libretro-common/audio/dsp_filters/iir.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (iir.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>
#include <string/stdstring.h>

#define sqr(a) ((a) * (a))

/* filter types */
enum IIRFilter
{
   LPF,        /* low pass filter */
   HPF,        /* High pass filter */
   BPCSGF,     /* band pass filter 1 */
   BPZPGF,     /* band pass filter 2 */
   APF,        /* Allpass filter*/
   NOTCH,      /* Notch Filter */
   RIAA_phono, /* RIAA record/tape deemphasis */
   PEQ,        /* Peaking band EQ filter */
   BBOOST,     /* Bassboost filter */
   LSH,        /* Low shelf filter */
   HSH,        /* High shelf filter */
   RIAA_CD     /* CD de-emphasis */
};

struct iir_data
{
   float b0, b1, b2;
   float a0, a1, a2;

   struct
   {
      float xn1, xn2;
      float yn1, yn2;
   } l, r;
};

static void iir_free(void *data)
{
   free(data);
}

static void iir_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   struct iir_data *iir = (struct iir_data*)data;
   float *out           = output->samples;

   float b0             = iir->b0;
   float b1             = iir->b1;
   float b2             = iir->b2;
   float a0             = iir->a0;
   float a1             = iir->a1;
   float a2             = iir->a2;

   float xn1_l          = iir->l.xn1;
   float xn2_l          = iir->l.xn2;
   float yn1_l          = iir->l.yn1;
   float yn2_l          = iir->l.yn2;

   float xn1_r          = iir->r.xn1;
   float xn2_r          = iir->r.xn2;
   float yn1_r          = iir->r.yn1;
   float yn2_r          = iir->r.yn2;

   output->samples      = input->samples;
   output->frames       = input->frames;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float in_l = out[0];
      float in_r = out[1];

      float l    = (b0 * in_l + b1 * xn1_l + b2 * xn2_l - a1 * yn1_l - a2 * yn2_l) / a0;
      float r    = (b0 * in_r + b1 * xn1_r + b2 * xn2_r - a1 * yn1_r - a2 * yn2_r) / a0;

      xn2_l      = xn1_l;
      xn1_l      = in_l;
      yn2_l      = yn1_l;
      yn1_l      = l;

      xn2_r      = xn1_r;
      xn1_r      = in_r;
      yn2_r      = yn1_r;
      yn1_r      = r;

      out[0]     = l;
      out[1]     = r;
   }

   iir->l.xn1 = xn1_l;
   iir->l.xn2 = xn2_l;
   iir->l.yn1 = yn1_l;
   iir->l.yn2 = yn2_l;

   iir->r.xn1 = xn1_r;
   iir->r.xn2 = xn2_r;
   iir->r.yn1 = yn1_r;
   iir->r.yn2 = yn2_r;
}

#define CHECK(x) if (string_is_equal(str, #x)) return x
static enum IIRFilter str_to_type(const char *str)
{
   CHECK(LPF);
   CHECK(HPF);
   CHECK(BPCSGF);
   CHECK(BPZPGF);
   CHECK(APF);
   CHECK(NOTCH);
   CHECK(RIAA_phono);
   CHECK(PEQ);
   CHECK(BBOOST);
   CHECK(LSH);
   CHECK(HSH);
   CHECK(RIAA_CD);

   return LPF; /* Fallback. */
}
#undef CHECK

static void make_poly_from_roots(
      const double *roots, unsigned num_roots, float *poly)
{
   unsigned i, j;

   poly[0] = 1;
   poly[1] = -roots[0];
   memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));

   for (i = 1; i < num_roots; i++)
      for (j = num_roots; j > 0; j--)
         poly[j] -= poly[j - 1] * roots[i];
}

static void iir_filter_init(struct iir_data *iir,
      float sample_rate, float freq, float qual, float gain, enum IIRFilter filter_type)
{
	double omega = 2.0 * M_PI * freq / sample_rate;
   double cs    = cos(omega);
   double sn    = sin(omega);
   double a1pha = sn / (2.0 * qual);
   double A     = exp(log(10.0) * gain / 40.0);
   double beta  = sqrt(A + A);

   float b0     = 0.0, b1 = 0.0, b2 = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0;

   /* Set up filter coefficients according to type */
   switch (filter_type)
   {
      case LPF:
         b0 =  (1.0 - cs) / 2.0;
         b1 =   1.0 - cs ;
         b2 =  (1.0 - cs) / 2.0;
         a0 =   1.0 + a1pha;
         a1 =  -2.0 * cs;
         a2 =   1.0 - a1pha;
         break;
      case HPF:
         b0 =  (1.0 + cs) / 2.0;
         b1 = -(1.0 + cs);
         b2 =  (1.0 + cs) / 2.0;
         a0 =   1.0 + a1pha;
         a1 =  -2.0 * cs;
         a2 =   1.0 - a1pha;
         break;
      case APF:
         b0 =  1.0 - a1pha;
         b1 = -2.0 * cs;
         b2 =  1.0 + a1pha;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case BPZPGF:
         b0 =  a1pha;
         b1 =  0.0;
         b2 = -a1pha;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case BPCSGF:
         b0 =  sn / 2.0;
         b1 =  0.0;
         b2 = -sn / 2.0;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case NOTCH:
         b0 =  1.0;
         b1 = -2.0 * cs;
         b2 =  1.0;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case RIAA_phono: /* http://www.dsprelated.com/showmessage/73300/3.php */
      {
         double y, b_re, a_re, b_im, a_im, g;
         float b[3] = {0.0f};
         float a[3] = {0.0f};

         if ((int)sample_rate == 44100)
         {
            static const double zeros[] = {-0.2014898, 0.9233820};
            static const double poles[] = {0.7083149, 0.9924091};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }
         else if ((int)sample_rate == 48000)
         {
            static const double zeros[] = {-0.1766069, 0.9321590};
            static const double poles[] = {0.7396325, 0.9931330};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }
         else if ((int)sample_rate == 88200)
         {
            static const double zeros[] = {-0.1168735, 0.9648312};
            static const double poles[] = {0.8590646, 0.9964002};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }
         else if ((int)sample_rate == 96000)
         {
            static const double zeros[] = {-0.1141486, 0.9676817};
            static const double poles[] = {0.8699137, 0.9966946};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }

         b0    = b[0];
         b1    = b[1];
         b2    = b[2];
         a0    = a[0];
         a1    = a[1];
         a2    = a[2];

         /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */
         y     = 2.0 * M_PI * 1000.0 / sample_rate;
         b_re  = b0 + b1 * cos(-y) + b2 * cos(-2.0 * y);
         a_re  = a0 + a1 * cos(-y) + a2 * cos(-2.0 * y);
         b_im  = b1 * sin(-y) + b2 * sin(-2.0 * y);
         a_im  = a1 * sin(-y) + a2 * sin(-2.0 * y);
         g     = 1.0 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));
         b0   *= g; b1 *= g; b2 *= g;
         break;
      }
      case PEQ:
         b0 =  1.0 + a1pha * A;
         b1 = -2.0 * cs;
         b2 =  1.0 - a1pha * A;
         a0 =  1.0 + a1pha / A;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha / A;
         break;
      case BBOOST:
         beta = sqrt((A * A + 1) / 1.0 - (pow((A - 1), 2)));
         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
         b1 = 2 * A * ((A - 1) - (A + 1) * cs);
         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
         a0 = ((A + 1) + (A - 1) * cs + beta * sn);
         a1 = -2 * ((A - 1) + (A + 1) * cs);
         a2 = (A + 1) + (A - 1) * cs - beta * sn;
         break;
      case LSH:
         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
         b1 = 2 * A * ((A - 1) - (A + 1) * cs);
         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
         a0 = (A + 1) + (A - 1) * cs + beta * sn;
         a1 = -2 * ((A - 1) + (A + 1) * cs);
         a2 = (A + 1) + (A - 1) * cs - beta * sn;
         break;
      case RIAA_CD:
         omega = 2.0 * M_PI * 5283.0 / sample_rate;
         cs = cos(omega);
         sn = sin(omega);
         a1pha = sn / (2.0 * 0.4845);
         A = exp(log(10.0) * -9.477 / 40.0);
         beta = sqrt(A + A);
         (void)a1pha;
      case HSH:
         b0 = A * ((A + 1.0) + (A - 1.0) * cs + beta * sn);
         b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * cs);
         b2 = A * ((A + 1.0) + (A - 1.0) * cs - beta * sn);
         a0 = (A + 1.0) - (A - 1.0) * cs + beta * sn;
         a1 = 2.0 * ((A - 1.0) - (A + 1.0) * cs);
         a2 = (A + 1.0) - (A - 1.0) * cs - beta * sn;
         break;
      default:
         break;
   }

   iir->b0 = b0;
   iir->b1 = b1;
   iir->b2 = b2;
   iir->a0 = a0;
   iir->a1 = a1;
   iir->a2 = a2;
}

static void *iir_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float freq, qual, gain;
   enum IIRFilter filter  = LPF;
   char           *type   = NULL;
   struct iir_data *iir   = (struct iir_data*)calloc(1, sizeof(*iir));
   if (!iir)
      return NULL;

   config->get_float(userdata, "frequency", &freq, 1024.0f);
   config->get_float(userdata, "quality", &qual, 0.707f);
   config->get_float(userdata, "gain", &gain, 0.0f);

   config->get_string(userdata, "type", &type, "LPF");

   filter = str_to_type(type);
   config->free(type);

   iir_filter_init(iir, info->input_rate, freq, qual, gain, filter);
   return iir;
}

static const struct dspfilter_implementation iir_plug = {
   iir_init,
   iir_process,
   iir_free,

   DSPFILTER_API_VERSION,
   "IIR",
   "iir",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation iir_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &iir_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/IIR.dsp

filters = 1
filter0 = iir

# Defaults.
#iir_frequency = 1024.0
#iir_quality = 0.707
#iir_gain = 0.0
#iir_type = LPF

# Filter types:
# LPF: Low-pass
# HPF: High-pass
# BPCSGF: Band-pass #1
# BPZPGF: Band-pass #2
# APF: Allpass
# NOTCH: Notch filter
# RIAA_phono: RIAA record/tape deemphasis
# PEQ: peaking band EQ
# BBOOST: Bassboost
# LSH: Low-shelf
# HSH: High-shelf
# RIAA_CD: CD de-emphasis

./include/libretro-common/audio/dsp_filters/link.T

{
  global: dspfilter_get_implementation;
  local: *;
};

./include/libretro-common/audio/dsp_filters/LowPassCPS.dsp

filters = 1
filter0 = eq

eq_frequencies = "8000 10000 12500 16000 20000"
eq_gains = "0 -30 -30 -30 -30"

# Low pass filter for the QSound chip from CPS-1/2.
# Some games have aliasing due low quality samples, so you can hear some annoying noisy near 11 kHz

# Defaults

# Beta factor for Kaiser window.
# Lower values will allow better frequency resolution, but more ripple.
# eq_window_beta = 4.0

# The block size on which FFT is done.
# Too high value requires more processing as well as longer latency but
# allows finer-grained control over the spectrum.
# eq_block_size_log2 = 8

# An array of which frequencies to control.
# You can create an arbitrary amount of these sampling points.
# The EQ will try to create a frequency response which fits well to these points.
# The filter response is linearly interpolated between sampling points here.
#
# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
#
# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
# eq_frequencies = "500 1000 2000"
# eq_gains = "0 3 0"
# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.

# By default, this filter has a low pass response with cuttof frequency at ~8600 Hz.

# Dumps the impulse response generated by the EQ as a plain-text file
# with one coefficient per line.
# eq_impulse_response_output = "eq_impulse.txt"
#
# Using GNU Octave or Matlab, you can plot the response with:
#
# f = fopen('/path/to/eq_impulse.txt');
# l = textscan(f, '%f');
# res = l{1};
# freqz(res, 1, 4096, 48000);
#
# It will give the response in Hz; 48000 is the default Output Rate of RetroArch

./include/libretro-common/audio/dsp_filters/Makefile

compiler    := gcc
extra_flags :=
use_neon    := 0
build       = release
DYLIB	      := so
PREFIX      := /usr
INSTALLDIR  := $(PREFIX)/lib/retroarch/filters/audio

ifeq ($(platform),)
   platform = unix
   ifeq ($(shell uname -s),)
      platform = win
   else ifneq ($(findstring Darwin,$(shell uname -s)),)
      platform = osx
      arch     = intel
      ifeq ($(shell uname -p),powerpc)
         arch = ppc
      endif
   else ifneq ($(findstring MINGW,$(shell uname -s)),)
      platform = win
   endif
endif

ifeq ($(platform),gcc)
   extra_rules_gcc := $(shell $(compiler) -dumpmachine)
endif

ifneq (,$(findstring armv7,$(extra_rules_gcc)))
   extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon
   use_neon := 1
endif

ifneq (,$(findstring hardfloat,$(extra_rules_gcc)))
   extra_flags += -mfloat-abi=hard
endif

ifeq (release,$(build))
   extra_flags += -O2
endif

ifeq (debug,$(build))
   extra_flags += -O0 -g
endif

ldflags := $(LDFLAGS) -shared -lm -Wl,--version-script=link.T

ifeq ($(platform), unix)
   DYLIB = so
else ifeq ($(platform), osx)
   compiler := $(CC)
   DYLIB = dylib
   ldflags := -dynamiclib
   ARCHFLAGS=
   MINVERFLAGS=
   ifeq ($(shell uname -p),arm)
      MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)
   else ifeq ($(HAVE_METAL),1)
      MINVERFLAGS = -mmacosx-version-min=10.13 -stdlib=libc++  # macOS  (Metal, x86 64bit)
   else ifeq ($(shell uname -p),powerpc)
      MINVERFLAGS = -mmacosx-version-min=10.5  # macOSX (PowerPC 32-bit)
   else ifeq ($(shell uname -m),i386)
      MINVERFLAGS = -mmacosx-version-min=10.6  # macOSX (OpenGL, x86 32bit)
   else
      MINVERFLAGS = -mmacosx-version-min=10.7 -stdlib=libc++ # macOSX (OpenGL, x86 64bit)
   endif

	# Build for a specific architecture when ARCH is defined as a switch
   ifeq ($(ARCH),arm64)
      MINVERFLAGS  = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)
      ARCHFLAGS    = -arch arm64
   else ifeq ($(ARCH),x86_64)
      ifeq ($(HAVE_METAL),1)
         MINVERFLAGS  = -mmacosx-version-min=10.13 -stdlib=libc++
      else
         MINVERFLAGS  = -mmacosx-version-min=10.7  -stdlib=libc++
      endif
      ARCHFLAGS       = -arch x86_64
   else ifeq ($(ARCH),x86)
      MINVERFLAGS     = -mmacosx-version-min=10.6
      ARCHFLAGS       = -arch x86
   else ifeq ($(ARCH),ppc)
      MINVERFLAGS     = -mmacosx-version-min=10.5
      ARCHFLAGS       = -arch ppc
   endif
   ifeq ($(BUILDBOT),1)
      ARCHFLAGS       = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT)
   endif
	extraflags += $(MINVERFLAGS) $(ARCHFLAGS)
	ldflags += $(MINVERFLAGS) $(ARCHFLAGS)
else
   extra_flags += -static-libgcc -static-libstdc++
   DYLIB = dll
endif

CC      := $(compiler) -Wall
CXX     := $(subst CC,++,$(compiler)) -std=gnu++0x -Wall
flags   := $(CPPFLAGS) $(CFLAGS) -fPIC $(extra_flags) -I../../include
asflags := $(ASFLAGS) -fPIC  $(extra_flags)
objects :=

ifeq (1,$(use_neon))
   ASMFLAGS := -INEON/asm
   asflags += -mfpu=neon
endif

plugs := $(wildcard *.c)
objects := $(plugs:.c=.o)
targets := $(objects:.o=.$(DYLIB))

all: build;

%.o: %.S
	$(CC) -c -o $@ $(asflags)  $(ASMFLAGS)  $<

%.o: %.c
	$(CC) -c -o $@ $(flags) $<

%.$(DYLIB): %.o
	$(CC) -o $@ $(ldflags) $(flags) $^

build: $(targets)

clean:
	rm -f *.o
	rm -f *.$(DYLIB)

strip:
	strip -s *.$(DYLIB)

install:
	mkdir -p $(DESTDIR)$(INSTALLDIR)
	cp -t $(DESTDIR)$(INSTALLDIR) $(targets) *.dsp

test-install:
	DESTDIR=/tmp/build $(MAKE) install

./include/libretro-common/audio/dsp_filters/Mono.dsp

filters = 1
filter0 = panning

# Gains are linear.

# Stereo Mono:
 panning_left_mix = "0.5 0.5"
 panning_right_mix = "0.5 0.5"

# Mono on one speaker:
# panning_left_mix = "0.5 0.5"
# panning_right_mix = "0.0 0.0"

./include/libretro-common/audio/dsp_filters/panning.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (panning.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <libretro_dspfilter.h>

struct panning_data
{
   float left[2];
   float right[2];
};

static void panning_free(void *data)
{
   free(data);
}

static void panning_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   struct panning_data *pan = (struct panning_data*)data;
   float *out               = output->samples;

   output->samples          = input->samples;
   output->frames           = input->frames;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float left  = out[0];
      float right = out[1];
      out[0]      = left * pan->left[0]  + right * pan->left[1];
      out[1]      = left * pan->right[0] + right * pan->right[1];
   }
}

static void *panning_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   static const float default_left[]  = { 1.0f, 0.0f };
   static const float default_right[] = { 0.0f, 1.0f };
   float *left                        = NULL;
   float *right                       = NULL;
   unsigned num_left                  = 0;
   unsigned num_right                 = 0;
   struct panning_data *pan           = (struct panning_data*)
      calloc(1, sizeof(*pan));

   if (!pan)
      return NULL;

   config->get_float_array(userdata, "left_mix",
         &left, &num_left, default_left, 2);
   config->get_float_array(userdata, "right_mix",
         &right, &num_right, default_right, 2);

   memcpy(pan->left,  (num_left  == 2) ?
         left :  default_left,  sizeof(pan->left));
   memcpy(pan->right, (num_right == 2) ?
         right : default_right, sizeof(pan->right));

   config->free(left);
   config->free(right);

   return pan;
}

static const struct dspfilter_implementation panning = {
   panning_init,
   panning_process,
   panning_free,

   DSPFILTER_API_VERSION,
   "Panning",
   "panning",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation panning_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *
dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &panning;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Panning.dsp

filters = 1
filter0 = panning

# Gains are linear.

# The default. Left and right channels map to each other.
panning_left_mix = "1.0 0.0"
panning_right_mix = "0.0 1.0"

# Some examples:
#
# Mono:
# panning_left_mix = "0.5 0.5"
# panning_right_mix = "0.5 0.5"

# Swap left and right channels:
# panning_left_mix = "0.0 1.0"
# panning_right_mix = "1.0 0.0"
#
# Mono on one speaker:
# panning_left_mix = "0.5 0.5"
# panning_right_mix = "0.0 0.0"

./include/libretro-common/audio/dsp_filters/phaser.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (phaser.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>

#define PHASER_LFO_SHAPE 4.0
#define PHASER_LFO_SKIP_SAMPLES 20

struct phaser_data
{
   float freq;
   float startphase;
   float fb;
   float depth;
   float drywet;
   float old[2][24];
   float gain;
   float fbout[2];
   float lfoskip;
   float phase;

   int stages;
   unsigned long skipcount;
};

static void phaser_free(void *data)
{
   free(data);
}

static void phaser_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i, c;
   int s;
   float m[2], tmp[2];
   struct phaser_data *ph = (struct phaser_data*)data;
   float *out             = output->samples;

   output->samples        = input->samples;
   output->frames         = input->frames;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float in[2] = { out[0], out[1] };

      for (c = 0; c < 2; c++)
         m[c] = in[c] + ph->fbout[c] * ph->fb * 0.01f;

      if ((ph->skipcount++ % PHASER_LFO_SKIP_SAMPLES) == 0)
      {
         ph->gain = 0.5 * (1.0 + cos(ph->skipcount * ph->lfoskip + ph->phase));
         ph->gain = (exp(ph->gain * PHASER_LFO_SHAPE) - 1.0) / (exp(PHASER_LFO_SHAPE) - 1);
         ph->gain = 1.0 - ph->gain * ph->depth;
      }

      for (s = 0; s < ph->stages; s++)
      {
         for (c = 0; c < 2; c++)
         {
            tmp[c] = ph->old[c][s];
            ph->old[c][s] = ph->gain * tmp[c] + m[c];
            m[c] = tmp[c] - ph->gain * ph->old[c][s];
         }
      }

      for (c = 0; c < 2; c++)
      {
         ph->fbout[c] = m[c];
         out[c] = m[c] * ph->drywet + in[c] * (1.0f - ph->drywet);
      }
   }
}

static void *phaser_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float lfo_freq, lfo_start_phase;
   struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));
   if (!ph)
      return NULL;

   config->get_float(userdata, "lfo_freq", &lfo_freq, 0.4f);
   config->get_float(userdata, "lfo_start_phase", &lfo_start_phase, 0.0f);
   config->get_float(userdata, "feedback", &ph->fb, 0.0f);
   config->get_float(userdata, "depth", &ph->depth, 0.4f);
   config->get_float(userdata, "dry_wet", &ph->drywet, 0.5f);
   config->get_int(userdata, "stages", &ph->stages, 2);

   if (ph->stages < 1)
      ph->stages = 1;
   else if (ph->stages > 24)
      ph->stages = 24;

   ph->lfoskip = lfo_freq * 2.0 * M_PI / info->input_rate;
   ph->phase   = lfo_start_phase * M_PI / 180.0;

   return ph;
}

static const struct dspfilter_implementation phaser_plug = {
   phaser_init,
   phaser_process,
   phaser_free,

   DSPFILTER_API_VERSION,
   "Phaser",
   "phaser",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation phaser_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &phaser_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Phaser.dsp

filters = 1
filter0 = phaser

# Defaults.
# phaser_lfo_freq = 0.4
# phaser_lfo_start_phase = 0.0
# phaser_feedback = 0.0
# phaser_depth = 0.4
# phaser_dry_wet = 0.5
# phaser_stages = 2

./include/libretro-common/audio/dsp_filters/reverb.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (reverb.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_inline.h>
#include <libretro_dspfilter.h>

struct comb
{
   float *buffer;
   unsigned bufsize;
   unsigned bufidx;

   float feedback;
   float filterstore;
   float damp1, damp2;
};

struct allpass
{
   float *buffer;
   float feedback;
   unsigned bufsize;
   unsigned bufidx;
};

static INLINE float comb_process(struct comb *c, float input)
{
   float output         = c->buffer[c->bufidx];
   c->filterstore       = (output * c->damp2) + (c->filterstore * c->damp1);

   c->buffer[c->bufidx] = input + (c->filterstore * c->feedback);

   c->bufidx++;
   if (c->bufidx >= c->bufsize)
      c->bufidx = 0;

   return output;
}

static INLINE float allpass_process(struct allpass *a, float input)
{
   float bufout         = a->buffer[a->bufidx];
   float output         = -input + bufout;
   a->buffer[a->bufidx] = input + bufout * a->feedback;

   a->bufidx++;
   if (a->bufidx >= a->bufsize)
      a->bufidx = 0;

   return output;
}

#define numcombs 8
#define numallpasses 4
static const float muted = 0;
static const float fixedgain = 0.015f;
static const float scalewet = 3;
static const float scaledry = 2;
static const float scaledamp = 0.4f;
static const float scaleroom = 0.28f;
static const float offsetroom = 0.7f;
static const float initialroom = 0.5f;
static const float initialdamp = 0.5f;
static const float initialwet = 1.0f / 3.0f;
static const float initialdry = 0;
static const float initialwidth = 1;
static const float initialmode = 0;
static const float freezemode = 0.5f;

struct revmodel
{
   struct comb combL[numcombs];
   struct allpass allpassL[numallpasses];

   float *bufcomb[numcombs];
   float *bufallpass[numallpasses];

   float gain;
   float roomsize, roomsize1;
   float damp, damp1;
   float wet, wet1, wet2;
   float dry;
   float width;
   float mode;
};

static float revmodel_process(struct revmodel *rev, float in)
{
   int i;
   float mono_out = 0.0f;
   float mono_in  = in;
   float input    = mono_in * rev->gain;

   for (i = 0; i < numcombs; i++)
      mono_out += comb_process(&rev->combL[i], input);

   for (i = 0; i < numallpasses; i++)
      mono_out = allpass_process(&rev->allpassL[i], mono_out);

   return mono_in * rev->dry + mono_out * rev->wet1;
}

static void revmodel_update(struct revmodel *rev)
{
   int i;
   rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);

   if (rev->mode >= freezemode)
   {
      rev->roomsize1 = 1.0f;
      rev->damp1 = 0.0f;
      rev->gain = muted;
   }
   else
   {
      rev->roomsize1 = rev->roomsize;
      rev->damp1 = rev->damp;
      rev->gain = fixedgain;
   }

   for (i = 0; i < numcombs; i++)
   {
      rev->combL[i].feedback = rev->roomsize1;
      rev->combL[i].damp1 = rev->damp1;
      rev->combL[i].damp2 = 1.0f - rev->damp1;
   }
}

static void revmodel_setroomsize(struct revmodel *rev, float value)
{
   rev->roomsize = value * scaleroom + offsetroom;
   revmodel_update(rev);
}

static void revmodel_setdamp(struct revmodel *rev, float value)
{
   rev->damp = value * scaledamp;
   revmodel_update(rev);
}

static void revmodel_setwet(struct revmodel *rev, float value)
{
   rev->wet = value * scalewet;
   revmodel_update(rev);
}

static void revmodel_setdry(struct revmodel *rev, float value)
{
   rev->dry = value * scaledry;
   revmodel_update(rev);
}

static void revmodel_setwidth(struct revmodel *rev, float value)
{
   rev->width = value;
   revmodel_update(rev);
}

static void revmodel_setmode(struct revmodel *rev, float value)
{
   rev->mode = value;
   revmodel_update(rev);
}

static void revmodel_init(struct revmodel *rev,int srate)
{

  static const int comb_lengths[8] = { 1116,1188,1277,1356,1422,1491,1557,1617 };
  static const int allpass_lengths[4] = { 225,341,441,556 };
  double r = srate * (1 / 44100.0);
  unsigned c;

   for (c = 0; c < numcombs; ++c)
   {
	   rev->bufcomb[c] = malloc(r*comb_lengths[c]*sizeof(float));
	   rev->combL[c].buffer  =  rev->bufcomb[c];
         memset(rev->combL[c].buffer,0,r*comb_lengths[c]*sizeof(float));
         rev->combL[c].bufsize=r*comb_lengths[c];
  }

   for (c = 0; c < numallpasses; ++c)
   {
	   rev->bufallpass[c] = malloc(r*allpass_lengths[c]*sizeof(float));
	   rev->allpassL[c].buffer  =  rev->bufallpass[c];
         memset(rev->allpassL[c].buffer,0,r*allpass_lengths[c]*sizeof(float));
         rev->allpassL[c].bufsize=r*allpass_lengths[c];
         rev->allpassL[c].feedback = 0.5f;
  }

   revmodel_setwet(rev, initialwet);
   revmodel_setroomsize(rev, initialroom);
   revmodel_setdry(rev, initialdry);
   revmodel_setdamp(rev, initialdamp);
   revmodel_setwidth(rev, initialwidth);
   revmodel_setmode(rev, initialmode);
}

struct reverb_data
{
   struct revmodel left, right;
};

static void reverb_free(void *data)
{
   unsigned i;
   struct reverb_data *rev = (struct reverb_data*)data;

   for (i = 0; i < numcombs; i++)
   {
      free(rev->left.bufcomb[i]);
      free(rev->right.bufcomb[i]);
   }

   for (i = 0; i < numallpasses; i++)
   {
      free(rev->left.bufallpass[i]);
      free(rev->right.bufallpass[i]);
   }
   free(data);
}

static void reverb_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out;
   struct reverb_data *rev = (struct reverb_data*)data;

   output->samples         = input->samples;
   output->frames          = input->frames;
   out                     = output->samples;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float in[2] = { out[0], out[1] };

      out[0] = revmodel_process(&rev->left, in[0]);
      out[1] = revmodel_process(&rev->right, in[1]);
   }
}

static void *reverb_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float drytime, wettime, damping, roomwidth, roomsize;
   struct reverb_data *rev = (struct reverb_data*)
      calloc(1, sizeof(*rev));
   if (!rev)
      return NULL;

   config->get_float(userdata, "drytime", &drytime, 0.43f);
   config->get_float(userdata, "wettime", &wettime, 0.4f);
   config->get_float(userdata, "damping", &damping, 0.8f);
   config->get_float(userdata, "roomwidth", &roomwidth, 0.56f);
   config->get_float(userdata, "roomsize", &roomsize, 0.56f);

   revmodel_init(&rev->left,info->input_rate);
   revmodel_init(&rev->right,info->input_rate);

   revmodel_setdamp(&rev->left, damping);
   revmodel_setdry(&rev->left, drytime);
   revmodel_setwet(&rev->left, wettime);
   revmodel_setwidth(&rev->left, roomwidth);
   revmodel_setroomsize(&rev->left, roomsize);

   revmodel_setdamp(&rev->right, damping);
   revmodel_setdry(&rev->right, drytime);
   revmodel_setwet(&rev->right, wettime);
   revmodel_setwidth(&rev->right, roomwidth);
   revmodel_setroomsize(&rev->right, roomsize);

   return rev;
}

static const struct dspfilter_implementation reverb_plug = {
   reverb_init,
   reverb_process,
   reverb_free,

   DSPFILTER_API_VERSION,
   "Reverb",
   "reverb",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation reverb_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &reverb_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Reverb.dsp

filters = 1
filter0 = reverb

# Defaults.
# reverb_drytime = 0.43
# reverb_wettime = 0.4
# reverb_damping = 0.8
# reverb_roomwidth = 0.56
# reverb_roomsize = 0.56

./include/libretro-common/audio/dsp_filters/tremolo.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (tremolo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>
#include <string/stdstring.h>

#define sqr(a) ((a) * (a))

struct tremolo_core
{
   float *wavetable;
   float freq;
   float depth;
   unsigned index;
   unsigned maxindex;
};

struct tremolo
{
   struct tremolo_core left, right;
};

static void tremolo_free(void *data)
{
   struct tremolo *tre = (struct tremolo*)data;
   free(tre->left.wavetable);
   free(tre->right.wavetable);
   free(data);
}

static void tremolocore_init(struct tremolo_core *core,float depth,int samplerate,float freq)
{
   double env;
   unsigned i;
   const double offset = 1. - depth / 2.;
   core->index     = 0;
   core->maxindex  = samplerate / freq;
   core->wavetable = malloc(core->maxindex   * sizeof(float));
   memset(core->wavetable, 0, core->maxindex * sizeof(float));
   for (i = 0; i < core->maxindex; i++)
   {
      env                = freq * i / samplerate;
      env                = sin((M_PI*2) * fmod(env + 0.25, 1.0));
      core->wavetable[i] = env * (1 - fabs(offset)) + offset;
   }
}

float tremolocore_core(struct tremolo_core *core,float in)
{
   core->index = core->index % core->maxindex;
   return in * core->wavetable[core->index++];
}

static void tremolo_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out;
   struct tremolo *tre = (struct tremolo*)data;

   output->samples     = input->samples;
   output->frames      = input->frames;
   out                 = output->samples;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float in[2]      = { out[0], out[1] };
      out[0]           = tremolocore_core(&tre->left, in[0]);
      out[1]           = tremolocore_core(&tre->right, in[1]);
   }
}

static void *tremolo_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float freq, depth;
   struct tremolo *tre = (struct tremolo*)calloc(1, sizeof(*tre));
   if (!tre)
      return NULL;

   config->get_float(userdata, "freq", &freq,4.0f);
   config->get_float(userdata, "depth", &depth, 0.9f);
   tremolocore_init(&tre->left,depth,info->input_rate,freq);
   tremolocore_init(&tre->right,depth,info->input_rate,freq);
   return tre;
}

static const struct dspfilter_implementation tremolo_plug = {
   tremolo_init,
   tremolo_process,
   tremolo_free,

   DSPFILTER_API_VERSION,
   "Tremolo",
   "tremolo",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation tremolo_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &tremolo_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Tremolo.dsp

filters = 1
filter0 = tremolo

# Defaults.
#tremolo_frequency = 4.0
#tremolo_depth = 0.9

./include/libretro-common/audio/dsp_filters/vibrato.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vibrato.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>
#include <string/stdstring.h>

#define sqr(a) ((a) * (a))

#define VIBRATO_BASE_DELAY_SEC 0.002f /* 2 ms */
#define VIBRATO_FREQUENCY_DEFAULT_HZ 2.0f
#define VIBRATO_FREQUENCY_MAX_HZ 14.0f
#define VIBRATO_DEPTH_DEFAULT_PERCENT 50.0f
#define VIBRATO_ADD_DELAY 3

static float hermite_interp(float x, float *y)
{
   float c0 = y[1];
   float c1 = (1.0f / 2.0f) * (y[2] - y[0]);
   float c2 = (y[0] - (5.0f / 2.0f) * y[1]) + (2.0f * y[2] - (1.0f / 2.0f) * y[3]);
   float c3 = (1.0f / 2.0f) * (y[3] - y[0]) + (3.0f / 2.0f) * (y[1] - y[2]);
   return ((c3 * x + c2) * x + c1) * x + c0;
}

struct vibrato_core
{
   float* buffer;
   float freq;
   float samplerate;
   float depth;
   int phase;
   int writeindex;
   int size;
};

struct vibrato
{
   struct vibrato_core left, right;
};

static void vibrato_free(void *data)
{
   struct vibrato *vib = (struct vibrato*)data;
   free(vib->left.buffer);
   free(vib->right.buffer);
   free(data);
}

static void vibratocore_init(struct vibrato_core *core,float depth,int samplerate,float freq)
{
	core->size       = VIBRATO_BASE_DELAY_SEC * samplerate * 2;
	core->buffer     = malloc((core->size + VIBRATO_ADD_DELAY) * sizeof(float));
	memset(core->buffer, 0, (core->size   + VIBRATO_ADD_DELAY) * sizeof(float));
	core->samplerate = samplerate;
	core->freq       = freq;
	core->depth      = depth;
	core->phase      = 0;
	core->writeindex = 0;
}

float vibratocore_core(struct vibrato_core *core,float in)
{
   int ipart;
   float delay, readindex, fpart, value;
   float M                        = core->freq / core->samplerate;
   int maxphase                   = core->samplerate / core->freq;
   float lfo                      = sin(M * 2. * M_PI * core->phase++);
   int maxdelay                   = VIBRATO_BASE_DELAY_SEC * core->samplerate;
   core->phase                    = core->phase % maxphase;
   lfo                            = (lfo + 1) * 1.; /* Transform from [-1; 1] to [0; 1] */
   delay                          =  lfo * core->depth * maxdelay;
   delay                         += VIBRATO_ADD_DELAY;
   readindex                      = core->writeindex - 1 - delay;
   while (readindex < 0)
      readindex                  += core->size;
   while (readindex >= core->size)
      readindex                  -= core->size;
   ipart                          = (int)readindex;    /* Integer part of the delay */
   fpart                          = readindex - ipart; /* fractional part of the delay */
   value                          = hermite_interp(fpart, &(core->buffer[ipart]));
   core->buffer[core->writeindex] = in;
   if (core->writeindex < VIBRATO_ADD_DELAY)
      core->buffer[core->size + core->writeindex] = in;
   core->writeindex++;
   if (core->writeindex == core->size)
      core->writeindex = 0;
   return value;
}

static void vibrato_process(void *data,
      struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out;
   struct vibrato *vib = (struct vibrato*)data;

   output->samples     = input->samples;
   output->frames      = input->frames;
   out                 = output->samples;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float in[2] = { out[0], out[1] };
      out[0]      = vibratocore_core(&vib->left, in[0]);
      out[1]      = vibratocore_core(&vib->right, in[1]);
   }
}

static void *vibrato_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float freq, depth;
   struct vibrato *vib = (struct vibrato*)calloc(1, sizeof(*vib));
   if (!vib)
      return NULL;

   config->get_float(userdata, "freq", &freq,5.0f);
   config->get_float(userdata, "depth", &depth, 0.5f);
   vibratocore_init(&vib->left,depth,info->input_rate,freq);
   vibratocore_init(&vib->right,depth,info->input_rate,freq);
   return vib;
}

static const struct dspfilter_implementation vibrato_plug = {
   vibrato_init,
   vibrato_process,
   vibrato_free,

   DSPFILTER_API_VERSION,
   "Vibrato",
   "vibrato",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation vibrato_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &vibrato_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/Vibrato.dsp

filters = 1
filter0 = vibrato

# Defaults.
#vibrato_frequency = 5.0
#vibrato_depth = 0.5

./include/libretro-common/audio/dsp_filters/wahwah.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (wahwah.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <retro_miscellaneous.h>
#include <libretro_dspfilter.h>

#define WAHWAH_LFO_SKIP_SAMPLES 30

struct wahwah_data
{
   float phase;
   float lfoskip;
   float b0, b1, b2, a0, a1, a2;
   float freq, startphase;
   float depth, freqofs, res;
   unsigned long skipcount;

   struct
   {
      float xn1, xn2, yn1, yn2;
   } l, r;
};

static void wahwah_free(void *data)
{
   if (data)
      free(data);
}

static void wahwah_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   struct wahwah_data *wah = (struct wahwah_data*)data;
   float *out              = output->samples;

   output->samples         = input->samples;
   output->frames          = input->frames;

   for (i = 0; i < input->frames; i++, out += 2)
   {
      float out_l, out_r;
      float in[2] = { out[0], out[1] };

      if ((wah->skipcount++ % WAHWAH_LFO_SKIP_SAMPLES) == 0)
      {
         float omega, sn, cs, alpha;
         float frequency = (1.0f + cos(wah->skipcount * wah->lfoskip + wah->phase)) / 2.0f;

         frequency       = frequency * wah->depth * (1.0f - wah->freqofs) + wah->freqofs;
         frequency       = exp((frequency - 1.0f) * 6.0f);

         omega           = M_PI * frequency;
         sn              = sin(omega);
         cs              = cos(omega);
         alpha           = sn / (2.0f * wah->res);

         wah->b0         = (1.0f - cs) / 2.0f;
         wah->b1         = 1.0f  - cs;
         wah->b2         = (1.0f - cs) / 2.0f;
         wah->a0         = 1.0f + alpha;
         wah->a1         = -2.0f * cs;
         wah->a2         = 1.0f - alpha;
      }

      out_l              = (wah->b0 * in[0] + wah->b1 * wah->l.xn1 + wah->b2 * wah->l.xn2 - wah->a1 * wah->l.yn1 - wah->a2 * wah->l.yn2) / wah->a0;
      out_r              = (wah->b0 * in[1] + wah->b1 * wah->r.xn1 + wah->b2 * wah->r.xn2 - wah->a1 * wah->r.yn1 - wah->a2 * wah->r.yn2) / wah->a0;

      wah->l.xn2         = wah->l.xn1;
      wah->l.xn1         = in[0];
      wah->l.yn2         = wah->l.yn1;
      wah->l.yn1         = out_l;

      wah->r.xn2         = wah->r.xn1;
      wah->r.xn1         = in[1];
      wah->r.yn2         = wah->r.yn1;
      wah->r.yn1         = out_r;

      out[0]             = out_l;
      out[1]             = out_r;
   }
}

static void *wahwah_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   struct wahwah_data *wah = (struct wahwah_data*)calloc(1, sizeof(*wah));
   if (!wah)
      return NULL;

   config->get_float(userdata, "lfo_freq", &wah->freq, 1.5f);
   config->get_float(userdata, "lfo_start_phase", &wah->startphase, 0.0f);
   config->get_float(userdata, "freq_offset", &wah->freqofs, 0.3f);
   config->get_float(userdata, "depth", &wah->depth, 0.7f);
   config->get_float(userdata, "resonance", &wah->res, 2.5f);

   wah->lfoskip = wah->freq * 2.0f * M_PI / info->input_rate;
   wah->phase   = wah->startphase * M_PI / 180.0f;

   return wah;
}

static const struct dspfilter_implementation wahwah_plug = {
   wahwah_init,
   wahwah_process,
   wahwah_free,

   DSPFILTER_API_VERSION,
   "Wah-Wah",
   "wahwah",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation wahwah_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *
dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   (void)mask;
   return &wahwah_plug;
}

#undef dspfilter_get_implementation

./include/libretro-common/audio/dsp_filters/WahWah.dsp

filters = 1
filter0 = wahwah

# Defaults.
# wahwah_lfo_freq = 1.5
# wahwah_lfo_start_phase = 0.0
# wahwah_freq_offset = 0.3
# wahwah_depth = 0.7
# wahwah_resonance = 2.5

./include/libretro-common/audio/resampler/audio_resampler.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_resampler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>

#include <string/stdstring.h>
#include <features/features_cpu.h>
#include <file/config_file_userdata.h>

#include <audio/audio_resampler.h>

static void resampler_null_process(void *a, struct resampler_data *b) { }
static void resampler_null_free(void *a) { }
static void *resampler_null_init(const struct resampler_config *a, double b,
      enum resampler_quality c, resampler_simd_mask_t d) { return (void*)0; }

retro_resampler_t null_resampler = {
   resampler_null_init,
   resampler_null_process,
   resampler_null_free,
   RESAMPLER_API_VERSION,
   "null",
   "null"
};

static const retro_resampler_t *resampler_drivers[] = {
   &sinc_resampler,
#ifdef HAVE_CC_RESAMPLER
   &CC_resampler,
#endif
#ifdef HAVE_NEAREST_RESAMPLER
   &nearest_resampler,
#endif
   &null_resampler,
   NULL,
};

static const struct resampler_config resampler_config = {
   config_userdata_get_float,
   config_userdata_get_int,
   config_userdata_get_float_array,
   config_userdata_get_int_array,
   config_userdata_get_string,
   config_userdata_free,
};

/**
 * find_resampler_driver_index:
 * @ident                      : Identifier of resampler driver to find.
 *
 * Finds resampler driver index by @ident name.
 *
 * Returns: resampler driver index if resampler driver was found, otherwise
 * -1.
 **/
static int find_resampler_driver_index(const char *ident)
{
   unsigned i;

   for (i = 0; resampler_drivers[i]; i++)
      if (string_is_equal_noncase(ident, resampler_drivers[i]->ident))
         return i;
   return -1;
}

/**
 * find_resampler_driver:
 * @ident                      : Identifier of resampler driver to find.
 *
 * Finds resampler by @ident name.
 *
 * Returns: resampler driver if resampler driver was found, otherwise
 * NULL.
 **/
static const retro_resampler_t *find_resampler_driver(const char *ident)
{
   int i = find_resampler_driver_index(ident);

   if (i >= 0)
      return resampler_drivers[i];

   return resampler_drivers[0];
}

/**
 * resampler_append_plugs:
 * @re                         : Resampler handle
 * @backend                    : Resampler backend that is about to be set.
 * @bw_ratio                   : Bandwidth ratio.
 *
 * Initializes resampler driver based on queried CPU features.
 *
 * Returns: true (1) if successfully initialized, otherwise false (0).
 **/
static bool resampler_append_plugs(void **re,
      const retro_resampler_t **backend,
      enum resampler_quality quality,
      double bw_ratio)
{
   resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get();

   if (*backend)
      *re = (*backend)->init(&resampler_config, bw_ratio, quality, mask);

   if (!*re)
      return false;
   return true;
}


/**
 * audio_resampler_driver_find_handle:
 * @idx                : index of driver to get handle to.
 *
 * Returns: handle to audio resampler driver at index. Can be NULL
 * if nothing found.
 **/
const void *audio_resampler_driver_find_handle(int idx)
{
   const void *drv = resampler_drivers[idx];
   if (!drv)
      return NULL;
   return drv;
}

/**
 * audio_resampler_driver_find_ident:
 * @idx                : index of driver to get handle to.
 *
 * Returns: Human-readable identifier of audio resampler driver at index.
 * Can be NULL if nothing found.
 **/
const char *audio_resampler_driver_find_ident(int idx)
{
   const retro_resampler_t *drv = resampler_drivers[idx];
   if (!drv)
      return NULL;
   return drv->ident;
}

/**
 * retro_resampler_realloc:
 * @re                         : Resampler handle
 * @backend                    : Resampler backend that is about to be set.
 * @ident                      : Identifier name for resampler we want.
 * @bw_ratio                   : Bandwidth ratio.
 *
 * Reallocates resampler. Will free previous handle before
 * allocating a new one. If ident is NULL, first resampler will be used.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
      const char *ident, enum resampler_quality quality, double bw_ratio)
{
   if (*re && *backend)
      (*backend)->free(*re);

   *re      = NULL;
   *backend = find_resampler_driver(ident);

   if (!resampler_append_plugs(re, backend, quality, bw_ratio))
   {
      if (!*re)
         *backend = NULL;
      return false;
   }

   return true;
}

./include/libretro-common/audio/resampler/drivers/nearest_resampler.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nearest_resampler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <stdlib.h>
#include <math.h>

#include <audio/audio_resampler.h>

typedef struct rarch_nearest_resampler
{
   float fraction;
} rarch_nearest_resampler_t;

static void resampler_nearest_process(
      void *re_, struct resampler_data *data)
{
   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
   audio_frame_float_t  *inp     = (audio_frame_float_t*)data->data_in;
   audio_frame_float_t  *inp_max = (audio_frame_float_t*)inp + data->input_frames;
   audio_frame_float_t  *outp    = (audio_frame_float_t*)data->data_out;
   float                   ratio = 1.0 / data->ratio;

   while (inp != inp_max)
   {
      while (re->fraction > 1)
      {
         *outp++       = *inp;
         re->fraction -= ratio;
      }
      re->fraction++;
      inp++;
   }

   data->output_frames = (outp - (audio_frame_float_t*)data->data_out);
}

static void resampler_nearest_free(void *re_)
{
   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
   if (re)
      free(re);
}

static void *resampler_nearest_init(const struct resampler_config *config,
      double bandwidth_mod,
      enum resampler_quality quality,
      resampler_simd_mask_t mask)
{
   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)
      calloc(1, sizeof(rarch_nearest_resampler_t));
   if (!re)
      return NULL;
   re->fraction = 0;
   return re;
}

retro_resampler_t nearest_resampler = {
   resampler_nearest_init,
   resampler_nearest_process,
   resampler_nearest_free,
   RESAMPLER_API_VERSION,
   "nearest",
   "nearest"
};

./include/libretro-common/audio/resampler/drivers/sinc_resampler.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (sinc_resampler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Bog-standard windowed SINC implementation. */

#if defined(__GNUC__) && defined(__OPTIMIZE__) && !defined(__clang__)
#pragma GCC push_options
#pragma GCC optimize ("fast-math")
#endif

#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#include <retro_environment.h>
#include <retro_inline.h>
#include <filters.h>
#include <memalign.h>

#include <audio/audio_resampler.h>
#include <filters.h>

#ifdef __SSE__
#include <xmmintrin.h>
#endif

#if defined(__AVX__)
#include <immintrin.h>
#endif

/* Rough SNR values for upsampling:
 * LOWEST: 40 dB
 * LOWER: 55 dB
 * NORMAL: 70 dB
 * HIGHER: 110 dB
 * HIGHEST: 140 dB
 */

/* TODO, make all this more configurable. */

enum sinc_window
{
   SINC_WINDOW_NONE   = 0,
   SINC_WINDOW_KAISER,
   SINC_WINDOW_LANCZOS
};

/* For the little amount of taps we're using,
 * SSE1 is faster than AVX for some reason.
 * AVX code is kept here though as by increasing number
 * of sinc taps, the AVX code is clearly faster than SSE1.
 */

typedef struct rarch_sinc_resampler
{
   /* A buffer for phase_table, buffer_l and buffer_r
    * are created in a single calloc().
    * Ensure that we get as good cache locality as we can hope for. */
   float *main_buffer;
   float *phase_table;
   float *buffer_l;
   float *buffer_r;
   unsigned phase_bits;
   unsigned subphase_bits;
   unsigned subphase_mask;
   unsigned taps;
   unsigned ptr;
   uint32_t time;
   float subphase_mod;
   float kaiser_beta;
} rarch_sinc_resampler_t;

#if (defined(__ARM_NEON__) || defined(HAVE_NEON))

#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
void process_sinc_neon_asm(float *out, const float *left,
      const float *right, const float *coeff, unsigned taps);
#else
#include <arm_neon.h>

/* Assumes that taps >= 8, and that taps is a multiple of 8.
 * Not bothering to reimplement this one for the external .S
 */
static void resampler_sinc_process_neon_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
   uint32_t ratio                 = phases / data->ratio;
   const float *input             = data->data_in;
   float *output                  = data->data_out;
   size_t frames                  = data->input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps] =
            resamp->buffer_l[resamp->ptr]     = *input++;

         resamp->buffer_r[resamp->ptr + taps] =
            resamp->buffer_r[resamp->ptr]     = *input++;

         resamp->time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            int i;
            unsigned phase           = resamp->time >> resamp->subphase_bits;
            const float *phase_table = resamp->phase_table + phase * taps * 2;
            const float *delta_table = phase_table + taps;
            float32x4_t delta        = vdupq_n_f32((resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
            float32x4_t p1 = {0, 0, 0, 0}, p2 = {0, 0, 0, 0};
            float32x2_t p3, p4;

            for (i = 0; i < (int)taps; i += 8)
            {
               float32x4x2_t coeff8  = vld2q_f32(&phase_table[i]);
               float32x4x2_t delta8  = vld2q_f32(&delta_table[i]);
               float32x4x2_t left8   = vld2q_f32(&buffer_l[i]);
               float32x4x2_t right8  = vld2q_f32(&buffer_r[i]);

               coeff8.val[0] = vmlaq_f32(coeff8.val[0], delta8.val[0], delta);
               coeff8.val[1] = vmlaq_f32(coeff8.val[1], delta8.val[1], delta);

               p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);
               p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);
               p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);
               p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);
            }

            p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));
            p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));
            vst1_f32(output, vpadd_f32(p3, p4));
            output                 += 2;
            out_frames++;
            resamp->time           += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}
#endif

/* Assumes that taps >= 8, and that taps is a multiple of 8. */
static void resampler_sinc_process_neon(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
   uint32_t ratio                 = phases / data->ratio;
   const float *input             = data->data_in;
   float *output                  = data->data_out;
   size_t frames                  = data->input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps] =
            resamp->buffer_l[resamp->ptr]     = *input++;

         resamp->buffer_r[resamp->ptr + taps] =
            resamp->buffer_r[resamp->ptr]     = *input++;

         resamp->time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            unsigned phase           = resamp->time >> resamp->subphase_bits;
            const float *phase_table = resamp->phase_table + phase * taps;
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
            process_sinc_neon_asm(output, buffer_l, buffer_r, phase_table, taps);
#else
            int i;
            float32x4_t p1 = {0, 0, 0, 0}, p2 = {0, 0, 0, 0};
            float32x2_t p3, p4;

            for (i = 0; i < (int)taps; i += 8)
            {
               float32x4x2_t coeff8  = vld2q_f32(&phase_table[i]);
               float32x4x2_t left8   = vld2q_f32(&buffer_l[i]);
               float32x4x2_t right8  = vld2q_f32(&buffer_r[i]);

               p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);
               p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);
               p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);
               p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);
            }

            p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));
            p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));
            vst1_f32(output, vpadd_f32(p3, p4));
#endif
            output                 += 2;
            out_frames++;
            resamp->time           += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}
#endif

#if defined(__AVX__)
static void resampler_sinc_process_avx_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);

   uint32_t ratio                 = phases / data->ratio;
   const float *input             = data->data_in;
   float *output                  = data->data_out;
   size_t frames                  = data->input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps] =
            resamp->buffer_l[resamp->ptr]     = *input++;

         resamp->buffer_r[resamp->ptr + taps] =
            resamp->buffer_r[resamp->ptr]     = *input++;

         resamp->time                                -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            int i;
            __m256 res_l, res_r;
            unsigned phase           = resamp->time >> resamp->subphase_bits;
            float *phase_table       = resamp->phase_table + phase * taps * 2;
            float *delta_table       = phase_table + taps;
            __m256 delta             = _mm256_set1_ps((float)
                  (resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
            __m256 sum_l             = _mm256_setzero_ps();
            __m256 sum_r             = _mm256_setzero_ps();

            for (i = 0; i < (int)taps; i += 8)
            {
               __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);
               __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);
               __m256 deltas = _mm256_load_ps(delta_table + i);
               __m256 sinc   = _mm256_add_ps(_mm256_load_ps((const float*)phase_table + i),
                     _mm256_mul_ps(deltas, delta));

               sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
               sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
            }

            /* hadd on AVX is weird, and acts on low-lanes
             * and high-lanes separately. */
            res_l = _mm256_hadd_ps(sum_l, sum_l);
            res_r = _mm256_hadd_ps(sum_r, sum_r);
            res_l = _mm256_hadd_ps(res_l, res_l);
            res_r = _mm256_hadd_ps(res_r, res_r);
            res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
            res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);

            /* This is optimized to mov %xmmN, [mem].
             * There doesn't seem to be any _mm256_store_ss intrinsic. */
            _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
            _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));

            output += 2;
            out_frames++;
            resamp->time += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}

static void resampler_sinc_process_avx(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases    = 1 << (resamp->phase_bits + resamp->subphase_bits);

   uint32_t ratio     = phases / data->ratio;
   const float *input = data->data_in;
   float *output      = data->data_out;
   size_t frames      = data->input_frames;
   size_t out_frames  = 0;
   unsigned taps      = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps] =
            resamp->buffer_l[resamp->ptr]     = *input++;

         resamp->buffer_r[resamp->ptr + taps] =
            resamp->buffer_r[resamp->ptr]     = *input++;

         resamp->time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            int i;
            __m256 delta, res_l, res_r;
            unsigned phase           = resamp->time >> resamp->subphase_bits;
            float *phase_table       = resamp->phase_table + phase * taps;

            __m256 sum_l             = _mm256_setzero_ps();
            __m256 sum_r             = _mm256_setzero_ps();

            for (i = 0; i < (int)taps; i += 8)
            {
               __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);
               __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);
               __m256 sinc   = _mm256_load_ps((const float*)phase_table + i);

               sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
               sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
            }

            /* hadd on AVX is weird, and acts on low-lanes
             * and high-lanes separately. */
            res_l = _mm256_hadd_ps(sum_l, sum_l);
            res_r = _mm256_hadd_ps(sum_r, sum_r);
            res_l = _mm256_hadd_ps(res_l, res_l);
            res_r = _mm256_hadd_ps(res_r, res_r);
            res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
            res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);

            /* This is optimized to mov %xmmN, [mem].
             * There doesn't seem to be any _mm256_store_ss intrinsic. */
            _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
            _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));

            output += 2;
            out_frames++;
            resamp->time += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}
#endif

#if defined(__SSE__)
static void resampler_sinc_process_sse_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);

   uint32_t ratio                 = phases / data->ratio;
   const float *input             = data->data_in;
   float *output                  = data->data_out;
   size_t frames                  = data->input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps] =
            resamp->buffer_l[resamp->ptr]     = *input++;

         resamp->buffer_r[resamp->ptr + taps] =
            resamp->buffer_r[resamp->ptr]     = *input++;

         resamp->time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            int i;
            __m128 sum;
            unsigned phase           = resamp->time >> resamp->subphase_bits;
            float *phase_table       = resamp->phase_table + phase * taps * 2;
            float *delta_table       = phase_table + taps;
            __m128 delta             = _mm_set1_ps((float)
                  (resamp->time & resamp->subphase_mask) * resamp->subphase_mod);

            __m128 sum_l             = _mm_setzero_ps();
            __m128 sum_r             = _mm_setzero_ps();

            for (i = 0; i < (int)taps; i += 4)
            {
               __m128 buf_l = _mm_loadu_ps(buffer_l + i);
               __m128 buf_r = _mm_loadu_ps(buffer_r + i);
               __m128 deltas = _mm_load_ps(delta_table + i);
               __m128 _sinc  = _mm_add_ps(_mm_load_ps((const float*)phase_table + i),
                     _mm_mul_ps(deltas, delta));
               sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
               sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
            }

            /* Them annoying shuffles.
             * sum_l = { l3, l2, l1, l0 }
             * sum_r = { r3, r2, r1, r0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
                     _MM_SHUFFLE(1, 0, 1, 0)),
                  _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));

            /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
             * sum   = { R1, R0, L1, L0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);

            /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
             * sum   = { X,  R,  X,  L }
             */

            /* Store L */
            _mm_store_ss(output + 0, sum);

            /* movehl { X, R, X, L } == { X, R, X, R } */
            _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));

            output += 2;
            out_frames++;
            resamp->time += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}

static void resampler_sinc_process_sse(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);

   uint32_t ratio                 = phases / data->ratio;
   const float *input             = data->data_in;
   float *output                  = data->data_out;
   size_t frames                  = data->input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps] =
            resamp->buffer_l[resamp->ptr]     = *input++;

         resamp->buffer_r[resamp->ptr + taps] =
            resamp->buffer_r[resamp->ptr]     = *input++;

         resamp->time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            int i;
            __m128 sum;
            unsigned phase           = resamp->time >> resamp->subphase_bits;
            float *phase_table       = resamp->phase_table + phase * taps;

            __m128 sum_l             = _mm_setzero_ps();
            __m128 sum_r             = _mm_setzero_ps();

            for (i = 0; i < (int)taps; i += 4)
            {
               __m128 buf_l = _mm_loadu_ps(buffer_l + i);
               __m128 buf_r = _mm_loadu_ps(buffer_r + i);
               __m128 _sinc = _mm_load_ps((const float*)phase_table + i);
               sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
               sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
            }

            /* Them annoying shuffles.
             * sum_l = { l3, l2, l1, l0 }
             * sum_r = { r3, r2, r1, r0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
                     _MM_SHUFFLE(1, 0, 1, 0)),
                  _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));

            /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
             * sum   = { R1, R0, L1, L0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);

            /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
             * sum   = { X,  R,  X,  L }
             */

            /* Store L */
            _mm_store_ss(output + 0, sum);

            /* movehl { X, R, X, L } == { X, R, X, R } */
            _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));

            output += 2;
            out_frames++;
            resamp->time += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}
#endif

static void resampler_sinc_process_c_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);

   uint32_t ratio                 = phases / data->ratio;
   const float *input             = data->data_in;
   float *output                  = data->data_out;
   size_t frames                  = data->input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps]    =
            resamp->buffer_l[resamp->ptr]        = *input++;

         resamp->buffer_r[resamp->ptr + taps]    =
            resamp->buffer_r[resamp->ptr]        = *input++;

         resamp->time                           -= phases;
         frames--;
      }

      {
         const float *buffer_l = resamp->buffer_l + resamp->ptr;
         const float *buffer_r = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            int i;
            float sum_l        = 0.0f;
            float sum_r        = 0.0f;
            unsigned phase     = resamp->time >> resamp->subphase_bits;
            float *phase_table = resamp->phase_table + phase * taps * 2;
            float *delta_table = phase_table + taps;
            float delta        = (float)
               (resamp->time & resamp->subphase_mask) * resamp->subphase_mod;

            for (i = 0; i < (int)taps; i++)
            {
               float sinc_val  = phase_table[i] + delta_table[i] * delta;

               sum_l          += buffer_l[i] * sinc_val;
               sum_r          += buffer_r[i] * sinc_val;
            }

            output[0]          = sum_l;
            output[1]          = sum_r;

            output            += 2;
            out_frames++;
            resamp->time      += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}

static void resampler_sinc_process_c(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);

   uint32_t ratio                 = phases / data->ratio;
   const float *input             = data->data_in;
   float *output                  = data->data_out;
   size_t frames                  = data->input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp->taps;

   while (frames)
   {
      while (frames && resamp->time >= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp->ptr)
            resamp->ptr = taps;
         resamp->ptr--;

         resamp->buffer_l[resamp->ptr + taps]    =
            resamp->buffer_l[resamp->ptr]        = *input++;

         resamp->buffer_r[resamp->ptr + taps]    =
            resamp->buffer_r[resamp->ptr]        = *input++;

         resamp->time                           -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
         while (resamp->time < phases)
         {
            int i;
            float sum_l           = 0.0f;
            float sum_r           = 0.0f;
            unsigned phase        = resamp->time >> resamp->subphase_bits;
            float *phase_table    = resamp->phase_table + phase * taps;

            for (i = 0; i < (int)taps; i++)
            {
               float sinc_val     = phase_table[i];

               sum_l             += buffer_l[i] * sinc_val;
               sum_r             += buffer_r[i] * sinc_val;
            }

            output[0]             = sum_l;
            output[1]             = sum_r;

            output               += 2;
            out_frames++;
            resamp->time         += ratio;
         }
      }
   }

   data->output_frames = out_frames;
}

static void resampler_sinc_free(void *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)data;
   if (resamp)
      memalign_free(resamp->main_buffer);
   free(resamp);
}

static void sinc_init_table_kaiser(rarch_sinc_resampler_t *resamp,
      double cutoff,
      float *phase_table, int phases, int taps, bool calculate_delta)
{
   int i, j;
   /* Kaiser window function - need to normalize w(0) to 1.0f */
   float kaiser_beta = resamp->kaiser_beta;
   double window_mod = besseli0(kaiser_beta);
   int stride        = calculate_delta ? 2 : 1;
   double sidelobes  = taps / 2.0;

   for (i = 0; i < phases; i++)
   {
      for (j = 0; j < taps; j++)
      {
         float val;
         double sinc_phase;
         int               n = j * phases + i;
         double window_phase = (double)n / (phases * taps); /* [0, 1). */
         window_phase        = 2.0 * window_phase - 1.0; /* [-1, 1) */
         sinc_phase          = sidelobes * window_phase;
         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
              besseli0(kaiser_beta * sqrtf(1 - window_phase * window_phase))
            / window_mod;
         phase_table[i * stride * taps + j] = val;
      }
   }

   if (calculate_delta)
   {
      int phase;
      int p;
      for (p = 0; p < phases - 1; p++)
      {
         for (j = 0; j < taps; j++)
         {
            float delta = phase_table[(p + 1) * stride * taps + j] -
               phase_table[p * stride * taps + j];
            phase_table[(p * stride + 1) * taps + j] = delta;
         }
      }

      phase = phases - 1;
      for (j = 0; j < taps; j++)
      {
         float val, delta;
         double sinc_phase;
         int n               = j * phases + (phase + 1);
         double window_phase = (double)n / (phases * taps); /* (0, 1]. */
         window_phase        = 2.0 * window_phase - 1.0; /* (-1, 1] */
         sinc_phase          = sidelobes * window_phase;

         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
              besseli0(resamp->kaiser_beta * sqrtf(1 - window_phase *
window_phase)) / window_mod;
         delta = (val - phase_table[phase * stride * taps + j]);
         phase_table[(phase * stride + 1) * taps + j] = delta;
      }
   }
}

static void sinc_init_table_lanczos(
      rarch_sinc_resampler_t *resamp, double cutoff,
      float *phase_table, int phases, int taps, bool calculate_delta)
{
   int i, j;
   /* Lanczos window function - need to normalize w(0) to 1.0f */
   double window_mod = 1.0;
   int stride        = calculate_delta ? 2 : 1;
   double sidelobes  = taps / 2.0;

   for (i = 0; i < phases; i++)
   {
      for (j = 0; j < taps; j++)
      {
         double sinc_phase;
         float val;
         int               n = j * phases + i;
         double window_phase = (double)n / (phases * taps); /* [0, 1). */
         window_phase        = 2.0 * window_phase - 1.0; /* [-1, 1) */
         sinc_phase          = sidelobes * window_phase;
         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
            sinc(M_PI * window_phase) / window_mod;
         phase_table[i * stride * taps + j] = val;
      }
   }

   if (calculate_delta)
   {
      int p;
      int phase;

      for (p = 0; p < phases - 1; p++)
      {
         for (j = 0; j < taps; j++)
         {
            float delta = phase_table[(p + 1) * stride * taps + j] -
               phase_table[p * stride * taps + j];
            phase_table[(p * stride + 1) * taps + j] = delta;
         }
      }

      phase = phases - 1;
      for (j = 0; j < taps; j++)
      {
         float val, delta;
         double sinc_phase;
         int n               = j * phases + (phase + 1);
         double window_phase = (double)n / (phases * taps); /* (0, 1]. */
         window_phase        = 2.0 * window_phase - 1.0; /* (-1, 1] */
         sinc_phase          = sidelobes * window_phase;

         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
            sinc(M_PI * window_phase) / window_mod;
         delta = (val - phase_table[phase * stride * taps + j]);
         phase_table[(phase * stride + 1) * taps + j] = delta;
      }
   }
}

static void *resampler_sinc_new(const struct resampler_config *config,
      double bandwidth_mod, enum resampler_quality quality,
      resampler_simd_mask_t mask)
{
   double cutoff                  = 0.0;
   size_t phase_elems             = 0;
   size_t elems                   = 0;
   unsigned enable_avx            = 0;
   unsigned sidelobes             = 0;
   enum sinc_window window_type   = SINC_WINDOW_NONE;
   rarch_sinc_resampler_t *re     = (rarch_sinc_resampler_t*)
      calloc(1, sizeof(*re));

   if (!re)
      return NULL;

   switch (quality)
   {
      case RESAMPLER_QUALITY_LOWEST:
         cutoff            = 0.98;
         sidelobes         = 2;
         re->phase_bits    = 12;
         re->subphase_bits = 10;
         window_type       = SINC_WINDOW_LANCZOS;
         break;
      case RESAMPLER_QUALITY_LOWER:
         cutoff            = 0.98;
         sidelobes         = 4;
         re->phase_bits    = 12;
         re->subphase_bits = 10;
         window_type       = SINC_WINDOW_LANCZOS;
         break;
      case RESAMPLER_QUALITY_HIGHER:
         cutoff            = 0.90;
         sidelobes         = 32;
         re->phase_bits    = 10;
         re->subphase_bits = 14;
         window_type       = SINC_WINDOW_KAISER;
         re->kaiser_beta   = 10.5;
         enable_avx        = 1;
         break;
      case RESAMPLER_QUALITY_HIGHEST:
         cutoff            = 0.962;
         sidelobes         = 128;
         re->phase_bits    = 10;
         re->subphase_bits = 14;
         window_type       = SINC_WINDOW_KAISER;
         re->kaiser_beta   = 14.5;
         enable_avx        = 1;
         break;
      case RESAMPLER_QUALITY_NORMAL:
      case RESAMPLER_QUALITY_DONTCARE:
         cutoff            = 0.825;
         sidelobes         = 8;
         re->phase_bits    = 8;
         re->subphase_bits = 16;
         window_type       = SINC_WINDOW_KAISER;
         re->kaiser_beta   = 5.5;
         break;
   }

   re->subphase_mask = (1 << re->subphase_bits) - 1;
   re->subphase_mod  = 1.0f / (1 << re->subphase_bits);
   re->taps          = sidelobes * 2;

   /* Downsampling, must lower cutoff, and extend number of
    * taps accordingly to keep same stopband attenuation. */
   if (bandwidth_mod < 1.0)
   {
      cutoff  *= bandwidth_mod;
      re->taps = (unsigned)ceil(re->taps / bandwidth_mod);
   }

   /* Be SIMD-friendly. */
#if defined(__AVX__)
   if (enable_avx)
      re->taps = (re->taps + 7) & ~7;
   else
#endif
   {
#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
      re->taps = (re->taps + 7) & ~7;
#else
      re->taps = (re->taps + 3) & ~3;
#endif
   }

   phase_elems = ((1 << re->phase_bits) * re->taps);
   if (window_type == SINC_WINDOW_KAISER)
      phase_elems  = phase_elems * 2;
   elems       = phase_elems + 4 * re->taps;

   re->main_buffer = (float*)memalign_alloc(128, sizeof(float) * elems);
   if (!re->main_buffer)
      goto error;

   memset(re->main_buffer, 0, sizeof(float) * elems);

   re->phase_table = re->main_buffer;
   re->buffer_l    = re->main_buffer + phase_elems;
   re->buffer_r    = re->buffer_l + 2 * re->taps;

   switch (window_type)
   {
      case SINC_WINDOW_LANCZOS:
         sinc_init_table_lanczos(re, cutoff, re->phase_table,
               1 << re->phase_bits, re->taps, false);
         break;
      case SINC_WINDOW_KAISER:
         sinc_init_table_kaiser(re, cutoff, re->phase_table,
               1 << re->phase_bits, re->taps, true);
         break;
      case SINC_WINDOW_NONE:
         goto error;
   }

   sinc_resampler.process = resampler_sinc_process_c;
   if (window_type == SINC_WINDOW_KAISER)
      sinc_resampler.process    = resampler_sinc_process_c_kaiser;

   if (mask & RESAMPLER_SIMD_AVX && enable_avx)
   {
#if defined(__AVX__)
      sinc_resampler.process    = resampler_sinc_process_avx;
      if (window_type == SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_avx_kaiser;
#endif
   }
   else if (mask & RESAMPLER_SIMD_SSE)
   {
#if defined(__SSE__)
      sinc_resampler.process = resampler_sinc_process_sse;
      if (window_type == SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_sse_kaiser;
#endif
   }
   else if (mask & RESAMPLER_SIMD_NEON)
   {
#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
      if (window_type != SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_neon;
#else
      sinc_resampler.process = resampler_sinc_process_neon;
      if (window_type == SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_neon_kaiser;
#endif
#endif
   }

   return re;

error:
   resampler_sinc_free(re);
   return NULL;
}

retro_resampler_t sinc_resampler = {
   resampler_sinc_new,
   resampler_sinc_process_c,
   resampler_sinc_free,
   RESAMPLER_API_VERSION,
   "sinc",
   "sinc"
};

#if defined(__GNUC__) && defined(__OPTIMIZE__) && !defined(__clang__)
#pragma GCC pop_options
#endif

./include/libretro-common/audio/resampler/drivers/sinc_resampler_neon.S

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (sinc_resampler_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#ifndef __MACH__
.arm
#endif
.align 4
.globl process_sinc_neon_asm
#ifndef __MACH__
.type process_sinc_neon_asm, %function
#endif
.globl _process_sinc_neon_asm
#ifndef __MACH__
.type _process_sinc_neon_asm, %function
#endif
# void process_sinc_neon(float *out, const float *left, const float *right, const float *coeff, unsigned taps)
# Assumes taps is >= 8, and a multiple of 8.
process_sinc_neon_asm:
_process_sinc_neon_asm:

   push {r4, lr}
   vmov.f32 q0, #0.0
   vmov.f32 q8, #0.0

   # Taps argument (r4) goes on stack in armeabi.
   ldr r4, [sp, #8]

1:
   # Left
   vld1.f32 {q2-q3}, [r1]!
   # Right
   vld1.f32 {q10-q11}, [r2]!
   # Coeff
   vld1.f32 {q12-q13}, [r3, :128]!

   # Left / Right
   vmla.f32 q0, q2, q12
   vmla.f32 q8, q10, q12
   vmla.f32 q0, q3, q13
   vmla.f32 q8, q11, q13

   subs r4, r4, #8
   bne 1b

   # Add everything together
   vadd.f32 d0, d0, d1
   vadd.f32 d16, d16, d17
   vpadd.f32 d0, d0, d16
   vst1.f32 d0, [r0]

   pop {r4, pc}

#endif

./include/libretro-common/cdrom/cdrom.c

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (cdrom.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <cdrom/cdrom.h>
#include <libretro.h>
#include <stdio.h>
#include <string.h>
#include <compat/strl.h>
#include <compat/strcasestr.h>
#include <retro_math.h>
#include <retro_timers.h>
#include <streams/file_stream.h>
#include <retro_endianness.h>
#include <retro_miscellaneous.h>
#include <vfs/vfs_implementation.h>
#include <lists/string_list.h>
#include <lists/dir_list.h>
#include <string/stdstring.h>
#include <memalign.h>

#include <math.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif

#if defined(__linux__) && !defined(ANDROID)
#include <sys/ioctl.h>
#include <scsi/sg.h>
#endif

#if defined(_WIN32) && !defined(_XBOX)
#include <windows.h>
#include <winioctl.h>
#include <ntddscsi.h>
#endif

#define CDROM_CUE_TRACK_BYTES 107
#define CDROM_MAX_SENSE_BYTES 16
#define CDROM_MAX_RETRIES 10
#define CDROM_MIN_BUFSIZE 9

typedef enum
{
   DIRECTION_NONE,
   DIRECTION_IN,
   DIRECTION_OUT
} CDROM_CMD_Direction;

void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame)
{
   if (!min || !sec || !frame)
      return;

   *frame  = lba % 75;
   lba    /= 75;
   *sec    = lba % 60;
   lba    /= 60;
   *min    = lba;
}

unsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame)
{
   return (min * 60 + sec) * 75 + frame;
}

void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
{
   if (!min || !sec || !frame)
      return;

   *min   = (*frame == 74) ? (*sec < 59 ? *min : *min + 1) : *min;
   *sec   = (*frame == 74) ? (*sec < 59 ? (*sec + 1) : 0) : *sec;
   *frame = (*frame  < 74) ? (*frame + 1) : 0;
}

#ifdef CDROM_DEBUG
static void cdrom_print_sense_data(const unsigned char *s, size_t len)
{
   unsigned i;
   const char *sense_key_text = NULL;
   unsigned char key;
   unsigned char asc;
   unsigned char ascq;

   if (len < 16)
   {
      printf("[CDROM] Sense data buffer length too small.\n");
      fflush(stdout);
      return;
   }

   key  = s[2] & 0xF;
   asc  = s[12];
   ascq = s[13];

   printf("[CDROM] Sense Data: ");

   for (i = 0; i < MIN(len, 16); i++)
      printf("%02X ", s[i]);

   printf("\n");

   if (s[0] == 0x70)
      printf("[CDROM] CURRENT ERROR:\n");
   if (s[0] == 0x71)
      printf("[CDROM] DEFERRED ERROR:\n");

   switch (key)
   {
      case 0:
         sense_key_text = "NO SENSE";
         break;
      case 1:
         sense_key_text = "RECOVERED ERROR";
         break;
      case 2:
         sense_key_text = "NOT READY";
         break;
      case 3:
         sense_key_text = "MEDIUM ERROR";
         break;
      case 4:
         sense_key_text = "HARDWARE ERROR";
         break;
      case 5:
         sense_key_text = "ILLEGAL REQUEST";
         break;
      case 6:
         sense_key_text = "UNIT ATTENTION";
         break;
      case 7:
         sense_key_text = "DATA PROTECT";
         break;
      case 8:
         sense_key_text = "BLANK CHECK";
         break;
      case 9:
         sense_key_text = "VENDOR SPECIFIC";
         break;
      case 10:
         sense_key_text = "COPY ABORTED";
         break;
      case 11:
         sense_key_text = "ABORTED COMMAND";
         break;
      case 13:
         sense_key_text = "VOLUME OVERFLOW";
         break;
      case 14:
         sense_key_text = "MISCOMPARE";
         break;
   }

   printf("[CDROM] Sense Key: %02X (%s)\n", key, sense_key_text ? sense_key_text : "null");
   printf("[CDROM] ASC: %02X\n", asc);
   printf("[CDROM] ASCQ: %02X\n", ascq);

   switch (key)
   {
      case 2:
      {
         switch (asc)
         {
            case 4:
            {
               switch (ascq)
               {
                  case 1:
                     printf("[CDROM] Description: LOGICAL UNIT IS IN PROCESS OF BECOMING READY\n");
                     break;
                  default:
                     break;
               }

               break;
            }
            case 0x3a:
            {
               switch (ascq)
               {
                  case 0:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT\n");
                     break;
                  case 3:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT - LOADABLE\n");
                     break;
                  case 1:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT - TRAY CLOSED\n");
                     break;
                  case 2:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT - TRAY OPEN\n");
                     break;
                  default:
                     break;
               }

               break;
            }
            default:
               break;
         }
      }
      case 3:
      {
         if (asc == 0x11 && ascq == 0x5)
            printf("[CDROM] Description: L-EC UNCORRECTABLE ERROR\n");
         break;
      }
      case 5:
      {
         if (asc == 0x20 && ascq == 0)
            printf("[CDROM] Description: INVALID COMMAND OPERATION CODE\n");
         else if (asc == 0x24 && ascq == 0)
            printf("[CDROM] Description: INVALID FIELD IN CDB\n");
         else if (asc == 0x26 && ascq == 0)
            printf("[CDROM] Description: INVALID FIELD IN PARAMETER LIST\n");
         break;
      }
      case 6:
      {
         if (asc == 0x28 && ascq == 0)
            printf("[CDROM] Description: NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED\n");
         break;
      }
      default:
         break;
   }

   fflush(stdout);
}
#endif

#if defined(_WIN32) && !defined(_XBOX)
static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
{
   DWORD ioctl_bytes;
   BOOL ioctl_rv;
#ifdef CDROM_DEBUG
   clock_t t                       = clock();
   const char *extra               = " ";
   static unsigned char last_min   = 0;
   static unsigned char last_sec   = 0;
   static unsigned char last_frame = 0;

   unsigned lba_cur = cdrom_msf_to_lba(last_min, last_sec, last_frame);
   unsigned lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);
#endif
   struct sptd_with_sense
   {
     SCSI_PASS_THROUGH_DIRECT s;
     UCHAR sense[128];
   } sptd;

   memset(&sptd, 0, sizeof(sptd));

   sptd.s.Length    = sizeof(sptd.s);
   sptd.s.CdbLength = cmd_len;

   switch (dir)
   {
      case DIRECTION_IN:
         sptd.s.DataIn = SCSI_IOCTL_DATA_IN;
         break;
      case DIRECTION_OUT:
         sptd.s.DataIn = SCSI_IOCTL_DATA_OUT;
         break;
      case DIRECTION_NONE:
      default:
         sptd.s.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
         break;
   }

   sptd.s.TimeOutValue       = 5;
   sptd.s.DataBuffer         = buf;
   sptd.s.DataTransferLength = len;
   sptd.s.SenseInfoLength    = sizeof(sptd.sense);
   sptd.s.SenseInfoOffset    = offsetof(struct sptd_with_sense, sense);

   memcpy(sptd.s.Cdb, cmd, cmd_len);

   ioctl_rv = DeviceIoControl(stream->fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd,
      sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL);

#ifdef CDROM_DEBUG
   if (lba_req < lba_cur)
      extra = " BACKWARDS SECTOR READ";
   else if (lba_req > lba_cur)
      extra = " SKIPPED SECTOR READ";

   if (cmd[0] == 0xB9)
   {
      double time_taken = (double)(((clock() - t) * 1000) / CLOCKS_PER_SEC);
      printf("time taken %f ms for DT received length %ld of %" PRId64 " for %02d:%02d:%02d to %02d:%02d:%02d%s req %d cur %d cur_lba %d\n", time_taken, sptd.s.DataTransferLength, len, cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], extra, lba_req, lba_cur, stream->cdrom.cur_lba);
      fflush(stdout);
   }

   last_min   = cmd[3];
   last_sec   = cmd[4];
   last_frame = cmd[5];
   increment_msf(&last_min, &last_sec, &last_frame);
#endif

   if (!ioctl_rv || sptd.s.ScsiStatus != 0)
      return 1;

   return 0;
}
#endif

#if defined(__linux__) && !defined(ANDROID)
static int cdrom_send_command_linux(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
{
   int rv;
   sg_io_hdr_t sgio = {0};

   switch (dir)
   {
      case DIRECTION_IN:
         sgio.dxfer_direction = SG_DXFER_FROM_DEV;
         break;
      case DIRECTION_OUT:
         sgio.dxfer_direction = SG_DXFER_TO_DEV;
         break;
      case DIRECTION_NONE:
      default:
         sgio.dxfer_direction = SG_DXFER_NONE;
         break;
   }

   sgio.interface_id = 'S';
   sgio.cmd_len      = cmd_len;
   sgio.cmdp         = cmd;
   sgio.dxferp       = buf;
   sgio.dxfer_len    = len;
   sgio.sbp          = sense;
   sgio.mx_sb_len    = sense_len;
   sgio.timeout      = 5000;

   rv = ioctl(fileno(stream->fp), SG_IO, &sgio);

   if (rv == -1 || sgio.info & SG_INFO_CHECK)
      return 1;

   return 0;
}
#endif

static int cdrom_send_command(libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir,
      void *s, size_t len, unsigned char *cmd, size_t cmd_len, size_t skip)
{
   int i, rv = 0;
   int frames = 1;
   unsigned char *xfer_buf     = NULL;
   unsigned char *xfer_buf_pos = xfer_buf;
   unsigned char sense[CDROM_MAX_SENSE_BYTES] = {0};
   unsigned char retries_left  = CDROM_MAX_RETRIES;
   size_t padded_req_bytes;
   size_t copied_bytes         = 0;
   bool read_cd                = false;

   if (!cmd || cmd_len == 0 || cmd_len < CDROM_MIN_BUFSIZE)
      return 1;

   if (cmd[0] == 0xBE || cmd[0] == 0xB9)
   {
      frames = ceil((len + skip) / 2352.0);
      padded_req_bytes = 2352 * frames;
      read_cd = true;
      /* these will be incremented below */
      cmd[6] = cmd[3];
      cmd[7] = cmd[4];
      cmd[8] = cmd[5];
   }
   else
   {
      padded_req_bytes = len + skip;
   }

   xfer_buf     = (unsigned char*)memalign_alloc(4096, padded_req_bytes);
   xfer_buf_pos = xfer_buf;

   if (!xfer_buf)
      return 1;

   memset(xfer_buf, 0, padded_req_bytes);
#ifdef CDROM_DEBUG
   printf("Number of frames to read: %d\n", frames);
   fflush(stdout);
#endif
   for (i = 0; i < frames; i++)
   {
      size_t request_len = padded_req_bytes;
      size_t copy_len = request_len;
      bool cached_read = false;

      if (read_cd)
      {
         unsigned lba_req = 0;

         request_len = 2352;
         copy_len = request_len;

         increment_msf(&cmd[6], &cmd[7], &cmd[8]);

         if (i > 0)
         {
            skip = 0;
            increment_msf(&cmd[3], &cmd[4], &cmd[5]);
         }
         else
         {
            if (skip)
               copy_len -= skip;
         }

         if (i == frames - 1)
         {
            copy_len = len - copied_bytes;
         }

         lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);

         if (stream->cdrom.last_frame_valid && lba_req == stream->cdrom.last_frame_lba)
         {
            /* use cached frame */
            cached_read = true;
#ifdef CDROM_DEBUG
            printf("[CDROM] Using cached frame\n");
            fflush(stdout);
#endif
            /* assumes request_len is always equal to the size of last_frame */
            memcpy(xfer_buf_pos, stream->cdrom.last_frame, sizeof(stream->cdrom.last_frame));
         }

      }

#ifdef CDROM_DEBUG
      if (!cached_read)
      {
         unsigned j;

         printf("[CDROM] Send Command: ");

         for (j = 0; j < cmd_len / sizeof(*cmd); j++)
         {
            printf("%02X ", cmd[j]);
         }

         if (len)
            printf("(buffer of size %" PRId64 " with skip bytes %" PRId64 " padded to %" PRId64 "), frame %d\n", len, skip, padded_req_bytes, i);
         else
            printf("\n");

         fflush(stdout);
      }
#endif

retry:
#if defined(__linux__) && !defined(ANDROID)
      if (cached_read || !cdrom_send_command_linux(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))
#else
#if defined(_WIN32) && !defined(_XBOX)
      if (cached_read || !cdrom_send_command_win32(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))
#endif
#endif
      {
         rv = 0;

         if (s)
         {
#if 0
            printf("offsetting %" PRId64 " from buf, copying at xfer_buf offset %" PRId64 ", copying %" PRId64 " bytes\n", copied_bytes, (xfer_buf_pos + skip) - xfer_buf, copy_len);
            fflush(stdout);
#endif
            memcpy((char*)s + copied_bytes, xfer_buf_pos + skip, copy_len);
            copied_bytes += copy_len;

            if (read_cd && !cached_read && request_len >= 2352)
            {
               unsigned frame_end = cdrom_msf_to_lba(cmd[6], cmd[7], cmd[8]);

               /* cache the last received frame */
               memcpy(stream->cdrom.last_frame, xfer_buf_pos, sizeof(stream->cdrom.last_frame));
               stream->cdrom.last_frame_valid = true;
               /* the ending frame is never actually read, so what we really just read is the one right before that */
               stream->cdrom.last_frame_lba = frame_end - 1;
            }
            else
               stream->cdrom.last_frame_valid = false;

#if 0
            printf("Frame %d, adding %" PRId64 " to buf_pos, is now %" PRId64 ". skip is %" PRId64 "\n", i, request_len, (xfer_buf_pos + request_len) - xfer_buf, skip);
            fflush(stdout);
#endif
            xfer_buf_pos += request_len;
         }
      }
      else
      {
#ifdef CDROM_DEBUG
         cdrom_print_sense_data(sense, sizeof(sense));
#endif

         /* INQUIRY/TEST/SENSE should never fail, don't retry. */
         /* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */
         if (cmd[0] != 0x0 && cmd[0] != 0x12 && cmd[0] != 0x5A && !(cmd[0] == 0x43 && cmd[2] == 0x4))
         {
            unsigned char key = sense[2] & 0xF;

            switch (key)
            {
               case 0:
               case 2:
               case 3:
               case 4:
               case 6:
                  if (retries_left)
                  {
   #ifdef CDROM_DEBUG
                     printf("[CDROM] Read Retry...\n");
                     fflush(stdout);
   #endif
                     retries_left--;
                      retro_sleep(1000);
                     goto retry;
                  }
                  else
                  {
                     rv = 1;
   #ifdef CDROM_DEBUG
                     printf("[CDROM] Read retries failed, giving up.\n");
                     fflush(stdout);
   #endif
                  }

                  break;
               default:
                  break;
            }
         }

         rv = 1;
      }
   }

   if (xfer_buf)
      memalign_free(xfer_buf);
   return rv;
}

static const char *cdrom_get_profile(unsigned short profile)
{
   switch (profile)
   {
      case 2:
         return "Removable disk";
      case 8:
         return "CD-ROM";
      case 9:
         return "CD-R";
      case 0xA:
         return "CD-RW";
      case 0x10:
         return "DVD-ROM";
      case 0x11:
         return "DVD-R Sequential Recording";
      case 0x12:
         return "DVD-RAM";
      case 0x13:
         return "DVD-RW Restricted Overwrite";
      case 0x14:
         return "DVD-RW Sequential recording";
      case 0x15:
         return "DVD-R Dual Layer Sequential Recording";
      case 0x16:
         return "DVD-R Dual Layer Jump Recording";
      case 0x17:
         return "DVD-RW Dual Layer";
      case 0x1A:
         return "DVD+RW";
      case 0x1B:
         return "DVD+R";
      case 0x2A:
         return "DVD+RW Dual Layer";
      case 0x2B:
         return "DVD+R Dual Layer";
      case 0x40:
         return "BD-ROM";
      case 0x41:
         return "BD-R SRM";
      case 0x42:
         return "BD-R RRM";
      case 0x43:
         return "BD-RE";
      case 0x50:
         return "HD DVD-ROM";
      case 0x51:
         return "HD DVD-R";
      case 0x52:
         return "HD DVD-RAM";
      case 0x53:
         return "HD DVD-RW";
      case 0x58:
         return "HD DVD-R Dual Layer";
      case 0x5A:
         return "HD DVD-RW Dual Layer";
      default:
         break;
   }

   return "Unknown";
}

/* TODO/FIXME - sense never used here? */
int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len)
{
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x3, 0, 0, 0, 0xFC, 0};
   unsigned char buf[0xFC] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] get sense data status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

#ifdef CDROM_DEBUG
   cdrom_print_sense_data(buf, sizeof(buf));
#endif

   return 0;
}

void cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x10, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[0x14] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config random readable status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i < 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] Random Readable Feature Descriptor: ");

   for (i = 0; i < 12; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   printf("[CDROM] Supported commands: READ CAPACITY, READ (10)\n");
}

void cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x1D, 0, 0, 0, 0, 0xC, 0};
   unsigned char buf[0xC] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config multi-read status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i < 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] Multi-Read Feature Descriptor: ");

   for (i = 0; i < 4; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   printf("[CDROM] Supported commands: READ (10), READ CD, READ DISC INFORMATION, READ TRACK INFORMATION\n");
}

void cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x1E, 0, 0, 0, 0, 0x10, 0};
   unsigned char buf[0x10] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config cd read status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i < 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] CD Read Feature Descriptor: ");

   for (i = 0; i < 8; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   if (buf[8 + 2] & 1)
      printf("(current)\n");

   printf("[CDROM] Supported commands: READ CD, READ CD MSF, READ TOC/PMA/ATIP\n");
}

void cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x0, 0, 0, 0, 0xFF, 0xFA, 0};
   unsigned char buf[0xFFFA] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config profiles status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i < 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] Profile List Descriptor: ");

   for (i = 0; i < 4; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   printf("[CDROM] Number of profiles: %u\n", buf[8 + 3] / 4);

   for (i = 0; i < buf[8 + 3] / 4; i++)
   {
      unsigned short profile = (buf[8 + (4 * (i + 1))] << 8) | buf[8 + (4 * (i + 1)) + 1];

      printf("[CDROM] Profile Number: %04X (%s) ", profile, cdrom_get_profile(profile));

      if (buf[8 + (4 * (i + 1)) + 2] & 1)
         printf("(current)\n");
      else
         printf("\n");
   }
}

void cdrom_get_current_config_core(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x1, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[20] = {0};
   unsigned intf_std = 0;
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;
   const char *intf_std_name = "Unknown";

   printf("[CDROM] get current config core status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i < 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   if (buf[6] == 0 && buf[7] == 8)
      printf("[CDROM] Current Profile: CD-ROM\n");
   else
      printf("[CDROM] Current Profile: %02X%02X\n", buf[6], buf[7]);

   printf("[CDROM] Core Feature Descriptor: ");

   for (i = 0; i < 12; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   intf_std = buf[8 + 4] << 24 | buf[8 + 5] << 16 | buf[8 + 6] << 8 | buf[8 + 7];

   switch (intf_std)
   {
      case 0:
         intf_std_name = "Unspecified";
         break;
      case 1:
         intf_std_name = "SCSI Family";
         break;
      case 2:
         intf_std_name = "ATAPI";
         break;
      case 7:
         intf_std_name = "Serial ATAPI";
         break;
      case 8:
         intf_std_name = "USB";
         break;
      default:
         break;
   }

   printf("[CDROM] Physical Interface Standard: %u (%s)\n", intf_std, intf_std_name);
}

int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *s, size_t len)
{
   /* MMC Command: READ TOC/PMA/ATIP */
   unsigned char cdb[] = {0x43, 0x2, 0x2, 0, 0, 0, 0x1, 0x9, 0x30, 0};
#ifdef CDROM_DEBUG
   unsigned short data_len = 0;
   unsigned char first_session = 0;
   unsigned char last_session = 0;
   int i;
#endif
   int rv;

   if (!s)
      return 1;

   rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), 0);

   if (rv)
     return 1;

#ifdef CDROM_DEBUG
   data_len      = s[0] << 8 | s[1];
   first_session = s[2];
   last_session  = s[3];

   printf("[CDROM] Data Length: %d\n", data_len);
   printf("[CDROM] First Session: %d\n", first_session);
   printf("[CDROM] Last Session: %d\n", last_session);

   for (i = 0; i < (data_len - 2) / 11; i++)
   {
      unsigned char session_num = s[4 + (i * 11) + 0];
      unsigned char adr         = (s[4 + (i * 11) + 1] >> 4) & 0xF;
#if 0
      unsigned char control     = s[4 + (i * 11) + 1] & 0xF;
#endif
      unsigned char tno         = s[4 + (i * 11) + 2];
      unsigned char point       = s[4 + (i * 11) + 3];
      unsigned char pmin        = s[4 + (i * 11) + 8];
      unsigned char psec        = s[4 + (i * 11) + 9];
      unsigned char pframe      = s[4 + (i * 11) + 10];

      /*printf("i %d control %d adr %d tno %d point %d: ", i, control, adr, tno, point);*/
      /* why is control always 0? */

      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("Track start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
      }
      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA0)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("First Track Number: %d ", pmin);
         printf("Disc Type: %d ", psec);
      }
      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("Last Track Number: %d ", pmin);
      }
      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA2)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("Lead-out start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
      }

      printf("\n");
   }

   fflush(stdout);
#endif
   return 0;
}

static int cdrom_read_track_info(libretro_vfs_implementation_file *stream, unsigned char track, cdrom_toc_t *toc)
{
   /* MMC Command: READ TRACK INFORMATION */
   unsigned char cdb[] = {0x52, 0x1, 0, 0, 0, 0, 0, 0x1, 0x80, 0};
   unsigned char buf[384] = {0};
   unsigned lba = 0;
   unsigned track_size = 0;
   int rv;
   ssize_t pregap_lba_len;

   cdb[5] = track;

   if ((rv = cdrom_send_command(stream, DIRECTION_IN, buf,
         sizeof(buf), cdb, sizeof(cdb), 0)))
     return 1;

   memcpy(&lba, buf + 8, 4);
   memcpy(&track_size, buf + 24, 4);

   lba = swap_if_little32(lba);
   track_size = swap_if_little32(track_size);

   /* lba_start may be earlier than the MSF start times seen in read_subq */
   toc->track[track - 1].lba_start = lba;
   toc->track[track - 1].track_size = track_size;

   pregap_lba_len = (toc->track[track - 1].audio ? 0 : (toc->track[track - 1].lba - toc->track[track - 1].lba_start));

   toc->track[track - 1].track_bytes = (track_size - pregap_lba_len) * 2352;
   toc->track[track - 1].mode = buf[6] & 0xF;

#ifdef CDROM_DEBUG
   printf("[CDROM] Track %d Info: ", track);
   printf("Copy: %d ", (buf[5] & 0x10) > 0);
   printf("Data Mode: %d ", toc->track[track - 1].mode);
   printf("LBA Start: %d (%d) ", lba, toc->track[track - 1].lba);
   printf("Track Size: %d\n", track_size);
   fflush(stdout);
#endif

   return 0;
}

int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed)
{
   /* MMC Command: SET CD SPEED */
   unsigned char cmd[] = {0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

   cmd[2] = (speed >> 24) & 0xFF;
   cmd[3] = (speed >> 16) & 0xFF;
   cmd[4] = (speed >> 8) & 0xFF;
   cmd[5] = speed & 0xFF;

   return cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cmd, sizeof(cmd), 0);
}

int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc)
{
   int i;
   unsigned char buf[2352] = {0};
   unsigned short data_len = 0;
   size_t _len = 0, pos = 0;
   int rv = 0;

   if (!out_buf || !out_len || !num_tracks || !toc)
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] Invalid buffer/length pointer for CDROM cue sheet\n");
      fflush(stdout);
#endif
      return 1;
   }

   cdrom_set_read_speed(stream, 0xFFFFFFFF);

   rv = cdrom_read_subq(stream, buf, sizeof(buf));

   if (rv)
      return rv;

   data_len = buf[0] << 8 | buf[1];

   for (i = 0; i < (data_len - 2) / 11; i++)
   {
      unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
      unsigned char tno = buf[4 + (i * 11) + 2];
      unsigned char point = buf[4 + (i * 11) + 3];
      unsigned char pmin = buf[4 + (i * 11) + 8];

      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)
      {
         *num_tracks = pmin;
#ifdef CDROM_DEBUG
         printf("[CDROM] Number of CDROM tracks: %d\n", *num_tracks);
         fflush(stdout);
#endif
         break;
      }
   }

   if (!*num_tracks || *num_tracks > 99)
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] Invalid number of CDROM tracks: %d\n", *num_tracks);
      fflush(stdout);
#endif
      return 1;
   }

   _len            = CDROM_CUE_TRACK_BYTES * (*num_tracks);
   toc->num_tracks = *num_tracks;
   *out_buf        = (char*)calloc(1, _len);
   *out_len        = _len;

   for (i = 0; i < (data_len - 2) / 11; i++)
   {
      /*unsigned char session_num = buf[4 + (i * 11) + 0];*/
      unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
      unsigned char control = buf[4 + (i * 11) + 1] & 0xF;
      unsigned char tno = buf[4 + (i * 11) + 2];
      unsigned char point = buf[4 + (i * 11) + 3];
      /*unsigned char amin = buf[4 + (i * 11) + 4];
      unsigned char asec = buf[4 + (i * 11) + 5];
      unsigned char aframe = buf[4 + (i * 11) + 6];*/
      unsigned char pmin = buf[4 + (i * 11) + 8];
      unsigned char psec = buf[4 + (i * 11) + 9];
      unsigned char pframe = buf[4 + (i * 11) + 10];
      unsigned lba = cdrom_msf_to_lba(pmin, psec, pframe);

      /*printf("i %d control %d adr %d tno %d point %d: amin %d asec %d aframe %d pmin %d psec %d pframe %d\n", i, control, adr, tno, point, amin, asec, aframe, pmin, psec, pframe);*/
      /* why is control always 0? */

      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)
      {
         bool audio = false;
         const char *track_type = "MODE1/2352";

         audio = (!(control & 0x4) && !(control & 0x5));

#ifdef CDROM_DEBUG
         printf("[CDROM] Track %02d CONTROL %01X ADR %01X AUDIO? %d\n", point, control, adr, audio);
         fflush(stdout);
#endif

         toc->track[point - 1].track_num = point;
         toc->track[point - 1].min = pmin;
         toc->track[point - 1].sec = psec;
         toc->track[point - 1].frame = pframe;
         toc->track[point - 1].lba = lba;
         toc->track[point - 1].audio = audio;

         cdrom_read_track_info(stream, point, toc);

         if (audio)
            track_type = "AUDIO";
         else if (toc->track[point - 1].mode == 1)
            track_type = "MODE1/2352";
         else if (toc->track[point - 1].mode == 2)
            track_type = "MODE2/2352";

#if defined(_WIN32) && !defined(_XBOX)
         pos += snprintf(*out_buf + pos, _len - pos, "FILE \"cdrom://%c:/drive-track%02d.bin\" BINARY\n", cdrom_drive, point);
#else
         pos += snprintf(*out_buf + pos, _len - pos, "FILE \"cdrom://drive%c-track%02d.bin\" BINARY\n", cdrom_drive, point);
#endif
         pos += snprintf(*out_buf + pos, _len - pos, "  TRACK %02d %s\n", point, track_type);

         {
            unsigned pregap_lba_len = toc->track[point - 1].lba - toc->track[point - 1].lba_start;

            if (toc->track[point - 1].audio && pregap_lba_len > 0)
            {
               unsigned char min = 0;
               unsigned char sec = 0;
               unsigned char frame = 0;

               cdrom_lba_to_msf(pregap_lba_len, &min, &sec, &frame);

               pos += snprintf(*out_buf + pos, _len - pos, "    INDEX 00 00:00:00\n");
               pos += snprintf(*out_buf + pos, _len - pos, "    INDEX 01 %02u:%02u:%02u\n", (unsigned)min, (unsigned)sec, (unsigned)frame);
            }
            else
               pos += snprintf(*out_buf + pos, _len - pos, "    INDEX 01 00:00:00\n");
         }
      }
   }

   return 0;
}

/* needs 32 bytes for full vendor, product and version */
int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *s, size_t len, bool *is_cdrom)
{
   /* MMC Command: INQUIRY */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x12, 0, 0, 0, 0xff, 0};
   unsigned char buf[256] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   bool cdrom = false;

   if (rv)
      return 1;

   if (s && len >= 32)
   {
      memset(s, 0, len);
      /* vendor */
      memcpy(s, buf + 8, 8);
      s[8] = ' ';
      /* product */
      memcpy(s + 9, buf + 16, 16);
      s[25] = ' ';
      /* version */
      memcpy(s + 26, buf + 32, 4);
   }

   cdrom = (buf[0] == 5);

   if (is_cdrom && cdrom)
      *is_cdrom = true;

#ifdef CDROM_DEBUG
   printf("[CDROM] Device Model: %s (is CD-ROM? %s)\n", s, (cdrom ? "yes" : "no"));
#endif
   return 0;
}

int cdrom_read(libretro_vfs_implementation_file *stream,
      cdrom_group_timeouts_t *timeouts, unsigned char min,
      unsigned char sec, unsigned char frame, void *s,
      size_t len, size_t skip)
{
   /* MMC Command: READ CD MSF */
   unsigned char cdb[] = {0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0xF8, 0, 0};
   int rv;
   double frames = ceil((len + skip) / 2352.0);
   unsigned frame_end = cdrom_msf_to_lba(min, sec, frame) + frames;

   cdb[3] = min;
   cdb[4] = sec;
   cdb[5] = frame;

   if (frames <= 1)
   {
      cdrom_lba_to_msf(frame_end, &cdb[6], &cdb[7], &cdb[8]);
#ifdef CDROM_DEBUG
      printf("[CDROM] single-frame read: %d %d %d skip %" PRId64 "\n", cdb[3], cdb[4], cdb[5], skip);
      fflush(stdout);
#endif
   }
   else
   {
      cdrom_lba_to_msf(frame_end, &cdb[6], &cdb[7], &cdb[8]);

#ifdef CDROM_DEBUG
      printf("[CDROM] multi-frame read: %d sectors starting from %02d:%02d:%02d skip %" PRId64 "\n", (int)frames, cdb[3], cdb[4], cdb[5], skip);
      fflush(stdout);
#endif
   }

   /* regardless of the length specified here, a new buffer will be allocated and padded to a sector multiple inside cdrom_send_command */
   rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), skip);

#ifdef CDROM_DEBUG
   printf("[CDROM] read msf status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
   {
      stream->cdrom.last_frame_valid = false;
      return 1;
   }

   return 0;
}

int cdrom_stop(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: START STOP UNIT */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x0, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] stop status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

int cdrom_unlock(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: PREVENT ALLOW MEDIUM REMOVAL */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1E, 0, 0, 0, 0x2, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] persistent prevent clear status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   cdb[4] = 0x0;

   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] prevent clear status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

int cdrom_open_tray(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: START STOP UNIT */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x2, 0};
   int rv;

   cdrom_unlock(stream);
   cdrom_stop(stream);

   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] open tray status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

int cdrom_close_tray(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: START STOP UNIT */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x3, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] close tray status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

struct string_list* cdrom_get_available_drives(void)
{
   struct string_list *list = string_list_new();
#if defined(__linux__) && !defined(ANDROID)
   struct string_list *dir_list = dir_list_new("/dev", NULL, false, false, false, false);
   int i;
   bool found = false;

   if (!dir_list)
      return list;

   for (i = 0; i < (int)dir_list->size; i++)
   {
      if (string_starts_with_size(dir_list->elems[i].data, "/dev/sg",
               STRLEN_CONST("/dev/sg")))
      {
         char drive_string[33];
         libretro_vfs_implementation_file *stream;
         char drive_model[32]             = {0};
         union string_list_elem_attr attr = {0};
         int dev_index                    = 0;
         RFILE *file                      = filestream_open(
               dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
         bool is_cdrom                    = false;

         found = true;

         if (!file)
         {
#ifdef CDROM_DEBUG
            printf("[CDROM] Could not open %s, please check permissions.\n", dir_list->elems[i].data);
            fflush(stdout);
#endif
            continue;
         }

         stream = filestream_get_vfs_handle(file);
         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom);
         filestream_close(file);

         if (!is_cdrom)
            continue;

         sscanf(dir_list->elems[i].data + STRLEN_CONST("/dev/sg"),
               "%d", &dev_index);

         dev_index = '0' + dev_index;
         attr.i    = dev_index;

         if (!string_is_empty(drive_model))
            strlcpy(drive_string, drive_model, sizeof(drive_string));
         else
            strlcpy(drive_string, "Unknown Drive", sizeof(drive_string));

         string_list_append(list, drive_string, attr);
      }
   }

   if (!found)
   {
      char *buf   = NULL;
      int64_t len = 0;

      if (filestream_read_file("/proc/modules", (void**)&buf, &len))
      {
#ifdef CDROM_DEBUG
         bool found              = false;
#endif
         struct string_list mods = {0};

         string_list_initialize(&mods);

         if (string_split_noalloc(&mods, buf, "\n"))
         {
            for (i = 0; i < (int)mods.size; i++)
            {
               if (strcasestr(mods.elems[i].data, "sg "))
               {
#ifdef CDROM_DEBUG
                  found = true;
#endif
                  break;
               }
            }
         }
         string_list_deinitialize(&mods);
         free(buf);

#ifdef CDROM_DEBUG
         if (found)
         {
            printf("[CDROM] No sg devices found but kernel module is loaded.\n");
            fflush(stdout);
         }
         else
         {
            printf("[CDROM] No sg devices found and sg kernel module is not loaded.\n");
            fflush(stdout);
         }
#endif
      }
#ifdef CDROM_DEBUG
      else
      {
         printf("[CDROM] No sg devices found, could not check if sg kernel module is loaded.\n");
         fflush(stdout);
      }
#endif
   }

   string_list_free(dir_list);
#endif
#if defined(_WIN32) && !defined(_XBOX)
   DWORD drive_mask = GetLogicalDrives();
   int i;

   for (i = 0; i < (int)(sizeof(DWORD) * 8); i++)
   {
      char path[]       = {"a:\\"};
      char cdrom_path[] = {"cdrom://a:/drive-track01.bin"};

      path[0]          += i;
      cdrom_path[8]    += i;

      /* this drive letter doesn't exist */
      if (!(drive_mask & (1 << i)))
         continue;

      if (GetDriveType(path) != DRIVE_CDROM)
         continue;

      {
         char drive_string[33];
         libretro_vfs_implementation_file *stream;
         bool is_cdrom                    = false;
         char drive_model[32]             = {0};
         union string_list_elem_attr attr = {0};
         RFILE *file = filestream_open(cdrom_path, RETRO_VFS_FILE_ACCESS_READ, 0);
         if (!file)
            continue;

         stream = filestream_get_vfs_handle(file);
         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom);
         filestream_close(file);

         if (!is_cdrom)
            continue;

         attr.i = path[0];

         if (!string_is_empty(drive_model))
            strlcpy(drive_string, drive_model, sizeof(drive_string));
         else
            strlcpy(drive_string, "Unknown Drive", sizeof(drive_string));

         string_list_append(list, drive_string, attr);
      }
   }
#endif
   return list;
}

bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: TEST UNIT READY */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x00, 0, 0, 0, 0, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] media inserted status code %d\n", rv);
   fflush(stdout);
#endif

   /* Will also return false if the drive is simply not ready yet (tray open, disc spinning back up after tray closed etc).
    * Command will not block or wait for media to become ready. */
   if (rv)
      return false;

   return true;
}

bool cdrom_drive_has_media(const char drive)
{
   RFILE *file;
   char cdrom_path_bin[256] = {0};

   cdrom_device_fillpath(cdrom_path_bin, sizeof(cdrom_path_bin), drive, 1, false);

   file = filestream_open(cdrom_path_bin, RETRO_VFS_FILE_ACCESS_READ, 0);

   if (file)
   {
      libretro_vfs_implementation_file *stream = filestream_get_vfs_handle(file);
      bool has_media = cdrom_is_media_inserted(stream);

      filestream_close(file);

      return has_media;
   }

   return false;
}

bool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled)
{
   int i;
   /* MMC Command: MODE SENSE (10) and MODE SELECT (10) */
   unsigned char cdb_sense_changeable[] = {0x5A, 0, 0x48, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char cdb_sense[]            = {0x5A, 0, 0x8, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char cdb_select[]           = {0x55, 0x10, 0, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[20]                = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf),
         cdb_sense_changeable, sizeof(cdb_sense_changeable), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] mode sense changeable status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

   if (!(buf[10] & 0x1))
   {
      /* RCD (read cache disable) bit is not changeable */
#ifdef CDROM_DEBUG
      printf("[CDROM] RCD (read cache disable) bit is not changeable.\n");
      fflush(stdout);
#endif
      return false;
   }

   memset(buf, 0, sizeof(buf));

   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb_sense, sizeof(cdb_sense), 0);

#ifdef CDROM_DEBUG
   printf("mode sense status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

#ifdef CDROM_DEBUG
   printf("Mode sense data for caching mode page: ");

   for (i = 0; i < (int)sizeof(buf); i++)
      printf("%02X ", buf[i]);

   printf("\n");
   fflush(stdout);
#endif

   /* "When transferred during execution of the MODE SELECT (10) command, Mode Data Length is reserved." */
   for (i = 0; i < 8; i++)
      buf[i] = 0;

   if (enabled)
      buf[10] &= ~1;
   else
      buf[10] |=  1;

   rv = cdrom_send_command(stream, DIRECTION_OUT, buf, sizeof(buf), cdb_select, sizeof(cdb_select), 0);

#ifdef CDROM_DEBUG
   printf("mode select status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

   return true;
}

bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts)
{
   /* MMC Command: MODE SENSE (10) */
   int rv;
   unsigned char cdb[]   = {0x5A, 0, 0x1D, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[20] = {0};
   unsigned short g1     = 0;
   unsigned short g2     = 0;
   unsigned short g3     = 0;

   if (!timeouts)
      return false;

   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("get timeouts status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

   g1 = buf[14] << 8 | buf[15];
   g2 = buf[16] << 8 | buf[17];
   g3 = buf[18] << 8 | buf[19];

#ifdef CDROM_DEBUG
   {
      int i;

      printf("Mode sense data for timeout groups: ");

      for (i = 0; i < (int)sizeof(buf); i++)
         printf("%02X ", buf[i]);

      printf("\n");

      printf("Group 1 Timeout: %d\n", g1);
      printf("Group 2 Timeout: %d\n", g2);
      printf("Group 3 Timeout: %d\n", g3);

      fflush(stdout);
   }
#endif

   timeouts->g1_timeout = g1;
   timeouts->g2_timeout = g2;
   timeouts->g3_timeout = g3;

   return true;
}

bool cdrom_has_atip(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: READ TOC/PMA/ATIP */
   unsigned char cdb[]     = {0x43, 0x2, 0x4, 0, 0, 0, 0, 0x9, 0x30, 0};
   unsigned char buf[32]   = {0};
   unsigned short atip_len = 0;
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);

   if (rv)
     return false;

   atip_len = buf[0] << 8 | buf[1];

#ifdef CDROM_DEBUG
   printf("ATIP Length %d, Disc Type %d, Disc Sub-Type %d\n",
         atip_len,
         (buf[6]  >> 6) & 0x1,
         ((buf[6] >> 5) & 0x1) << 2 | ((buf[6] >> 4) & 0x1) << 1 | ((buf[6] >> 3) & 0x1) << 0);
#endif

   if (atip_len < 5)
      return false;

   return true;
}

size_t cdrom_device_fillpath(char *s, size_t len, char drive, unsigned char track, bool is_cue)
{
   if (s && len > 0)
   {
      if (is_cue)
      {
#ifdef _WIN32
         size_t _len = strlcpy(s, "cdrom://", len);
         if (len > _len)
            s[_len++] = drive;
         _len += strlcpy(s + _len, ":/drive.cue", len - _len);
         return _len;
#else
#ifdef __linux__
         size_t _len = strlcpy(s, "cdrom://drive", len);
         if (len > _len + 1)
         {
            s[_len++] = drive;
            s[_len]   = '\0';
         }
         _len += strlcpy(s + _len, ".cue", len - _len);
         return _len;
#endif
#endif
      }
      else
      {
#ifdef _WIN32
         size_t _len = strlcpy(s, "cdrom://", len);
         if (len > _len + 1)
         {
            s[_len++] = drive;
            s[_len]   = '\0';
         }
         _len += snprintf(s + _len, len - _len, ":/drive-track%02d.bin", track);
         return _len;
#else
#ifdef __linux__
         size_t _len = strlcpy(s, "cdrom://drive", len);
         if (len > _len)
            s[_len++] = drive;
         _len += snprintf(s + _len, len - _len, "-track%02d.bin", track);
         return _len;
#endif
#endif
      }
   }
   return 0;
}

./include/libretro-common/compat/compat_fnmatch.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_fnmatch.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stddef.h>

#include <compat/fnmatch.h>

/* Implementation of fnmatch(3) so it can be
 * distributed to non *nix platforms.
 *
 * No flags are implemented ATM.
 * We don't use them. Add flags as needed. */

int rl_fnmatch(const char *pattern, const char *string, int flags)
{
   int rv;
   const char *c = NULL;
   int charmatch = 0;

   for (c = pattern; *c != '\0'; c++)
   {
      /* String ended before pattern */
      if ((*c != '*') && (*string == '\0'))
         return FNM_NOMATCH;

      switch (*c)
      {
         /* Match any number of unknown chars */
         case '*':
            /* Find next node in the pattern
             * ignoring multiple asterixes
             */
            do {
               c++;
               if (*c == '\0')
                  return 0;
            } while (*c == '*');

            /* Match the remaining pattern
             * ignoring more and more characters. */
            do {
               /* We reached the end of the string without a
                * match. There is a way to optimize this by
                * calculating the minimum chars needed to
                * match the remaining pattern but I don't
                * think it is worth the work ATM.
                */
               if (*string == '\0')
                  return FNM_NOMATCH;

               rv = rl_fnmatch(c, string, flags);
               string++;
            } while (rv != 0);

            return 0;
            /* Match char from list */
         case '[':
            charmatch = 0;
            for (c++; *c != ']'; c++)
            {
               /* Bad format */
               if (*c == '\0')
                  return FNM_NOMATCH;

               /* Match already found */
               if (charmatch)
                  continue;

               if (*c == *string)
                  charmatch = 1;
            }

            /* No match in list */
            if (!charmatch)
               return FNM_NOMATCH;

            string++;
            break;
            /* Has any character */
         case '?':
            string++;
            break;
            /* Match following character verbatim */
         case '\\':
            c++;
            /* Dangling escape at end of pattern.
             * FIXME: Was c == '\0' (makes no sense).
             * Not sure if c == NULL or *c == '\0'
             * is intended. Assuming *c due to c++ right before. */
            if (*c == '\0')
               return FNM_NOMATCH;
         default:
            if (*c != *string)
               return FNM_NOMATCH;
            string++;
      }
   }

   /* End of string and end of pattend */
   if (*string == '\0')
      return 0;
   return FNM_NOMATCH;
}

./include/libretro-common/compat/compat_getopt.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_getopt.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <ctype.h>

#include <string.h>
#include <boolean.h>
#include <stddef.h>
#include <stdlib.h>

#include <retro_miscellaneous.h>

#include <compat/getopt.h>
#include <compat/strl.h>
#include <compat/strcasestr.h>
#include <compat/posix_string.h>

char *optarg;
int optind, opterr, optopt;

static bool is_short_option(const char *str)
{
   return str[0] == '-' && str[1] != '-';
}

static bool is_long_option(const char *str)
{
   return str[0] == '-' && str[1] == '-';
}

static int find_short_index(char * const *argv)
{
   int idx;
   for (idx = 0; argv[idx]; idx++)
   {
      if (is_short_option(argv[idx]))
         return idx;
   }

   return -1;
}

static int find_long_index(char * const *argv)
{
   int idx;
   for (idx = 0; argv[idx]; idx++)
   {
      if (is_long_option(argv[idx]))
         return idx;
   }

   return -1;
}

static int parse_short(const char *optstring, char * const *argv)
{
   bool extra_opt, takes_arg, embedded_arg;
   const char *opt = NULL;
   char        arg = argv[0][1];

   if (arg == ':')
      return '?';

   opt = strchr(optstring, arg);
   if (!opt)
      return '?';

   extra_opt = argv[0][2];
   takes_arg = opt[1] == ':';

   /* If we take an argument, and we see additional characters,
    * this is in fact the argument (i.e. -cfoo is same as -c foo). */
   embedded_arg = extra_opt && takes_arg;

   if (takes_arg)
   {
      if (embedded_arg)
      {
         optarg = argv[0] + 2;
         optind++;
      }
      else
      {
         optarg = argv[1];
         optind += 2;
      }

      return optarg ? opt[0] : '?';
   }

   if (embedded_arg)
   {
      /* If we see additional characters,
       * and they don't take arguments, this
       * means we have multiple flags in one. */
      memmove(&argv[0][1], &argv[0][2], strlen(&argv[0][2]) + 1);
      return opt[0];
   }

   optind++;
   return opt[0];
}

static int parse_long(const struct option *longopts, char * const *argv)
{
   size_t i;
   char *save  = NULL;
   char *argv0 = strdup(&argv[0][2]);
   char *token = strtok_r(argv0, "=", &save);
   const struct option *opt = NULL;

   for (i = 0; longopts[i].name; i++)
   {
      if (token && !strcmp(longopts[i].name, token))
      {
         opt = &longopts[i];
         break;
      }
   }

   free(argv0);
   argv0 = NULL;

   if (!opt)
      return '?';

   /* Handle args with '=' instead of space */
   if (opt->has_arg)
   {
      char *special_arg = strchr(argv[0], '=');
      if (special_arg)
      {
         optarg = ++special_arg;
         optind++;
         return opt->val;
      }
   }

   /* getopt_long has an "optional" arg, but we don't bother with that. */
   if (opt->has_arg && !argv[1])
      return '?';

   if (opt->has_arg)
   {
      optarg = argv[1];
      optind += 2;
   }
   else
      optind++;

   if (opt->flag)
   {
      *opt->flag = opt->val;
      return 0;
   }

   return opt->val;
}

static void shuffle_block(char **begin, char **last, char **end)
{
   ptrdiff_t    len = last - begin;
   const char **tmp = (const char**)calloc(len, sizeof(const char*));

   memcpy((void*)tmp, begin, len * sizeof(const char*));
   memmove(begin, last, (end - last) * sizeof(const char*));
   memcpy(end - len, tmp, len * sizeof(const char*));

   free((void*)tmp);
}

int getopt_long(int argc, char *argv[],
      const char *optstring, const struct option *longopts, int *longindex)
{
   int short_index, long_index;

   if (optind == 0)
      optind = 1;

   if (argc < 2)
      return -1;

   short_index = find_short_index(&argv[optind]);
   long_index  = find_long_index(&argv[optind]);

   /* We're done here. */
   if (short_index == -1 && long_index == -1)
      return -1;

   /* Reorder argv so that non-options come last.
    * Non-POSIXy, but that's what getopt does by default. */
   if ((short_index > 0) && ((short_index < long_index) || (long_index == -1)))
   {
      shuffle_block(&argv[optind], &argv[optind + short_index], &argv[argc]);
      short_index = 0;
   }
   else if ((long_index > 0) && ((long_index < short_index)
            || (short_index == -1)))
   {
      shuffle_block(&argv[optind], &argv[optind + long_index], &argv[argc]);
      long_index = 0;
   }

   if (short_index == 0)
      return parse_short(optstring, &argv[optind]);
   if (long_index == 0)
      return parse_long(longopts, &argv[optind]);

   return '?';
}

./include/libretro-common/compat/compat_ifaddrs.c

/*
Copyright (c) 2013, Kenneth MacKay
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <compat/ifaddrs.h>

#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>

typedef struct NetlinkList
{
    struct NetlinkList *m_next;
    struct nlmsghdr *m_data;
    unsigned int m_size;
} NetlinkList;

static int netlink_socket(void)
{
   struct sockaddr_nl l_addr;
   int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

   if (l_socket < 0)
      return -1;

   memset(&l_addr, 0, sizeof(l_addr));
   l_addr.nl_family = AF_NETLINK;

   if (bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
   {
      close(l_socket);
      return -1;
   }

   return l_socket;
}

static int netlink_send(int p_socket, int p_request)
{
   struct
   {
      struct nlmsghdr m_hdr;
      struct rtgenmsg m_msg;
   } l_data;
   struct sockaddr_nl l_addr;

   memset(&l_data, 0, sizeof(l_data));

   l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
   l_data.m_hdr.nlmsg_type = p_request;
   l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
   l_data.m_hdr.nlmsg_pid = 0;
   l_data.m_hdr.nlmsg_seq = p_socket;
   l_data.m_msg.rtgen_family = AF_UNSPEC;

   memset(&l_addr, 0, sizeof(l_addr));
   l_addr.nl_family = AF_NETLINK;
   return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
}

static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
{
   struct msghdr l_msg;
   struct iovec l_iov = { p_buffer, p_len };
   struct sockaddr_nl l_addr;

   for (;;)
   {
      int l_result;

      l_msg.msg_name       = (void *)&l_addr;
      l_msg.msg_namelen    = sizeof(l_addr);
      l_msg.msg_iov        = &l_iov;
      l_msg.msg_iovlen     = 1;
      l_msg.msg_control    = NULL;
      l_msg.msg_controllen = 0;
      l_msg.msg_flags      = 0;

      l_result             = recvmsg(p_socket, &l_msg, 0);

      if (l_result < 0)
      {
         if (errno == EINTR)
            continue;
         return -2;
      }

      if (l_msg.msg_flags & MSG_TRUNC) /* buffer too small */
         return -1;
      return l_result;
   }
}

static struct nlmsghdr *getNetlinkResponse(int p_socket,
      int *p_size, int *p_done)
{
   size_t l_size  = 4096;
   void *l_buffer = NULL;

   for (;;)
   {
      int l_read;

      free(l_buffer);
      l_buffer = malloc(l_size);
      if (!l_buffer)
         return NULL;

      l_read  = netlink_recv(p_socket, l_buffer, l_size);
      *p_size = l_read;

      if (l_read == -2)
      {
         free(l_buffer);
         return NULL;
      }

      if (l_read >= 0)
      {
         pid_t l_pid = getpid();
         struct nlmsghdr *l_hdr;

         for (l_hdr = (struct nlmsghdr *)l_buffer;
               NLMSG_OK(l_hdr, (unsigned int)l_read);
               l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
         {
            if (  (pid_t)l_hdr->nlmsg_pid != l_pid || 
                  (int)l_hdr->nlmsg_seq   != p_socket)
               continue;

            if (l_hdr->nlmsg_type == NLMSG_DONE)
            {
               *p_done = 1;
               break;
            }

            if (l_hdr->nlmsg_type == NLMSG_ERROR)
            {
               free(l_buffer);
               return NULL;
            }
         }
         return l_buffer;
      }

      l_size *= 2;
   }
}

static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
{
   NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList));
   if (!l_item)
      return NULL;

   l_item->m_next = NULL;
   l_item->m_data = p_data;
   l_item->m_size = p_size;
   return l_item;
}

static void freeResultList(NetlinkList *p_list)
{
   NetlinkList *l_cur;

   while (p_list)
   {
      l_cur = p_list;
      p_list = p_list->m_next;
      free(l_cur->m_data);
      free(l_cur);
   }
}

static NetlinkList *getResultList(int p_socket, int p_request)
{
   int l_size;
   NetlinkList *l_list = NULL;
   NetlinkList *l_end  = NULL;
   int l_done          = 0;

   if (netlink_send(p_socket, p_request) < 0)
      return NULL;

   while (!l_done)
   {
      NetlinkList *l_item    = NULL;
      struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
      if (!l_hdr)
         goto error;

      l_item = newListItem(l_hdr, l_size);
      if (!l_item)
         goto error;

      if (!l_list)
         l_list        = l_item;
      else
         l_end->m_next = l_item;
      l_end            = l_item;
   }

   return l_list;

error:
   freeResultList(l_list);
   return NULL;
}

static size_t maxSize(size_t a, size_t b)
{
   return (a > b ? a : b);
}

static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
{
   switch(p_family)
   {
      case AF_INET:
         return sizeof(struct sockaddr_in);
      case AF_INET6:
         return sizeof(struct sockaddr_in6);
      case AF_PACKET:
         return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
      default:
         break;
   }

   return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
}

static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
{
   switch(p_family)
   {
      case AF_INET:
         memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
         break;
      case AF_INET6:
         memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
         break;
      case AF_PACKET:
         memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
         ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
         break;
      default:
         memcpy(p_dest->sa_data, p_data, p_size);
         break;
   }
   p_dest->sa_family = p_family;
}

static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
{
   if (!*p_resultList)
      *p_resultList = p_entry;
   else
   {
      struct ifaddrs *l_cur = *p_resultList;
      while (l_cur->ifa_next)
         l_cur = l_cur->ifa_next;
      l_cur->ifa_next = p_entry;
   }
}

static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
{
   struct ifaddrs *l_entry  = NULL;
   struct rtattr *l_rta     = NULL;
   struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
   size_t l_nameSize        = 0;
   size_t l_addrSize        = 0;
   size_t l_dataSize        = 0;
   size_t l_rtaSize         = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));

   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
      switch(l_rta->rta_type)
      {
         case IFLA_ADDRESS:
         case IFLA_BROADCAST:
            l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
            break;
         case IFLA_IFNAME:
            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
            break;
         case IFLA_STATS:
            l_dataSize += NLMSG_ALIGN(l_rtaSize);
            break;
         default:
            break;
      }
   }

   l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
   if (!l_entry)
      return -1;

   memset(l_entry, 0, sizeof(struct ifaddrs));
   l_entry->ifa_name = "";

   char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
   char *l_name = l_index + sizeof(int);
   char *l_addr = l_name + l_nameSize;
   char *l_data = l_addr + l_addrSize;

   /* save the interface index so we can look 
    * it up when handling the addresses. */
   memcpy(l_index, &l_info->ifi_index, sizeof(int));

   l_entry->ifa_flags = l_info->ifi_flags;

   l_rtaSize          = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));

   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      void      *l_rtaData = RTA_DATA(l_rta);
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);

      switch(l_rta->rta_type)
      {
         case IFLA_ADDRESS:
         case IFLA_BROADCAST:
            {
               size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
               makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
               ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
               ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
               if (l_rta->rta_type == IFLA_ADDRESS)
                  l_entry->ifa_addr      = (struct sockaddr *)l_addr;
               else
                  l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
               l_addr += NLMSG_ALIGN(l_addrLen);
               break;
            }
         case IFLA_IFNAME:
            strncpy(l_name, l_rtaData, l_rtaDataSize);
            l_name[l_rtaDataSize] = '\0';
            l_entry->ifa_name = l_name;
            break;
         case IFLA_STATS:
            memcpy(l_data, l_rtaData, l_rtaDataSize);
            l_entry->ifa_data = l_data;
            break;
         default:
            break;
      }
   }

   addToEnd(p_resultList, l_entry);
   return 0;
}

static struct ifaddrs *findInterface(int p_index,
      struct ifaddrs **p_links, int p_numLinks)
{
   int l_num             = 0;
   struct ifaddrs *l_cur = *p_links;

   while (l_cur && l_num < p_numLinks)
   {
      int l_index;
      char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);

      memcpy(&l_index, l_indexPtr, sizeof(int));
      if (l_index == p_index)
         return l_cur;

      l_cur = l_cur->ifa_next;
      ++l_num;
   }
   return NULL;
}

static int interpretAddr(struct nlmsghdr *p_hdr,
      struct ifaddrs **p_resultList, int p_numLinks)
{
   struct rtattr *l_rta;
   size_t l_rtaSize;
   size_t l_nameSize           = 0;
   size_t l_addrSize           = 0;
   int l_addedNetmask          = 0;
   struct ifaddrmsg *l_info    = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
   struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);

   if (l_info->ifa_family == AF_PACKET)
      return 0;

   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));

   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);

      switch(l_rta->rta_type)
      {
         case IFA_ADDRESS:
         case IFA_LOCAL:
            if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
            {
               /* make room for netmask */
               l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
               l_addedNetmask = 1;
            }
         case IFA_BROADCAST:
            l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
            break;
         case IFA_LABEL:
            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
            break;
         default:
            break;
      }
   }

   struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
   if (!l_entry)
      return -1;

   memset(l_entry, 0, sizeof(struct ifaddrs));
   l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");

   char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
   char *l_addr = l_name + l_nameSize;

   l_entry->ifa_flags = l_info->ifa_flags;
   if (l_interface)
      l_entry->ifa_flags |= l_interface->ifa_flags;

   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      void *l_rtaData = RTA_DATA(l_rta);
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
      switch(l_rta->rta_type)
      {
         case IFA_ADDRESS:
         case IFA_BROADCAST:
         case IFA_LOCAL:
            {
               size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
               makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
               if (l_info->ifa_family == AF_INET6)
               {
                  if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
                     ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
               }

               if (l_rta->rta_type == IFA_ADDRESS)
               {
                  /* apparently in a point-to-point network IFA_ADDRESS
                   * contains the dest address and IFA_LOCAL contains the local address */
                  if (l_entry->ifa_addr)
                     l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
                  else
                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
               }
               else if (l_rta->rta_type == IFA_LOCAL)
               {
                  if (l_entry->ifa_addr)
                     l_entry->ifa_dstaddr = l_entry->ifa_addr;
                  l_entry->ifa_addr = (struct sockaddr *)l_addr;
               }
               else
                  l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
               l_addr += NLMSG_ALIGN(l_addrLen);
               break;
            }
         case IFA_LABEL:
            strncpy(l_name, l_rtaData, l_rtaDataSize);
            l_name[l_rtaDataSize] = '\0';
            l_entry->ifa_name = l_name;
            break;
         default:
            break;
      }
   }

   if (l_entry->ifa_addr &&
         (   l_entry->ifa_addr->sa_family == AF_INET
          || l_entry->ifa_addr->sa_family == AF_INET6))
   {
      unsigned i;
      char l_mask[16];
      unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET
            ? 32 : 128);
      unsigned l_prefix    = (l_info->ifa_prefixlen > l_maxPrefix
            ? l_maxPrefix : l_info->ifa_prefixlen);

      l_mask[0] = '\0';

      for (i=0; i<(l_prefix/8); ++i)
         l_mask[i] = 0xff;
      if (l_prefix % 8)
         l_mask[i] = 0xff << (8 - (l_prefix % 8));

      makeSockaddr(l_entry->ifa_addr->sa_family,
            (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
      l_entry->ifa_netmask = (struct sockaddr *)l_addr;
   }

   addToEnd(p_resultList, l_entry);
   return 0;
}

static int interpretLinks(int p_socket, NetlinkList *p_netlinkList,
      struct ifaddrs **p_resultList)
{
   int l_numLinks = 0;
   pid_t l_pid    = getpid();

   for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
   {
      struct nlmsghdr *l_hdr = NULL;
      unsigned int l_nlsize  = p_netlinkList->m_size;

      for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
            l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
      {
         if (  (pid_t)l_hdr->nlmsg_pid != l_pid || 
               (int)l_hdr->nlmsg_seq   != p_socket)
            continue;

         if (l_hdr->nlmsg_type == NLMSG_DONE)
            break;

         if (l_hdr->nlmsg_type == RTM_NEWLINK)
         {
            if (interpretLink(l_hdr, p_resultList) == -1)
               return -1;
            ++l_numLinks;
         }
      }
   }
   return l_numLinks;
}

static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
      struct ifaddrs **p_resultList, int p_numLinks)
{
   pid_t l_pid = getpid();
   for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
   {
      struct nlmsghdr *l_hdr = NULL;
      unsigned int l_nlsize  = p_netlinkList->m_size;

      for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
            l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
      {
         if (     (pid_t)l_hdr->nlmsg_pid != l_pid 
               || (int)l_hdr->nlmsg_seq   != p_socket)
            continue;

         if (l_hdr->nlmsg_type == NLMSG_DONE)
            break;

         if (l_hdr->nlmsg_type == RTM_NEWADDR)
         {
            if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
               return -1;
         }
      }
   }
   return 0;
}

int getifaddrs(struct ifaddrs **ifap)
{
   NetlinkList *l_linkResults;
   NetlinkList *l_addrResults;
   int l_numLinks;
   int l_socket   = 0;
   int l_result   = 0;
   if (!ifap)
      return -1;

   *ifap    = NULL;

   l_socket = netlink_socket();

   if (l_socket < 0)
      return -1;

   l_linkResults = getResultList(l_socket, RTM_GETLINK);
   if (!l_linkResults)
   {
      close(l_socket);
      return -1;
   }

   l_addrResults = getResultList(l_socket, RTM_GETADDR);
   if (!l_addrResults)
   {
      close(l_socket);
      freeResultList(l_linkResults);
      return -1;
   }

   l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);

   if (  l_numLinks == -1 || 
         interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
      l_result = -1;

   freeResultList(l_linkResults);
   freeResultList(l_addrResults);
   close(l_socket);
   return l_result;
}

void freeifaddrs(struct ifaddrs *ifa)
{
   struct ifaddrs *l_cur = NULL;

   while (ifa)
   {
      l_cur = ifa;
      ifa   = ifa->ifa_next;
      free(l_cur);
   }
}

./include/libretro-common/compat/compat_posix_string.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_posix_string.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <ctype.h>

#include <compat/posix_string.h>

#ifdef _WIN32

#undef strcasecmp
#undef strdup
#undef isblank
#undef strtok_r
#include <ctype.h>
#include <stdlib.h>
#include <stddef.h>
#include <compat/strl.h>

#include <string.h>

int retro_strcasecmp__(const char *a, const char *b)
{
   while (*a && *b)
   {
      int a_ = tolower(*a);
      int b_ = tolower(*b);

      if (a_ != b_)
         return a_ - b_;

      a++;
      b++;
   }

   return tolower(*a) - tolower(*b);
}

char *retro_strdup__(const char *orig)
{
   size_t _len = strlen(orig) + 1;
   char *ret   = (char*)malloc(_len);
   if (!ret)
      return NULL;
   strlcpy(ret, orig, _len);
   return ret;
}

int retro_isblank__(int c)
{
   return (c == ' ') || (c == '\t');
}

char *retro_strtok_r__(char *str, const char *delim, char **saveptr)
{
   char *first = NULL;
   if (!saveptr || !delim)
      return NULL;

   if (str)
      *saveptr = str;

   do
   {
      char *ptr = NULL;
      first = *saveptr;
      while (*first && strchr(delim, *first))
         *first++ = '\0';

      if (*first == '\0')
         return NULL;

      ptr = first + 1;

      while (*ptr && !strchr(delim, *ptr))
         ptr++;

      *saveptr = ptr + (*ptr ? 1 : 0);
      *ptr     = '\0';
   } while (strlen(first) == 0);

   return first;
}

#endif

./include/libretro-common/compat/compat_snprintf.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_snprintf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
#ifdef _MSC_VER

#include <stdio.h>
#include <stdarg.h>

#if _MSC_VER < 1800
#define va_copy(dst, src) ((dst) = (src))
#endif

#if _MSC_VER < 1300
#define _vscprintf c89_vscprintf_retro__

static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
{
   int _len;
   va_list argcopy;
   va_copy(argcopy, pargs);
   _len = vsnprintf(NULL, 0, fmt, argcopy);
   va_end(argcopy);
   return _len;
}
#endif

/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */

int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
{
   int _len = -1;
   if (len != 0)
   {
#if (_MSC_VER <= 1310)
      _len = _vsnprintf(s, len - 1, fmt, ap);
#else
      _len = _vsnprintf_s(s, len, len - 1, fmt, ap);
#endif
   }
   if (_len == -1)
       _len = _vscprintf(fmt, ap);
   /* there was no room for a NULL, so truncate the last character */
   if (_len == len && len)
      s[len - 1] = '\0';
   return _len;
}

int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
{
   int _len;
   va_list ap;
   va_start(ap, fmt);
   _len = c99_vsnprintf_retro__(s, len, fmt, ap);
   va_end(ap);
   return _len;
}
#endif

./include/libretro-common/compat/compat_strcasestr.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_strcasestr.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <ctype.h>

#include <compat/strcasestr.h>

/* Pretty much strncasecmp. */
static int casencmp(const char *a, const char *b, size_t n)
{
   size_t i;

   for (i = 0; i < n; i++)
   {
      int a_lower = tolower(a[i]);
      int b_lower = tolower(b[i]);
      if (a_lower != b_lower)
         return a_lower - b_lower;
   }

   return 0;
}

char *strcasestr_retro__(const char *haystack, const char *needle)
{
   size_t _len  = strlen(needle);
   size_t __len = strlen(haystack);
   if (_len <= __len)
   {
      size_t i;
      __len -= _len; /* offset */
      for (i = 0; i <= __len; i++)
         if (!casencmp(haystack + i, needle, _len))
            return (char*)haystack + i;
   }
   return NULL;
}

./include/libretro-common/compat/compat_strl.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_strl.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <ctype.h>

#include <compat/strl.h>

/* Implementation of strlcpy()/strlcat() based on OpenBSD. */

#ifndef __MACH__
size_t strlcpy(char *s, const char *source, size_t len)
{
   size_t _len  = len;
   size_t __len = 0;
   if (_len)
      while (--_len && (*s++ = *source++)) __len++;
   if (!_len)
   {
      if (len) *s = '\0';
      while (*source++) __len++;
   }
   return __len;
}

size_t strlcat(char *s, const char *source, size_t len)
{
   size_t _len = strlen(s);
   s += _len;
   if (_len > len)
      len = 0;
   else
      len -= _len;
   return _len + strlcpy(s, source, len);
}
#endif

./include/libretro-common/compat/compat_strldup.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_strl.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <ctype.h>

#include <compat/strl.h>

char *strldup(const char *s, size_t n)
{
   char *dst = (char*)malloc(sizeof(char) * (n + 1));
   strlcpy(dst, s, n);
   return dst;
}

./include/libretro-common/compat/compat_vscprintf.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_snprintf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
#ifdef _MSC_VER

#include <retro_common.h>

#include <stdio.h>
#include <stdarg.h>

#if defined(_MSC_VER) && _MSC_VER < 1800
#define va_copy(dst, src) ((dst) = (src))
#endif

int c89_vscprintf_retro__(const char *format, va_list pargs)
{
   int _len;
   va_list argcopy;
   va_copy(argcopy, pargs);
   _len = vsnprintf(NULL, 0, format, argcopy);
   va_end(argcopy);
   return _len;
}
#endif

./include/libretro-common/compat/fopen_utf8.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fopen_utf8.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <compat/fopen_utf8.h>
#include <encodings/utf.h>
#include <stdio.h>
#include <stdlib.h>

#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif
#endif

#ifdef _WIN32
#undef fopen

void *fopen_utf8(const char * filename, const char * mode)
{
#if defined(LEGACY_WIN32)
   char * filename_local = utf8_to_local_string_alloc(filename);
   if (filename_local)
   {
      FILE *ret          = fopen(filename_local, mode);
      free(filename_local);
      return ret;
   }
#else
   wchar_t * filename_w  = utf8_to_utf16_string_alloc(filename);
   if (filename_w)
   {
      FILE    *ret       = NULL;
      wchar_t *mode_w    = utf8_to_utf16_string_alloc(mode);
      if (mode_w)
      {
         ret             = _wfopen(filename_w, mode_w);
         free(mode_w);
      }
      free(filename_w);
      return ret;
   }
#endif
   return NULL;
}
#endif

./include/libretro-common/crt/include/string.h

#ifndef __LIBRETRO_SDK_CRT_STRING_H_
#define __LIBRETRO_SDK_CRT_STRING_H_

#include <stdio.h>

void *memcpy(void *dst, const void *src, size_t len);

void *memset(void *b, int c, size_t len);

#endif

./include/libretro-common/crt/string.c

#ifdef _MSC_VER
#include <cruntime.h>
#endif
#include <stdio.h>
#include <string.h>

void *memset(void *dst, int val, size_t count)
{
   void *start = dst;

#if defined(_M_IA64) || defined (_M_AMD64) || defined(_M_ALPHA) || defined (_M_PPC)
   extern void RtlFillMemory(void *, size_t count, char);

   RtlFillMemory(dst, count, (char)val);
#else
   while (count--)
   {
      *(char*)dst = (char)val;
      dst = (char*)dst + 1;
   }
#endif

   return start;
}

void *memcpy(void *dst, const void *src, size_t len)
{
   size_t i;

   for (i = 0; i < len; i++)
      ((unsigned char *)dst)[i] = ((unsigned char *)src)[i];

   return dst;
}

./include/libretro-common/dynamic/dylib.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dylib.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>
#include <stdio.h>
#include <dynamic/dylib.h>
#include <encodings/utf.h>
#include <string/stdstring.h>
#include <retro_miscellaneous.h>
#include <file/file_path.h>

#if defined(ORBIS)
#include <orbis/libkernel.h>
#endif

#ifdef NEED_DYNAMIC

#ifdef _WIN32
#include <compat/posix_string.h>
#include <windows.h>
#else
#if !defined(ORBIS)
#include <dlfcn.h>
#endif
#endif

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#ifdef _WIN32
static char last_dyn_err[512];

static void set_dl_err(void)
{
   DWORD err = GetLastError();
   if (FormatMessage(
              FORMAT_MESSAGE_IGNORE_INSERTS
            | FORMAT_MESSAGE_FROM_SYSTEM,
            NULL, err,
            MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
            last_dyn_err, sizeof(last_dyn_err) - 1,
            NULL) == 0)
      snprintf(last_dyn_err, sizeof(last_dyn_err) - 1,
            "unknown error %lu", err);
}
#endif

/**
 * dylib_load:
 * @path                         : Path to libretro core library.
 *
 * Platform independent dylib loading.
 *
 * @return Library handle on success, otherwise NULL.
 **/
dylib_t dylib_load(const char *path)
{
#ifdef _WIN32
#ifndef __WINRT__
   int prevmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
#endif
#ifdef __WINRT__
   dylib_t lib;
   /* On UWP, you can only load DLLs inside your install directory, using a special function that takes a relative path */
   char relative_path_abbrev[PATH_MAX_LENGTH];
   char *relative_path = relative_path_abbrev;
   wchar_t *path_wide  = NULL;

   relative_path_abbrev[0] = '\0';

   if (!path_is_absolute(path))
      RARCH_WARN("Relative path in dylib_load! This is likely an attempt to load a system library that will fail.\n");

   fill_pathname_abbreviate_special(relative_path_abbrev, path, sizeof(relative_path_abbrev));

   /* Path to dylib_load is not inside app install directory.
    * Loading will probably fail. */
   if (relative_path[0] != ':' || !PATH_CHAR_IS_SLASH(relative_path[1])) { }
   else
      relative_path += 2;

   path_wide = utf8_to_utf16_string_alloc(relative_path);
   lib       = LoadPackagedLibrary(path_wide, 0);
   free(path_wide);
#elif defined(LEGACY_WIN32)
   dylib_t lib        = LoadLibrary(path);
#else
   wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
   dylib_t lib        = LoadLibraryW(path_wide);
   free(path_wide);
#endif

#ifndef __WINRT__
   SetErrorMode(prevmode);
#endif

   if (!lib)
   {
      set_dl_err();
      return NULL;
   }
   last_dyn_err[0] = 0;
#elif defined(ORBIS)
   int res;
   dylib_t lib = (dylib_t)sceKernelLoadStartModule(path, 0, NULL, 0, NULL, &res);
#elif defined(IOS) || defined(OSX)
    dylib_t lib;
    static const char fw_suffix[] = ".framework";
    if (string_ends_with(path, fw_suffix))
    {
        char fw_path[PATH_MAX_LENGTH];
        const char *fw_name = path_basename(path);
        size_t _len         = strlcpy(fw_path, path, sizeof(fw_path));
        _len += strlcpy(fw_path + _len, "/", sizeof(fw_path) - _len);
        /* Assume every framework binary is named for the framework. Not always
         * a great assumption but correct enough for our uses. */
        strlcpy(fw_path + _len, fw_name, strlen(fw_name) - STRLEN_CONST(fw_suffix) + 1);
        lib = dlopen(fw_path, RTLD_LAZY | RTLD_LOCAL);
    }
    else
        lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
#else
   dylib_t lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
#endif
   return lib;
}

char *dylib_error(void)
{
#ifdef _WIN32
   if (last_dyn_err[0])
      return last_dyn_err;
   return NULL;
#else
   return (char*)dlerror();
#endif
}

function_t dylib_proc(dylib_t lib, const char *proc)
{
   function_t sym;

#ifdef _WIN32
   HMODULE mod = (HMODULE)lib;
   if (!mod)
   {
#ifdef __WINRT__
      /* GetModuleHandle is not available on UWP */
      /* It's not possible to lookup symbols in current executable
       * on UWP. */
      DebugBreak();
      return NULL;
#else
      mod = GetModuleHandle(NULL);
#endif
   }
   if (!(sym = (function_t)GetProcAddress(mod, proc)))
   {
      set_dl_err();
      return NULL;
   }
   last_dyn_err[0] = 0;
#elif defined(ORBIS)
   void *ptr_sym = NULL;
   sym = NULL;

   if (lib)
   {
     sceKernelDlsym((SceKernelModule)lib, proc, &ptr_sym);
     memcpy(&sym, &ptr_sym, sizeof(void*));
   }
#else
   void *ptr_sym = NULL;

   if (lib)
      ptr_sym = dlsym(lib, proc);
   else
   {
      void *handle = dlopen(NULL, RTLD_LAZY);
      if (handle)
      {
         ptr_sym = dlsym(handle, proc);
         dlclose(handle);
      }
   }

   /* Dirty hack to workaround the non-legality of
    * (void*) -> fn-pointer casts. */
   memcpy(&sym, &ptr_sym, sizeof(void*));
#endif

   return sym;
}

/**
 * dylib_close:
 * @lib                          : Library handle.
 *
 * Frees library handle.
 **/
void dylib_close(dylib_t lib)
{
#ifdef _WIN32
   if (!FreeLibrary((HMODULE)lib))
      set_dl_err();
   last_dyn_err[0] = 0;
#elif defined(ORBIS)
   int res;
   sceKernelStopUnloadModule((SceKernelModule)lib, 0, NULL, 0, NULL, &res);
#else
#ifndef NO_DLCLOSE
   dlclose(lib);
#endif
#endif
}

#endif

./include/libretro-common/encodings/encoding_base64.c

/*
  https://github.com/superwills/NibbleAndAHalf
  base64.h -- Fast base64 encoding and decoding.
  version 1.0.0, April 17, 2013 143a
  Copyright (C) 2013 William Sherif
  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.
  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:
  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
  William Sherif
  will.sherif@gmail.com
  YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz


  Modified for RetroArch formatting, logging, and header files.
*/


#include <stdio.h>
#include <stdlib.h>
#include <encodings/base64.h>

static const char* b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/* maps A=>0,B=>1.. */
static const unsigned char unb64[]={
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,  62,   0,   0,   0,  63,  52,  53,
 54,  55,  56,  57,  58,  59,  60,  61,   0,   0,
  0,   0,   0,   0,   0,   0,   1,   2,   3,   4,
  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
 25,   0,   0,   0,   0,   0,   0,  26,  27,  28,
 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
 49,  50,  51,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,
}; /* This array has 256 elements */

/*
   Converts binary data of length=len to base64 characters.
   Length of the resultant string is stored in flen
   (you must pass pointer flen).
*/
char* base64(const void* binaryData, int len, int *flen)
{
   char* res;
   int byteNo; /* I need this after the loop */
   const unsigned char* bin = (const unsigned char*) binaryData;
   int rc                   = 0; /* result counter */
   int modulusLen           = len % 3 ;
   /* 2 gives 1 and 1 gives 2, but 0 gives 0. */
   int pad                  = ((modulusLen&1)<<1) + ((modulusLen&2)>>1);

   *flen                    = 4*(len + pad)/3;
   if (!(res = (char*) malloc(*flen + 1))) /* and one for the NULL */
      return 0;
  
   for (byteNo=0; byteNo <= len-3; byteNo+=3)
   {
      unsigned char BYTE0            = bin[byteNo];
      unsigned char BYTE1            = bin[byteNo+1];
      unsigned char BYTE2            = bin[byteNo+2];

      res[rc++] = b64[BYTE0 >> 2];
      res[rc++] = b64[((0x3&BYTE0)<<4) + (BYTE1 >> 4)];
      res[rc++] = b64[((0x0f&BYTE1)<<2) + (BYTE2>>6)];
      res[rc++] = b64[0x3f&BYTE2];
   }
  
   if (pad==2)
   {
      res[rc++] = b64[bin[byteNo] >> 2];
      res[rc++] = b64[(0x3&bin[byteNo])<<4];
      res[rc++] = '=';
      res[rc++] = '=';
   }
   else if (pad==1)
   {
      res[rc++] = b64[bin[byteNo] >> 2];
      res[rc++] = b64[((0x3&bin[byteNo])<<4) + (bin[byteNo+1] >> 4)];
      res[rc++] = b64[(0x0f&bin[byteNo+1])<<2];
      res[rc++] = '=';
   }
  
   res[rc]=0; /* NULL TERMINATOR! ;) */
   return res;
}

unsigned char* unbase64(const char* ascii, int len, int *flen)
{
   int charNo;
   unsigned char *bin;
   const unsigned char *safeAsciiPtr = (const unsigned char*) ascii;
   int cb                            = 0;
   int pad                           = 0;

   if (len < 2) /* 2 accesses below would be OOB (Out Of Bounds). */
   {
      /* catch empty string, return NULL as result. */
      /* ERROR: You passed an invalid base64 string (too short). 
       * You get NULL back. */
      *flen = 0;
      return 0;
   }

   if (safeAsciiPtr[len-1]=='=')
      ++pad;
   if (safeAsciiPtr[len-2]=='=')
      ++pad;
  
   *flen = 3*len/4 - pad;
   if (!(bin = (unsigned char*)malloc(*flen)))
      return 0;
  
   for (charNo=0; charNo <= len-4-pad; charNo+=4)
   {
      int A = unb64[safeAsciiPtr[charNo]];
      int B = unb64[safeAsciiPtr[charNo+1]];
      int C = unb64[safeAsciiPtr[charNo+2]];
      int D = unb64[safeAsciiPtr[charNo+3]];
    
      bin[cb++] = (A<<2) | (B>>4);
      bin[cb++] = (B<<4) | (C>>2);
      bin[cb++] = (C<<6) | (D);
   }
  
   if (pad==1)
   {
      int A = unb64[safeAsciiPtr[charNo]];
      int B = unb64[safeAsciiPtr[charNo+1]];
      int C = unb64[safeAsciiPtr[charNo+2]];
    
      bin[cb++] = (A<<2) | (B>>4);
      bin[cb++] = (B<<4) | (C>>2);
   }
   else if (pad==2)
   {
      int A = unb64[safeAsciiPtr[charNo]];
      int B = unb64[safeAsciiPtr[charNo+1]];
    
      bin[cb++] = (A<<2) | (B>>4);
   }
  
   return bin;
}

./include/libretro-common/encodings/encoding_crc32.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (encoding_crc32.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <stddef.h>
#include <encodings/crc32.h>
#include <stdlib.h>

#if __ARM_FEATURE_CRC32

#ifdef _M_ARM64
# include <arm64_neon.h>
#else
# include <arm_acle.h>
#endif

uint32_t encoding_crc32(uint32_t crc, const uint8_t *data, size_t len)
{
   crc = ~crc;
   /* Align data if it is not aligned */
   while (((uintptr_t)data & 7) && len > 0)
   {
      crc = __crc32b(crc, *(uint8_t *)data);
      data++;
      len--;
   }
   while (len >= 8)
   {
      crc = __crc32d(crc, *(uint64_t *)data);
      data += 8;
      len -= 8;
   }
   while (len > 0)
   {
      crc = __crc32b(crc, *(uint8_t *)data);
      data++;
      len--;
   }
   return ~crc;
}

#else
uint32_t encoding_crc32(uint32_t crc, const uint8_t *s, size_t len)
{
   static const uint32_t crc32_table[256] = {
      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
      0x2d02ef8dL
   };
   crc = ~crc;
   while (len--)
      crc = crc32_table[(crc ^ (*s++)) & 0xff] ^ (crc >> 8);
   return ~crc;
}

#endif

./include/libretro-common/encodings/encoding_utf.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (encoding_utf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>

#include <boolean.h>
#include <compat/strl.h>
#include <retro_inline.h>

#include <encodings/utf.h>

#if defined(_WIN32) && !defined(_XBOX)
#include <windows.h>
#elif defined(_XBOX)
#include <xtl.h>
#endif

#define UTF8_WALKBYTE(string) (*((*(string))++))

static unsigned leading_ones(uint8_t c)
{
   unsigned ones = 0;
   while (c & 0x80)
   {
      ones++;
      c <<= 1;
   }

   return ones;
}

/**
 * utf8_conv_utf32:
 *
 * Simple implementation. Assumes the sequence is
 * properly synchronized and terminated.
 **/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
      const char *in, size_t in_size)
{
   unsigned i;
   size_t ret = 0;
   while (in_size && out_chars)
   {
      unsigned extra, shift;
      uint32_t c;
      uint8_t first = *in++;
      unsigned ones = leading_ones(first);

      if (ones > 6 || ones == 1) /* Invalid or desync. */
         break;

      extra = ones ? ones - 1 : ones;
      if (1 + extra > in_size) /* Overflow. */
         break;

      shift = (extra - 1) * 6;
      c     = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);

      for (i = 0; i < extra; i++, in++, shift -= 6)
         c |= (*in & 0x3f) << shift;

      *out++   = c;
      in_size -= 1 + extra;
      out_chars--;
      ret++;
   }
   return ret;
}

/**
 * utf16_conv_utf8:
 *
 * Leaf function.
 **/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
     const uint16_t *in, size_t in_size)
{
   size_t out_pos            = 0;
   size_t in_pos             = 0;
   static const
      uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };

   for (;;)
   {
      unsigned num_adds;
      uint32_t value;

      if (in_pos == in_size)
      {
         *out_chars = out_pos;
         return true;
      }
      value = in[in_pos++];
      if (value < 0x80)
      {
         if (out)
            out[out_pos] = (char)value;
         out_pos++;
         continue;
      }

      if (value >= 0xD800 && value < 0xE000)
      {
         uint32_t c2;

         if (value >= 0xDC00 || in_pos == in_size)
            break;
         c2 = in[in_pos++];
         if (c2 < 0xDC00 || c2 >= 0xE000)
            break;
         value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
      }

      for (num_adds = 1; num_adds < 5; num_adds++)
         if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
            break;
      if (out)
         out[out_pos] = (char)(utf8_limits[num_adds - 1]
               + (value >> (6 * num_adds)));
      out_pos++;
      do
      {
         num_adds--;
         if (out)
            out[out_pos] = (char)(0x80
                  + ((value >> (6 * num_adds)) & 0x3F));
         out_pos++;
      }while (num_adds != 0);
   }

   *out_chars = out_pos;
   return false;
}

/**
 * utf8cpy:
 *
 * Acts mostly like strlcpy.
 *
 * Copies the given number of UTF-8 characters,
 * but at most @len bytes.
 *
 * Always NULL terminates. Does not copy half a character.
 * @s is assumed valid UTF-8.
 * Use only if @chars is considerably less than @len.
 *
 * @return Number of bytes.
 **/
size_t utf8cpy(char *s, size_t len, const char *in, size_t chars)
{
   const uint8_t *sb     = (const uint8_t*)in;
   const uint8_t *sb_org = sb;

   if (!in)
      return 0;

   while (*sb && chars-- > 0)
   {
      sb++;
      while ((*sb & 0xC0) == 0x80)
         sb++;
   }

   if ((size_t)(sb - sb_org) > len - 1)
   {
      sb = sb_org + len - 1;
      while ((*sb & 0xC0) == 0x80)
         sb--;
   }

   memcpy(s, sb_org, sb - sb_org);
   s[sb-sb_org] = '\0';
   return sb - sb_org;
}

/**
 * utf8skip:
 *
 * Leaf function
 **/
const char *utf8skip(const char *str, size_t chars)
{
   const uint8_t *strb = (const uint8_t*)str;

   if (!chars)
      return str;

   do
   {
      strb++;
      while ((*strb & 0xC0)==0x80)
         strb++;
      chars--;
   }while (chars);

   return (const char*)strb;
}

/**
 * utf8len:
 *
 * Leaf function.
 **/
size_t utf8len(const char *string)
{
   size_t ret = 0;

   if (!string)
      return 0;

   while (*string)
   {
      if ((*string & 0xC0) != 0x80)
         ret++;
      string++;
   }
   return ret;
}

/**
 * utf8_walk:
 *
 * Does not validate the input.
 *
 * Leaf function.
 *
 * @return Returns garbage if it's not UTF-8.
 **/
uint32_t utf8_walk(const char **string)
{
   uint8_t first = UTF8_WALKBYTE(string);
   uint32_t ret  = 0;

   if (first < 128)
      return first;

   ret    = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
   if (first >= 0xE0)
   {
      ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
      if (first >= 0xF0)
      {
         ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
         return ret | (first & 7) << 18;
      }
      return ret | (first & 15) << 12;
   }

   return ret | (first & 31) << 6;
}

static bool utf16_to_char(uint8_t **utf_data,
      size_t *dest_len, const uint16_t *in)
{
   size_t _len    = 0;
   while (in[_len] != '\0')
      _len++;
   utf16_conv_utf8(NULL, dest_len, in, _len);
   *dest_len  += 1;
   if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)
      return utf16_conv_utf8(*utf_data, dest_len, in, _len);
   return false;
}

/**
 * utf16_to_char_string:
 **/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
{
   size_t  _len        = 0;
   uint8_t *utf16_data = NULL;
   bool            ret = utf16_to_char(&utf16_data, &_len, in);
   if (ret)
   {
      utf16_data[_len] = 0;
      strlcpy(s, (const char*)utf16_data, len);
   }
   free(utf16_data);
   utf16_data          = NULL;
   return ret;
}

#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
/**
 * mb_to_mb_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
static char *mb_to_mb_string_alloc(const char *str,
      enum CodePage cp_in, enum CodePage cp_out)
{
   wchar_t *path_buf_wide = NULL;
   int path_buf_wide_len  = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);

   /* Windows 95 will return 0 from these functions with
    * a UTF8 codepage set without MSLU.
    *
    * From an unknown MSDN version (others omit this info):
    *   - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:
    *   Translate using UTF-8. When this is set, dwFlags must be zero.
    *   - Windows 95: Under the Microsoft Layer for Unicode,
    *   MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
    */

   if (!path_buf_wide_len)
      return strdup(str);

   if ((path_buf_wide = (wchar_t*)
      calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t))))
   {
      MultiByteToWideChar(cp_in, 0,
            str, -1, path_buf_wide, path_buf_wide_len);

      if (*path_buf_wide)
      {
         int path_buf_len = WideCharToMultiByte(cp_out, 0,
               path_buf_wide, -1, NULL, 0, NULL, NULL);

         if (path_buf_len)
         {
            char *path_buf = (char*)
               calloc(path_buf_len + sizeof(char), sizeof(char));

            if (path_buf)
            {
               WideCharToMultiByte(cp_out, 0,
                     path_buf_wide, -1, path_buf,
                     path_buf_len, NULL, NULL);

               free(path_buf_wide);

               if (*path_buf)
                  return path_buf;

               free(path_buf);
               return NULL;
            }
         }
         else
         {
            free(path_buf_wide);
            return strdup(str);
         }
      }

      free(path_buf_wide);
   }

   return NULL;
}
#endif

/**
 * utf8_to_local_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char* utf8_to_local_string_alloc(const char *str)
{
   if (str && *str)
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
      return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
#else
      return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
   return NULL;
}

/**
 * local_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *local_to_utf8_string_alloc(const char *str)
{
	if (str && *str)
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
		return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
#else
      return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
	return NULL;
}

/**
 * utf8_to_utf16_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
wchar_t* utf8_to_utf16_string_alloc(const char *str)
{
#ifdef _WIN32
   int _len       = 0;
#else
   size_t _len    = 0;
#endif
   wchar_t *buf   = NULL;

   if (!str || !*str)
      return NULL;

#ifdef _WIN32
   if ((_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
   {
      if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))
         return NULL;

      if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, _len)) < 0)
      {
         free(buf);
         return NULL;
      }
   }
   else
   {
      /* Fallback to ANSI codepage instead */
      if ((_len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))
      {
         if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))
            return NULL;

         if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, _len)) < 0)
         {
            free(buf);
            return NULL;
         }
      }
   }
#else
   /* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
   if ((_len = mbstowcs(NULL, str, 0) + 1))
   {
      if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))
         return NULL;

      if ((mbstowcs(buf, str, _len)) == (size_t)-1)
      {
         free(buf);
         return NULL;
      }
   }
#endif

   return buf;
}

/**
 * utf16_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char* utf16_to_utf8_string_alloc(const wchar_t *str)
{
#ifdef _WIN32
   int _len       = 0;
#else
   size_t _len    = 0;
#endif
   char *buf      = NULL;

   if (!str || !*str)
      return NULL;

#ifdef _WIN32
   {
      UINT code_page = CP_UTF8;

      /* fallback to ANSI codepage instead */
      if (!(_len = WideCharToMultiByte(code_page,
            0, str, -1, NULL, 0, NULL, NULL)))
      {
         code_page   = CP_ACP;
         _len        = WideCharToMultiByte(code_page,
               0, str, -1, NULL, 0, NULL, NULL);
      }

      if (!(buf = (char*)calloc(_len, sizeof(char))))
         return NULL;

      if (WideCharToMultiByte(code_page,
            0, str, -1, buf, _len, NULL, NULL) < 0)
      {
         free(buf);
         return NULL;
      }
   }
#else
   /* NOTE: For now, assume non-Windows platforms'
    * locale is already UTF-8. */
   if ((_len = wcstombs(NULL, str, 0) + 1))
   {
      if (!(buf = (char*)calloc(_len, sizeof(char))))
         return NULL;

      if (wcstombs(buf, str, _len) == (size_t)-1)
      {
         free(buf);
         return NULL;
      }
   }
#endif

   return buf;
}

./include/libretro-common/features/features_cpu.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (features_cpu.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>

#if defined(_WIN32)
#include <direct.h>
#else
#include <unistd.h>
#endif

#include <compat/strl.h>
#include <streams/file_stream.h>
#include <libretro.h>
#include <features/features_cpu.h>
#include <retro_timers.h>

#if defined(_WIN32) && !defined(_XBOX)
#include <windows.h>
#endif

#ifdef __PSL1GHT__
#include <lv2/systime.h>
#endif

#if defined(_XBOX360)
#include <PPCIntrinsics.h>
#elif !defined(__MACH__) && !defined(__FreeBSD__) && (defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC64__) || defined(__powerpc64__))
#ifndef _PPU_INTRINSICS_H
#include <ppu_intrinsics.h>
#endif
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
#include <time.h>
#endif

#if defined(__QNX__) && !defined(CLOCK_MONOTONIC)
#define CLOCK_MONOTONIC 2
#endif

#if defined(PSP)
#include <pspkernel.h>
#endif

#if defined(PSP) || defined(__PSL1GHT__)
#include <sys/time.h>
#endif

#if defined(PSP)
#include <psprtc.h>
#endif

#if defined(VITA)
#include <psp2/kernel/processmgr.h>
#include <psp2/rtc.h>
#endif

#if defined(ORBIS)
#include <orbis/libkernel.h>
#endif

#if defined(PS2)
#include <ps2sdkapi.h>
#endif

#if !defined(__PSL1GHT__) && defined(__PS3__)
#include <sys/sys_time.h>
#endif

#ifdef GEKKO
#include <ogc/lwp_watchdog.h>
#endif

#ifdef WIIU
#include <wiiu/os/time.h>
#endif

#if defined(HAVE_LIBNX)
#include <switch.h>
#elif defined(SWITCH)
#include <libtransistor/types.h>
#include <libtransistor/svc.h>
#endif

#if defined(_3DS)
#include <3ds/svc.h>
#include <3ds/os.h>
#include <3ds/services/cfgu.h>
#endif

/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
#ifdef __MACH__
#include <sys/time.h>

#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 0
#endif

#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif

/**
 * TODO/FIXME: clock_gettime function is part of iOS 10 now
 **/
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
static int ra_clock_gettime(int clk_ik, struct timespec *t)
{
   struct timeval now;
   int rv     = gettimeofday(&now, NULL);
   if (rv)
      return rv;
   t->tv_sec  = now.tv_sec;
   t->tv_nsec = now.tv_usec * 1000;
   return 0;
}
#endif
#endif

#if defined(__MACH__) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
#else
#define ra_clock_gettime clock_gettime
#endif

#ifdef EMSCRIPTEN
#include <emscripten.h>
#endif

#if defined(BSD) || defined(__APPLE__)
#include <sys/sysctl.h>
#endif

#include <string.h>

retro_perf_tick_t cpu_features_get_perf_counter(void)
{
   retro_perf_tick_t time_ticks = 0;
#if defined(_WIN32)
   long tv_sec, tv_usec;
#if defined(_MSC_VER) && _MSC_VER <= 1200
   static const unsigned __int64 epoch = 11644473600000000;
#else
   static const unsigned __int64 epoch = 11644473600000000ULL;
#endif
   FILETIME file_time;
   SYSTEMTIME system_time;
   ULARGE_INTEGER ularge;

   GetSystemTime(&system_time);
   SystemTimeToFileTime(&system_time, &file_time);
   ularge.LowPart  = file_time.dwLowDateTime;
   ularge.HighPart = file_time.dwHighDateTime;

   tv_sec     = (long)((ularge.QuadPart - epoch) / 10000000L);
   tv_usec    = (long)(system_time.wMilliseconds * 1000);
   time_ticks = (1000000 * tv_sec + tv_usec);
#elif defined(GEKKO)
   time_ticks = gettime();
#elif !defined(__MACH__) && !defined(__FreeBSD__) && (defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__) || defined(__PPC64__) || defined(__powerpc64__))
   time_ticks = __mftb();
#elif (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0) || defined(__QNX__) || defined(ANDROID)
   struct timespec tv;
   if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
      time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
         (retro_perf_tick_t)tv.tv_nsec;

#elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)
   __asm__ volatile ("rdtsc" : "=A" (time_ticks));
#elif defined(__GNUC__) && defined(__x86_64__) || defined(_M_IX86)
   unsigned a, d;
   __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
   time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
#elif defined(__ARM_ARCH_6__)
   __asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
#elif defined(__aarch64__)
   __asm__ volatile( "mrs %0, cntvct_el0" : "=r"(time_ticks) );
#elif defined(PSP) || defined(VITA)
   time_ticks = sceKernelGetSystemTimeWide();
#elif defined(ORBIS)
   sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);
#elif defined(PS2)
   time_ticks = ps2_clock();
#elif defined(_3DS)
   time_ticks = svcGetSystemTick();
#elif defined(WIIU)
   time_ticks = OSGetSystemTime();
#elif defined(HAVE_LIBNX)
   time_ticks = armGetSystemTick();
#elif defined(EMSCRIPTEN)
   time_ticks = emscripten_get_now() * 1000;
#endif

   return time_ticks;
}

retro_time_t cpu_features_get_time_usec(void)
{
#if defined(_WIN32)
   static LARGE_INTEGER freq;
   LARGE_INTEGER count;

   /* Frequency is guaranteed to not change. */
   if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
      return 0;

   if (!QueryPerformanceCounter(&count))
      return 0;
   return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);
#elif defined(__PSL1GHT__)
   return sysGetSystemTime();
#elif !defined(__PSL1GHT__) && defined(__PS3__)
   return sys_time_get_system_time();
#elif defined(GEKKO)
   return ticks_to_microsecs(gettime());
#elif defined(WIIU)
   return ticks_to_us(OSGetSystemTime());
#elif defined(SWITCH) || defined(HAVE_LIBNX)
   return (svcGetSystemTick() * 10) / 192;
#elif defined(_3DS)
   return osGetTime() * 1000;
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
   struct timespec tv;
   if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
      return 0;
   return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
#elif defined(EMSCRIPTEN)
   return emscripten_get_now() * 1000;
#elif defined(PS2)
   return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;
#elif defined(VITA) || defined(PSP)
   return sceKernelGetSystemTimeWide();
#elif defined(DJGPP)
   return uclock() * 1000000LL / UCLOCKS_PER_SEC;
#elif defined(ORBIS)
   return sceKernelGetProcessTime();
#else
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
#endif
}

#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)
#define CPU_X86
#endif

#if defined(_MSC_VER) && !defined(_XBOX)
#if (_MSC_VER > 1310)
#include <intrin.h>
#endif
#endif

#if defined(CPU_X86) && !defined(__MACH__)
#include <limits.h>
void x86_cpuid(int func, int32_t flags[4])
{
   /* On Android, we compile RetroArch with PIC, and we
    * are not allowed to clobber the ebx register. */
#ifdef __x86_64__
#define REG_b "rbx"
#define REG_S "rsi"
#else
#define REG_b "ebx"
#define REG_S "esi"
#endif

#if defined(__GNUC__)
   __asm__ volatile (
         "mov %%" REG_b ", %%" REG_S "\n"
         "cpuid\n"
         "xchg %%" REG_b ", %%" REG_S "\n"
         : "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
         : "a"(func));
#elif defined(_MSC_VER) && INT_MAX == 2147483647
   __cpuid((int*)flags, func);
#else
#ifndef NDEBUG
   printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
#endif
   memset(flags, 0, 4 * sizeof(int));
#endif
}

/* Only runs on i686 and above. Needs to be conditionally run. */
static uint64_t xgetbv_x86(uint32_t idx)
{
#if defined(__GNUC__)
   uint32_t eax, edx;
   __asm__ volatile (
         /* Older GCC versions (Apple's GCC for example) do
          * not understand xgetbv instruction.
          * Stamp out the machine code directly.
          */
         ".byte 0x0f, 0x01, 0xd0\n"
         : "=a"(eax), "=d"(edx) : "c"(idx));
   return ((uint64_t)edx << 32) | eax;
#elif _MSC_FULL_VER >= 160040219
   /* Intrinsic only works on 2010 SP1 and above. */
   return _xgetbv(idx);
#else
#ifndef NDEBUG
   printf("Unknown compiler. Cannot check xgetbv bits.\n");
#endif
   return 0;
#endif
}
#endif

#if defined(__ARM_NEON__)
#if defined(__arm__)
static void arm_enable_runfast_mode(void)
{
   /* RunFast mode. Enables flush-to-zero and some
    * floating point optimizations. */
   static const unsigned x = 0x04086060;
   static const unsigned y = 0x03000000;
   int r;
   __asm__ volatile(
         "fmrx	%0, fpscr   \n\t" /* r0 = FPSCR */
         "and	%0, %0, %1  \n\t" /* r0 = r0 & 0x04086060 */
         "orr	%0, %0, %2  \n\t" /* r0 = r0 | 0x03000000 */
         "fmxr	fpscr, %0   \n\t" /* FPSCR = r0 */
         : "=r"(r)
         : "r"(x), "r"(y)
        );
}
#endif
#endif

#if defined(__linux__) && !defined(CPU_X86)
static unsigned char check_arm_cpu_feature(const char* feature)
{
   char line[1024];
   unsigned char status = 0;
   RFILE *fp = filestream_open("/proc/cpuinfo",
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fp)
      return 0;

   while (filestream_gets(fp, line, sizeof(line)))
   {
      if (strncmp(line, "Features\t: ", 11))
         continue;

      if (strstr(line + 11, feature))
         status = 1;

      break;
   }

   filestream_close(fp);

   return status;
}

#if !defined(_SC_NPROCESSORS_ONLN)
/**
 * parse_decimal:
 *
 * Parse an decimal integer starting from 'input', but not going further
 * than 'limit'. Return the value into '*result'.
 *
 * NOTE: Does not skip over leading spaces, or deal with sign characters.
 * NOTE: Ignores overflows.
 *
 * The function returns NULL in case of error (bad format), or the new
 * position after the decimal number in case of success (which will always
 * be <= 'limit').
 *
 * Leaf function.
 **/
static const char *parse_decimal(const char* input,
      const char* limit, int* result)
{
    const char* p = input;
    int       val = 0;

    while (p < limit)
    {
        int d = (*p - '0');
        if ((unsigned)d >= 10U)
            break;
        val = val*10 + d;
        p++;
    }
    if (p == input)
        return NULL;

    *result = val;
    return p;
}

/**
 * cpulist_parse:
 * Parse a textual list of cpus and store the result inside a CpuList object.
 * Input format is the following:
 * - comma-separated list of items (no spaces)
 * - each item is either a single decimal number (cpu index), or a range made
 *   of two numbers separated by a single dash (-). Ranges are inclusive.
 *
 * Examples:   0
 *             2,4-127,128-143
 *             0-1
 **/
static void cpulist_parse(CpuList* list, char **buf, ssize_t len)
{
   const char* p   = (const char*)buf;
   const char* end = p + len;

   /* NOTE: the input line coming from sysfs typically contains a
    * trailing newline, so take care of it in the code below
    */
   while (p < end && *p != '\n')
   {
      int val, start_value, end_value;
      /* Find the end of current item, and put it into 'q' */
      const char *q = (const char*)memchr(p, ',', end-p);

      if (!q)
         q = end;

      /* Get first value */
      if (!(p = parse_decimal(p, q, &start_value)))
         return;

      end_value = start_value;

      /* If we're not at the end of the item, expect a dash and
       * and integer; extract end value.
       */
      if (p < q && *p == '-')
      {
         if (!(p = parse_decimal(p+1, q, &end_value)))
            return;
      }

      /* Set bits CPU list bits */
      for (val = start_value; val <= end_value; val++)
      {
         if ((unsigned)val < 32)
            list->mask |= (uint32_t)(UINT32_C(1) << val);
      }

      /* Jump to next item */
      p = q;
      if (p < end)
         p++;
   }
}

/**
 * cpulist_read_from:
 *
 * Read a CPU list from one sysfs file
 **/
static void cpulist_read_from(CpuList* list, const char* filename)
{
   ssize_t _len;
   char *buf  = NULL;

   list->mask = 0;

   if (filestream_read_file(filename, (void**)&buf, &_len) != 1)
      return;

   cpulist_parse(list, &buf, _len);
   if (buf)
      free(buf);
   buf = NULL;
}
#endif

#endif

unsigned cpu_features_get_core_amount(void)
{
#if defined(_WIN32) && !defined(_XBOX)
   /* Win32 */
   SYSTEM_INFO sysinfo;
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
   GetNativeSystemInfo(&sysinfo);
#else
   GetSystemInfo(&sysinfo);
#endif
   return sysinfo.dwNumberOfProcessors;
#elif defined(GEKKO)
   return 1;
#elif defined(PSP) || defined(PS2)
   return 1;
#elif defined(__PSL1GHT__) || !defined(__PSL1GHT__) && defined(__PS3__)
   return 1; /* Only one PPU, SPUs don't really count */
#elif defined(VITA)
   return 4;
#elif defined(HAVE_LIBNX) || defined(SWITCH)
   return 4;
#elif defined(_3DS)
   u8 device_model = 0xFF;
   CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
   switch (device_model)
   {
		case 0:
		case 1:
		case 3:
			/*Old 3/2DS*/
			return 2;

		case 2:
		case 4:
		case 5:
			/*New 3/2DS*/
			return 4;

		default:
			/*Unknown Device Or Check Failed*/
			break;
   }
   return 1;
#elif defined(WIIU)
   return 3;
#elif defined(_SC_NPROCESSORS_ONLN)
   /* Linux, most UNIX-likes. */
   long ret = sysconf(_SC_NPROCESSORS_ONLN);
   if (ret <= 0)
      return (unsigned)1;
   return (unsigned)ret;
#elif defined(BSD) || defined(__APPLE__)
   /* BSD */
   /* Copypasta from stackoverflow, dunno if it works. */
   int num_cpu = 0;
   int mib[4];
   size_t _len = sizeof(num_cpu);

   mib[0] = CTL_HW;
   mib[1] = HW_AVAILCPU;
   sysctl(mib, 2, &num_cpu, &_len, NULL, 0);
   if (num_cpu < 1)
   {
      mib[1] = HW_NCPU;
      sysctl(mib, 2, &num_cpu, &_len, NULL, 0);
      if (num_cpu < 1)
         num_cpu = 1;
   }
   return num_cpu;
#elif defined(__linux__)
   CpuList  cpus_present[1];
   CpuList  cpus_possible[1];
   int amount = 0;

   cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
   cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");

   /* Compute the intersection of both sets to get the actual number of
    * CPU cores that can be used on this device by the kernel.
    */
   cpus_present->mask &= cpus_possible->mask;
   amount              = __builtin_popcount(cpus_present->mask);

   if (amount == 0)
      return 1;
   return amount;
#elif defined(_XBOX360)
   return 3;
#else
   /* No idea, assume single core. */
   return 1;
#endif
}

/* According to http://en.wikipedia.org/wiki/CPUID */
#define VENDOR_INTEL_b  0x756e6547
#define VENDOR_INTEL_c  0x6c65746e
#define VENDOR_INTEL_d  0x49656e69

uint64_t cpu_features_get(void)
{
   uint64_t cpu        = 0;
#if defined(CPU_X86) && !defined(__MACH__)
   int vendor_is_intel = 0;
   const int avx_flags = (1 << 27) | (1 << 28);
#endif
#if defined(__MACH__)
   size_t _len          = sizeof(size_t);
   if (sysctlbyname("hw.optional.floatingpoint", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_CMOV;

#if defined(CPU_X86)
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.mmx", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_MMX | RETRO_SIMD_MMXEXT;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse2", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE2;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse3", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE3;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.supplementalsse3", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSSE3;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse4_1", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE4;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse4_2", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE42;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.aes", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_AES;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.avx1_0", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_AVX;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.avx2_0", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_AVX2;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.altivec", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_VMX;
#else
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.neon", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_NEON;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.neon_fp16", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_VFPV3;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.neon_hpfp", NULL, &_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_VFPV4;
#endif
#elif defined(_XBOX1)
   cpu |= RETRO_SIMD_MMX | RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
#elif defined(CPU_X86)
   unsigned max_flag   = 0;
   int32_t flags[4];
   int vendor_shuffle[3];
   char vendor[13];
   x86_cpuid(0, flags);
   vendor_shuffle[0] = flags[1];
   vendor_shuffle[1] = flags[3];
   vendor_shuffle[2] = flags[2];

   vendor[0]         = '\0';
   memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));

   /* printf("[CPUID]: Vendor: %s\n", vendor); */

   vendor_is_intel = (
         flags[1] == VENDOR_INTEL_b &&
         flags[2] == VENDOR_INTEL_c &&
         flags[3] == VENDOR_INTEL_d);

   max_flag = flags[0];
   if (max_flag < 1) /* Does CPUID not support func = 1? (unlikely ...) */
      return 0;

   x86_cpuid(1, flags);

   if (flags[3] & (1 << 15))
      cpu |= RETRO_SIMD_CMOV;

   if (flags[3] & (1 << 23))
      cpu |= RETRO_SIMD_MMX;

   /* SSE also implies MMXEXT (according to FFmpeg source). */
   if (flags[3] & (1 << 25))
      cpu |= RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;

   if (flags[3] & (1 << 26))
      cpu |= RETRO_SIMD_SSE2;

   if (flags[2] & (1 << 0))
      cpu |= RETRO_SIMD_SSE3;

   if (flags[2] & (1 << 9))
      cpu |= RETRO_SIMD_SSSE3;

   if (flags[2] & (1 << 19))
      cpu |= RETRO_SIMD_SSE4;

   if (flags[2] & (1 << 20))
      cpu |= RETRO_SIMD_SSE42;

   if ((flags[2] & (1 << 23)))
      cpu |= RETRO_SIMD_POPCNT;

   if (vendor_is_intel && (flags[2] & (1 << 22)))
      cpu |= RETRO_SIMD_MOVBE;

   if (flags[2] & (1 << 25))
      cpu |= RETRO_SIMD_AES;

   /* Must only perform xgetbv check if we have
    * AVX CPU support (guaranteed to have at least i686). */
   if (((flags[2] & avx_flags) == avx_flags)
         && ((xgetbv_x86(0) & 0x6) == 0x6))
      cpu |= RETRO_SIMD_AVX;

   if (max_flag >= 7)
   {
      x86_cpuid(7, flags);
      if (flags[1] & (1 << 5))
         cpu |= RETRO_SIMD_AVX2;
   }

   x86_cpuid(0x80000000, flags);
   max_flag = flags[0];
   if (max_flag >= 0x80000001u)
   {
      x86_cpuid(0x80000001, flags);
      if (flags[3] & (1 << 23))
         cpu |= RETRO_SIMD_MMX;
      if (flags[3] & (1 << 22))
         cpu |= RETRO_SIMD_MMXEXT;
   }
#elif defined(__linux__)
   if (check_arm_cpu_feature("neon"))
   {
      cpu |= RETRO_SIMD_NEON;
#if defined(__ARM_NEON__) && defined(__arm__)
      arm_enable_runfast_mode();
#endif
   }

   if (check_arm_cpu_feature("vfpv3"))
      cpu |= RETRO_SIMD_VFPV3;

   if (check_arm_cpu_feature("vfpv4"))
      cpu |= RETRO_SIMD_VFPV4;

   if (check_arm_cpu_feature("asimd"))
   {
      cpu |= RETRO_SIMD_ASIMD;
#ifdef __ARM_NEON__
      cpu |= RETRO_SIMD_NEON;
#if defined(__arm__)
      arm_enable_runfast_mode();
#endif
#endif
   }
#elif defined(__ARM_NEON__)
   cpu |= RETRO_SIMD_NEON;
#if defined(__arm__)
   arm_enable_runfast_mode();
#endif
#elif defined(__ALTIVEC__)
   cpu |= RETRO_SIMD_VMX;
#elif defined(XBOX360)
   cpu |= RETRO_SIMD_VMX128;
#elif defined(PSP) || defined(PS2)
   cpu |= RETRO_SIMD_VFPU;
#elif defined(GEKKO)
   cpu |= RETRO_SIMD_PS;
#endif

   return cpu;
}

void cpu_features_get_model_name(char *s, int len)
{
#if defined(CPU_X86) && !defined(__MACH__)
   union {
      int32_t i[4];
      uint32_t u[4];
      uint8_t s[16];
   } flags;
   int i, j;
   int pos = 0;
   bool start = false;

   if (!s)
      return;

   x86_cpuid(0x80000000, flags.i);

   /* Check for additional cpuid attributes availability */
   if (flags.u[0] < 0x80000004)
      return;

   for (i = 0; i < 3; i++)
   {
      memset(flags.i, 0, sizeof(flags.i));
      x86_cpuid(0x80000002 + i, flags.i);

      for (j = 0; j < (int)sizeof(flags.s); j++)
      {
         if (!start && flags.s[j] == ' ')
            continue;
         else
            start = true;

         if (pos == len - 1)
         {
            /* truncate if we ran out of room */
            s[pos] = '\0';
            goto end;
         }

         s[pos++] = flags.s[j];
      }
   }
end:
   /* terminate our string */
   if (pos < len)
      s[pos] = '\0';
#elif defined(__MACH__)
   if (!s)
      return;
   {
      size_t __len = len;
      sysctlbyname("machdep.cpu.brand_string", s, &__len, NULL, 0);
   }
#elif defined(__linux__)
   if (!s)
      return;
   {
      char *model_name, line[128];
      RFILE *fp = filestream_open("/proc/cpuinfo",
            RETRO_VFS_FILE_ACCESS_READ,
            RETRO_VFS_FILE_ACCESS_HINT_NONE);

      if (!fp)
         return;

      while (filestream_gets(fp, line, sizeof(line)))
      {
         if (strncmp(line, "model name", 10))
            continue;

         if ((model_name = strstr(line + 10, ": ")))
         {
            model_name += 2;
            strncpy(s, model_name, len);
            s[len - 1] = '\0';
         }

         break;
      }

      filestream_close(fp);
   }
#endif
}

./include/libretro-common/file/archive_file_7z.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file_sevenzip.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>

#include <boolean.h>
#include <file/archive_file.h>
#include <streams/file_stream.h>
#include <retro_miscellaneous.h>
#include <encodings/utf.h>
#include <encodings/crc32.h>
#include <string/stdstring.h>
#include <lists/string_list.h>
#include <file/file_path.h>
#include <compat/strl.h>
#include <7zip/7z.h>
#include <7zip/7zCrc.h>
#include <7zip/7zFile.h>

#define SEVENZIP_MAGIC "7z\xBC\xAF\x27\x1C"
#define SEVENZIP_MAGIC_LEN 6
#define SEVENZIP_LOOKTOREAD_BUF_SIZE (1 << 14)

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif
#endif

struct sevenzip_context_t
{
   uint8_t *output;
   CFileInStream archiveStream;
   CLookToRead2 lookStream;
   ISzAlloc allocImp;
   ISzAlloc allocTempImp;
   CSzArEx db;
   size_t temp_size;
   uint32_t parse_index;
   uint32_t decompress_index;
   uint32_t packIndex;
   uint32_t block_index;
};

static void *sevenzip_stream_alloc_impl(ISzAllocPtr p, size_t len)
{
   if (len == 0)
      return 0;
   return malloc(len);
}

static void sevenzip_stream_free_impl(ISzAllocPtr p, void *address)
{
   if (address)
      free(address);
}

static void *sevenzip_stream_alloc_tmp_impl(ISzAllocPtr p, size_t len)
{
   if (len == 0)
      return 0;
   return malloc(len);
}

static void* sevenzip_stream_new(void)
{
   struct sevenzip_context_t *sevenzip_context =
         (struct sevenzip_context_t*)calloc(1, sizeof(struct sevenzip_context_t));

   /* These are the allocation routines - currently using
    * the non-standard 7zip choices. */
   sevenzip_context->allocImp.Alloc     = sevenzip_stream_alloc_impl;
   sevenzip_context->allocImp.Free      = sevenzip_stream_free_impl;
   sevenzip_context->allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;
   sevenzip_context->allocTempImp.Free  = sevenzip_stream_free_impl;
   sevenzip_context->block_index        = 0xFFFFFFFF;
   sevenzip_context->output             = NULL;

   sevenzip_context->lookStream.bufSize = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);
   sevenzip_context->lookStream.buf     = (Byte*)malloc(sevenzip_context->lookStream.bufSize);

   if (!sevenzip_context->lookStream.buf)
      sevenzip_context->lookStream.bufSize = 0;

   return sevenzip_context;
}

static void sevenzip_parse_file_free(void *context)
{
   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;

   if (!sevenzip_context)
      return;

   if (sevenzip_context->output)
   {
      IAlloc_Free(&sevenzip_context->allocImp, sevenzip_context->output);
      sevenzip_context->output       = NULL;
   }

   SzArEx_Free(&sevenzip_context->db, &sevenzip_context->allocImp);
   File_Close(&sevenzip_context->archiveStream.file);

   if (sevenzip_context->lookStream.buf)
      free(sevenzip_context->lookStream.buf);

   free(sevenzip_context);
}

/* Extract the relative path (needle) from a 7z archive
 * (path) and allocate a buf for it to write it in.
 * If optional_outfile is set, extract to that instead
 * and don't allocate buffer.
 */
static int64_t sevenzip_file_read(
      const char *path,
      const char *needle, void **buf,
      const char *optional_outfile)
{
   CSzArEx db;
   CFileInStream archiveStream;
   CLookToRead2 lookStream;
   ISzAlloc allocImp;
   ISzAlloc allocTempImp;
   uint8_t *output      = 0;
   int64_t outsize      = -1;

   /*These are the allocation routines.
    * Currently using the non-standard 7zip choices. */
   allocImp.Alloc       = sevenzip_stream_alloc_impl;
   allocImp.Free        = sevenzip_stream_free_impl;
   allocTempImp.Alloc   = sevenzip_stream_alloc_tmp_impl;
   allocTempImp.Free    = sevenzip_stream_free_impl;

   lookStream.bufSize   = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);
   lookStream.buf       = (Byte*)malloc(lookStream.bufSize);

   if (!lookStream.buf)
      lookStream.bufSize = 0;

#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)
   if (!string_is_empty(path))
   {
      wchar_t *path_w = utf8_to_utf16_string_alloc(path);
      if (path_w)
      {
         /* Could not open 7zip archive? */
         if (InFile_OpenW(&archiveStream.file, path_w))
         {
            free(path_w);
            return -1;
         }
         free(path_w);
      }
   }
#else
   /* Could not open 7zip archive? */
   if (InFile_Open(&archiveStream.file, path))
      return -1;
#endif

   FileInStream_CreateVTable(&archiveStream);
   LookToRead2_CreateVTable(&lookStream, false);
   lookStream.realStream = &archiveStream.vt;
   LookToRead2_Init(&lookStream);
   CrcGenerateTable();

   memset(&db, 0, sizeof(db));

   SzArEx_Init(&db);

   if (SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp) == SZ_OK)
   {
      uint32_t i;
      bool file_found      = false;
      uint16_t *temp       = NULL;
      size_t temp_size     = 0;
      uint32_t block_index   = 0xFFFFFFFF;
      SRes res             = SZ_OK;

      for (i = 0; i < db.NumFiles; i++)
      {
         size_t _len;
         char infile[PATH_MAX_LENGTH];
         size_t offset                = 0;
         size_t outSizeProcessed      = 0;

         /* We skip over everything which is not a directory.
          * FIXME: Why continue then if IsDir is true?*/
         if (SzArEx_IsDir(&db, i))
            continue;

         _len = SzArEx_GetFileNameUtf16(&db, i, NULL);

         if (_len > temp_size)
         {
            if (temp)
               free(temp);
            temp_size = _len;
            temp      = (uint16_t *)malloc(temp_size * sizeof(temp[0]));

            if (temp == 0)
            {
               res = SZ_ERROR_MEM;
               break;
            }
         }

         SzArEx_GetFileNameUtf16(&db, i, temp);
         res       = SZ_ERROR_FAIL;
         infile[0] = '\0';

         if (temp)
            res = utf16_to_char_string(temp, infile, sizeof(infile))
               ? SZ_OK : SZ_ERROR_FAIL;

         if (string_is_equal(infile, needle))
         {
            size_t output_size   = 0;

            /* C LZMA SDK does not support chunked extraction - see here:
             * sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/
             * */
            file_found = true;
            res = SzArEx_Extract(&db, &lookStream.vt, i, &block_index,
                  &output, &output_size, &offset, &outSizeProcessed,
                  &allocImp, &allocTempImp);

            if (res != SZ_OK)
               break; /* This goes to the error section. */

            outsize = (int64_t)outSizeProcessed;

            if (optional_outfile)
            {
               const void *ptr = (const void*)(output + offset);

               if (!filestream_write_file(optional_outfile, ptr, outsize))
               {
                  res        = SZ_OK;
                  file_found = true;
                  outsize    = -1;
               }
            }
            else
            {
               /*We could either use the 7Zip allocated buffer,
                * or create our own and use it.
                * We would however need to realloc anyways, because RetroArch
                * expects a \0 at the end, therefore we allocate new,
                * copy and free the old one. */
               *buf = malloc((size_t)(outsize + 1));
               ((char*)(*buf))[outsize] = '\0';
               memcpy(*buf, output + offset, outsize);
            }
            break;
         }
      }

      if (temp)
         free(temp);
      IAlloc_Free(&allocImp, output);

      if (!(file_found && res == SZ_OK))
      {
         /* Error handling
          *
          * Failed to open compressed file inside 7zip archive.
          */

         outsize    = -1;
      }
   }

   SzArEx_Free(&db, &allocImp);
   File_Close(&archiveStream.file);

   if (lookStream.buf)
      free(lookStream.buf);

   return outsize;
}

static bool sevenzip_stream_decompress_data_to_file_init(
      void *context, file_archive_file_handle_t *handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
{
   struct sevenzip_context_t *sevenzip_context =
         (struct sevenzip_context_t*)context;

   if (!sevenzip_context)
      return false;

   sevenzip_context->decompress_index = (uint32_t)(size_t)cdata;

   return true;
}

static int sevenzip_stream_decompress_data_to_file_iterate(
      void *context, file_archive_file_handle_t *handle)
{
   struct sevenzip_context_t *sevenzip_context =
         (struct sevenzip_context_t*)context;

   SRes res                = SZ_ERROR_FAIL;
   size_t output_size      = 0;
   size_t offset           = 0;
   size_t outSizeProcessed = 0;

   res = SzArEx_Extract(&sevenzip_context->db,
         &sevenzip_context->lookStream.vt, sevenzip_context->decompress_index,
         &sevenzip_context->block_index, &sevenzip_context->output,
         &output_size, &offset, &outSizeProcessed,
         &sevenzip_context->allocImp, &sevenzip_context->allocTempImp);

   if (res != SZ_OK)
      return 0;

   if (handle)
      handle->data = sevenzip_context->output + offset;

   return 1;
}

static int sevenzip_parse_file_init(file_archive_transfer_t *state,
      const char *file)
{
   uint8_t magic_buf[SEVENZIP_MAGIC_LEN];
   struct sevenzip_context_t *sevenzip_context = NULL;

   if (state->archive_size < SEVENZIP_MAGIC_LEN)
      goto error;

   filestream_seek(state->archive_file, 0, SEEK_SET);
   if (filestream_read(state->archive_file, magic_buf, SEVENZIP_MAGIC_LEN) != SEVENZIP_MAGIC_LEN)
      goto error;

   if (memcmp(magic_buf, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN) != 0)
      goto error;

   sevenzip_context = (struct sevenzip_context_t*)sevenzip_stream_new();
   state->context = sevenzip_context;

#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)
   if (!string_is_empty(file))
   {
      wchar_t *file_w = utf8_to_utf16_string_alloc(file);

      if (file_w)
      {
         /* could not open 7zip archive? */
         if (InFile_OpenW(&sevenzip_context->archiveStream.file, file_w))
         {
            free(file_w);
            goto error;
         }

         free(file_w);
      }
   }
#else
   /* could not open 7zip archive? */
   if (InFile_Open(&sevenzip_context->archiveStream.file, file))
      goto error;
#endif

   FileInStream_CreateVTable(&sevenzip_context->archiveStream);
   LookToRead2_CreateVTable(&sevenzip_context->lookStream, false);
   sevenzip_context->lookStream.realStream = &sevenzip_context->archiveStream.vt;
   LookToRead2_Init(&sevenzip_context->lookStream);
   CrcGenerateTable();
   SzArEx_Init(&sevenzip_context->db);

   if (SzArEx_Open(&sevenzip_context->db, &sevenzip_context->lookStream.vt,
         &sevenzip_context->allocImp, &sevenzip_context->allocTempImp) != SZ_OK)
      goto error;

   state->step_total = sevenzip_context->db.NumFiles;

   return 0;

error:
   if (sevenzip_context)
      sevenzip_parse_file_free(sevenzip_context);
   state->context = NULL;
   return -1;
}

static int sevenzip_parse_file_iterate_step_internal(
      struct sevenzip_context_t *sevenzip_context,
      char *s,
      const uint8_t **cdata,
      unsigned *cmode,
      uint32_t *size,
      uint32_t *csize,
      uint32_t *checksum,
      unsigned *payback,
      struct archive_extract_userdata *userdata)
{
   if (sevenzip_context->parse_index < sevenzip_context->db.NumFiles)
   {
      size_t _len = SzArEx_GetFileNameUtf16(&sevenzip_context->db,
            sevenzip_context->parse_index, NULL);
      uint64_t compressed_size = 0;

      if (sevenzip_context->packIndex < sevenzip_context->db.db.NumPackStreams)
      {
         compressed_size = sevenzip_context->db.db.PackPositions[sevenzip_context->packIndex + 1] -
               sevenzip_context->db.db.PackPositions[sevenzip_context->packIndex];

         sevenzip_context->packIndex++;
      }

      if (   (_len < PATH_MAX_LENGTH)
          && !SzArEx_IsDir(&sevenzip_context->db, sevenzip_context->parse_index))
      {
         SRes res       = SZ_ERROR_FAIL;
         uint16_t *temp = (uint16_t*)malloc(_len * sizeof(uint16_t));

         if (!temp)
            return -1;

         SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->parse_index,
               temp);

         if (temp)
         {
            res  = utf16_to_char_string(temp, s, PATH_MAX_LENGTH)
               ? SZ_OK : SZ_ERROR_FAIL;
            free(temp);
         }

         if (res != SZ_OK)
            return -1;

         *cmode    = 0; /* unused for 7zip */
         *checksum = sevenzip_context->db.CRCs.Vals[sevenzip_context->parse_index];
         *size     = (uint32_t)SzArEx_GetFileSize(&sevenzip_context->db, sevenzip_context->parse_index);
         *csize    = (uint32_t)compressed_size;

         *cdata    = (uint8_t *)(size_t)sevenzip_context->parse_index;
      }
   }
   else
      return 0;

   *payback = 1;

   return 1;
}

static int sevenzip_parse_file_iterate_step(void *context,
      const char *valid_exts,
      struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)
{
   const uint8_t *cdata = NULL;
   uint32_t checksum    = 0;
   uint32_t size        = 0;
   uint32_t csize       = 0;
   unsigned cmode       = 0;
   unsigned payload     = 0;
   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;
   int ret;

   userdata->current_file_path[0] = '\0';

   ret = sevenzip_parse_file_iterate_step_internal(sevenzip_context,
         userdata->current_file_path,
         &cdata, &cmode, &size, &csize,
         &checksum, &payload, userdata);

   if (ret != 1)
      return ret;

   userdata->crc                 = checksum;

   if (file_cb && !file_cb(userdata->current_file_path, valid_exts,
            cdata, cmode,
            csize, size, checksum, userdata))
      return 0;

   sevenzip_context->parse_index += payload;

   return 1;
}

static uint32_t sevenzip_stream_crc32_calculate(uint32_t crc,
      const uint8_t *data, size_t len)
{
   return encoding_crc32(crc, data, len);
}

const struct file_archive_file_backend sevenzip_backend = {
   sevenzip_parse_file_init,
   sevenzip_parse_file_iterate_step,
   sevenzip_parse_file_free,
   sevenzip_stream_decompress_data_to_file_init,
   sevenzip_stream_decompress_data_to_file_iterate,
   sevenzip_stream_crc32_calculate,
   sevenzip_file_read,
   "7z"
};

./include/libretro-common/file/archive_file.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <compat/strl.h>
#include <file/archive_file.h>
#include <file/file_path.h>
#include <streams/file_stream.h>
#include <retro_miscellaneous.h>
#include <lists/string_list.h>
#include <string/stdstring.h>

#ifdef HAVE_MMAP
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#endif

static int file_archive_get_file_list_cb(
      const char *path,
      const char *valid_exts,
      const uint8_t *cdata,
      unsigned cmode,
      uint32_t csize,
      uint32_t size,
      uint32_t checksum,
      struct archive_extract_userdata *userdata)
{
   union string_list_elem_attr attr;
   attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;

   if (valid_exts)
   {
      size_t _len                  = strlen(path);
      /* Checks if this entry is a directory or a file. */
      char last_char               = path[_len - 1];
      struct string_list ext_list  = {0};

      /* Skip if directory. */
      if (last_char == '/' || last_char == '\\' )
         return 1;

      string_list_initialize(&ext_list);
      if (string_split_noalloc(&ext_list, valid_exts, "|"))
      {
         const char *file_ext = path_get_extension(path);

         if (!file_ext)
         {
            string_list_deinitialize(&ext_list);
            return 1;
         }

         if (!string_list_find_elem_prefix(&ext_list, ".", file_ext))
         {
            /* keep iterating */
            string_list_deinitialize(&ext_list);
            return -1;
         }
      }

      string_list_deinitialize(&ext_list);
   }

   return string_list_append(userdata->list, path, attr);
}

static int file_archive_extract_cb(const char *name, const char *valid_exts,
      const uint8_t *cdata,
      unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t checksum, struct archive_extract_userdata *userdata)
{
   const char *ext                   = path_get_extension(name);

   /* Extract first file that matches our list. */
   if (ext && string_list_find_elem(userdata->ext, ext))
   {
      char new_path[PATH_MAX_LENGTH];
      const char *delim;

      if ((delim = path_get_archive_delim(userdata->archive_path)))
      {
         if (!string_is_equal_noncase(
                  userdata->current_file_path, delim + 1))
           return 1; /* keep searching for the right file */
      }

      if (userdata->extraction_directory)
         fill_pathname_join_special(new_path, userdata->extraction_directory,
               path_basename(name), sizeof(new_path));
      else
         fill_pathname_resolve_relative(new_path, userdata->archive_path,
               path_basename(name), sizeof(new_path));

      if (file_archive_perform_mode(new_path,
                valid_exts, cdata, cmode, csize, size,
                checksum, userdata))
      {
         userdata->found_file = true;
         userdata->first_extracted_file_path = strdup(new_path);
      }

      return 0;
   }

   return 1;
}

static int file_archive_parse_file_init(file_archive_transfer_t *state,
      const char *file)
{
   char path[PATH_MAX_LENGTH];
   char *last                 = NULL;

   strlcpy(path, file, sizeof(path));

   if ((last = (char*)path_get_archive_delim(path)))
      *last  = '\0';

   if (!(state->backend = file_archive_get_file_backend(path)))
      return -1;

   /* Failed to open archive. */
   if (!(state->archive_file = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return -1;

   state->archive_size = filestream_get_size(state->archive_file);

#ifdef HAVE_MMAP
   if (state->archive_size <= (256*1024*1024))
   {
      state->archive_mmap_fd = open(path, O_RDONLY);
      if (state->archive_mmap_fd)
      {
         state->archive_mmap_data = (uint8_t*)mmap(NULL,
               (size_t)state->archive_size,
               PROT_READ, MAP_SHARED, state->archive_mmap_fd, 0);

         if (state->archive_mmap_data == (uint8_t*)MAP_FAILED)
         {
            close(state->archive_mmap_fd);
            state->archive_mmap_fd = 0;
            state->archive_mmap_data = NULL;
         }
      }
   }
#endif

   state->step_current = 0;
   state->step_total   = 0;

   return state->backend->archive_parse_file_init(state, path);
}

void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state)
{
   if (!state || !state->archive_file)
      return;

   state->type = ARCHIVE_TRANSFER_DEINIT;
   file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL);
}

int file_archive_parse_file_iterate(
      file_archive_transfer_t *state,
      bool *returnerr,
      const char *file,
      const char *valid_exts,
      file_archive_file_cb file_cb,
      struct archive_extract_userdata *userdata)
{
   if (!state)
      return -1;

   switch (state->type)
   {
      case ARCHIVE_TRANSFER_NONE:
         break;
      case ARCHIVE_TRANSFER_INIT:
         if (file_archive_parse_file_init(state, file) == 0)
         {
            if (userdata)
            {
               userdata->transfer = state;
               strlcpy(userdata->archive_path, file,
                     sizeof(userdata->archive_path));
            }
            state->type = ARCHIVE_TRANSFER_ITERATE;
         }
         else
            state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
         break;
      case ARCHIVE_TRANSFER_ITERATE:
         if (state->backend)
         {
            int ret = state->backend->archive_parse_file_iterate_step(
                  state->context, valid_exts, userdata, file_cb);

            if (ret == 1)
               state->step_current++; /* found another file */
            if (ret != 1)
               state->type = ARCHIVE_TRANSFER_DEINIT;
            if (ret == -1)
               state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;

            /* early return to prevent deinit from never firing */
            return 0;
         }
         return -1;
      case ARCHIVE_TRANSFER_DEINIT_ERROR:
         *returnerr = false;
      case ARCHIVE_TRANSFER_DEINIT:
         if (state->context)
         {
            if (state->backend->archive_parse_file_free)
               state->backend->archive_parse_file_free(state->context);
            state->context = NULL;
         }

         if (state->archive_file)
         {
            filestream_close(state->archive_file);
            state->archive_file = NULL;
         }

#ifdef HAVE_MMAP
         if (state->archive_mmap_data)
         {
            munmap(state->archive_mmap_data, (size_t)state->archive_size);
            close(state->archive_mmap_fd);
            state->archive_mmap_fd = 0;
            state->archive_mmap_data = NULL;
         }
#endif

         if (userdata)
            userdata->transfer = NULL;
         break;
   }

   if (  state->type == ARCHIVE_TRANSFER_DEINIT ||
         state->type == ARCHIVE_TRANSFER_DEINIT_ERROR)
      return -1;

   return 0;
}

/**
 * file_archive_walk:
 * @file                        : filename path of archive
 * @valid_exts                  : Valid extensions of archive to be parsed.
 *                                If NULL, allow all.
 * @file_cb                     : file_cb function pointer
 * @userdata                    : userdata to pass to file_cb function pointer.
 *
 * Low-level file parsing. Enumerates over all files and calls
 * file_cb with userdata.
 *
 * Returns: true (1) on success, otherwise false (0).
 **/
static bool file_archive_walk(const char *file, const char *valid_exts,
      file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)
{
   file_archive_transfer_t state;
   bool returnerr          = true;

   state.type              = ARCHIVE_TRANSFER_INIT;
   state.archive_file      = NULL;
#ifdef HAVE_MMAP
   state.archive_mmap_fd   = 0;
   state.archive_mmap_data = NULL;
#endif
   state.archive_size      = 0;
   state.context           = NULL;
   state.step_total        = 0;
   state.step_current      = 0;
   state.backend           = NULL;

   for (;;)
   {
      if (file_archive_parse_file_iterate(&state, &returnerr, file,
            valid_exts, file_cb, userdata) != 0)
         break;
   }

   return returnerr;
}

int file_archive_parse_file_progress(file_archive_transfer_t *state)
{
   if (!state || state->step_total == 0)
      return 0;

   return (int)((state->step_current * 100) / (state->step_total));
}

/**
 * file_archive_extract_file:
 * @archive_path                : filename path to archive.
 * @valid_exts                  : valid extensions for the file.
 * @extraction_directory        : the directory to extract temporary
 *                                file to.
 *
 * Extract file from archive. If no file inside the archive is
 * specified, the first file found will be used.
 *
 * Returns : true (1) on success, otherwise false (0).
 **/
bool file_archive_extract_file(
      const char *archive_path,
      const char *valid_exts,
      const char *extraction_directory,
      char *s, size_t len)
{
   struct archive_extract_userdata userdata;
   struct string_list *list                 = string_split(valid_exts, "|");

   userdata.archive_path[0]                 = '\0';
   userdata.current_file_path[0]            = '\0';
   userdata.first_extracted_file_path       = NULL;
   userdata.extraction_directory            = extraction_directory;
   userdata.ext                             = list;
   userdata.list                            = NULL;
   userdata.found_file                      = false;
   userdata.list_only                       = false;
   userdata.crc                             = 0;
   userdata.transfer                        = NULL;
   userdata.dec                             = NULL;

   if (     list
         && file_archive_walk(archive_path, valid_exts,
            file_archive_extract_cb, &userdata)
         && userdata.found_file
      )
   {
      if (!string_is_empty(userdata.first_extracted_file_path))
         strlcpy(s, userdata.first_extracted_file_path, len);
      return true;
   }

   if (userdata.first_extracted_file_path)
      free(userdata.first_extracted_file_path);
   if (list)
      string_list_free(list);
   return false;
}

/* Warning: 'list' must zero initialised before
 * calling this function, otherwise memory leaks/
 * undefined behaviour will occur */
bool file_archive_get_file_list_noalloc(struct string_list *list,
      const char *path,
      const char *valid_exts)
{
   struct archive_extract_userdata userdata;

   if (!list || !string_list_initialize(list))
      return false;

   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
   userdata.current_file_path[0]            = '\0';
   userdata.first_extracted_file_path       = NULL;
   userdata.extraction_directory            = NULL;
   userdata.ext                             = NULL;
   userdata.list                            = list;
   userdata.found_file                      = false;
   userdata.list_only                       = true;
   userdata.crc                             = 0;
   userdata.transfer                        = NULL;
   userdata.dec                             = NULL;

   if (!file_archive_walk(path, valid_exts,
            file_archive_get_file_list_cb, &userdata))
      return false;
   return true;
}

/**
 * file_archive_get_file_list:
 * @path                        : filename path of archive
 *
 * Returns: string listing of files from archive on success, otherwise NULL.
 **/
struct string_list *file_archive_get_file_list(const char *path,
      const char *valid_exts)
{
   struct archive_extract_userdata userdata;

   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
   userdata.current_file_path[0]            = '\0';
   userdata.first_extracted_file_path       = NULL;
   userdata.extraction_directory            = NULL;
   userdata.ext                             = NULL;
   userdata.list                            = string_list_new();
   userdata.found_file                      = false;
   userdata.list_only                       = true;
   userdata.crc                             = 0;
   userdata.transfer                        = NULL;
   userdata.dec                             = NULL;

   if (!userdata.list)
      return NULL;
   if (!file_archive_walk(path, valid_exts,
         file_archive_get_file_list_cb, &userdata))
   {
      string_list_free(userdata.list);
      return NULL;
   }
   return userdata.list;
}

bool file_archive_perform_mode(const char *path, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata)
{
   int ret;
   file_archive_file_handle_t handle;

   if (!userdata->transfer || !userdata->transfer->backend)
      return false;

   handle.data          = NULL;
   handle.real_checksum = 0;

   if (!userdata->transfer->backend->stream_decompress_data_to_file_init(
            userdata->transfer->context, &handle, cdata, cmode, csize, size))
      return false;

   do
   {
      ret = userdata->transfer->backend->stream_decompress_data_to_file_iterate(
               userdata->transfer->context, &handle);
   }while (ret == 0);

   if (ret == -1 || !filestream_write_file(path, handle.data, size))
      return false;

   return true;
}

/**
 * string_list_append_n:
 * @list             : pointer to string list
 * @elem             : element to add to the string list
 * @length           : read at most this many bytes from elem
 * @attr             : attributes of new element.
 *
 * Appends a new element to the string list.
 *
 * @return true if successful, otherwise false.
 **/
static bool string_list_append_n(struct string_list *list,
      const char *elem, unsigned length,
      union string_list_elem_attr attr)
{
   char *data_dup = NULL;

   if (list->size >= list->cap &&
         !string_list_capacity(list, list->cap * 2))
      return false;

   if (!(data_dup = (char*)malloc(length + 1)))
      return false;

   strlcpy(data_dup, elem, length + 1);

   list->elems[list->size].data = data_dup;
   list->elems[list->size].attr = attr;

   list->size++;
   return true;
}


/**
 * file_archive_filename_split:
 * @str              : filename to turn into a string list
 *
 * Creates a new string list based on filename @path, delimited by a hash (#).
 *
 * Returns: new string list if successful, otherwise NULL.
 */
static struct string_list *file_archive_filename_split(const char *path)
{
   union string_list_elem_attr attr;
   struct string_list *list = string_list_new();
   const char *delim        = path_get_archive_delim(path);

   attr.i = 0;

   if (delim)
   {
      /* add archive path to list first */
      if (!string_list_append_n(list, path, (unsigned)(delim - path), attr))
      {
         string_list_free(list);
         return NULL;
      }

      /* now add the path within the archive */
      delim++;

      if (*delim)
      {
         if (!string_list_append(list, delim, attr))
         {
            string_list_free(list);
            return NULL;
         }
      }
   }
   else
   {
      if (!string_list_append(list, path, attr))
      {
         string_list_free(list);
         return NULL;
      }
   }

   return list;
}

/* Generic compressed file loader.
 * Extracts to buf, unless optional_filename != 0
 * Then extracts to optional_filename and leaves buf alone.
 */
int file_archive_compressed_read(
      const char * path, void **buf,
      const char* optional_filename, int64_t *len)
{
   const struct
      file_archive_file_backend *backend = NULL;
   struct string_list *str_list          = NULL;

   /* Safety check.
    * If optional_filename and optional_filename
    * exists, we simply return 0,
    * hoping that optional_filename is the
    * same as requested.
    */
   if (optional_filename && path_is_valid(optional_filename))
   {
      *len = 0;
      return 1;
   }

   str_list       = file_archive_filename_split(path);
   /* We assure that there is something after the '#' symbol.
    *
    * This error condition happens for example, when
    * path = /path/to/file.7z, or
    * path = /path/to/file.7z#
    */
   if (str_list->size <= 1)
   {
      /* could not extract string and substring. */
      string_list_free(str_list);
      *len = 0;
      return 0;
   }

   backend = file_archive_get_file_backend(str_list->elems[0].data);
   *len    = backend->compressed_file_read(str_list->elems[0].data,
         str_list->elems[1].data, buf, optional_filename);

   string_list_free(str_list);

   if (*len != -1)
      return 1;

   return 0;
}

const struct file_archive_file_backend *file_archive_get_zlib_file_backend(void)
{
#ifdef HAVE_ZLIB
   return &zlib_backend;
#else
   return NULL;
#endif
}

const struct file_archive_file_backend *file_archive_get_7z_file_backend(void)
{
#ifdef HAVE_7ZIP
   return &sevenzip_backend;
#else
   return NULL;
#endif
}

const struct file_archive_file_backend* file_archive_get_file_backend(const char *path)
{
#if defined(HAVE_7ZIP) || defined(HAVE_ZLIB)
   char newpath[PATH_MAX_LENGTH];
   const char *file_ext          = NULL;
   char *last                    = NULL;

   strlcpy(newpath, path, sizeof(newpath));

   if ((last = (char*)path_get_archive_delim(newpath)))
      *last  = '\0';

   file_ext  = path_get_extension(newpath);

#ifdef HAVE_7ZIP
   if (string_is_equal_noncase(file_ext, "7z"))
      return &sevenzip_backend;
#endif

#ifdef HAVE_ZLIB
   if (     string_is_equal_noncase(file_ext, "zip")
         || string_is_equal_noncase(file_ext, "apk")
      )
      return &zlib_backend;
#endif
#endif

   return NULL;
}

/**
 * file_archive_get_file_crc32:
 * @path                         : filename path of archive
 *
 * Returns: CRC32 of the specified file in the archive, otherwise 0.
 * If no path within the archive is specified, the first
 * file found inside is used.
 **/
uint32_t file_archive_get_file_crc32(const char *path)
{
   file_archive_transfer_t state;
   struct archive_extract_userdata userdata        = {0};
   bool returnerr                                  = false;
   const char *archive_path                        = NULL;
   bool contains_compressed = path_contains_compressed_file(path);

   if (contains_compressed)
   {
      archive_path = path_get_archive_delim(path);

      /* move pointer right after the delimiter to give us the path */
      if (archive_path)
         archive_path += 1;
   }

   state.type              = ARCHIVE_TRANSFER_INIT;
   state.archive_file      = NULL;
#ifdef HAVE_MMAP
   state.archive_mmap_fd   = 0;
   state.archive_mmap_data = NULL;
#endif
   state.archive_size      = 0;
   state.context           = NULL;
   state.step_total        = 0;
   state.step_current      = 0;
   state.backend           = NULL;

   /* Initialize and open archive first.
      Sets next state type to ITERATE. */
   file_archive_parse_file_iterate(&state,
            &returnerr, path, NULL, NULL,
            &userdata);

   for (;;)
   {
      /* Now find the first file in the archive. */
      if (state.type == ARCHIVE_TRANSFER_ITERATE)
         file_archive_parse_file_iterate(&state,
                  &returnerr, path, NULL, NULL,
                  &userdata);

      /* If no path specified within archive, stop after
       * finding the first file.
       */
      if (!contains_compressed)
         break;

      /* Stop when the right file in the archive is found. */
      if (archive_path)
      {
         if (string_is_equal(userdata.current_file_path, archive_path))
            break;
      }
      else
         break;
   }

   file_archive_parse_file_iterate_stop(&state);

   return userdata.crc;
}

./include/libretro-common/file/archive_file_zlib.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file_zlib.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <file/archive_file.h>
#include <streams/file_stream.h>
#include <retro_inline.h>
#include <retro_miscellaneous.h>
#include <encodings/crc32.h>

#include <zlib.h>

#ifndef CENTRAL_FILE_HEADER_SIGNATURE
#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
#endif

#ifndef END_OF_CENTRAL_DIR_SIGNATURE
#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
#endif

#define _READ_CHUNK_SIZE   (128*1024)   /* Read 128KiB compressed chunks */

enum file_archive_compression_mode
{
   ZIP_MODE_STORED   = 0,
   ZIP_MODE_DEFLATED = 8
};

typedef struct
{
   struct file_archive_transfer *state;
   uint8_t *directory;
   uint8_t *directory_entry;
   uint8_t *directory_end;
   uint64_t fdoffset;
   uint32_t boffset, csize, usize;
   unsigned cmode;
   z_stream *zstream;
   uint8_t *tmpbuf;
   uint8_t *decompressed_data;
} zip_context_t;

static INLINE uint32_t read_le(const uint8_t *data, size_t len)
{
   unsigned i;
   uint32_t val = 0;
   len *= 8;
   for (i = 0; i < len; i += 8)
      val |= (uint32_t)*data++ << i;
   return val;
}

static void zip_context_free_stream(
      zip_context_t *zip_context, bool keep_decompressed)
{
   if (zip_context->zstream)
   {
      inflateEnd(zip_context->zstream);
      free(zip_context->zstream);
      zip_context->fdoffset = 0;
      zip_context->csize = 0;
      zip_context->usize = 0;
      zip_context->zstream = NULL;
   }
   if (zip_context->tmpbuf)
   {
      free(zip_context->tmpbuf);
      zip_context->tmpbuf = NULL;
   }
   if (zip_context->decompressed_data && !keep_decompressed)
   {
      free(zip_context->decompressed_data);
      zip_context->decompressed_data = NULL;
   }
}

static bool zlib_stream_decompress_data_to_file_init(
      void *context, file_archive_file_handle_t *handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
{
   int64_t offsetData;
   uint8_t *local_header;
   uint32_t offsetNL, offsetEL;
   uint8_t local_header_buf[4];
   zip_context_t *zip_context = (zip_context_t *)context;
   struct file_archive_transfer *state = zip_context->state;

   /* free previous data and stream if left unfinished */
   zip_context_free_stream(zip_context, false);

   /* seek past most of the local directory header */
#ifdef HAVE_MMAP
   if (state->archive_mmap_data)
      local_header = state->archive_mmap_data + (size_t)cdata + 26;
   else
#endif
   {
      filestream_seek(state->archive_file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);
      if (filestream_read(state->archive_file, local_header_buf, 4) != 4)
      {
         zip_context_free_stream(zip_context, false);
         return false;
      }
      local_header = local_header_buf;
   }

   offsetNL = read_le(local_header,     2); /* file name length */
   offsetEL = read_le(local_header + 2, 2); /* extra field length */
   offsetData = (int64_t)(size_t)cdata + 26 + 4 + offsetNL + offsetEL;

   zip_context->fdoffset              = offsetData;
   zip_context->usize                 = size;
   zip_context->csize                 = csize;
   zip_context->boffset               = 0;
   zip_context->cmode                 = cmode;
   zip_context->decompressed_data     = (uint8_t*)malloc(size);
   zip_context->zstream               = NULL;
   zip_context->tmpbuf                = NULL;

   if (cmode == ZIP_MODE_DEFLATED)
   {
      /* Initialize the zlib inflate machinery */
      zip_context->zstream            = (z_stream*)malloc(sizeof(z_stream));
      zip_context->tmpbuf             = (uint8_t*)malloc(_READ_CHUNK_SIZE);

      zip_context->zstream->next_in   = NULL;
      zip_context->zstream->avail_in  = 0;
      zip_context->zstream->total_in  = 0;
      zip_context->zstream->next_out  = zip_context->decompressed_data;
      zip_context->zstream->avail_out = size;
      zip_context->zstream->total_out = 0;

      zip_context->zstream->zalloc    = NULL;
      zip_context->zstream->zfree     = NULL;
      zip_context->zstream->opaque    = NULL;

      if (inflateInit2(zip_context->zstream, -MAX_WBITS) != Z_OK)
      {
         free(zip_context->zstream);
         zip_context->zstream = NULL;
         zip_context_free_stream(zip_context, false);
         return false;
      }
   }

   return true;
}

static int zlib_stream_decompress_data_to_file_iterate(
      void *context, file_archive_file_handle_t *handle)
{
   int64_t rd;
   zip_context_t *zip_context = (zip_context_t *)context;
   struct file_archive_transfer *state = zip_context->state;

   if (zip_context->cmode == ZIP_MODE_STORED)
   {
#ifdef HAVE_MMAP
      /* Simply copy the data to the output buffer */
      if (zip_context->state->archive_mmap_data)
         memcpy(zip_context->decompressed_data,
               zip_context->state->archive_mmap_data + (size_t)zip_context->fdoffset,
               zip_context->usize);
      else
#endif
      {
         /* Read the entire file to memory */
         filestream_seek(state->archive_file, zip_context->fdoffset, RETRO_VFS_SEEK_POSITION_START);
         if (filestream_read(state->archive_file,
                             zip_context->decompressed_data,
                             zip_context->usize) < 0)
            return -1;
      }

      handle->data = zip_context->decompressed_data;
      return 1;
   }
   else if (zip_context->cmode == ZIP_MODE_DEFLATED)
   {
      uint8_t *dptr;
      int to_read = MIN(zip_context->csize - zip_context->boffset, _READ_CHUNK_SIZE);
      /* File was uncompressed or decompression finished before */
      if (!zip_context->zstream)
         return 1;

#ifdef HAVE_MMAP
      if (state->archive_mmap_data)
      {
         /* Decompress from the mapped file */
         dptr = state->archive_mmap_data + (size_t)zip_context->fdoffset + zip_context->boffset;
         rd   = to_read;
      }
      else
#endif
      {
         /* Read some compressed data from file to the temp buffer */
         filestream_seek(state->archive_file,
               zip_context->fdoffset + zip_context->boffset,
               RETRO_VFS_SEEK_POSITION_START);
         rd = filestream_read(state->archive_file, zip_context->tmpbuf, to_read);
         if (rd < 0)
            return -1;
         dptr = zip_context->tmpbuf;
      }

      zip_context->boffset           += rd;
      zip_context->zstream->next_in   = dptr;
      zip_context->zstream->avail_in  = (uInt)rd;

      if (inflate(zip_context->zstream, 0) < 0)
         return -1;

      if (zip_context->boffset >= zip_context->csize)
      {
         inflateEnd(zip_context->zstream);
         free(zip_context->zstream);
         zip_context->zstream = NULL;

         handle->data = zip_context->decompressed_data;
         return 1;
      }

      return 0;   /* still more data to process */
   }

   /* No idea what kind of compression this is */
   return -1;
}

static uint32_t zlib_stream_crc32_calculate(uint32_t crc,
      const uint8_t *data, size_t len)
{
   return encoding_crc32(crc, data, len);
}

static bool zip_file_decompressed_handle(
      file_archive_transfer_t *transfer,
      file_archive_file_handle_t* handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize,
      uint32_t size, uint32_t crc32)
{
   int ret   = 0;

   transfer->backend = &zlib_backend;

   if (!transfer->backend->stream_decompress_data_to_file_init(
            transfer->context, handle, cdata, cmode, csize, size))
      return false;

   do
   {
      ret = transfer->backend->stream_decompress_data_to_file_iterate(
            transfer->context, handle);
      if (ret < 0)
         return false;
   }while (ret == 0);

   return true;
}

typedef struct
{
   char *opt_file;
   char *needle;
   void **buf;
   size_t size;
   bool found;
} decomp_state_t;

/* Extract the relative path (needle) from a
 * ZIP archive (path) and allocate a buffer for it to write it in.
 *
 * optional_outfile if not NULL will be used to extract the file to.
 * buf will be 0 then.
 */

static int zip_file_decompressed(
      const char *name, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode,
      uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata)
{
   decomp_state_t* decomp_state = (decomp_state_t*)userdata->cb_data;
   char last_char = name[strlen(name) - 1];
   /* Ignore directories. */
   if (last_char == '/' || last_char == '\\')
      return 1;

   if (strstr(name, decomp_state->needle))
   {
      file_archive_file_handle_t handle = {0};

      if (zip_file_decompressed_handle(userdata->transfer,
               &handle, cdata, cmode, csize, size, crc32))
      {
         if (decomp_state->opt_file != 0)
         {
            /* Called in case core has need_fullpath enabled. */
            bool success = filestream_write_file(decomp_state->opt_file, handle.data, size);

            /* Note: Do not free handle.data here - this
             * will be done when stream is deinitialised */
            handle.data = NULL;

            decomp_state->size = 0;

            if (!success)
               return -1;
         }
         else
         {
            /* Called in case core has need_fullpath disabled.
             * Will move decompressed content directly into
             * RetroArch's ROM buffer. */
            zip_context_t *zip_context = (zip_context_t *)userdata->transfer->context;

            decomp_state->size = 0;
            *decomp_state->buf             = handle.data;
            decomp_state->size             = size;
            /* We keep the data, prevent its deallocation during free */
            zip_context->decompressed_data = NULL;
            handle.data = NULL;
         }
      }

      decomp_state->found = true;
   }

   return 1;
}

static int64_t zip_file_read(
      const char *path,
      const char *needle, void **buf,
      const char *optional_outfile)
{
   file_archive_transfer_t state            = {0};
   decomp_state_t decomp                    = {0};
   struct archive_extract_userdata userdata = {0};
   int ret                                  = 0;

   if (needle)
      decomp.needle          = strdup(needle);
   if (optional_outfile)
      decomp.opt_file        = strdup(optional_outfile);

   state.type                = ARCHIVE_TRANSFER_INIT;
   userdata.transfer         = &state;
   userdata.cb_data          = &decomp;
   decomp.buf                = buf;

   do
   {
      bool returnerr = true;
      ret = file_archive_parse_file_iterate(&state, &returnerr, path,
            "", zip_file_decompressed, &userdata);
      if (!returnerr)
         break;
   }while (ret == 0 && !decomp.found);

   file_archive_parse_file_iterate_stop(&state);

   if (decomp.opt_file)
      free(decomp.opt_file);
   if (decomp.needle)
      free(decomp.needle);

   if (!decomp.found)
      return -1;

   return (int64_t)decomp.size;
}

static int zip_parse_file_init(file_archive_transfer_t *state,
      const char *file)
{
   uint8_t footer_buf[1024];
   uint8_t *footer = footer_buf;
   int64_t read_pos = state->archive_size;
   int64_t read_block = MIN(read_pos, (ssize_t)sizeof(footer_buf));
   int64_t directory_size, directory_offset;
   zip_context_t *zip_context = NULL;

   /* Minimal ZIP file size is 22 bytes */
   if (read_block < 22)
      return -1;

   /* Find the end of central directory record by scanning
    * the file from the end towards the beginning.
    */
   for (;;)
   {
      if (--footer < footer_buf)
      {
         if (read_pos <= 0)
            return -1; /* reached beginning of file */

         /* Read 21 bytes of overlaps except on the first block. */
         if (read_pos == state->archive_size)
            read_pos = read_pos - read_block;
         else
            read_pos = MAX(read_pos - read_block + 21, 0);

         /* Seek to read_pos and read read_block bytes. */
         filestream_seek(state->archive_file, read_pos, RETRO_VFS_SEEK_POSITION_START);
         if (filestream_read(state->archive_file, footer_buf, read_block) != read_block)
            return -1;

         footer = footer_buf + read_block - 22;
      }
      if (read_le(footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)
      {
         unsigned comment_len = read_le(footer + 20, 2);
         if (read_pos + (footer - footer_buf) + 22 + comment_len == state->archive_size)
            break; /* found it! */
      }
   }

   /* Read directory info and do basic sanity checks. */
   directory_size   = read_le(footer + 12, 4);
   directory_offset = read_le(footer + 16, 4);
   if (directory_size > state->archive_size
         || directory_offset > state->archive_size)
      return -1;

   /* This is a ZIP file, allocate one block of memory for both the
    * context and the entire directory, then read the directory.
    */
   zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);
   zip_context->state             = state;
   zip_context->directory         = (uint8_t*)(zip_context + 1);
   zip_context->directory_entry   = zip_context->directory;
   zip_context->directory_end     = zip_context->directory + (size_t)directory_size;
   zip_context->zstream           = NULL;
   zip_context->tmpbuf            = NULL;
   zip_context->decompressed_data = NULL;

   filestream_seek(state->archive_file, directory_offset, RETRO_VFS_SEEK_POSITION_START);
   if (filestream_read(state->archive_file, zip_context->directory, directory_size) != directory_size)
   {
      free(zip_context);
      return -1;
   }

   state->context = zip_context;
   state->step_total = read_le(footer + 10, 2); /* total entries */;

   return 0;
}

static int zip_parse_file_iterate_step_internal(
      zip_context_t * zip_context, char *filename,
      const uint8_t **cdata,
      unsigned *cmode, uint32_t *size, uint32_t *csize,
      uint32_t *checksum, unsigned *payback)
{
   uint8_t *entry = zip_context->directory_entry;
   uint32_t signature, namelength, extralength, commentlength, offset;

   if (entry < zip_context->directory || entry >= zip_context->directory_end)
      return 0;

   signature = read_le(zip_context->directory_entry + 0, 4);

   if (signature != CENTRAL_FILE_HEADER_SIGNATURE)
      return 0;

   *cmode         = read_le(zip_context->directory_entry + 10, 2); /* compression mode, 0 = store, 8 = deflate */
   *checksum      = read_le(zip_context->directory_entry + 16, 4); /* CRC32 */
   *csize         = read_le(zip_context->directory_entry + 20, 4); /* compressed size */
   *size          = read_le(zip_context->directory_entry + 24, 4); /* uncompressed size */

   namelength     = read_le(zip_context->directory_entry + 28, 2); /* file name length */
   extralength    = read_le(zip_context->directory_entry + 30, 2); /* extra field length */
   commentlength  = read_le(zip_context->directory_entry + 32, 2); /* file comment length */

   if (namelength >= PATH_MAX_LENGTH)
      return -1;

   memcpy(filename, zip_context->directory_entry + 46, namelength); /* file name */
   filename[namelength] = '\0';

   offset   = read_le(zip_context->directory_entry + 42, 4); /* relative offset of local file header */

   *cdata   = (uint8_t*)(size_t)offset; /* store file offset in data pointer */

   *payback = 46 + namelength + extralength + commentlength;

   return 1;
}

static int zip_parse_file_iterate_step(void *context,
      const char *valid_exts, struct archive_extract_userdata *userdata,
      file_archive_file_cb file_cb)
{
   zip_context_t *zip_context = (zip_context_t *)context;
   const uint8_t *cdata       = NULL;
   uint32_t checksum          = 0;
   uint32_t size              = 0;
   uint32_t csize             = 0;
   unsigned cmode             = 0;
   unsigned payload           = 0;
   int ret                    = zip_parse_file_iterate_step_internal(zip_context,
         userdata->current_file_path, &cdata, &cmode, &size, &csize, &checksum, &payload);

   if (ret != 1)
      return ret;

   userdata->crc = checksum;

   if (file_cb && !file_cb(userdata->current_file_path, valid_exts, cdata, cmode,
            csize, size, checksum, userdata))
      return 0;

   zip_context->directory_entry += payload;

   return 1;
}

static void zip_parse_file_free(void *context)
{
   zip_context_t *zip_context = (zip_context_t *)context;
   zip_context_free_stream(zip_context, false);
   free(zip_context);
}

const struct file_archive_file_backend zlib_backend = {
   zip_parse_file_init,
   zip_parse_file_iterate_step,
   zip_parse_file_free,
   zlib_stream_decompress_data_to_file_init,
   zlib_stream_decompress_data_to_file_iterate,
   zlib_stream_crc32_calculate,
   zip_file_read,
   "zlib"
};

./include/libretro-common/file/config_file.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>

#include <retro_miscellaneous.h>
#include <compat/strl.h>
#include <compat/posix_string.h>
#include <compat/fopen_utf8.h>
#include <compat/msvc.h>
#include <file/config_file.h>
#include <file/file_path.h>
#include <string/stdstring.h>
#include <streams/file_stream.h>
#include <array/rhmap.h>

#define MAX_INCLUDE_DEPTH 16

struct config_include_list
{
   char *path;
   struct config_include_list *next;
};

/* Forward declaration */
static bool config_file_parse_line(config_file_t *conf,
      struct config_entry_list *list, char *line, config_file_cb_t *cb);

static int config_file_sort_compare_func(struct config_entry_list *a,
      struct config_entry_list *b)
{
   if (a && b)
   {
      if (a->key)
      {
         if (b->key)
            return strcasecmp(a->key, b->key);
         return 1;
      }
      else if (b->key)
         return -1;
   }

   return 0;
}

/* https://stackoverflow.com/questions/7685/merge-sort-a-linked-list */
static struct config_entry_list* config_file_merge_sort_linked_list(
         struct config_entry_list *list, int (*compare)(
         struct config_entry_list *one,struct config_entry_list *two))
{
   struct config_entry_list
         *right  = list,
         *temp   = list,
         *last   = list,
         *result = 0,
         *next   = 0,
         *tail   = 0;

   /* Trivial case. */
   if (!list || !list->next)
      return list;

   /* Find halfway through the list (by running two pointers,
    * one at twice the speed of the other). */
   while (temp && temp->next)
   {
      last     = right;
      right    = right->next;
      temp     = temp->next->next;
   }

   /* Break the list in two. (prev pointers are broken here,
    * but we fix later) */
   last->next  = 0;

   /* Recurse on the two smaller lists: */
   list        = config_file_merge_sort_linked_list(list, compare);
   right       = config_file_merge_sort_linked_list(right, compare);

   /* Merge: */
   while (list || right)
   {
      /* Take from empty lists, or compare: */
      if (!right)
      {
         next  = list;
         list  = list->next;
      }
      else if (!list)
      {
         next  = right;
         right = right->next;
      }
      else if (compare(list, right) < 0)
      {
         next  = list;
         list  = list->next;
      }
      else
      {
         next  = right;
         right = right->next;
      }

      if (!result)
         result     = next;
      else
         tail->next = next;

      tail          = next;
   }

   return result;
}

/**
 * config_file_strip_comment:
 *
 * Searches input string for a comment ('#') entry
 * > If first character is '#', then entire line is
 *   a comment and may correspond to a directive
 *   (command action - e.g. include sub-config file).
 *   In this case, 'str' is set to NUL and the comment
 *   itself (everything after the '#' character) is
 *   returned
 * > If a '#' character is found inside a string literal
 *   value, then it does not correspond to a comment and
 *   is ignored. In this case, 'str' is left untouched
 *   and NULL is returned
 * > If a '#' character is found anywhere else, then the
 *   comment text is a suffix of the input string and
 *   has no programmatic value. In this case, the comment
 *   is removed from the end of 'str' and NULL is returned
 **/
static char *config_file_strip_comment(char *str)
{
   /* Search for a comment (#) character */
   char *comment = strchr(str, '#');

   if (comment)
   {
      char *literal_start = NULL;

      /* Check whether entire line is a comment
       * > First character == '#' */
      if (str == comment)
      {
         /* Set 'str' to NUL and return comment
          * for processing at a higher level */
         *str = '\0';
         return ++comment;
      }

      /* Comment character occurs at an offset:
       * Search for the start of a string literal value */
      literal_start = strchr(str, '\"');

      /* Check whether string literal start occurs
       * *before* the comment character */
      if (literal_start && (literal_start < comment))
      {
         /* Search for the end of the string literal
          * value */
         char *literal_end = strchr(literal_start + 1, '\"');

         /* Check whether string literal end occurs
          * *after* the comment character
          * > If this is the case, ignore the comment
          * > Leave 'str' untouched and return NULL */
         if (literal_end && (literal_end > comment))
            return NULL;
      }

      /* If we reach this point, then a comment
       * exists outside of a string literal
       * > Trim the entire comment from the end
       *   of 'str' */
      *comment = '\0';
   }

   return NULL;
}

static char *config_file_extract_value(char *line)
{
   char *dst = NULL;
   while (ISSPACE((int)*line))
      line++;

   /* Note: From this point on, an empty value
    * string is valid - and in this case, strldup("", sizeof(""))
    * will be returned (see Note 2)
    * > If we instead return NULL, the the entry
    *   is ignored completely - which means we cannot
    *   track *changes* in entry value */

   /* If first character is ("), we have a full string
    * literal */
   if (*line == '"')
   {
      size_t idx  = 0;
      char *value = NULL;
      /* Skip to next character */
      line++;

      /* If this a ("), then value string is empty */
      if (*line != '"')
      {
         /* Find the next (") character */
         while (line[idx] && (line[idx] != '\"'))
            idx++;

         line[idx] = '\0';
         if ((value = line) && *value)
            return strdup(value);
      }
   }
   /* This is not a string literal - just read
    * until the next space is found
    * > Note: Skip this if line is empty */
   else if (*line != '\0')
   {
      size_t idx  = 0;
      char *value = NULL;
      /* Find next space character */
      while (line[idx] && isgraph((int)line[idx]))
         idx++;

      line[idx] = '\0';
      if ((value = line) && *value)
         return strdup(value);
   }

   /* Note 2: This is an unrolled strldup call
    * to avoid an unnecessary dependency -
    * call is strldup("", sizeof(""))
    **/
   dst = (char*)malloc(sizeof(char) * 2);
   strlcpy(dst, "", 1);
   return dst;
}

/* Move semantics? */
static void config_file_add_child_list(config_file_t *parent,
      config_file_t *child)
{
   struct config_entry_list *list = child->entries;
   bool merge_hash_map            = false;

   if (parent->entries)
   {
      struct config_entry_list *head = parent->entries;
      while (head->next)
         head = head->next;

      /* set list readonly */
      while (list)
      {
         list->readonly = true;
         list           = list->next;
      }
      head->next        = child->entries;

      merge_hash_map    = true;
   }
   else
   {
      /* set list readonly */
      while (list)
      {
         list->readonly = true;
         list           = list->next;
      }
      parent->entries   = child->entries;
   }

   /* Rebase tail. */
   if (parent->entries)
   {
      struct config_entry_list *head =
         (struct config_entry_list*)parent->entries;

      while (head->next)
         head = head->next;
      parent->tail = head;
   }
   else
      parent->tail = NULL;

   /* Update hash map */
   if (merge_hash_map)
   {
      size_t i;
      size_t cap;

      /* We are merging two lists - if any child entry
       * (key) is not present in the parent list, add it
       * to the parent hash map */
      for (i = 0, cap = RHMAP_CAP(child->entries_map); i != cap; i++)
      {
         uint32_t child_hash   = RHMAP_KEY(child->entries_map, i);
         const char *child_key = RHMAP_KEY_STR(child->entries_map, i);

         if (child_hash &&
             child_key &&
             !RHMAP_HAS_FULL(parent->entries_map, child_hash, child_key))
         {
            struct config_entry_list *entry = child->entries_map[i];

            if (entry)
               RHMAP_SET_FULL(parent->entries_map, child_hash, child_key, entry);
         }
      }

      /* Child entries map is no longer required,
       * so free it now */
      RHMAP_FREE(child->entries_map);
   }
   else
   {
      /* If parent list was originally empty,
       * take map from child list */
      RHMAP_FREE(parent->entries_map);
      parent->entries_map = child->entries_map;
      child->entries_map  = NULL;
   }

   child->entries = NULL;
}

static void config_file_get_realpath(char *s, size_t len,
      char *path, const char *config_path)
{
#if !defined(_WIN32) && !defined(__PSL1GHT__) && !defined(__PS3__)
   if (*path == '~')
   {
      const char *home = getenv("HOME");
      if (home)
      {
         size_t _len = strlcpy(s, home,     len);
         strlcpy(s + _len, path + 1, len - _len);
      }
      else
         strlcpy(s, path + 1, len);
   }
   else
#endif
   {
      if (!string_is_empty(config_path))
         fill_pathname_resolve_relative(s, config_path,
            path, len);
   }
}

static void config_file_add_sub_conf(config_file_t *conf, char *path,
      char *s, size_t len, config_file_cb_t *cb)
{
   struct config_include_list *head = conf->includes;
   struct config_include_list *node = (struct config_include_list*)
      malloc(sizeof(*node));

   if (node)
   {
      node->next        = NULL;
      /* Add include list */
      node->path        = strdup(path);

      if (head)
      {
         while (head->next)
            head        = head->next;

         head->next     = node;
      }
      else
         conf->includes = node;
   }

   config_file_get_realpath(s, len, path,
         conf->path);
}

size_t config_file_add_reference(config_file_t *conf, char *path)
{
   size_t _len;
   /* It is expected that the conf has it's path already set */
   char short_path[NAME_MAX_LENGTH];
   if (!conf->references)
   {
      conf->references       = (struct path_linked_list*)malloc(sizeof(*conf->references));
      conf->references->next = NULL;
      conf->references->path = NULL;
   }
   _len = fill_pathname_abbreviated_or_relative(short_path, conf->path, path, sizeof(short_path));
   path_linked_list_add_path(conf->references, short_path);
   return _len;
}

static int config_file_load_internal(
      struct config_file *conf,
      const char *path, unsigned depth, config_file_cb_t *cb)
{
   RFILE         *file = NULL;
   char      *new_path = strdup(path);
   if (!new_path)
      return 1;

   conf->path          = new_path;
   conf->include_depth = depth;

   if (!(file = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
   {
      free(conf->path);
      return 1;
   }

   while (!filestream_eof(file))
   {
      char *line                     = NULL;
      struct config_entry_list *list = (struct config_entry_list*)
         malloc(sizeof(*list));

      if (!list)
      {
         filestream_close(file);
         return -1;
      }

      list->readonly  = false;
      list->key       = NULL;
      list->value     = NULL;
      list->next      = NULL;

      line            = filestream_getline(file);

      if (!line)
      {
         free(list);
         continue;
      }

      if (
              !string_is_empty(line)
            && config_file_parse_line(conf, list, line, cb))
      {
         if (conf->entries)
            conf->tail->next = list;
         else
            conf->entries    = list;

         conf->tail = list;

         if (list->key)
         {
            /* Only add entry to the map if an entry
             * with the specified value does not
             * already exist */
            uint32_t hash = rhmap_hash_string(list->key);

            if (!RHMAP_HAS_FULL(conf->entries_map, hash, list->key))
            {
               RHMAP_SET_FULL(conf->entries_map, hash, list->key, list);

               if (cb && list->value)
                  cb->config_file_new_entry_cb(list->key, list->value);
            }
         }
      }

      free(line);

      if (list != conf->tail)
         free(list);
   }

   filestream_close(file);

   return 0;
}

static bool config_file_parse_line(config_file_t *conf,
      struct config_entry_list *list, char *line, config_file_cb_t *cb)
{
   size_t cur_size       = 32;
   size_t idx            = 0;
   char *key             = NULL;
   char *key_tmp         = NULL;
   /* Remove any comment text */
   char *comment         = config_file_strip_comment(line);

   /* Check whether entire line is a comment */
   if (comment)
   {
      char *path               = NULL;
      bool include_found       = string_starts_with_size(comment,
            "include ",   STRLEN_CONST("include "));
      bool reference_found     = string_starts_with_size(comment,
            "reference ", STRLEN_CONST("reference "));

      /* All comments except those starting with the include or
       * reference directive are ignored */
      if (!include_found && !reference_found)
         return false;

      /* Starting a line with an 'include' directive
       * appends a sub-config file */
      if (include_found)
      {
         config_file_t sub_conf;
         char real_path[PATH_MAX_LENGTH];
         char *include_line = comment + STRLEN_CONST("include ");

         if (string_is_empty(include_line))
            return false;

         if (!(path = config_file_extract_value(include_line)))
            return false;

         if (     string_is_empty(path)
               || conf->include_depth >= MAX_INCLUDE_DEPTH)
         {
            free(path);
            return false;
         }

         config_file_add_sub_conf(conf, path,
            real_path, sizeof(real_path), cb);

         config_file_initialize(&sub_conf);

         switch (config_file_load_internal(&sub_conf, real_path,
            conf->include_depth + 1, cb))
         {
            case 0:
               /* Pilfer internal list. */
               config_file_add_child_list(conf, &sub_conf);
               /* fall-through to deinitialize */
            case -1:
               config_file_deinitialize(&sub_conf);
               break;
            case 1:
            default:
               break;
         }
      }

      /* Starting a line with an 'reference' directive
       * sets the reference path */
      if (reference_found)
      {
         char *reference_line = comment + STRLEN_CONST("reference ");

         if (string_is_empty(reference_line))
            return false;

         if (!(path = config_file_extract_value(reference_line)))
            return false;

         config_file_add_reference(conf, path);

         if (!path)
            return false;
      }

      free(path);
      return true;
   }

   /* Skip to first non-space character */
   while (ISSPACE((int)*line))
      line++;

   /* Allocate storage for key */
   if (!(key = (char*)malloc(cur_size + 1)))
      return false;

   /* Copy line contents into key until we
    * reach the next space character */
   while (isgraph((int)*line))
   {
      /* If current key storage is too small,
       * double its size */
      if (idx == cur_size)
      {
         cur_size *= 2;
         if (!(key_tmp   = (char*)realloc(key, cur_size + 1)))
         {
            free(key);
            return false;
         }

         key     = key_tmp;
      }

      key[idx++] = *line++;
   }
   key[idx]      = '\0';

   /* Add key and value entries to list */
   list->key     = key;

   /* An entry without a value is invalid */
   while (ISSPACE((int)*line))
      line++;

   /* If we don't have an equal sign here,
    * we've got an invalid string. */
   if (*line != '=')
   {
      list->value = NULL;
      list->key   = NULL;
      free(key);
      return false;
   }

   line++;

   if (!(list->value   = config_file_extract_value(line)))
   {
      list->key   = NULL;
      free(key);
      return false;
   }

   return true;
}

static int config_file_from_string_internal(
      struct config_file *conf,
      char *from_string,
      const char *path)
{
   char *lines                    = from_string;
   char *save_ptr                 = NULL;
   char *line                     = NULL;

   if (!string_is_empty(path))
      conf->path                  = strdup(path);
   if (string_is_empty(lines))
      return 0;

   /* Get first line of config file */
   line = strtok_r(lines, "\n", &save_ptr);

   while (line)
   {
      struct config_entry_list *list = (struct config_entry_list*)
            malloc(sizeof(*list));

      if (!list)
         return -1;

      list->readonly  = false;
      list->key       = NULL;
      list->value     = NULL;
      list->next      = NULL;

      /* Parse current line */
      if (
              !string_is_empty(line)
            && config_file_parse_line(conf, list, line, NULL))
      {
         if (conf->entries)
            conf->tail->next = list;
         else
            conf->entries    = list;

         conf->tail          = list;

         if (list->key)
         {
            /* Only add entry to the map if an entry
             * with the specified value does not
             * already exist */
            uint32_t hash = rhmap_hash_string(list->key);
            if (!RHMAP_HAS_FULL(conf->entries_map, hash, list->key))
               RHMAP_SET_FULL(conf->entries_map, hash, list->key, list);
         }
      }

      if (list != conf->tail)
         free(list);

      /* Get next line of config file */
      line = strtok_r(NULL, "\n", &save_ptr);
   }

   return 0;
}


bool config_file_deinitialize(config_file_t *conf)
{
   struct config_include_list *inc_tmp = NULL;
   struct config_entry_list *tmp       = NULL;

   if (!conf)
      return false;

   tmp = conf->entries;
   while (tmp)
   {
      struct config_entry_list *hold = NULL;
      if (tmp->key)
         free(tmp->key);
      if (tmp->value)
         free(tmp->value);

      tmp->value = NULL;
      tmp->key   = NULL;

      hold       = tmp;
      tmp        = tmp->next;

      if (hold)
         free(hold);
   }

   inc_tmp = (struct config_include_list*)conf->includes;
   while (inc_tmp)
   {
      struct config_include_list *hold = NULL;
      if (inc_tmp->path)
         free(inc_tmp->path);
      hold    = (struct config_include_list*)inc_tmp;
      inc_tmp = inc_tmp->next;
      if (hold)
         free(hold);
   }

   path_linked_list_free(conf->references);

   if (conf->path)
      free(conf->path);

   RHMAP_FREE(conf->entries_map);

   return true;
}

/**
 * config_file_free:
 *
 * Frees config file.
 **/
void config_file_free(config_file_t *conf)
{
   if (config_file_deinitialize(conf))
      free(conf);
}

/**
 * config_append_file:
 *
 * Loads a new config, and appends its data to @conf.
 * The key-value pairs of the new config file takes priority over the old.
 **/
bool config_append_file(config_file_t *conf, const char *path)
{
   size_t i, cap;
   config_file_t *new_conf = config_file_new_from_path_to_string(path);

   if (!new_conf)
      return false;

   /* Update hash map */
   for (i = 0, cap = RHMAP_CAP(new_conf->entries_map); i != cap; i++)
   {
      uint32_t new_hash   = RHMAP_KEY(new_conf->entries_map, i);
      const char *new_key = RHMAP_KEY_STR(new_conf->entries_map, i);

      if (new_hash && new_key)
      {
         struct config_entry_list *entry = new_conf->entries_map[i];

         if (entry)
            RHMAP_SET_FULL(conf->entries_map, new_hash, new_key, entry);
      }
   }

   if (new_conf->tail)
   {
      new_conf->tail->next = conf->entries;
      conf->entries        = new_conf->entries; /* Pilfer. */
      new_conf->entries    = NULL;
   }

   config_file_free(new_conf);
   return true;
}

/**
 * config_file_new_from_string:
 *
 * Load a config file from a string.
 *
 * NOTE: This will modify @from_string.
 * Pass a copy of source string if original
 * contents must be preserved
 **/
config_file_t *config_file_new_from_string(char *from_string,
      const char *path)
{
   struct config_file *conf      = config_file_new_alloc();
   if (     conf
         && config_file_from_string_internal(
            conf, from_string, path) != -1)
      return conf;
   if (conf)
      config_file_free(conf);
   return NULL;
}

config_file_t *config_file_new_from_path_to_string(const char *path)
{
   if (path_is_valid(path))
   {
      uint8_t *ret_buf                 = NULL;
      int64_t length                   = 0;
      if (filestream_read_file(path, (void**)&ret_buf, &length))
      {
         config_file_t *conf           = NULL;
         /* Note: 'ret_buf' is not used outside this
          * function - we do not care that it will be
          * modified by config_file_new_from_string() */
         if (length >= 0)
            conf = config_file_new_from_string((char*)ret_buf, path);

         if ((void*)ret_buf)
            free((void*)ret_buf);

         return conf;
      }
   }

   return NULL;
}

/**
 * config_file_new_with_callback:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 * Includes cb callbacks  to run custom code during config file processing.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new_with_callback(
      const char *path, config_file_cb_t *cb)
{
   int ret                  = 0;
   struct config_file *conf = config_file_new_alloc();
   if (!path || !*path)
      return conf;
   if ((ret = config_file_load_internal(conf, path, 0, cb)) == -1)
   {
      config_file_free(conf);
      return NULL;
   }
   else if (ret == 1)
   {
      free(conf);
      return NULL;
   }
   return conf;
}

/**
 * config_file_new:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new(const char *path)
{
   int ret                  = 0;
   struct config_file *conf = config_file_new_alloc();
   if (!path || !*path)
      return conf;
   if ((ret = config_file_load_internal(conf, path, 0, NULL)) == -1)
   {
      config_file_free(conf);
      return NULL;
   }
   else if (ret == 1)
   {
      free(conf);
      return NULL;
   }
   return conf;
}

/**
 * config_file_initialize:
 *
 * Leaf function.
 **/
void config_file_initialize(struct config_file *conf)
{
   if (!conf)
      return;

   conf->path                     = NULL;
   conf->entries_map              = NULL;
   conf->entries                  = NULL;
   conf->tail                     = NULL;
   conf->last                     = NULL;
   conf->references               = NULL;
   conf->includes                 = NULL;
   conf->include_depth            = 0;
   conf->flags                    = 0;
}

config_file_t *config_file_new_alloc(void)
{
   struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));
   if (!conf)
      return NULL;
   config_file_initialize(conf);
   return conf;
}

/**
 * config_get_entry_internal:
 *
 * Leaf function.
 **/
static struct config_entry_list *config_get_entry_internal(
      const config_file_t *conf,
      const char *key, struct config_entry_list **prev)
{
   struct config_entry_list *entry = RHMAP_GET_STR(conf->entries_map, key);

   if (entry)
      return entry;

   if (prev)
   {
      struct config_entry_list *previous = *prev;
      for (entry = conf->entries; entry; entry = entry->next)
         previous = entry;

      *prev = previous;
   }

   return NULL;
}

struct config_entry_list *config_get_entry(
      const config_file_t *conf, const char *key)
{
   return RHMAP_GET_STR(conf->entries_map, key);
}

/**
 * config_get_double:
 *
 * Extracts a double from config file.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_double(config_file_t *conf, const char *key, double *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry)
      return false;

   *in = strtod(entry->value, NULL);
   return true;
}

/**
 * config_get_float:
 *
 * Extracts a float from config file.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_float(config_file_t *conf, const char *key, float *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry)
      return false;

   /* strtof() is C99/POSIX. Just use the more portable kind. */
   *in = (float)strtod(entry->value, NULL);
   return true;
}

bool config_get_int(config_file_t *conf, const char *key, int *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      int val = (int)strtol(entry->value, NULL, 0);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

bool config_get_size_t(config_file_t *conf, const char *key, size_t *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      size_t val = 0;
      if (sscanf(entry->value, "%" PRI_SIZET, &val) == 1)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
bool config_get_uint64(config_file_t *conf, const char *key, uint64_t *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      uint64_t val = strtoull(entry->value, NULL, 0);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }
   return false;
}
#endif

bool config_get_uint(config_file_t *conf, const char *key, unsigned *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      unsigned val = (unsigned)strtoul(entry->value, NULL, 0);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

bool config_get_hex(config_file_t *conf, const char *key, unsigned *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      unsigned val = (unsigned)strtoul(entry->value, NULL, 16);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

/**
 * config_get_char:
 *
 * Extracts a single char from config file.
 * If value consists of several chars, this is an error.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_char(config_file_t *conf, const char *key, char *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (entry)
   {
      if (entry->value[0] && entry->value[1])
         return false;

      *in = *entry->value;
      return true;
   }

   return false;
}

/**
 * config_get_string:
 *
 * Extracts an allocated string in *in. This must be free()-d if
 * this function succeeds.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_string(config_file_t *conf, const char *key, char **str)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry || !entry->value)
      return false;

   *str = strdup(entry->value);
   return true;
}

/**
  * config_get_config_path:
  *
  * Extracts a string to a preallocated buffer.
  * Avoid memory allocation.
  **/
size_t config_get_config_path(config_file_t *conf, char *s, size_t len)
{
   if (conf)
      return strlcpy(s, conf->path, len);
   return 0;
}

bool config_get_array(config_file_t *conf, const char *key,
      char *s, size_t len)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   if (entry)
      return strlcpy(s, entry->value, len) < len;
   return false;
}

bool config_get_path(config_file_t *conf, const char *key,
      char *s, size_t len)
{
#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)
   return config_get_array(conf, key, s, len);
#else
   const struct config_entry_list *entry = config_get_entry(conf, key);
   if (entry)
   {
      fill_pathname_expand_special(s, entry->value, len);
      return true;
   }
   return false;
#endif
}

/**
 * config_get_bool:
 *
 * Extracts a boolean from config.
 * Valid boolean true are "true" and "1". Valid false are "false" and "0".
 * Other values will be treated as an error.
 *
 * @return true if preconditions are true, otherwise false.
 **/
bool config_get_bool(config_file_t *conf, const char *key, bool *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry)
      return false;

   if      (
         (
            entry->value[0] == '1'
         && entry->value[1] == '\0'
         )
         || string_is_equal(entry->value, "true")
         )
      *in = true;
   else if (
         (
            entry->value[0] == '0'
         && entry->value[1] == '\0'
         )
         || string_is_equal(entry->value, "false")
         )
      *in = false;
   else
      return false;

   return true;
}

void config_set_string(config_file_t *conf, const char *key, const char *val)
{
   struct config_entry_list *last  = NULL;
   struct config_entry_list *entry = NULL;

   if (!conf || !key || !val)
      return;

   last                            = conf->entries;

   if (conf->flags & CONF_FILE_FLG_GUARANTEED_NO_DUPLICATES)
   {
      if (conf->last)
         last                      = conf->last;
   }
   else
   {
      if ((entry = config_get_entry_internal(conf, key, &last)))
      {
         /* An entry corresponding to 'key' already exists
          * > Check whether value is currently set */
         if (entry->value)
         {
            /* Do nothing if value is unchanged */
            if (string_is_equal(entry->value, val))
               return;

            /* Value is to be updated
             * > Free existing */
            free(entry->value);
         }

         /* Update value
          * > Note that once a value is set, it
          *   is no longer considered 'read only' */
         entry->value    = strdup(val);
         entry->readonly = false;
         conf->flags    |= CONF_FILE_FLG_MODIFIED;
         return;
      }
   }

   /* Entry corresponding to 'key' does not exist
    * > Create new entry */
   if (!(entry = (struct config_entry_list*)malloc(sizeof(*entry))))
      return;

   entry->readonly  = false;
   entry->key       = strdup(key);
   entry->value     = strdup(val);
   entry->next      = NULL;
   conf->flags     |= CONF_FILE_FLG_MODIFIED;

   if (last)
      last->next    = entry;
   else
      conf->entries = entry;

   conf->last       = entry;

   RHMAP_SET_STR(conf->entries_map, entry->key, entry);
}

void config_unset(config_file_t *conf, const char *key)
{
   struct config_entry_list *last  = NULL;
   struct config_entry_list *entry = NULL;

   if (!conf || !key)
      return;

   last  = conf->entries;

   if (!(entry = config_get_entry_internal(conf, key, &last)))
      return;

   (void)RHMAP_DEL_STR(conf->entries_map, entry->key);

   if (entry->key)
      free(entry->key);

   if (entry->value)
      free(entry->value);

   entry->key     = NULL;
   entry->value   = NULL;
   conf->flags   |= CONF_FILE_FLG_MODIFIED;
}

void config_set_path(config_file_t *conf, const char *entry, const char *val)
{
#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)
   config_set_string(conf, entry, val);
#else
   char buf[PATH_MAX_LENGTH];
   fill_pathname_abbreviate_special(buf, val, sizeof(buf));
   config_set_string(conf, entry, buf);
#endif
}

size_t config_set_double(config_file_t *conf, const char *key, double val)
{
   char buf[320];
#ifdef __cplusplus
   size_t _len = snprintf(buf, sizeof(buf), "%f", (float)val);
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
   size_t _len = snprintf(buf, sizeof(buf), "%lf", val);
#else
   size_t _len = snprintf(buf, sizeof(buf), "%f", (float)val);
#endif
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_float(config_file_t *conf, const char *key, float val)
{
   char buf[64];
   size_t _len = snprintf(buf, sizeof(buf), "%f", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_int(config_file_t *conf, const char *key, int val)
{
   char buf[16];
   size_t _len = snprintf(buf, sizeof(buf), "%d", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_uint(config_file_t *conf, const char *key, unsigned int val)
{
   char buf[16];
   size_t _len = snprintf(buf, sizeof(buf), "%u", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_hex(config_file_t *conf, const char *key, unsigned val)
{
   char buf[16];
   size_t _len = snprintf(buf, sizeof(buf), "%x", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_uint64(config_file_t *conf, const char *key, uint64_t val)
{
   char buf[32];
   size_t _len = snprintf(buf, sizeof(buf), "%" PRIu64, val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_char(config_file_t *conf, const char *key, char val)
{
   char buf[2];
   size_t _len = snprintf(buf, sizeof(buf), "%c", val);
   config_set_string(conf, key, buf);
   return _len;
}

/**
 * config_file_write:
 *
 * Write the current config to a file.
 **/
bool config_file_write(config_file_t *conf, const char *path, bool sort)
{
   if (!conf)
      return false;

   if (conf->flags & CONF_FILE_FLG_MODIFIED)
   {
      if (string_is_empty(path))
         config_file_dump(conf, stdout, sort);
      else
      {
         void* buf  = NULL;
         FILE *file = (FILE*)fopen_utf8(path, "wb");
         if (!file)
            return false;

         buf        = calloc(1, 0x4000);
         setvbuf(file, (char*)buf, _IOFBF, 0x4000);

         config_file_dump(conf, file, sort);

         if (file != stdout)
            fclose(file);
         if (buf)
            free(buf);

         /* Only update modified flag if config file
          * is actually written to disk */
         conf->flags &= ~CONF_FILE_FLG_MODIFIED;
      }
   }

   return true;
}

/**
 * config_file_dump:
 *
 * Dump the current config to an already opened file.
 * Does not close the file.
 **/
void config_file_dump(config_file_t *conf, FILE *file, bool sort)
{
   struct config_entry_list       *list = NULL;
   struct config_include_list *includes = conf->includes;
   struct path_linked_list *ref_tmp = conf->references;

   while (ref_tmp)
   {
      pathname_make_slashes_portable(ref_tmp->path);
      fprintf(file, "#reference \"%s\"\n", ref_tmp->path);
      ref_tmp = ref_tmp->next;
   }

   if (sort)
      list = config_file_merge_sort_linked_list(
            (struct config_entry_list*)conf->entries,
            config_file_sort_compare_func);
   else
      list = (struct config_entry_list*)conf->entries;

   conf->entries = list;

   while (list)
   {
      if (!list->readonly && list->key)
         fprintf(file, "%s = \"%s\"\n", list->key, list->value);
      list = list->next;
   }

   /* Config files are read from the top down - if
    * duplicate entries are found then the topmost
    * one in the list takes precedence. This means
    * '#include' directives must go *after* individual
    * config entries, otherwise they will override
    * any custom-set values */
   while (includes)
   {
      fprintf(file, "#include \"%s\"\n", includes->path);
      includes = includes->next;
   }
}

/**
 * config_get_entry_list_head:
 *
 * Leaf function.
 **/
bool config_get_entry_list_head(config_file_t *conf,
      struct config_file_entry *entry)
{
   const struct config_entry_list *head = conf->entries;

   if (!head)
      return false;

   entry->key   = head->key;
   entry->value = head->value;
   entry->next  = head->next;
   return true;
}

/**
 * config_get_entry_list_next:
 *
 * Leaf function.
 **/
bool config_get_entry_list_next(struct config_file_entry *entry)
{
   const struct config_entry_list *next = entry->next;

   if (!next)
      return false;

   entry->key   = next->key;
   entry->value = next->value;
   entry->next  = next->next;
   return true;
}

./include/libretro-common/file/config_file_userdata.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_userdata.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <file/file_path.h>
#include <lists/string_list.h>

#include <file/config_file_userdata.h>

int config_userdata_get_float(void *userdata, const char *key_str,
      float *value, float default_value)
{
   char key[256];
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key, usr->prefix[0], key_str, '_', sizeof(key));
   if (config_get_float(usr->conf, key, value))
      return true;
   *value = default_value;
   fill_pathname_join_delim(key, usr->prefix[1], key_str, '_', sizeof(key));
   if (config_get_float(usr->conf, key, value))
      return true;
   return false;
}

int config_userdata_get_int(void *userdata, const char *key_str,
      int *value, int default_value)
{
   char key[256];
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key, usr->prefix[0], key_str, '_', sizeof(key));
   if (config_get_int(usr->conf, key, value))
      return true;
   *value = default_value;
   fill_pathname_join_delim(key, usr->prefix[1], key_str, '_', sizeof(key));
   if (config_get_int(usr->conf, key, value))
      return true;
   return false;
}

int config_userdata_get_hex(void *userdata, const char *key_str,
      unsigned *value, unsigned default_value)
{
   char key[256];
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key, usr->prefix[0], key_str, '_', sizeof(key));
   if (config_get_hex(usr->conf, key, value))
      return true;
   *value = default_value;
   fill_pathname_join_delim(key, usr->prefix[1], key_str, '_', sizeof(key));
   if (config_get_hex(usr->conf, key, value))
      return true;
   return false;
}

int config_userdata_get_float_array(void *userdata, const char *key_str,
      float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values)
{
   char key[2][256];
   char *str = NULL;
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;

   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));

   if (     config_get_string(usr->conf, key[0], &str)
         || config_get_string(usr->conf, key[1], &str))
   {
      unsigned i;
      struct string_list list = {0};
      string_list_initialize(&list);
      string_split_noalloc(&list, str, " ");
      *values = (float*)calloc(list.size, sizeof(float));
      for (i = 0; i < list.size; i++)
         (*values)[i] = (float)strtod(list.elems[i].data, NULL);
      *out_num_values = (unsigned)list.size;
      string_list_deinitialize(&list);
      free(str);
      return true;
   }

   *values = (float*)calloc(num_default_values, sizeof(float));
   memcpy(*values, default_values, sizeof(float) * num_default_values);
   *out_num_values = num_default_values;
   return false;
}

int config_userdata_get_int_array(void *userdata, const char *key_str,
      int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values)
{
   char key[2][256];
   char *str = NULL;
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));

   if (     config_get_string(usr->conf, key[0], &str)
         || config_get_string(usr->conf, key[1], &str))
   {
      unsigned i;
      struct string_list list = {0};
      string_list_initialize(&list);
      string_split_noalloc(&list, str, " ");
      *values = (int*)calloc(list.size, sizeof(int));
      for (i = 0; i < list.size; i++)
         (*values)[i] = (int)strtod(list.elems[i].data, NULL);
      *out_num_values = (unsigned)list.size;
      string_list_deinitialize(&list);
      free(str);
      return true;
   }

   *values = (int*)calloc(num_default_values, sizeof(int));
   memcpy(*values, default_values, sizeof(int) * num_default_values);
   *out_num_values = num_default_values;
   return false;
}

int config_userdata_get_string(void *userdata, const char *key_str,
      char **output, const char *default_output)
{
   char key[2][256];
   char *str = NULL;
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));

   if (     config_get_string(usr->conf, key[0], &str)
         || config_get_string(usr->conf, key[1], &str))
   {
      *output = str;
      return true;
   }

   *output = strdup(default_output);
   return false;
}

void config_userdata_free(void *ptr)
{
   if (ptr)
      free(ptr);
}

./include/libretro-common/file/file_path.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_path.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <locale.h>

#include <sys/stat.h>

#include <boolean.h>
#include <file/file_path.h>
#include <retro_miscellaneous.h>
#include <string/stdstring.h>
#include <time/rtime.h>

/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifdef __HAIKU__
#include <kernel/image.h>
#endif
#ifndef __MACH__
#include <compat/strl.h>
#include <compat/posix_string.h>
#endif
#include <retro_miscellaneous.h>
#include <encodings/utf.h>

#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h> /* stat() is defined here */
#endif

#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
#ifdef __WINRT__
#include <uwp/uwp_func.h>
#endif
#endif

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

/* Time format strings with AM-PM designation require special
 * handling due to platform dependence */
size_t strftime_am_pm(char *s, size_t len, const char* format,
      const void *ptr)
{
   size_t _len              = 0;
#if !(defined(__linux__) && !defined(ANDROID))
   char *local              = NULL;
#endif
   const struct tm *timeptr = (const struct tm*)ptr;
   /* Ensure correct locale is set
    * > Required for localised AM/PM strings */
   setlocale(LC_TIME, "");
   _len = strftime(s, len, format, timeptr);
#if !(defined(__linux__) && !defined(ANDROID))
   if ((local = local_to_utf8_string_alloc(s)))
   {
      if (!string_is_empty(local))
         _len = strlcpy(s, local, len);

      free(local);
      local = NULL;
   }
#endif
   return _len;
}

/**
 * Create a new linked list with one node in it
 * The path on this node will be set to NULL
**/
struct path_linked_list* path_linked_list_new(void)
{
   struct path_linked_list* paths_list = (struct path_linked_list*)malloc(sizeof(*paths_list));
   paths_list->next = NULL;
   paths_list->path = NULL;
   return paths_list;
}

/**
 * path_linked_list_free:
 *
 * Free the entire linked list
 **/
void path_linked_list_free(struct path_linked_list *in_path_llist)
{
   struct path_linked_list *node_tmp = (struct path_linked_list*)in_path_llist;
   while (node_tmp)
   {
      struct path_linked_list *hold = NULL;
      if (node_tmp->path)
         free(node_tmp->path);
      hold     = (struct path_linked_list*)node_tmp;
      node_tmp = node_tmp->next;
      if (hold)
         free(hold);
   }
}

/**
 * path_linked_list_add_path:
 *
 * Add a node to the linked list with this path
 * If the first node's path if it's not yet set the path
 * on this node instead
**/
void path_linked_list_add_path(struct path_linked_list *in_path_llist,
      char *path)
{
    /* If the first item does not have a path this is
      a list which has just been created, so we just fill
      the path for the first item
   */
   if (!in_path_llist->path)
      in_path_llist->path = strdup(path);
   else
   {
      struct path_linked_list *node = (struct path_linked_list*)malloc(sizeof(*node));

      if (node)
      {
         struct path_linked_list *head = in_path_llist;

         node->next        = NULL;
         node->path        = strdup(path);

         if (head)
         {
            while (head->next)
               head        = head->next;
            head->next     = node;
         }
         else
            in_path_llist  = node;
      }
   }
}

/**
 * path_get_archive_delim:
 * @path               : path
 *
 * Find delimiter of an archive file. Only the first '#'
 * after a compression extension is considered.
 *
 * @return pointer to the delimiter in the path if it contains
 * a path inside a compressed file, otherwise NULL.
 **/
const char *path_get_archive_delim(const char *path)
{
   char buf[5];
   /* Find delimiter position
    * > Since filenames may contain '#' characters,
    *   must loop until we find the first '#' that
    *   is directly *after* a compression extension */
   const char *delim      = strchr(path, '#');

   while (delim)
   {
      /* Check whether this is a known archive type
       * > Note: The code duplication here is
       *   deliberate, to maximise performance */
      if (delim - path > 4)
      {
         strlcpy(buf, delim - 4, sizeof(buf));
         buf[4] = '\0';

         string_to_lower(buf);

         /* Check if this is a '.zip', '.apk' or '.7z' file */
         if (   string_is_equal(buf,     ".zip")
             || string_is_equal(buf,     ".apk")
             || string_is_equal(buf + 1, ".7z"))
            return delim;
      }
      else if (delim - path > 3)
      {
         strlcpy(buf, delim - 3, sizeof(buf));
         buf[3] = '\0';

         string_to_lower(buf);

         /* Check if this is a '.7z' file */
         if (string_is_equal(buf, ".7z"))
            return delim;
      }

      delim++;
      delim = strchr(delim, '#');
   }

   return NULL;
}

/**
 * path_get_extension:
 * @path               : path
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * @return extension part from the path.
 **/
const char *path_get_extension(const char *path)
{
   const char *ext;
   if (!string_is_empty(path) && ((ext = (char*)strrchr(path_basename(path), '.'))))
      return ext + 1;
   return "";
}

/**
 * path_get_extension_mutable:
 * @path               : path
 *
 * Specialized version of path_get_extension(). Return
 * value is mutable.
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * @return extension part from the path.
 **/
char *path_get_extension_mutable(const char *path)
{
   char *ext = NULL;
   if (    !string_is_empty(path)
       && ((ext = (char*)strrchr(path_basename(path), '.'))))
      return ext;
   return NULL;
}

/**
 * path_remove_extension:
 * @s                  : path
 *
 * Mutates path by removing its extension. Removes all
 * text after and including the last '.'.
 * Only '.'s after the last slash are considered.
 *
 * @return
 * 1) If path has an extension, returns path with the
 *    extension removed.
 * 2) If there is no extension, returns NULL.
 * 3) If path is empty or NULL, returns NULL
 **/
char *path_remove_extension(char *s)
{
   char *last = path_get_extension_mutable(s);
   if (!last)
      return NULL;
   if (*last)
      *last = '\0';
   return s;
}

/**
 * path_is_compressed_file:
 * @path               : path
 *
 * Checks if path is a compressed file.
 *
 * @return true if path is a compressed file, otherwise false.
 **/
bool path_is_compressed_file(const char* path)
{
   const char *ext = path_get_extension(path);
   if (!string_is_empty(ext))
      return (   string_is_equal_noncase(ext, "zip")
              || string_is_equal_noncase(ext, "apk")
              || string_is_equal_noncase(ext, "7z"));
   return false;
}

/**
 * fill_pathname:
 * @s                  : output path
 * @in_path            : input  path
 * @replace            : what to replace
 * @len                : buffer size of output path
 *
 * FIXME: Verify
 *
 * Replaces filename extension with 'replace' and outputs result to @s.
 * The extension here is considered to be the string from the last '.'
 * to the end.
 *
 * Only '.'s after the last slash are considered as extensions.
 * If no '.' is present, in_path and replace will simply be concatenated.
 * 'len' is buffer size of 's'.
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
 * s = "/foo/bar/baz/boo.asm"
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =>
 * s = "/foo/bar/baz/boo"
 *
 * @return Length of the string copied into @out
 */
size_t fill_pathname(char *s, const char *in_path,
      const char *replace, size_t len)
{
   char *tok   = NULL;
   size_t _len = strlcpy(s, in_path, len);
   if ((tok = (char*)strrchr(path_basename(s), '.')))
   {
      *tok = '\0'; _len = tok - s;
   }
   _len += strlcpy(s + _len, replace,  len - _len);
   return _len;
}


/**
 * find_last_slash:
 * @str                : path
 * @size               : size of path
 *
 * Find last slash in path. Tries to find
 * a backslash as used for Windows paths,
 * otherwise checks for a regular slash.

 * @return pointer to last slash/backslash found in @str.
 **/
char *find_last_slash(const char *str)
{
   const char *p;
   const char *last_slash     = NULL;
   const char *last_backslash = NULL;

   /* Traverse the string once */
   for (p = str; *p != '\0'; ++p)
   {
      if (*p == '/')
         last_slash = p; /*   Update last forward slash */
      else if (*p == '\\')
         last_backslash = p; /* Update last backslash */
   }

   /* Determine which one is last */
   if (!last_slash) /* Backslash */
      return (char*)last_backslash;
   if (!last_backslash) /* Forward slash */
      return (char*)last_slash;
   return (last_backslash > last_slash) ? (char*)last_backslash : (char*)last_slash;
}

/**
 * fill_pathname_slash:
 * @s                  : path
 * @len                : size of @s
 *
 * Assumes path is a directory. Appends a slash
 * if not already there.
 **/
size_t fill_pathname_slash(char *s, size_t len)
{
   char *last_slash = find_last_slash(s);
   len              = strlen(s);
   if (!last_slash)
   {
      s[  len]      = PATH_DEFAULT_SLASH_C();
      s[++len]      = '\0';
   }
   else if (last_slash != (s + len - 1))
   {
      /* Try to preserve slash type. */
      s[  len]       = last_slash[0];
      s[++len]       = '\0';
   }
   return len;
}

/**
 * fill_pathname_dir:
 * @s                  : input directory path
 * @in_basename        : input basename to be appended to @s
 * @replace            : replacement to be appended to @in_basename
 * @size               : size of buffer
 *
 * Appends basename of 'in_basename', to 's', along with 'replace'.
 * Basename of in_basename is the string after the last '/' or '\\',
 * i.e the filename without directories.
 *
 * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
 * 'size' is buffer size of 's'.
 *
 * E.g..: s = "/tmp/some_dir", in_basename = "/some_content/foo.c",
 * replace = ".asm" => s = "/tmp/some_dir/foo.c.asm"
 **/
size_t fill_pathname_dir(char *s, const char *in_basename,
      const char *replace, size_t len)
{
   size_t _len  = fill_pathname_slash(s, len);
   _len        += strlcpy(s + _len, path_basename(in_basename), len - _len);
   _len        += strlcpy(s + _len, replace, len - _len);
   return _len;
}

/**
 * fill_pathname_base:
 * @s                  : output path
 * @in_path            : input path
 * @len                : size of output path
 *
 * Copies basename of @in_path into @s.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_base(char *s, const char *in_path, size_t len)
{
   const char     *ptr = path_basename(in_path);
   if (ptr)
      return strlcpy(s, ptr, len);
   return strlcpy(s, in_path, len);
}

/**
 * fill_pathname_basedir:
 * @s                  : output directory
 * @in_path            : input path
 * @len                : size of output directory
 *
 * Copies base directory of @in_path into @s.
 * If in_path is a path without any slashes (relative current directory),
 * @s will get path "./".
 *
 * @return Length of the string copied in @s
 **/
size_t fill_pathname_basedir(char *s, const char *in_path, size_t len)
{
   if (s != in_path)
      strlcpy(s, in_path, len);
   return path_basedir(s);
}

/**
 * fill_pathname_parent_dir_name:
 * @s                  : output string
 * @in_dir             : input directory
 * @len                : size of @s
 *
 * Copies only the parent directory name of @in_dir into @s.
 * The two buffers must not overlap. Removes trailing '/'.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_parent_dir_name(char *s, const char *in_dir, size_t len)
{
   size_t _len        = 0;
   char *tmp          = strdup(in_dir);
   char *last_slash   = find_last_slash(tmp);

   if (last_slash && last_slash[1] == 0)
   {
      *last_slash     = '\0';
      last_slash      = find_last_slash(tmp);
   }

   /* Cut the last part of the string (the filename) after the slash,
      leaving the directory name (or nested directory names) only. */
   if (last_slash)
      *last_slash     = '\0';

   /* Point in_dir to the address of the last slash.
    * If in_dir is NULL, it means there was no slash in tmp,
    * so use tmp as-is. */
   if (!(in_dir = find_last_slash(tmp)))
       in_dir         = tmp;

   if (in_dir && in_dir[1])
   {
       /* If path starts with an slash, eliminate it. */
       if (path_is_absolute(in_dir))
           _len = strlcpy(s, in_dir + 1, len);
       else
           _len = strlcpy(s, in_dir,     len);
   }

   free(tmp);
   return _len;
}

/**
 * fill_pathname_parent_dir:
 * @s                  : output directory
 * @in_dir             : input directory
 * @len                : size of @s
 *
 * Copies parent directory of @in_dir into @s.
 * Assumes @in_dir is a directory. Keeps trailing '/'.
 * If the path was already at the root directory,
 * @s will be an empty string.
 **/
size_t fill_pathname_parent_dir(char *s,
      const char *in_dir, size_t len)
{
   size_t _len = 0;
   if (s == in_dir)
      _len = strlen(s);
   else
      _len = strlcpy(s, in_dir, len);
   return path_parent_dir(s, _len);
}

/**
 * fill_dated_filename:
 * @s                  : output filename
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by 'RetroArch', and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
 **/
size_t fill_dated_filename(char *s,
      const char *ext, size_t len)
{
   size_t _len;
   struct tm tm_;
   time_t cur_time = time(NULL);
   rtime_localtime(&cur_time, &tm_);
   _len  = strftime(s, len,
         "RetroArch-%m%d-%H%M%S", &tm_);
   _len += strlcpy(s + _len, ext, len - _len);
   return _len;
}

/**
 * fill_str_dated_filename:
 * @s                  : output filename
 * @in_str             : input string
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by the string @in_str, and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
 *
 * @return Length of the string copied into @s
 **/
size_t fill_str_dated_filename(char *s,
      const char *in_str, const char *ext, size_t len)
{
   struct tm tm_;
   size_t _len     = 0;
   time_t cur_time = time(NULL);
   rtime_localtime(&cur_time, &tm_);
   _len      = strlcpy(s, in_str, len);
   if (string_is_empty(ext))
      _len += strftime(s + _len, len - _len, "-%y%m%d-%H%M%S", &tm_);
   else
   {
      _len  += strftime(s + _len, len - _len, "-%y%m%d-%H%M%S.", &tm_);
      _len  += strlcpy(s + _len, ext,    len - _len);
   }
   return _len;
}

/**
 * path_basedir:
 * @s                  : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 *
 * @return The new size of @s
 **/
size_t path_basedir(char *s)
{
   char *last_slash = NULL;
   if (!s || s[0] == '\0' || s[1] == '\0')
      return (s && s[0] != '\0') ? 1 : 0;
   last_slash       = find_last_slash(s);
   if (last_slash)
   {
      last_slash[1] = '\0';
      return last_slash + 1 - s;
   }
   s[0]             = '.';
   s[1]             = PATH_DEFAULT_SLASH_C();
   s[2]             = '\0';
   return 2;
}

/**
 * path_parent_dir:
 * @s                  : path
 * @len                : length of @path
 *
 * Extracts parent directory by mutating path.
 * Assumes that @s is a directory. Keeps trailing '/'.
 * If the path was already at the root directory, returns empty string
 *
 * @return The new size of @s
 **/
size_t path_parent_dir(char *s, size_t len)
{
   if (!s)
      return 0;

   if (len && PATH_CHAR_IS_SLASH(s[len - 1]))
   {
      char *last_slash;
      bool was_absolute = path_is_absolute(s);

      s[len - 1]        = '\0';
      last_slash        = find_last_slash(s);

      if (was_absolute && !last_slash)
      {
         /* We removed the only slash from what used to be an absolute path.
          * On Linux, this goes from "/" to an empty string and everything works fine,
          * but on Windows, we went from C:\ to C:, which is not a valid path and that later
          * gets erroneously treated as a relative one by path_basedir and returns "./".
          * What we really wanted is an empty string. */
         s[0] = '\0';
         return 0;
      }
   }
   return path_basedir(s);
}

/**
 * path_basename:
 * @path               : path
 *
 * Get basename from @path.
 *
 * @return basename from path.
 **/
const char *path_basename(const char *path)
{
   /* We cut either at the first compression-related hash,
    * or we cut at the last slash */
   const char *ptr       = NULL;
   char *last_slash      = find_last_slash(path);
   return ((ptr = path_get_archive_delim(path)) || (ptr = last_slash))
      ? (ptr + 1) : path;
}

/* Specialized version */
/**
 * path_basename_nocompression:
 * @path               : path
 *
 * Specialized version of path_basename().
 * Get basename from @path.
 *
 * @return basename from path.
 **/
const char *path_basename_nocompression(const char *path)
{
   /* We cut at the last slash */
   char *last_slash = find_last_slash(path);
   return (last_slash) ? (last_slash + 1) : path;
}

/**
 * path_is_absolute:
 * @path               : path
 *
 * Checks if @path is an absolute path or a relative path.
 *
 * @return true if path is absolute, false if path is relative.
 **/
bool path_is_absolute(const char *path)
{
   if (!string_is_empty(path))
   {
      if (path[0] == '/')
         return true;
#if defined(_WIN32)
      /* Many roads lead to Rome...
       * Note: Drive letter can only be 1 character long */
      return ( string_starts_with_size(path,     "\\\\", STRLEN_CONST("\\\\"))
            || string_starts_with_size(path + 1, ":/",   STRLEN_CONST(":/"))
            || string_starts_with_size(path + 1, ":\\",  STRLEN_CONST(":\\")));
#elif defined(__wiiu__) || defined(VITA)
      {
         const char *separator = strchr(path, ':');
         return (separator && (separator[1] == '/'));
      }
#endif
   }

   return false;
}

/**
 * path_resolve_realpath:
 * @s                  : input and output buffer for path
 * @len                : size of @s
 * @resolve_symlinks   : whether to resolve symlinks or not
 *
 * Resolves use of ".", "..", multiple slashes etc in absolute paths.
 *
 * Relative paths are rebased on the current working dir.
 *
 * @return @s if successful, NULL otherwise.
 * Note: Not implemented on consoles
 * Note: Symlinks are only resolved on Unix-likes
 * Note: The current working dir might not be what you expect,
 *       e.g. on Android it is "/"
 *       Use of fill_pathname_resolve_relative() should be preferred
 **/
char *path_resolve_realpath(char *s, size_t len, bool resolve_symlinks)
{
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
#ifdef _WIN32
   char *ret         = NULL;
   wchar_t *rel_path = utf8_to_utf16_string_alloc(s);

   if (rel_path)
   {
      wchar_t abs_path[PATH_MAX_LENGTH];

      if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH))
      {
         char *tmp = utf16_to_utf8_string_alloc(abs_path);

         if (tmp)
         {
            strlcpy(s, tmp, len);
            free(tmp);
            ret = s;
         }
      }

      free(rel_path);
   }

   return ret;
#else
   char tmp[PATH_MAX_LENGTH];
   size_t t;
   char *p;
   const char *next;
   const char *buf_end;

   if (resolve_symlinks)
   {
      strlcpy(tmp, s, sizeof(tmp));

      /* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in @s.
       * Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways.
       * POSIX 2008 can automatically allocate for you,
       * but don't rely on that. */
      if (!realpath(tmp, s))
      {
         strlcpy(s, tmp, len);
         return NULL;
      }

      return s;
   }

   t       = 0; /* length of output */
   buf_end = s + strlen(s);

   if (!path_is_absolute(s))
   {
      size_t _len;
      /* rebase on working directory */
      if (!getcwd(tmp, PATH_MAX_LENGTH - 1))
         return NULL;

      _len = strlen(tmp);
      t  += _len;

      if (tmp[_len - 1] != '/')
         tmp[t++] = '/';

      if (string_is_empty(s))
      {
         tmp[t] = '\0';
         strlcpy(s, tmp, len);
         return s;
      }

      p = s;
   }
   else
   {
      /* UNIX paths can start with multiple '/', copy those */
      for (p = s; *p == '/'; p++)
         tmp[t++] = '/';
   }

   /* p points to just after a slash while 'next' points to the next slash
    * if there are no slashes, they point relative to where one would be */
   do
   {
      if (!(next = strchr(p, '/')))
         next = buf_end;

      if ((next - p == 2 && p[0] == '.' && p[1] == '.'))
      {
         p += 3;

         /* fail for illegal /.., //.. etc */
         if (t == 1 || tmp[t-2] == '/')
            return NULL;

         /* delete previous segment in tmp by adjusting size t
          * tmp[t - 1] == '/', find '/' before that */
         t -= 2;
         while (tmp[t] != '/')
            t--;
         t++;
      }
      else if (next - p == 1 && p[0] == '.')
         p += 2;
      else if (next - p == 0)
         p += 1;
      else
      {
         /* fail when truncating */
         if (t + next - p + 1 > PATH_MAX_LENGTH - 1)
            return NULL;

         while (p <= next)
            tmp[t++] = *p++;
      }
   } while(next < buf_end);

   tmp[t] = '\0';
   strlcpy(s, tmp, len);
   return s;
#endif
#endif
   return NULL;
}

/**
 * path_relative_to:
 * @s                  : buffer to write the relative path to
 * @path               : path to be expressed relatively
 * @base               : base directory to start out on
 * @len                : size of @s
 *
 * Turns @path into a path relative to @base and writes it to @s.
 *
 * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
 * Both @path and @base are assumed to be absolute paths without "." or "..".
 *
 * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg
 *
 * @return Length of the string copied into @s
 **/
size_t path_relative_to(char *s,
      const char *path, const char *base, size_t len)
{
   size_t i, j;
   const char *trimmed_path, *trimmed_base;

#ifdef _WIN32
   /* For different drives, return absolute path */
   if (
            path
         && base
         && path[0] != '\0'
         && path[1] != '\0'
         && base[0] != '\0'
         && base[1] != '\0'
         && path[1] == ':'
         && base[1] == ':'
         && path[0] != base[0])
      return strlcpy(s, path, len);
#endif

   /* Trim common beginning */
   for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)
      if (path[i] == PATH_DEFAULT_SLASH_C())
         j = i + 1;

   trimmed_path = path + j;
   trimmed_base = base + i;

   /* Each segment of base turns into ".." */
   s[0] = '\0';
   for (i = 0; trimmed_base[i]; i++)
      if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
         strlcat(s, ".." PATH_DEFAULT_SLASH(), len);

   return strlcat(s, trimmed_path, len);
}

/**
 * fill_pathname_resolve_relative:
 * @s                  : output path
 * @in_refpath         : input reference path
 * @in_path            : input path
 * @len                : size of @s
 *
 * Joins basedir of @in_refpath together with @in_path.
 * If @in_path is an absolute path, s = in_path.
 * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
 * s = "/foo/bar/foobar.cg".
 **/
void fill_pathname_resolve_relative(char *s,
      const char *in_refpath, const char *in_path, size_t len)
{
   if (path_is_absolute(in_path))
   {
      strlcpy(s, in_path, len);
      return;
   }

   fill_pathname_basedir(s, in_refpath, len);
   strlcat(s, in_path, len);
   path_resolve_realpath(s, len, false);
}

/**
 * fill_pathname_join:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get  two consecutive slashes
 * between directory and path.
 *
 * Deprecated. Use fill_pathname_join_special() instead
 * if you can ensure @dir and @s won't overlap.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join(char *s, const char *dir,
      const char *path, size_t len)
{
   size_t _len = 0;
   if (s != dir)
      _len = strlcpy(s, dir, len);
   if (*s)
      _len = fill_pathname_slash(s, len);
   _len   += strlcpy(s + _len, path, len - _len);
   return _len;
}

/**
 * fill_pathname_join_special:
 * @s                  : output path
 * @dir                : directory. Cannot be identical to @s
 * @path               : path
 * @len                : size of @s
 *
 * Specialized version of fill_pathname_join.
 * Unlike fill_pathname_join(),
 * @dir and @s CANNOT be identical.
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get  two consecutive slashes
 * between directory and path.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join_special(char *s,
      const char *dir, const char *path, size_t len)
{
   size_t _len = strlcpy(s, dir, len);

   if (*s)
   {
      char *last_slash = find_last_slash(s);
      if (!last_slash)
      {
         s[  _len]     = PATH_DEFAULT_SLASH_C();
         s[++_len]     = '\0';
      }
      else if (last_slash != (s + _len - 1))
      {
         /* Try to preserve slash type. */
         s[  _len]     = last_slash[0];
         s[++_len]     = '\0';
      }
   }

   _len += strlcpy(s + _len, path, len - _len);
   return _len;
}

size_t fill_pathname_join_special_ext(char *s,
      const char *dir,  const char *path,
      const char *last, const char *ext,
      size_t len)
{
   size_t _len = fill_pathname_join(s, dir, path, len);
   if (*s)
      _len     = fill_pathname_slash(s, len);
   _len       += strlcpy(s + _len, last, len - _len);
   _len       += strlcpy(s + _len, ext,  len - _len);
   return _len;
}

/**
 * fill_pathname_join_delim:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @delim              : delimiter
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together
 * using the given delimiter (@delim).
 **/
size_t fill_pathname_join_delim(char *s, const char *dir,
      const char *path, const char delim, size_t len)
{
   size_t _len;
   /* Behavior of strlcpy is undefined if dst and src overlap */
   if (s == dir)
      _len     = strlen(dir);
   else
      _len     = strlcpy(s, dir, len);
   if (len - _len < 2)
      return _len;
   s[_len++]   = delim;
   s[_len  ]   = '\0';
   if (path)
      _len    += strlcpy(s + _len, path, len - _len);
   return _len;
}

size_t fill_pathname_expand_special(char *s, const char *in_path, size_t len)
{
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
   char *app_dir = NULL;
   if (in_path[0] == '~')
   {
      app_dir    = (char*)malloc(DIR_MAX_LENGTH * sizeof(char));
      fill_pathname_home_dir(app_dir, DIR_MAX_LENGTH * sizeof(char));
   }
   else if (in_path[0] == ':')
   {
      app_dir    = (char*)malloc(DIR_MAX_LENGTH * sizeof(char));
      app_dir[0] = '\0';
      fill_pathname_application_dir(app_dir, DIR_MAX_LENGTH * sizeof(char));
   }

   if (app_dir)
   {
      if (*app_dir)
      {
         size_t _len     = strlcpy(s, app_dir, len);

         s              += _len;
         len            -= _len;

         if (!PATH_CHAR_IS_SLASH(s[-1]))
         {
            _len      = strlcpy(s, PATH_DEFAULT_SLASH(), len);

            s        += _len;
            len      -= _len;
         }

         in_path += 2;
      }

      free(app_dir);
   }
#endif
   return strlcpy(s, in_path, len);
}

size_t fill_pathname_abbreviate_special(char *s,
      const char *in_path, size_t len)
{
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
   unsigned i;
   const char *candidates[3];
   const char *notations[3];
   char application_dir[DIR_MAX_LENGTH];
   char home_dir[DIR_MAX_LENGTH];

   application_dir[0] = '\0';

   /* application_dir could be zero-string. Safeguard against this.
    *
    * Keep application dir in front of home, moving app dir to a
    * new location inside home would break otherwise. */

   /* ugly hack - use application_dir pointer
    * before filling it in. C89 reasons */
   candidates[0] = application_dir;
   candidates[1] = home_dir;
   candidates[2] = NULL;

   notations [0] = ":";
   notations [1] = "~";
   notations [2] = NULL;

   fill_pathname_application_dir(application_dir, sizeof(application_dir));
   fill_pathname_home_dir(home_dir, sizeof(home_dir));

   for (i = 0; candidates[i]; i++)
   {
      if (  !string_is_empty(candidates[i])
          && string_starts_with(in_path, candidates[i]))
      {
         size_t _len      = strlcpy(s, notations[i], len);

         s               += _len;
         len             -= _len;
         in_path         += strlen(candidates[i]);

         if (!PATH_CHAR_IS_SLASH(*in_path))
         {
            strcpy(s, PATH_DEFAULT_SLASH());
            s++;
            len--;
         }

         break; /* Don't allow more abbrevs to take place. */
      }
   }
#endif
   return strlcpy(s, in_path, len);
}

/**
 * sanitize_path_part:
 *
 * @path_part               : directory or filename
 *
 * Takes single part of a path eg. single filename
 * or directory, and removes any special chars that are
 * unavailable.
 *
 * @returns new string that has been sanitized
 **/
const char *sanitize_path_part(const char *path_part, size_t len)
{
   int i;
   int j = 0;
   char *tmp = NULL;
   const char *special_chars = "<>:\"/\\|?*";

   if (string_is_empty(path_part))
      return NULL;

   tmp = (char *)malloc((len + 1) * sizeof(char));

   for (i = 0; path_part[i] != '\0'; i++)
   {
      /* Check if the current character is
       * one of the special characters */

      /*  If not, copy it to the temporary array */
      if (!strchr(special_chars, path_part[i]))
         tmp[j++] = path_part[i];
   }

   tmp[j] = '\0';

   /* Return the new string */
   return tmp;
}

/**
 * pathname_conform_slashes_to_os:
 *
 * @s                  : path
 *
 * Leaf function.
 *
 * Changes the slashes to the correct kind for the OS
 * So forward slash on linux and backslash on Windows
 **/
void pathname_conform_slashes_to_os(char *s)
{
   /* Conform slashes to OS standard so we get proper matching */
   char *p;
   for (p = s; *p; p++)
      if (*p == '/' || *p == '\\')
         *p = PATH_DEFAULT_SLASH_C();
}

/**
 * pathname_make_slashes_portable:
 * @s                  : path
 *
 * Leaf function.
 *
 * Change all slashes to forward so they are more
 * portable between Windows and Linux
 **/
void pathname_make_slashes_portable(char *s)
{
   /* Conform slashes to OS standard so we get proper matching */
   char *p;
   for (p = s; *p; p++)
      if (*p == '/' || *p == '\\')
         *p = '/';
}

/**
 * get_pathname_num_slashes:
 * @in_path            : input path
 *
 * Leaf function.
 *
 * Get the number of slashes in a path.
 *
 * @return number of slashes found in @in_path.
 **/
static int get_pathname_num_slashes(const char *in_path)
{
   int num_slashes = 0;
   int i = 0;

   for (i = 0; i < PATH_MAX_LENGTH; i++)
   {
      if (PATH_CHAR_IS_SLASH(in_path[i]))
         num_slashes++;
      if (in_path[i] == '\0')
         break;
   }

   return num_slashes;
}

/**
 * fill_pathname_abbreviated_or_relative:
 *
 * Fills the supplied path with either the abbreviated path or
 * the relative path, which ever one has less depth / number of slashes
 *
 * If lengths of abbreviated and relative paths are the same,
 * the relative path will be used
 * @in_path can be an absolute, relative or abbreviated path
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_abbreviated_or_relative(char *s,
      const char *in_refpath, const char *in_path, size_t len)
{
   size_t _len;
   char in_path_conformed[PATH_MAX_LENGTH];
   char in_refpath_conformed[PATH_MAX_LENGTH];
   char absolute_path[PATH_MAX_LENGTH];
   char relative_path[PATH_MAX_LENGTH];

   absolute_path[0]        = '\0';
   relative_path[0]        = '\0';

   strlcpy(in_path_conformed,    in_path,    sizeof(in_path_conformed));
   strlcpy(in_refpath_conformed, in_refpath, sizeof(in_refpath_conformed));

   pathname_conform_slashes_to_os(in_path_conformed);
   pathname_conform_slashes_to_os(in_refpath_conformed);

   /* Expand paths which start with :\ to an absolute path */
   fill_pathname_expand_special(absolute_path,
         in_path_conformed, sizeof(absolute_path));

   /* Get the absolute path if it is not already */
   if (!path_is_absolute(absolute_path))
      fill_pathname_resolve_relative(absolute_path,
            in_refpath_conformed, in_path_conformed,
            sizeof(absolute_path));
   pathname_conform_slashes_to_os(absolute_path);

   /* Get the relative path and see how many directories long it is */
   path_relative_to(relative_path, absolute_path,
         in_refpath_conformed, sizeof(relative_path));

   /* Get the abbreviated path and see how many directories long it is */
   _len = fill_pathname_abbreviate_special(s, absolute_path, len);

   /* Use the shortest path, preferring the relative path*/
   if (     get_pathname_num_slashes(relative_path)
         <= get_pathname_num_slashes(s))
      return strlcpy(s, relative_path, len);
   return _len;
}

/**
 * path_basedir:
 * @s                  : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 **/
void path_basedir_wrapper(char *s)
{
   char *last_slash = NULL;
   if (!s || s[0] == '\0' || s[1] == '\0')
      return;
#ifdef HAVE_COMPRESSION
   /* We want to find the directory with the archive in basedir. */
   if ((last_slash  = (char*)path_get_archive_delim(s)))
      *last_slash   = '\0';
#endif
   last_slash       = find_last_slash(s);
   if (!last_slash)
   {
      s[0]          = '.';
      s[1]          = PATH_DEFAULT_SLASH_C();
      s[2]          = '\0';
   }
   else
      last_slash[1] = '\0';
}

#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
size_t fill_pathname_application_path(char *s, size_t len)
{
   if (len)
   {
#if defined(_WIN32)
#ifdef LEGACY_WIN32
      DWORD ret = GetModuleFileNameA(NULL, s, len);
#else
      wchar_t wstr[PATH_MAX_LENGTH] = {0};
      DWORD ret = GetModuleFileNameW(NULL, wstr, ARRAY_SIZE(wstr));
      if (*wstr)
      {
         char *str = utf16_to_utf8_string_alloc(wstr);
         if (str)
         {
            strlcpy(s, str, len);
            free(str);
         }
      }
#endif
      s[ret] = '\0';
      return ret;
#elif defined(__APPLE__)
      CFBundleRef bundle = CFBundleGetMainBundle();
      if (bundle)
      {
         size_t rv               = 0;
         CFURLRef bundle_url     = CFBundleCopyBundleURL(bundle);
         CFStringRef bundle_path = CFURLCopyPath(bundle_url);
         CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8);
#ifdef HAVE_COCOATOUCH
         {
            /* This needs to be done so that the path becomes
             * /private/var/... and this
             * is used consistently throughout for the iOS bundle path */
            char resolved_bundle_dir_buf[DIR_MAX_LENGTH] = {0};
            if (realpath(s, resolved_bundle_dir_buf))
            {
               size_t _len = strlcpy(s, resolved_bundle_dir_buf, len - 1);
               s[  _len]   = '/';
               s[++_len]   = '\0';
               rv          = _len;
            }
         }
#else
         rv = CFStringGetLength(bundle_path);
#endif

         CFRelease(bundle_path);
         CFRelease(bundle_url);
         return rv;
      }
#elif defined(__HAIKU__)
      image_info info;
      int32_t cookie = 0;
      while (get_next_image_info(0, &cookie, &info) == B_OK)
      {
         if (info.type == B_APP_IMAGE)
            return strlcpy(s, info.name, len);
      }
#elif defined(__QNX__)
      char *buff  = (char*)malloc(len);
      size_t _len = 0;
      if (_cmdname(buff))
         _len = strlcpy(s, buff, len);
      free(buff);
      return _len;
#else
      size_t i;
      static const char *exts[] = { "exe", "file", "path/a.out" };
      char link_path[255];
      pid_t pid   = getpid();
      size_t _len = snprintf(link_path, sizeof(link_path), "/proc/%u/",
            (unsigned)pid);

      *s           = '\0';

      /* Linux, BSD and Solaris paths. Not standardized. */
      for (i = 0; i < ARRAY_SIZE(exts); i++)
      {
         ssize_t ret;
         strlcpy(link_path + _len, exts[i], sizeof(link_path) - _len);

         if ((ret = readlink(link_path, s, len - 1)) >= 0)
         {
            s[ret] = '\0';
            return ret;
         }
      }
#endif
   }
   return 0;
}

size_t fill_pathname_application_dir(char *s, size_t len)
{
#ifdef __WINRT__
   return strlcpy(s, uwp_dir_install, len);
#else
   fill_pathname_application_path(s, len);
   return path_basedir(s);
#endif
}

size_t fill_pathname_home_dir(char *s, size_t len)
{
#ifdef __WINRT__
   const char *home = uwp_dir_data;
#else
   const char *home = getenv("HOME");
#endif
   if (home)
      return strlcpy(s, home, len);
   *s = 0;
   return 0;
}
#endif

bool is_path_accessible_using_standard_io(const char *path)
{
#ifdef __WINRT__
   return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
#else
   return true;
#endif
}

./include/libretro-common/file/file_path_io.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_path_io.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <sys/stat.h>

#include <boolean.h>
#include <file/file_path.h>
#include <compat/strl.h>
#include <compat/posix_string.h>
#include <retro_miscellaneous.h>
#include <string/stdstring.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>

#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h> /* stat() is defined here */
#endif

/* TODO/FIXME - globals */
static retro_vfs_stat_t path_stat_cb   = retro_vfs_stat_impl;
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;

void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
   const struct retro_vfs_interface* 
      vfs_iface           = vfs_info->iface;

   path_stat_cb           = retro_vfs_stat_impl;
   path_mkdir_cb          = retro_vfs_mkdir_impl;

   if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
      return;

   path_stat_cb           = vfs_iface->stat;
   path_mkdir_cb          = vfs_iface->mkdir;
}

int path_stat(const char *path)
{
   return path_stat_cb(path, NULL);
}

/**
 * path_is_directory:
 * @path               : path
 *
 * Checks if path is a directory.
 *
 * @return true if path is a directory, otherwise false.
 */
bool path_is_directory(const char *path)
{
   return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
}

bool path_is_character_special(const char *path)
{
   return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
}

bool path_is_valid(const char *path)
{
   return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
}

int32_t path_get_size(const char *path)
{
   int32_t filesize = 0;
   if (path_stat_cb(path, &filesize) != 0)
      return filesize;

   return -1;
}

/**
 * path_mkdir:
 * @dir                : directory
 *
 * Create directory on filesystem.
 * 
 * Recursive function.
 *
 * @return true if directory could be created, otherwise false.
 **/
bool path_mkdir(const char *dir)
{
   bool norecurse     = false;
   char     *basedir  = NULL;

   if (!(dir && *dir))
      return false;

   /* Use heap. Real chance of stack 
    * overflow if we recurse too hard. */
   if (!(basedir = strdup(dir)))
      return false;

   path_parent_dir(basedir, strlen(basedir));

   if (!*basedir || !strcmp(basedir, dir))
   {
      free(basedir);
      return false;
   }

   if (     path_is_directory(basedir)
         || path_mkdir(basedir))
      norecurse = true;

   free(basedir);

   if (norecurse)
   {
      int ret = path_mkdir_cb(dir);

      /* Don't treat this as an error. */
      if (ret == -2 && path_is_directory(dir))
         return true;
      else if (ret == 0)
         return true;
   }
   return false;
}

./include/libretro-common/file/nbio/nbio_intf.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_intf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <file/nbio.h>

extern nbio_intf_t nbio_linux;
extern nbio_intf_t nbio_mmap_unix;
extern nbio_intf_t nbio_mmap_win32;
extern nbio_intf_t nbio_stdio;

#ifndef _XBOX
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1500

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif

#elif !defined(_MSC_VER)

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#endif
#endif

#endif

#if defined(_linux__)
static nbio_intf_t *internal_nbio = &nbio_linux;
#elif defined(HAVE_MMAP) && defined(BSD)
static nbio_intf_t *internal_nbio = &nbio_mmap_unix;
#elif defined(HAVE_MMAP_WIN32)
static nbio_intf_t *internal_nbio = &nbio_mmap_win32;
#else
static nbio_intf_t *internal_nbio = &nbio_stdio;
#endif

void *nbio_open(const char * filename, unsigned mode)
{
   return internal_nbio->open(filename, mode);
}

void nbio_begin_read(void *data)
{
   internal_nbio->begin_read(data);
}

void nbio_begin_write(void *data)
{
   internal_nbio->begin_write(data);
}

bool nbio_iterate(void *data)
{
   return internal_nbio->iterate(data);
}

void nbio_resize(void *data, size_t len)
{
   internal_nbio->resize(data, len);
}

void *nbio_get_ptr(void *data, size_t* len)
{
   return internal_nbio->get_ptr(data, len);
}

void nbio_cancel(void *data)
{
   internal_nbio->cancel(data);
}

void nbio_free(void *data)
{
   internal_nbio->free(data);
}

./include/libretro-common/file/nbio/nbio_linux.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_linux.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <file/nbio.h>

#if defined(__linux__)

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <linux/aio_abi.h>

struct nbio_linux_t
{
   void* ptr;
   aio_context_t ctx;
   struct iocb cb;
   size_t len;
   int fd;
   bool busy;
};

/* there's also a Unix AIO thingy, but it's not in glibc
 * and we don't want more dependencies */

static int io_setup(unsigned nr, aio_context_t * ctxp)
{
   return syscall(__NR_io_setup, nr, ctxp);
}

static int io_destroy(aio_context_t ctx)
{
   return syscall(__NR_io_destroy, ctx);
}

static int io_submit(aio_context_t ctx, long nr, struct iocb ** cbp)
{
   return syscall(__NR_io_submit, ctx, nr, cbp);
}

static int io_cancel(aio_context_t ctx, struct iocb * iocb, struct io_event * result)
{
   return syscall(__NR_io_cancel, ctx, iocb, result);
}

static int io_getevents(aio_context_t ctx, long min_nr, long nr,
      struct io_event * events, struct timespec * timeout)
{
   return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
}

static void nbio_begin_op(struct nbio_linux_t* handle, uint16_t op)
{
   struct iocb * cbp         = &handle->cb;

   memset(&handle->cb, 0, sizeof(handle->cb));

   handle->cb.aio_fildes     = handle->fd;
   handle->cb.aio_lio_opcode = op;

   handle->cb.aio_buf        = (uint64_t)(uintptr_t)handle->ptr;
   handle->cb.aio_offset     = 0;
   handle->cb.aio_nbytes     = handle->len;

   if (io_submit(handle->ctx, 1, &cbp) != 1)
      abort();

   handle->busy = true;
}

static void *nbio_linux_open(const char * filename, unsigned mode)
{
   static const int o_flags[]  =   { O_RDONLY, O_RDWR|O_CREAT|O_TRUNC, O_RDWR, O_RDONLY, O_RDWR|O_CREAT|O_TRUNC };

   aio_context_t ctx           = 0;
   struct nbio_linux_t* handle = NULL;
   int fd                      = open(filename, o_flags[mode]|O_CLOEXEC, 0644);
   if (fd < 0)
      return NULL;

   if (io_setup(128, &ctx) < 0)
   {
      close(fd);
      return NULL;
   }

   handle       = (struct nbio_linux_t*)malloc(sizeof(struct nbio_linux_t));
   handle->fd   = fd;
   handle->ctx  = ctx;
   handle->len  = lseek(fd, 0, SEEK_END);
   handle->ptr  = malloc(handle->len);
   handle->busy = false;

   return handle;
}

static void nbio_linux_begin_read(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (handle)
      nbio_begin_op(handle, IOCB_CMD_PREAD);
}

static void nbio_linux_begin_write(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (handle)
      nbio_begin_op(handle, IOCB_CMD_PWRITE);
}

static bool nbio_linux_iterate(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return false;
   if (handle->busy)
   {
      struct io_event ev;
      if (io_getevents(handle->ctx, 0, 1, &ev, NULL) == 1)
         handle->busy = false;
   }
   return !handle->busy;
}

static void nbio_linux_resize(void *data, size_t len)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return;

   /* This works perfectly fine if this check is removed, but it
    * won't work on other nbio implementations */
   /* therefore, it's blocked so nobody accidentally relies on it */
   if (len < handle->len)
      abort();

   if (ftruncate(handle->fd, len) != 0)
      abort(); /* this one returns void and I can't find any other way
                  for it to report failure */

   handle->ptr = realloc(handle->ptr, len);
   handle->len = len;
}

static void *nbio_linux_get_ptr(void *data, size_t* len)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle->len;
   if (!handle->busy)
      return handle->ptr;
   return NULL;
}

static void nbio_linux_cancel(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return;

   if (handle->busy)
   {
      struct io_event ev;
      io_cancel(handle->ctx, &handle->cb, &ev);
      handle->busy = false;
   }
}

static void nbio_linux_free(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return;

   io_destroy(handle->ctx);
   close(handle->fd);
   free(handle->ptr);
   free(handle);
}

nbio_intf_t nbio_linux = {
   nbio_linux_open,
   nbio_linux_begin_read,
   nbio_linux_begin_write,
   nbio_linux_iterate,
   nbio_linux_resize,
   nbio_linux_get_ptr,
   nbio_linux_cancel,
   nbio_linux_free,
   "nbio_linux",
};
#else
nbio_intf_t nbio_linux = {
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   "nbio_linux",
};

#endif

./include/libretro-common/file/nbio/nbio_orbis.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_orbis.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <file/nbio.h>

#if defined(ORBIS)
#include <stdio.h>
#include <stdlib.h>
#include <orbisFile.h>
#include <unistd.h>
#include <sys/fcntl.h>

struct nbio_orbis_t
{
   void* data;
   size_t progress;
   size_t len;
   int fd;
   unsigned int mode;
   /*
    * possible values:
    * NBIO_READ, NBIO_WRITE - obvious
    * -1 - currently doing nothing
    * -2 - the pointer was reallocated since the last operation
    */
   signed char op;
};

static void *nbio_orbis_open(const char * filename, unsigned int mode)
{
   static const int o_flags[]  =   { O_RDONLY, O_RDWR | O_CREAT | O_TRUNC,
      O_RDWR, O_RDONLY, O_RDWR | O_CREAT | O_TRUNC };
   void *buf                   = NULL;
   struct nbio_orbis_t* handle = NULL;
   size_t len                  = 0;
   int fd                      = orbisOpen(filename, o_flags[mode], 0644);

   if (fd < 0)
      return NULL;
   handle                = (struct nbio_orbis_t*)malloc(sizeof(struct nbio_orbis_t));

   if (!handle)
      goto error;

   handle->fd             = fd;

   switch (mode)
   {
      case NBIO_WRITE:
      case BIO_WRITE:
         break;
      default:
         len=orbisLseek(handle->fd, 0, SEEK_END);
         orbisLseek(handle->fd, 0, SEEK_SET);
         break;
   }

   handle->mode          = mode;

   if (len)
      buf                = malloc(len);

   if (len && !buf)
      goto error;

   handle->data          = buf;
   handle->len           = len;
   handle->progress      = handle->len;
   handle->op            = -2;

   return handle;

error:
   if (handle)
      free(handle);
   orbisClose(fd);
   return NULL;
}

static void nbio_orbis_begin_read(void *data)
{

   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle->op >= 0)
      return;

   orbisLseek(handle->fd, 0, SEEK_SET);

   handle->op       = NBIO_READ;
   handle->progress = 0;
}

static void nbio_orbis_begin_write(void *data)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle->op >= 0)
      return;

   orbisLseek(handle->fd, 0, SEEK_SET);
   handle->op = NBIO_WRITE;
   handle->progress = 0;
}

static bool nbio_orbis_iterate(void *data)
{
   size_t amount               = 65536;
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;

   if (!handle)
      return false;

   if (amount > handle->len - handle->progress)
      amount = handle->len - handle->progress;

   switch (handle->op)
   {
      case NBIO_READ:
         if (handle->mode == BIO_READ)
            amount = handle->len;
         break;
      case NBIO_WRITE:
         if (handle->mode == BIO_WRITE)
         {
            size_t written = 0;
            amount = handle->len;
            written = orbisWrite(handle->fd, (char*)handle->data, amount);

            if (written != amount)
               return false;
         }
         break;
   }

   handle->progress += amount;

   if (handle->progress == handle->len)
      handle->op = -1;
   return (handle->op < 0);
}

static void nbio_orbis_resize(void *data, size_t len)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle->op >= 0)
      return;
   if (len < handle->len)
      return;

   handle->len      = len;
   handle->data     = realloc(handle->data, handle->len);
   handle->op       = -1;
   handle->progress = handle->len;
}

static void *nbio_orbis_get_ptr(void *data, size_t* len)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle->len;
   if (handle->op == -1)
      return handle->data;
   return NULL;
}

static void nbio_orbis_cancel(void *data)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;
   handle->op = -1;
   handle->progress = handle->len;
}

static void nbio_orbis_free(void *data)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle->op >= 0)
      return;

   orbisClose(handle->fd);
   free(handle->data);

   handle->data = NULL;
   free(handle);
}

nbio_intf_t nbio_orbis = {
   nbio_orbis_open,
   nbio_orbis_begin_read,
   nbio_orbis_begin_write,
   nbio_orbis_iterate,
   nbio_orbis_resize,
   nbio_orbis_get_ptr,
   nbio_orbis_cancel,
   nbio_orbis_free,
   "nbio_orbis",
};
#endif

./include/libretro-common/file/nbio/nbio_stdio.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_stdio.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#if defined(WIIU)
#include <malloc.h>
#endif

#include <file/nbio.h>
#include <encodings/utf.h>

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1400
#define ATLEAST_VC2005
#endif
#endif

#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
#endif

struct nbio_stdio_t
{
   FILE* f;
   void* data;
   size_t progress;
   size_t len;
   /*
    * possible values:
    * NBIO_READ, NBIO_WRITE - obvious
    * -1 - currently doing nothing
    * -2 - the pointer was reallocated since the last operation
    */
   signed char op;
   signed char mode;
};

#if !defined(_WIN32) || defined(LEGACY_WIN32)
static const char    *stdio_modes[] = { "rb", "wb", "r+b", "rb", "wb", "r+b" };
#else
static const wchar_t *stdio_modes[] = { L"rb", L"wb", L"r+b", L"rb", L"wb", L"r+b" };
#endif

static int64_t fseek_wrap(FILE *f, int64_t offset, int origin)
{
#ifdef ATLEAST_VC2005
   /* VC2005 and up have a special 64-bit fseek */
   return _fseeki64(f, offset, origin);
#elif defined(HAVE_64BIT_OFFSETS)
   return fseeko(f, (off_t)offset, origin);
#else
   return fseek(f, (long)offset, origin);
#endif
}

static int64_t ftell_wrap(FILE *f)
{
#ifdef ATLEAST_VC2005
   /* VC2005 and up have a special 64-bit ftell */
   return _ftelli64(f);
#elif defined(HAVE_64BIT_OFFSETS)
   return ftello(f);
#else
   return ftell(f);
#endif
}

static void *nbio_stdio_open(const char * filename, unsigned mode)
{
   void *buf                   = NULL;
   struct nbio_stdio_t* handle = NULL;
   int64_t len                 = 0;
#if !defined(_WIN32) || defined(LEGACY_WIN32)
   FILE* f                     = fopen(filename, stdio_modes[mode]);
#else
   wchar_t *filename_wide      = utf8_to_utf16_string_alloc(filename);
   FILE* f                     = _wfopen(filename_wide, stdio_modes[mode]);

   if (filename_wide)
      free(filename_wide);
#endif
   if (!f)
      return NULL;

   handle = (struct nbio_stdio_t*)malloc(sizeof(struct nbio_stdio_t));

   if (!handle)
   {
      fclose(f);
      return NULL;
   }

   handle->f = f;

   switch (mode)
   {
      case NBIO_WRITE:
      case BIO_WRITE:
         break;
      default:
         fseek_wrap(handle->f, 0, SEEK_END);
         len = ftell_wrap(handle->f);
         break;
   }

   handle->mode          = mode;

#if defined(WIIU)
   /* hit the aligned-buffer fast path on Wii U */
   if (len)
      buf                = memalign(0x40, (size_t)len);
#else
   if (len)
      buf                = malloc((size_t)len);
#endif

   if (len && !buf)
   {
      free(handle);
      fclose(f);
      return NULL;
   }

   handle->data          = buf;
   handle->len           = len;
   handle->progress      = handle->len;
   handle->op            = -2;

   return handle;
}

static void nbio_stdio_begin_read(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   if (handle->op >= 0)
      abort();

   fseek_wrap(handle->f, 0, SEEK_SET);

   handle->op       = NBIO_READ;
   handle->progress = 0;
}

static void nbio_stdio_begin_write(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   if (handle->op >= 0)
      abort();

   fseek_wrap(handle->f, 0, SEEK_SET);
   handle->op = NBIO_WRITE;
   handle->progress = 0;
}

static bool nbio_stdio_iterate(void *data)
{
   size_t amount               = 65536;
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;

   if (!handle)
      return false;

   if (amount > handle->len - handle->progress)
      amount = handle->len - handle->progress;

   switch (handle->op)
   {
      case NBIO_READ:
         if (handle->mode == BIO_READ)
         {
            amount = handle->len;
            fread((char*)handle->data, 1, amount, handle->f);
         }
         else
            fread((char*)handle->data + handle->progress, 1, amount, handle->f);
         break;
      case NBIO_WRITE:
         if (handle->mode == BIO_WRITE)
         {
            size_t written = 0;
            amount = handle->len;
            written = fwrite((char*)handle->data, 1, amount, handle->f);
            if (written != amount)
               return false;
         }
         else
            fwrite((char*)handle->data + handle->progress, 1, amount, handle->f);
         break;
   }

   handle->progress += amount;

   if (handle->progress == handle->len)
      handle->op = -1;
   return (handle->op < 0);
}

static void nbio_stdio_resize(void *data, size_t len)
{
   void *new_data              = NULL;
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   if (handle->op >= 0)
      abort();
   if (len < handle->len)
      abort();

   handle->len      = len;
   handle->progress = len;
   handle->op       = -1;

   new_data         = realloc(handle->data, handle->len);

   if (new_data)
      handle->data  = new_data;
}

static void *nbio_stdio_get_ptr(void *data, size_t* len)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle->len;
   if (handle->op == -1)
      return handle->data;
   return NULL;
}

static void nbio_stdio_cancel(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   handle->op = -1;
   handle->progress = handle->len;
}

static void nbio_stdio_free(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;
   if (handle->op >= 0)
      abort();
   fclose(handle->f);
   free(handle->data);

   handle->f    = NULL;
   handle->data = NULL;
   free(handle);
}

nbio_intf_t nbio_stdio = {
   nbio_stdio_open,
   nbio_stdio_begin_read,
   nbio_stdio_begin_write,
   nbio_stdio_iterate,
   nbio_stdio_resize,
   nbio_stdio_get_ptr,
   nbio_stdio_cancel,
   nbio_stdio_free,
   "nbio_stdio",
};

./include/libretro-common/file/nbio/nbio_unixmmap.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_unixmmap.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <file/nbio.h>

#if defined(HAVE_MMAP) && defined(BSD)

#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/mman.h>

#ifdef __APPLE__

#ifndef O_CLOEXEC
#define O_CLOEXEC 0x1000000
#endif

#else

#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif

#endif

struct nbio_mmap_unix_t
{
   void* ptr;
   size_t len;
   int fd;
   int map_flags;
};

static void *nbio_mmap_unix_open(const char * filename, unsigned mode)
{
   static const int o_flags[] =   { O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC, O_RDWR,               O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC };
   static const int map_flags[] = { PROT_READ, PROT_WRITE|PROT_READ,   PROT_WRITE|PROT_READ, PROT_READ, PROT_WRITE|PROT_READ   };

   size_t _len;
   void* ptr                       = NULL;
   struct nbio_mmap_unix_t* handle = NULL;
   int fd                          = open(filename, o_flags[mode]|O_CLOEXEC, 0644);
   if (fd < 0)
      return NULL;

   _len = lseek(fd, 0, SEEK_END);
   if (_len != 0)
      ptr = mmap(NULL, _len, map_flags[mode], MAP_SHARED, fd, 0);

   if (ptr == MAP_FAILED)
   {
      close(fd);
      return NULL;
   }

   handle            = malloc(sizeof(struct nbio_mmap_unix_t));
   handle->fd        = fd;
   handle->map_flags = map_flags[mode];
   handle->len       = _len;
   handle->ptr       = ptr;
   return handle;
}

static void nbio_mmap_unix_begin_read(void *data)
{
   /* not needed */
}

static void nbio_mmap_unix_begin_write(void *data)
{
   /* not needed */
}

static bool nbio_mmap_unix_iterate(void *data)
{
   return true; /* not needed */
}

static void nbio_mmap_unix_resize(void *data, size_t len)
{
   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
   if (!handle)
      return;
   if (len < handle->len)
   {
      /* this works perfectly fine if this check is removed, but it
       * won't work on other nbio implementations */
      /* therefore, it's blocked so nobody accidentally relies on it */
      abort();
   }

   if (ftruncate(handle->fd, len) != 0)
      abort(); /* this one returns void and I can't find any other
                  way for it to report failure */

   munmap(handle->ptr, handle->len);

   handle->ptr = mmap(NULL, len, handle->map_flags, MAP_SHARED, handle->fd, 0);
   handle->len = len;

   if (handle->ptr == MAP_FAILED)
      abort();
}

static void *nbio_mmap_unix_get_ptr(void *data, size_t *len)
{
   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle->len;
   return handle->ptr;
}

static void nbio_mmap_unix_cancel(void *data)
{
   /* not needed */
}

static void nbio_mmap_unix_free(void *data)
{
   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
   if (!handle)
      return;
   close(handle->fd);
   munmap(handle->ptr, handle->len);
   free(handle);
}

nbio_intf_t nbio_mmap_unix = {
   nbio_mmap_unix_open,
   nbio_mmap_unix_begin_read,
   nbio_mmap_unix_begin_write,
   nbio_mmap_unix_iterate,
   nbio_mmap_unix_resize,
   nbio_mmap_unix_get_ptr,
   nbio_mmap_unix_cancel,
   nbio_mmap_unix_free,
   "nbio_mmap_unix",
};
#else
nbio_intf_t nbio_mmap_unix = {
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   "nbio_mmap_unix",
};

#endif

./include/libretro-common/file/nbio/nbio_windowsmmap.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_windowsmmap.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <file/nbio.h>

#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1500

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif

#elif !defined(_MSC_VER)

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#endif

#endif

#if defined(HAVE_MMAP_WIN32)

#include <stdio.h>
#include <stdlib.h>

#include <encodings/utf.h>

#include <windows.h>

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#ifndef FILE_SHARE_ALL
#define FILE_SHARE_ALL (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)
#endif

struct nbio_mmap_win32_t
{
   HANDLE file;
   void* ptr;
   size_t len;
   bool is_write;
};

static void *nbio_mmap_win32_open(const char * filename, unsigned mode)
{
   static const DWORD dispositions[] = { OPEN_EXISTING, CREATE_ALWAYS, OPEN_ALWAYS, OPEN_EXISTING, CREATE_ALWAYS };
   HANDLE mem;
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
   LARGE_INTEGER len;
#else
   SIZE_T len;
#endif
   struct nbio_mmap_win32_t* handle  = NULL;
   void* ptr                         = NULL;
   bool is_write                     = (mode == NBIO_WRITE || mode == NBIO_UPDATE || mode == BIO_WRITE);
   DWORD access                      = (is_write ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ);
#if !defined(_WIN32) || defined(LEGACY_WIN32)
   HANDLE file                       = CreateFile(filename, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
#else
   wchar_t *filename_wide            = utf8_to_utf16_string_alloc(filename);
#ifdef __WINRT__
   HANDLE file                       = CreateFile2(filename_wide, access, FILE_SHARE_ALL, dispositions[mode], NULL);
#else
   HANDLE file                       = CreateFileW(filename_wide, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
#endif

   if (filename_wide)
      free(filename_wide);
#endif

   if (file == INVALID_HANDLE_VALUE)
      return NULL;

#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
   /* GetFileSizeEx is new for Windows 2000 */
   GetFileSizeEx(file, &len);
   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len.QuadPart);
#else
   GetFileSize(file, &len);
   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
#endif

   CloseHandle(mem);

   handle           = (struct nbio_mmap_win32_t*)malloc(sizeof(struct nbio_mmap_win32_t));

   handle->file     = file;
   handle->is_write = is_write;
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
   handle->len      = len.QuadPart;
#else
   handle->len      = len;
#endif
   handle->ptr      = ptr;

   return handle;
}

static void nbio_mmap_win32_begin_read(void *data)
{
   /* not needed */
}

static void nbio_mmap_win32_begin_write(void *data)
{
   /* not needed */
}

static bool nbio_mmap_win32_iterate(void *data)
{
   /* not needed */
   return true;
}

static void nbio_mmap_win32_resize(void *data, size_t len)
{
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
   LARGE_INTEGER len_li;
#else
   SIZE_T len_li;
#endif
   HANDLE mem;
   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;

   if (!handle)
      return;

   if (len < handle->len)
   {
      /* this works perfectly fine if this check is removed,
       * but it won't work on other nbio implementations */
      /* therefore, it's blocked so nobody accidentally
       * relies on it. */
      abort();
   }

#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
   /* SetFilePointerEx is new for Windows 2000 */
   len_li.QuadPart = len;
   SetFilePointerEx(handle->file, len_li, NULL, FILE_BEGIN);
#else
   len_li = len;
   SetFilePointer(handle->file, len_li, NULL, FILE_BEGIN);
#endif

   if (!SetEndOfFile(handle->file))
      abort(); /* this one returns void and I can't find any other way for it to report failure */
   handle->len = len;

   UnmapViewOfFile(handle->ptr);
   mem = CreateFileMapping(handle->file, NULL, handle->is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
   handle->ptr = MapViewOfFile(mem, handle->is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
   CloseHandle(mem);

   if (!handle->ptr)
      abort();
}

static void *nbio_mmap_win32_get_ptr(void *data, size_t* len)
{
   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle->len;
   return handle->ptr;
}

static void nbio_mmap_win32_cancel(void *data)
{
   /* not needed */
}

static void nbio_mmap_win32_free(void *data)
{
   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;
   if (!handle)
      return;
   CloseHandle(handle->file);
   UnmapViewOfFile(handle->ptr);
   free(handle);
}

nbio_intf_t nbio_mmap_win32 = {
   nbio_mmap_win32_open,
   nbio_mmap_win32_begin_read,
   nbio_mmap_win32_begin_write,
   nbio_mmap_win32_iterate,
   nbio_mmap_win32_resize,
   nbio_mmap_win32_get_ptr,
   nbio_mmap_win32_cancel,
   nbio_mmap_win32_free,
   "nbio_mmap_win32",
};
#else
nbio_intf_t nbio_mmap_win32 = {
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   "nbio_mmap_win32",
};

#endif

./include/libretro-common/file/retro_dirent.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_dirent.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <retro_common.h>

#include <boolean.h>
#include <retro_dirent.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>

/* TODO/FIXME - static globals */
static retro_vfs_opendir_t dirent_opendir_cb                 = NULL;
static retro_vfs_readdir_t dirent_readdir_cb                 = NULL;
static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb     = NULL;
static retro_vfs_closedir_t dirent_closedir_cb               = NULL;

void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
   const struct retro_vfs_interface* vfs_iface;

   dirent_opendir_cb         = NULL;
   dirent_readdir_cb         = NULL;
   dirent_dirent_get_name_cb = NULL;
   dirent_dirent_is_dir_cb   = NULL;
   dirent_closedir_cb        = NULL;

   vfs_iface                 = vfs_info->iface;

   if (
         vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION || 
         !vfs_iface)
      return;

   dirent_opendir_cb         = vfs_iface->opendir;
   dirent_readdir_cb         = vfs_iface->readdir;
   dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;
   dirent_dirent_is_dir_cb   = vfs_iface->dirent_is_dir;
   dirent_closedir_cb        = vfs_iface->closedir;
}

struct RDIR *retro_opendir_include_hidden(
      const char *name, bool include_hidden)
{
   if (dirent_opendir_cb)
      return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
   return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
}

struct RDIR *retro_opendir(const char *name)
{
   return retro_opendir_include_hidden(name, false);
}

bool retro_dirent_error(struct RDIR *rdir)
{
   /* Left for compatibility */
   return false;
}

int retro_readdir(struct RDIR *rdir)
{
   if (dirent_readdir_cb)
      return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
   return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
}

const char *retro_dirent_get_name(struct RDIR *rdir)
{
   if (dirent_dirent_get_name_cb)
      return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
   return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
}

/**
 *
 * retro_dirent_is_dir:
 * @rdir         : pointer to the directory entry.
 * @unused       : deprecated, included for compatibility reasons, pass NULL
 *
 * Is the directory listing entry a directory?
 *
 * Returns: true if directory listing entry is
 * a directory, false if not.
 */
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
{
   if (dirent_dirent_is_dir_cb)
      return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
   return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
}

void retro_closedir(struct RDIR *rdir)
{
   if (dirent_closedir_cb)
      dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
   else
      retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);
}

./include/libretro-common/formats/bmp/rbmp.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbmp.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Modified version of stb_image's BMP sources. */

#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h> /* ptrdiff_t on osx */
#include <stdlib.h>
#include <string.h>

#include <retro_inline.h>

#include <formats/image.h>
#include <formats/rbmp.h>

/* truncate int to byte without warnings */
#define RBMP_BYTECAST(x)  ((unsigned char) ((x) & 255))

#define RBMP_COMPUTE_Y(r, g, b) ((unsigned char) ((((r) * 77) + ((g) * 150) +  (29 * (b))) >> 8))

typedef struct
{
   unsigned char *img_buffer;
   unsigned char *img_buffer_end;
   unsigned char *img_buffer_original;
   int img_n;
   int img_out_n;
   int buflen;
   uint32_t img_x;
   uint32_t img_y;
   unsigned char buffer_start[128];
} rbmp_context;

struct rbmp
{
   uint8_t *buff_data;
   uint32_t *output_image;
};

static INLINE unsigned char rbmp_get8(rbmp_context *s)
{
   if (s->img_buffer < s->img_buffer_end)
      return *s->img_buffer++;

   return 0;
}

static void rbmp_skip(rbmp_context *s, int n)
{
   if (n < 0)
   {
      s->img_buffer = s->img_buffer_end;
      return;
   }

   s->img_buffer += n;
}

static int rbmp_get16le(rbmp_context *s)
{
   return rbmp_get8(s) + (rbmp_get8(s) << 8);
}

#define RBMP_GET32LE(s) (rbmp_get16le(s) + (rbmp_get16le(s) << 16))

static unsigned char *rbmp_convert_format(
      unsigned char *data,
      int img_n,
      int req_comp,
      unsigned int x,
      unsigned int y)
{
   int i,j;
   unsigned char *good = (unsigned char *)malloc(req_comp * x * y);

   if (!good)
      return NULL;

   for (j=0; j < (int) y; ++j)
   {
      unsigned char *src  = data + j * x * img_n   ;
      unsigned char *dest = good + j * x * req_comp;

      switch (((img_n)*8+(req_comp)))
      {
         case 10:
            for (i = x-1; i >= 0; --i, src += 1, dest += 2)
            {
               dest[0]=src[0];
               dest[1]=255;
            }
            break;
         case 11:
            for (i = x-1; i >= 0; --i, src += 1, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case 12:
            for (i = x-1; i >= 0; --i, src += 1, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=255;
            }
            break;
         case 17:
            for (i = x-1; i >= 0; --i, src += 2, dest += 1)
               dest[0]=src[0];
            break;
         case 19:
            for (i = x-1; i >= 0; --i, src += 2, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case 20:
            for (i = x-1; i >= 0; --i, src += 2, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=src[1];
            }
            break;
         case 28:
            for (i = x-1; i >= 0; --i, src += 3, dest += 4)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
               dest[3]=255;
            }
            break;
         case 25:
            for (i = x-1; i >= 0; --i, src += 3, dest += 1)
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case 26:
            for (i = x-1; i >= 0; --i, src += 3, dest += 2)
            {
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = 255;
            }
            break;
         case 33:
            for (i = x-1; i >= 0; --i, src += 4, dest += 1)
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case 34:
            for (i = x-1; i >= 0; --i, src += 4, dest += 2)
            {
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = src[3];
            }
            break;
         case 35:
            for (i = x-1; i >= 0; --i, src += 4, dest += 3)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
            }
            break;
         default:
            break;
      }

   }

   return good;
}

/* Microsoft/Windows BMP image */

/* returns 0..31 for the highest set bit */
static int rbmp_high_bit(unsigned int z)
{
   int n=0;
   if (z == 0)
      return -1;

   if (z >= 0x10000)
   {
      n  += 16;
      z >>= 16;
   }
   if (z >= 0x00100)
   {
      n  +=  8;
      z >>=  8;
   }
   if (z >= 0x00010)
   {
      n  +=  4;
      z >>=  4;
   }
   if (z >= 0x00004)
   {
      n  +=  2;
      z >>=  2;
   }
   if (z >= 0x00002)
      n +=  1;
   return n;
}

static int rbmp_bitcount(unsigned int a)
{
   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); /* max 2 */
   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); /* max 4 */
   a = (a + (a >> 4)) & 0x0f0f0f0f; /* max 8 per 4, now 8 bits */
   a = (a + (a >> 8));              /* max 16 per 8 bits */
   a = (a + (a >> 16));             /* max 32 per 8 bits */
   return a & 0xff;
}

static int rbmp_shiftsigned(int v, int shift, int bits)
{
   int ret;
   int z = bits;

   if (shift < 0)
      v <<= -shift;
   else
      v >>= shift;

   ret = v;

   while (z < 8)
   {
      ret += v >> z;
      z   += bits;
   }
   return ret;
}

static unsigned char *rbmp_bmp_load(rbmp_context *s, unsigned *x, unsigned *y,
      int *comp, int req_comp)
{
   unsigned char *out;
   int bpp, flip_vertically, pad, target, offset, hsz;
   int psize=0,i,j,width;
   unsigned int mr=0,mg=0,mb=0,ma=0;

   /* Corrupt BMP? */
   if (rbmp_get8(s) != 'B' || rbmp_get8(s) != 'M')
      return 0;

   /* discard filesize */
   rbmp_get16le(s);
   rbmp_get16le(s);
   /* discard reserved */
   rbmp_get16le(s);
   rbmp_get16le(s);

   offset = (uint32_t)RBMP_GET32LE(s);
   hsz    = (uint32_t)RBMP_GET32LE(s);

   /* BMP type not supported? */
   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)
      return 0;

   if (hsz == 12)
   {
      s->img_x = rbmp_get16le(s);
      s->img_y = rbmp_get16le(s);
   }
   else
   {
      s->img_x = (uint32_t)RBMP_GET32LE(s);
      s->img_y = (uint32_t)RBMP_GET32LE(s);
   }

   /* Bad BMP? */
   if (rbmp_get16le(s) != 1)
      return 0;

   bpp = rbmp_get16le(s);

   /* BMP 1-bit type not supported? */
   if (bpp == 1)
      return 0;

   flip_vertically = ((int) s->img_y) > 0;
   s->img_y        = abs((int) s->img_y);

   if (hsz == 12)
   {
      if (bpp < 24)
         psize = (offset - 14 - 24) / 3;
   }
   else
   {
      int compress = (uint32_t)RBMP_GET32LE(s);

      /* BMP RLE type not supported? */
      if (compress == 1 || compress == 2)
         return 0;

      /* discard sizeof */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard hres */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard vres */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard colors used */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard max important */
      rbmp_get16le(s);
      rbmp_get16le(s);

      if (hsz == 40 || hsz == 56)
      {
         if (hsz == 56)
         {
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
         }
         if (bpp == 16 || bpp == 32)
         {
            switch (compress)
            {
               case 0:
                  break;
               case 3:
                  mr = (uint32_t)RBMP_GET32LE(s);
                  mg = (uint32_t)RBMP_GET32LE(s);
                  mb = (uint32_t)RBMP_GET32LE(s);
                  /* not documented, but generated by
                   * Photoshop and handled by MS Paint */
                  /* Bad BMP ?*/
                  if (mr == mg && mg == mb)
                     return 0;
                  break;
               default:
                  break;
            }

            /* Bad BMP? */
            return 0;
         }
      }
      else
      {
         mr = (uint32_t)RBMP_GET32LE(s);
         mg = (uint32_t)RBMP_GET32LE(s);
         mb = (uint32_t)RBMP_GET32LE(s);
         ma = (uint32_t)RBMP_GET32LE(s);
         /* Discard color space */
         rbmp_get16le(s);
         rbmp_get16le(s);
         for (i = 0; i < 12; ++i)
         {
            /* Discard color space parameters */
            rbmp_get16le(s);
            rbmp_get16le(s);
         }
         if (hsz == 124)
         {
            /* Discard rendering intent */
            rbmp_get16le(s);
            rbmp_get16le(s);
            /* Discard offset of profile data */
            rbmp_get16le(s);
            rbmp_get16le(s);
            /* Discard size of profile data */
            rbmp_get16le(s);
            rbmp_get16le(s);
            /* Discard reserved */
            rbmp_get16le(s);
            rbmp_get16le(s);
         }
      }
      if (bpp < 16)
         psize = (offset - 14 - hsz) >> 2;
   }
   s->img_n = ma ? 4 : 3;
   if (req_comp && req_comp >= 3) /* We can directly decode 3 or 4 */
      target = req_comp;
   else
      target = s->img_n; /* If they want monochrome, we'll post-convert */

   out = (unsigned char *) malloc(target * s->img_x * s->img_y);

   if (!out)
      return 0;

   if (bpp < 16)
   {
      unsigned char pal[256][4];
      int z=0;

      /* Corrupt BMP? */
      if (psize == 0 || psize > 256)
      {
         free(out);
         return 0;
      }

      for (i = 0; i < psize; ++i)
      {
         pal[i][2] = rbmp_get8(s);
         pal[i][1] = rbmp_get8(s);
         pal[i][0] = rbmp_get8(s);
         if (hsz != 12)
            rbmp_get8(s);
         pal[i][3] = 255;
      }

      rbmp_skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
      if (bpp == 4)
         width = (s->img_x + 1) >> 1;
      else if (bpp == 8)
         width = s->img_x;
      else
      {
         /* Corrupt BMP */
         free(out);
         return 0;
      }

      pad = (-width)&3;
      for (j=0; j < (int) s->img_y; ++j)
      {
         for (i = 0; i < (int) s->img_x; i += 2)
         {
            int v  = rbmp_get8(s);
            int v2 = 0;
            if (bpp == 4)
            {
               v2  = v & 15;
               v >>= 4;
            }
            out[z++] = pal[v][0];
            out[z++] = pal[v][1];
            out[z++] = pal[v][2];
            if (target == 4)
               out[z++] = 255;

            if (i+1 == (int)s->img_x)
               break;

            v        = (bpp == 8) ? rbmp_get8(s) : v2;
            out[z++] = pal[v][0];
            out[z++] = pal[v][1];
            out[z++] = pal[v][2];

            if (target == 4)
               out[z++] = 255;
         }
         rbmp_skip(s, pad);
      }
   }
   else
   {
      int rshift = 0;
      int gshift = 0;
      int bshift = 0;
      int ashift = 0;
      int rcount = 0;
      int gcount = 0;
      int bcount = 0;
      int acount = 0;
      int z      = 0;
      int easy   = 0;

      rbmp_skip(s, offset - 14 - hsz);

      if (bpp == 24)
         width = 3 * s->img_x;
      else if (bpp == 16)
         width = 2*s->img_x;
      else /* bpp = 32 and pad = 0 */
         width=0;

      pad = (-width) & 3;

      switch (bpp)
      {
         case 24:
            easy = 1;
            break;
         case 32:
            if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
               easy = 2;
            break;
         default:
            break;
      }

      if (!easy)
      {
         /* Corrupt BMP? */
         if (!mr || !mg || !mb)
         {
            free(out);
            return 0;
         }

         /* right shift amt to put high bit in position #7 */
         rshift = rbmp_high_bit(mr)-7;
         rcount = rbmp_bitcount(mr);
         gshift = rbmp_high_bit(mg)-7;
         gcount = rbmp_bitcount(mg);
         bshift = rbmp_high_bit(mb)-7;
         bcount = rbmp_bitcount(mb);
         ashift = rbmp_high_bit(ma)-7;
         acount = rbmp_bitcount(ma);
      }

      for (j=0; j < (int) s->img_y; ++j)
      {
         if (easy)
         {
            if (target == 4)
            {
               /* Need to apply alpha channel as well */
               if (easy == 2)
               {
                  for (i = 0; i < (int) s->img_x; ++i)
                  {
                     out[z+2]        = rbmp_get8(s);
                     out[z+1]        = rbmp_get8(s);
                     out[z+0]        = rbmp_get8(s);
                     z              += 3;
                     out[z++]        = rbmp_get8(s);
                  }
               }
               else
               {
                  for (i = 0; i < (int) s->img_x; ++i)
                  {
                     out[z+2]        = rbmp_get8(s);
                     out[z+1]        = rbmp_get8(s);
                     out[z+0]        = rbmp_get8(s);
                     z              += 3;
                     out[z++]        = 255;
                  }
               }
            }
            else
            {
               for (i = 0; i < (int) s->img_x; ++i)
               {
                  out[z+2]        = rbmp_get8(s);
                  out[z+1]        = rbmp_get8(s);
                  out[z+0]        = rbmp_get8(s);
                  z              += 3;
               }
            }
         }
         else
         {
            if (target == 4)
            {
               /* Need to apply alpha channel as well */
               if (ma)
               {
                  if (bpp == 16)
                  {
                     for (i = 0; i < (int) s->img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)rbmp_get16le(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & ma, ashift, acount));
                     }
                  }
                  else
                  {
                     for (i = 0; i < (int) s->img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)RBMP_GET32LE(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & ma, ashift, acount));
                     }
                  }
               }
               else
               {
                  if (bpp == 16)
                  {
                     for (i = 0; i < (int) s->img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)rbmp_get16le(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(255);
                     }
                  }
                  else
                  {
                     for (i = 0; i < (int) s->img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)RBMP_GET32LE(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(255);
                     }
                  }
               }
            }
            else
            {
               if (bpp == 16)
               {
                  for (i = 0; i < (int) s->img_x; ++i)
                  {
                     uint32_t v  = (uint32_t)rbmp_get16le(s);
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
                  }
               }
               else
               {
                  for (i = 0; i < (int) s->img_x; ++i)
                  {
                     uint32_t v  = (uint32_t)RBMP_GET32LE(s);
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
                  }
               }
            }
         }
         rbmp_skip(s, pad);
      }
   }

   if (flip_vertically)
   {
      unsigned char t;
      for (j=0; j < (int) s->img_y>>1; ++j)
      {
         unsigned char *p1 = out +      j     *s->img_x*target;
         unsigned char *p2 = out + (s->img_y-1-j)*s->img_x*target;
         for (i = 0; i < (int) s->img_x*target; ++i)
         {
            t     = p1[i];
            p1[i] = p2[i];
            p2[i] = t;
         }
      }
   }

   if (
            req_comp
         && (req_comp >= 1 && req_comp <= 4)
         && (req_comp != target))
   {
      unsigned char *tmp = rbmp_convert_format(out, target, req_comp, s->img_x, s->img_y);

      free(out);
      out = NULL;

      if (!tmp)
         return NULL;

      out = tmp;
   }

   *x = s->img_x;
   *y = s->img_y;

   if (comp)
      *comp = s->img_n;

   return out;
}

static unsigned char *rbmp_load_from_memory(unsigned char const *buffer, int len,
      unsigned *x, unsigned *y, int *comp, int req_comp)
{
   rbmp_context s;

   s.img_buffer          = (unsigned char*)buffer;
   s.img_buffer_original = (unsigned char*)buffer;
   s.img_buffer_end      = (unsigned char*)buffer+len;

   return rbmp_bmp_load(&s,x,y,comp,req_comp);
}

static void rbmp_convert_frame(uint32_t *frame, unsigned width, unsigned height)
{
   uint32_t *end = frame + (width * height * sizeof(uint32_t))/4;

   while (frame < end)
   {
      uint32_t pixel = *frame;
      *frame = (pixel & 0xff00ff00) | ((pixel << 16) & 0x00ff0000) | ((pixel >> 16) & 0xff);
      frame++;
   }
}

int rbmp_process_image(rbmp_t *rbmp, void **buf_data,
      size_t size, unsigned *width, unsigned *height)
{
   int comp;

   if (!rbmp)
      return IMAGE_PROCESS_ERROR;

   rbmp->output_image   = (uint32_t*)rbmp_load_from_memory(rbmp->buff_data,
                           (int)size, width, height, &comp, 4);
   *buf_data             = rbmp->output_image;

   rbmp_convert_frame(rbmp->output_image, *width, *height);

   return IMAGE_PROCESS_END;
}

bool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data)
{
   if (!rbmp)
      return false;

   rbmp->buff_data = (uint8_t*)data;

   return true;
}

void rbmp_free(rbmp_t *rbmp)
{
   if (!rbmp)
      return;

   free(rbmp);
}

rbmp_t *rbmp_alloc(void)
{
   rbmp_t *rbmp = (rbmp_t*)calloc(1, sizeof(*rbmp));
   if (!rbmp)
      return NULL;
   return rbmp;
}

./include/libretro-common/formats/bmp/rbmp_encode.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbmp_encode.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <streams/file_stream.h>
#include <formats/rbmp.h>

void form_bmp_header(uint8_t *header,
      unsigned width, unsigned height,
      bool is32bpp)
{
   unsigned line_size  = (width * (is32bpp?4:3) + 3) & ~3;
   unsigned size       = line_size * height + 54;
   unsigned size_array = line_size * height;

   /* Generic BMP stuff. */
   /* signature */
   header[0] = 'B';
   header[1] = 'M';
   /* file size */
   header[2] = (uint8_t)(size >> 0);
   header[3] = (uint8_t)(size >> 8);
   header[4] = (uint8_t)(size >> 16);
   header[5] = (uint8_t)(size >> 24);
   /* reserved */
   header[6] = 0;
   header[7] = 0;
   header[8] = 0;
   header[9] = 0;
   /* offset */
   header[10] = 54;
   header[11] = 0;
   header[12] = 0;
   header[13] = 0;
   /* DIB size */
   header[14] = 40;
   header[15] = 0;
   header[16] = 0;
   header[17] = 0;
   /* Width */
   header[18] = (uint8_t)(width >> 0);
   header[19] = (uint8_t)(width >> 8);
   header[20] = (uint8_t)(width >> 16);
   header[21] = (uint8_t)(width >> 24);
   /* Height */
   header[22] = (uint8_t)(height >> 0);
   header[23] = (uint8_t)(height >> 8);
   header[24] = (uint8_t)(height >> 16);
   header[25] = (uint8_t)(height >> 24);
   /* Color planes */
   header[26] = 1;
   header[27] = 0;
   /* Bits per pixel */
   header[28] = is32bpp ? 32 : 24;
   header[29] = 0;
   /* Compression method */
   header[30] = 0;
   header[31] = 0;
   header[32] = 0;
   header[33] = 0;
   /* Image data size */
   header[34] = (uint8_t)(size_array >> 0);
   header[35] = (uint8_t)(size_array >> 8);
   header[36] = (uint8_t)(size_array >> 16);
   header[37] = (uint8_t)(size_array >> 24);
   /* Horizontal resolution */
   header[38] = 19;
   header[39] = 11;
   header[40] = 0;
   header[41] = 0;
   /* Vertical resolution */
   header[42] = 19;
   header[43] = 11;
   header[44] = 0;
   header[45] = 0;
   /* Palette size */
   header[46] = 0;
   header[47] = 0;
   header[48] = 0;
   header[49] = 0;
   /* Important color count */
   header[50] = 0;
   header[51] = 0;
   header[52] = 0;
   header[53] = 0;
}

static bool write_header_bmp(RFILE *file, unsigned width, unsigned height, bool is32bpp)
{
   uint8_t header[54];
   form_bmp_header(header, width, height, is32bpp);
   return filestream_write(file, header, sizeof(header)) == sizeof(header);
}

static void dump_line_565_to_24(uint8_t *line, const uint16_t *src, unsigned width)
{
   unsigned i;

   for (i = 0; i < width; i++)
   {
      uint16_t pixel = *src++;
      uint8_t b = (pixel >>  0) & 0x1f;
      uint8_t g = (pixel >>  5) & 0x3f;
      uint8_t r = (pixel >> 11) & 0x1f;
      *line++   = (b << 3) | (b >> 2);
      *line++   = (g << 2) | (g >> 4);
      *line++   = (r << 3) | (r >> 2);
   }
}

static void dump_line_32_to_24(uint8_t *line, const uint32_t *src, unsigned width)
{
   unsigned i;

   for (i = 0; i < width; i++)
   {
      uint32_t pixel = *src++;
      *line++ = (pixel >>  0) & 0xff;
      *line++ = (pixel >>  8) & 0xff;
      *line++ = (pixel >> 16) & 0xff;
   }
}

static void dump_content(RFILE *file, const void *frame,
      int width, int height, int pitch, enum rbmp_source_type type)
{
   int j;
   size_t line_size;
   uint8_t *line       = NULL;
   int bytes_per_pixel = (type==RBMP_SOURCE_TYPE_ARGB8888?4:3);
   union
   {
      const uint8_t *u8;
      const uint16_t *u16;
      const uint32_t *u32;
   } u;

   u.u8      = (const uint8_t*)frame;
   line_size = (width * bytes_per_pixel + 3) & ~3;

   switch (type)
   {
      case RBMP_SOURCE_TYPE_BGR24:
         {
            /* BGR24 byte order input matches output. Can directly copy, but... need to make sure we pad it. */
            uint32_t zeros = 0;
            int padding    = (int)(line_size-pitch);
            for (j = 0; j < height; j++, u.u8 += pitch)
            {
               filestream_write(file, u.u8, pitch);
               if (padding != 0)
                  filestream_write(file, &zeros, padding);
            }
         }
         break;
      case RBMP_SOURCE_TYPE_ARGB8888:
         /* ARGB8888 byte order input matches output. Can directly copy. */
         for (j = 0; j < height; j++, u.u8 += pitch)
            filestream_write(file, u.u8, line_size);
         return;
      default:
         break;
   }

   /* allocate line buffer, and initialize the final four bytes to zero, for deterministic padding */
   if (!(line = (uint8_t*)malloc(line_size)))
      return;
   *(uint32_t*)(line + line_size - 4) = 0;

   switch (type)
   {
      case RBMP_SOURCE_TYPE_XRGB888:
         for (j = 0; j < height; j++, u.u8 += pitch)
         {
            dump_line_32_to_24(line, u.u32, width);
            filestream_write(file, line, line_size);
         }
         break;
      case RBMP_SOURCE_TYPE_RGB565:
         for (j = 0; j < height; j++, u.u8 += pitch)
         {
            dump_line_565_to_24(line, u.u16, width);
            filestream_write(file, line, line_size);
         }
         break;
      default:
         break;
   }

   /* Free allocated line buffer */
   free(line);
}

bool rbmp_save_image(
      const char *filename,
      const void *frame,
      unsigned width, unsigned height,
      unsigned pitch, enum rbmp_source_type type)
{
   bool ret    = false;
   RFILE *file = filestream_open(filename,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!file)
      return false;

   ret = write_header_bmp(file, width, height, type==RBMP_SOURCE_TYPE_ARGB8888);

   if (ret)
      dump_content(file, frame, width, height, pitch, type);

   filestream_close(file);

   return ret;
}

./include/libretro-common/formats/cdfs/cdfs.c

#include <formats/cdfs.h>

#include <retro_miscellaneous.h>
#include <compat/strl.h>
#include <file/file_path.h>
#include <string/stdstring.h>

#ifdef HAVE_CHD
#include <streams/chd_stream.h>
#endif

static void cdfs_determine_sector_size(cdfs_track_t* track)
{
   uint8_t buffer[32];
   const int toc_sector = 16;

   /* MODE information is normally found in the CUE sheet, but we can try to determine it from the raw data.
    *
    *   MODE1/2048 - CDROM Mode1 Data (cooked) [no header, no footer]
    *   MODE1/2352 - CDROM Mode1 Data (raw)    [16 byte header, 288 byte footer]
    *   MODE2/2336 - CDROM-XA Mode2 Data       [8 byte header, 280 byte footer]
    *   MODE2/2352 - CDROM-XA Mode2 Data       [24 byte header, 280 byte footer]
    *
    * Note that MODE is actually a property on each sector and can change between 1 and 2 depending on how much error
    * correction the author desired. To support that, the data format must be "/2352" to include the full header and
    * data without error correction information, at which point the CUE sheet information becomes just a hint.
    */

   /* The boot record or primary volume descriptor is always at sector 16 and will contain a "CD001" marker */
   intfstream_seek(track->stream, toc_sector * 2352 + track->first_sector_offset, SEEK_SET);
   if (intfstream_read(track->stream, &buffer, sizeof(buffer)) != (int64_t)sizeof(buffer))
      return;

   /* if this is a CDROM-XA data source, the "CD001" tag will be 25 bytes into the sector */
   if (  buffer[25] == 0x43
      && buffer[26] == 0x44
      && buffer[27] == 0x30
      && buffer[28] == 0x30
      && buffer[29] == 0x31)
   {
      track->stream_sector_size        = 2352;
      track->stream_sector_header_size = 24;
   }
   /* otherwise it should be 17 bytes into the sector */
   else if (buffer[17] == 0x43
      &&    buffer[18] == 0x44
      &&    buffer[19] == 0x30
      &&    buffer[20] == 0x30
      &&    buffer[21] == 0x31)
   {
      track->stream_sector_size = 2352;
      track->stream_sector_header_size = 16;
   }
   else
   {
      /* ISO-9660 says the first twelve bytes of a sector should be the sync pattern 00 FF FF FF FF FF FF FF FF FF FF 00 */
      if (
            buffer[ 0] == 0
         && buffer[ 1] == 0xFF
         && buffer[ 2] == 0xFF
         && buffer[ 3] == 0xFF
         && buffer[ 4] == 0xFF
         && buffer[ 5] == 0xFF
         && buffer[ 6] == 0xFF
         && buffer[ 7] == 0xFF
         && buffer[ 8] == 0xFF
         && buffer[ 9] == 0xFF
         && buffer[10] == 0xFF
         && buffer[11] == 0)
      {
         /* if we didn't find a CD001 tag, this format may predate ISO-9660 */

         /* after the 12 byte sync pattern is three bytes identifying the sector and then one byte for the mode (total 16 bytes) */
         track->stream_sector_size        = 2352;
         track->stream_sector_header_size = 16;
      }
   }
}

static void cdfs_determine_sector_size_from_file_size(cdfs_track_t* track)
{
   /* attempt to determine stream_sector_size from file size */
   size_t _len = intfstream_get_size(track->stream);

   if ((_len % 2352) == 0)
   {
      /* raw tracks use all 2352 bytes and have a 24 byte header */
      track->stream_sector_size        = 2352;
      track->stream_sector_header_size = 24;
   }
   else if ((_len % 2048) == 0)
   {
      /* cooked tracks eliminate all header/footer data */
      track->stream_sector_size        = 2048;
      track->stream_sector_header_size = 0;
   }
   else if ((_len % 2336) == 0)
   {
      /* MODE 2 format without 16-byte sync data */
      track->stream_sector_size        = 2336;
      track->stream_sector_header_size = 8;
   }
}

static void cdfs_seek_track_sector(cdfs_track_t* track, unsigned int sector)
{
   intfstream_seek(track->stream,
           sector * track->stream_sector_size
         + track->stream_sector_header_size
         + track->first_sector_offset, SEEK_SET);
}

void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector)
{
   /* only allowed if open_file was called with a NULL path */
   if (file->first_sector == 0)
   {
      if (file->current_sector != (int)sector)
      {
         file->current_sector      = (int)sector;
         file->sector_buffer_valid = 0;
      }

      file->pos                    = sector * 2048;
      file->current_sector_offset  = 0;
   }
}

uint32_t cdfs_get_num_sectors(cdfs_file_t* file)
{
   uint32_t frame_size = intfstream_get_frame_size(file->track->stream);
   if (frame_size == 0)
   {
      frame_size = file->track->stream_sector_size;
      if (frame_size == 0)
         frame_size = 1; /* prevent divide by 0 error if sector size is unknown */
   }
   return (uint32_t)(intfstream_get_size(file->track->stream) / frame_size);
}

uint32_t cdfs_get_first_sector(cdfs_file_t* file)
{
   return file->track->first_sector_index;
}

static int cdfs_find_file(cdfs_file_t* file, const char* path)
{
   size_t path_length;
   int sector;
   uint8_t buffer[2048], *tmp;
   const char* slash = strrchr(path, '\\');

   if (slash)
   {
      /* navigate the path to the directory record for the file */
      const int dir_length = (int)(slash - path);
      memcpy(buffer, path, dir_length);
      buffer[dir_length] = '\0';

      sector = cdfs_find_file(file, (const char*)buffer);
      if (sector < 0)
         return sector;

      path += dir_length + 1;
   }
   else
   {
      int offset;

      /* find the CD information (always 16 frames in) */
      cdfs_seek_track_sector(file->track, 16);
      intfstream_read(file->track->stream, buffer, sizeof(buffer));

      /* the directory_record starts at 156 bytes into the sector.
       * the sector containing the root directory contents is a
       * 3 byte value that is 2 bytes into the directory_record. */
      offset = 156 + 2;
      sector = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16);
   }

   /* process the contents of the directory */
   cdfs_seek_track_sector(file->track, sector);
   intfstream_read(file->track->stream, buffer, sizeof(buffer));

   path_length = strlen(path);
   tmp         = buffer;

   while (tmp < buffer + sizeof(buffer))
   {
      /* The first byte of the record is the length of
       * the record - if 0, we reached the end of the data */
      if (!*tmp)
         break;

      /* filename is 33 bytes into the record and
       * the format is "FILENAME;version" or "DIRECTORY" */
      if (        (tmp[33 + path_length] == ';'
               || (tmp[33 + path_length] == '\0'))
               &&  strncasecmp((const char*)(tmp + 33), path, path_length) == 0)
      {
         /* the file size is in bytes 10-13 of the record */
         file->size =
              (tmp[10])
            | (tmp[11] << 8)
            | (tmp[12] << 16)
            | (tmp[13] << 24);

         /* the file contents are in the sector identified
          * in bytes 2-4 of the record */
         sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);
         return sector;
      }

      /* the first byte of the record is the length of the record */
      tmp += tmp[0];
   }

   return -1;
}

int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* track, const char* path)
{
   if (!file || !track)
      return 0;

   memset(file, 0, sizeof(*file));

   file->track          = track;
   file->current_sector = -1;
   file->first_sector   = -1;

   if (path)
      file->first_sector = cdfs_find_file(file, path);
   else if (file->track->stream_sector_size)
   {
      file->first_sector = 0;
      file->size         = (unsigned int)((intfstream_get_size(
               file->track->stream) / file->track->stream_sector_size)
         * 2048);
      return 1;
   }

   return (file->first_sector >= 0);
}

int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
{
   int bytes_read = 0;

   if (!file || file->first_sector < 0 || !buffer)
      return 0;

   if (len > file->size - file->pos)
      len = file->size - file->pos;

   if (len == 0)
      return 0;

   if (file->sector_buffer_valid)
   {
      size_t remaining = 2048 - file->current_sector_offset;
      if (remaining > 0)
      {
         if (remaining >= len)
         {
            memcpy(buffer,
                  &file->sector_buffer[file->current_sector_offset],
                  (size_t)len);
            file->current_sector_offset += len;
            return len;
         }

         memcpy(buffer,
               &file->sector_buffer[file->current_sector_offset], remaining);
         buffer      = (char*)buffer + remaining;
         bytes_read += remaining;
         len        -= remaining;

         file->current_sector_offset += remaining;
      }

      ++file->current_sector;
      file->current_sector_offset = 0;
      file->sector_buffer_valid   = 0;
   }
   else if (file->current_sector < file->first_sector)
   {
      file->current_sector        = file->first_sector;
      file->current_sector_offset = 0;
   }

   while (len >= 2048)
   {
      cdfs_seek_track_sector(file->track, file->current_sector);
      intfstream_read(file->track->stream, buffer, 2048);

      buffer      = (char*)buffer + 2048;
      bytes_read += 2048;

      ++file->current_sector;

      len        -= 2048;
   }

   if (len > 0)
   {
      cdfs_seek_track_sector(file->track, file->current_sector);
      intfstream_read(file->track->stream, file->sector_buffer, 2048);
      memcpy(buffer, file->sector_buffer, (size_t)len);
      file->current_sector_offset = (unsigned int)len;
      file->sector_buffer_valid   = 1;

      bytes_read += len;
   }

   file->pos += bytes_read;
   return bytes_read;
}

void cdfs_close_file(cdfs_file_t* file)
{
   /* Not really anything to do here, just
    * clear out the first_sector so
    * read() won't do anything */
   if (file)
      file->first_sector = -1;
}

int64_t cdfs_get_size(cdfs_file_t* file)
{
   if (!file || file->first_sector < 0)
      return 0;
   return file->size;
}

int64_t cdfs_tell(cdfs_file_t* file)
{
   if (!file || file->first_sector < 0)
      return -1;
   return file->pos;
}

int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence)
{
   int64_t new_pos;
   int new_sector;

   if (!file || file->first_sector < 0)
      return -1;

   switch (whence)
   {
      case SEEK_SET:
         new_pos = offset;
         break;

      case SEEK_CUR:
         new_pos = file->pos + offset;
         break;

      case SEEK_END:
         new_pos = file->size - offset;
         break;

      default:
         return -1;
   }

   if (new_pos < 0)
      return -1;
   else if (new_pos > file->size)
      return -1;

   file->pos = (unsigned int)new_pos;
   file->current_sector_offset = file->pos % 2048;

   new_sector = file->pos / 2048;
   if (new_sector != file->current_sector)
   {
      file->current_sector      = new_sector;
      file->sector_buffer_valid = false;
   }

   return 0;
}

static void cdfs_skip_spaces(const char** ptr)
{
   while (**ptr && (**ptr == ' ' || **ptr == '\t'))
      ++(*ptr);
}

static cdfs_track_t* cdfs_wrap_stream(
      intfstream_t* stream,
      unsigned first_sector_offset,
      unsigned first_sector_index)
{
   cdfs_track_t* track = NULL;

   if (!stream)
      return NULL;

   track                      = (cdfs_track_t*)
      calloc(1, sizeof(*track));
   track->stream              = stream;
   track->first_sector_offset = first_sector_offset;
   track->first_sector_index  = first_sector_index;

   cdfs_determine_sector_size(track);

   return track;
}

static cdfs_track_t* cdfs_open_cue_track(
      const char* path, unsigned int track_index)
{
   char* cue                                = NULL;
   const char* line                         = NULL;
   int found_track                          = 0;
   char current_track_path[PATH_MAX_LENGTH] = {0};
   char track_path[PATH_MAX_LENGTH]         = {0};
   unsigned int sector_size                 = 0;
   unsigned int previous_sector_size        = 0;
   unsigned int previous_index_sector_offset= 0;
   unsigned int track_offset                = 0;
   intfstream_t *cue_stream                 = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
   int64_t stream_size                      = intfstream_get_size(cue_stream);
   char *cue_contents                       = (char*)malloc((size_t)(stream_size + 1));
   cdfs_track_t* track                      = NULL;

   if (!cue_contents)
   {
      intfstream_close(cue_stream);
      return NULL;
   }

   intfstream_read(cue_stream, cue_contents, stream_size);
   intfstream_close(cue_stream);

   cue_contents[stream_size] = '\0';

   cue = cue_contents;
   while (*cue)
   {
      cdfs_skip_spaces((const char**)&cue);
      line = cue;

      while (*cue && *cue != '\n')
         ++cue;
      if (*cue)
         *cue++ = '\0';

      if (!strncasecmp(line, "FILE", 4))
      {
         const char *file = line + 4;
         cdfs_skip_spaces(&file);

         if (file[0])
         {
            const char *file_end = cue - 1;
            while (file_end > file && *file_end != ' ' && *file_end != '\t')
               --file_end;

            if (     file[0]      == '"'
                  && file_end[-1] == '"')
            {
               ++file;
               --file_end;
            }

            memcpy(current_track_path, file, file_end - file);
            current_track_path[file_end - file] = '\0';
         }

         previous_sector_size = 0;
         previous_index_sector_offset = 0;
         track_offset = 0;
      }
      else if (!strncasecmp(line, "TRACK", 5))
      {
         char *ptr             = NULL;
         unsigned track_number = 0;
         const char *track     = line + 5;
         cdfs_skip_spaces(&track);

         track_number = (unsigned)strtol(track, &ptr, 10);
         while (*track && *track != ' ' && *track != '\n')
            ++track;

         previous_sector_size = sector_size;

         cdfs_skip_spaces(&track);

         if (!strncasecmp(track, "MODE", 4))
         {
            /* track_index = 0 means find the first data track */
            if (!track_index || track_index == track_number)
               found_track = track_number;

            sector_size = atoi(track + 6);
         }
         else /* assume AUDIO */
            sector_size = 2352;
      }
      else if (!strncasecmp(line, "INDEX", 5))
      {
         unsigned sector_offset;
         unsigned min = 0, sec = 0, frame = 0;
         unsigned index_number = 0;
         const char *index     = line + 5;

         cdfs_skip_spaces(&index);
         sscanf(index, "%u", &index_number);
         while (*index && *index != ' ' && *index != '\n')
            ++index;
         cdfs_skip_spaces(&index);

         sscanf(index, "%u:%u:%u", &min, &sec, &frame);
         sector_offset                 = ((min * 60) + sec) * 75 + frame;
         sector_offset                -= previous_index_sector_offset;
         track_offset                 += sector_offset * previous_sector_size;
         previous_sector_size          = sector_size;
         previous_index_sector_offset += sector_offset;

         if (found_track && index_number == 1)
         {
            if (     strstr(current_track_path, "/")
                  || strstr(current_track_path, "\\"))
               strncpy(track_path, current_track_path, sizeof(track_path));
            else
            {
               fill_pathname_basedir(track_path, path, sizeof(track_path));
               strlcat(track_path, current_track_path, sizeof(track_path));
            }

            break;
         }
      }
   }

   free(cue_contents);

   if (string_is_empty(track_path))
      return NULL;

   /* NOTE: previous_index_sector_offset will only be valid if all tracks are in the same BIN file.
    * Otherwise, we need to determine how many tracks are in each previous BIN file, which is not
    * stored in the CUE file. This will affect cdfs_get_first_sector, which luckily isn't used much. */
   track = cdfs_wrap_stream(intfstream_open_file(
            track_path, RETRO_VFS_FILE_ACCESS_READ,
            RETRO_VFS_FILE_ACCESS_HINT_NONE), track_offset, previous_index_sector_offset);

   if (track && track->stream_sector_size == 0)
   {
      track->stream_sector_size = sector_size;

      if (sector_size == 2352)
         track->stream_sector_header_size = 16;
      else if (sector_size == 2336)
         track->stream_sector_header_size = 8;
   }

   return track;
}

#ifdef HAVE_CHD
static cdfs_track_t* cdfs_open_chd_track(const char* path, int32_t track_index)
{
   cdfs_track_t *track;
   intfstream_t *intf_stream = intfstream_open_chd_track(path,
         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE,
         track_index);
   if (!intf_stream)
      return NULL;

   track = cdfs_wrap_stream(intf_stream,
         intfstream_get_offset_to_start(intf_stream),
         intfstream_get_first_sector(intf_stream));

   if (track && track->stream_sector_header_size == 0)
   {
      track->stream_sector_size = intfstream_get_frame_size(intf_stream);

      if (track->stream_sector_size == 2352)
         track->stream_sector_header_size = 16;
      else if (track->stream_sector_size == 2336)
         track->stream_sector_header_size = 8;
   }

   return track;
}
#endif

struct cdfs_track_t* cdfs_open_track(const char* path,
      unsigned int track_index)
{
   const char* ext = path_get_extension(path);

   if (string_is_equal_noncase(ext, "cue"))
      return cdfs_open_cue_track(path, track_index);

#ifdef HAVE_CHD
   if (string_is_equal_noncase(ext, "chd"))
      return cdfs_open_chd_track(path, track_index);
#endif

   /* if opening track 1, try opening as a raw track */
   if (track_index == 1)
      return cdfs_open_raw_track(path);

   /* unsupported file type */
   return NULL;
}

struct cdfs_track_t* cdfs_open_data_track(const char* path)
{
   const char* ext = path_get_extension(path);

   if (string_is_equal_noncase(ext, "cue"))
      return cdfs_open_cue_track(path, 0);

#ifdef HAVE_CHD
   if (string_is_equal_noncase(ext, "chd"))
      return cdfs_open_chd_track(path, CHDSTREAM_TRACK_PRIMARY);
#endif

   /* unsupported file type - try opening as a raw track */
   return cdfs_open_raw_track(path);
}

cdfs_track_t* cdfs_open_raw_track(const char* path)
{
   const char *ext     = path_get_extension(path);
   cdfs_track_t *track = NULL;

   if (     string_is_equal_noncase(ext, "bin")
         || string_is_equal_noncase(ext, "iso"))
   {
      intfstream_t* file = intfstream_open_file(path,
         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);

      track = cdfs_wrap_stream(file, 0, 0);
      if (track && track->stream_sector_size == 0)
      {
         cdfs_determine_sector_size_from_file_size(track);
         if (track->stream_sector_size == 0)
         {
            cdfs_close_track(track);
            track = NULL;
         }
      }
   }

   return track;
}

void cdfs_close_track(cdfs_track_t* track)
{
   if (track)
   {
      if (track->stream)
      {
         intfstream_close(track->stream);
         free(track->stream);
      }

      free(track);
   }
}

./include/libretro-common/formats/image_texture.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (image_texture.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>

#include <boolean.h>
#include <formats/image.h>
#include <file/nbio.h>
#include <string/stdstring.h>

enum image_type_enum image_texture_get_type(const char *path)
{
   /* We are comparing against a fixed list of file
    * extensions, the longest (jpeg) being 4 characters
    * in length. We therefore only need to extract the first
    * 5 characters from the extension of the input path
    * to correctly validate a match */
   const char *ext = NULL;
   char ext_lower[6];

   ext_lower[0] = '\0';

   if (string_is_empty(path))
      return IMAGE_TYPE_NONE;

   /* Get file extension */
   ext = strrchr(path, '.');

   if (!ext || (*(++ext) == '\0'))
      return IMAGE_TYPE_NONE;

   /* Copy and convert to lower case */
   strlcpy(ext_lower, ext, sizeof(ext_lower));
   string_to_lower(ext_lower);

#ifdef HAVE_RPNG
   if (string_is_equal(ext_lower, "png"))
      return IMAGE_TYPE_PNG;
#endif
#ifdef HAVE_RJPEG
   if (string_is_equal(ext_lower, "jpg") ||
       string_is_equal(ext_lower, "jpeg"))
      return IMAGE_TYPE_JPEG;
#endif
#ifdef HAVE_RBMP
   if (string_is_equal(ext_lower, "bmp"))
      return IMAGE_TYPE_BMP;
#endif
#ifdef HAVE_RTGA
   if (string_is_equal(ext_lower, "tga"))
      return IMAGE_TYPE_TGA;
#endif

   return IMAGE_TYPE_NONE;
}

bool image_texture_set_color_shifts(
      unsigned *r_shift, unsigned *g_shift, unsigned *b_shift,
      unsigned *a_shift,
      struct texture_image *out_img
      )
{
   *a_shift             = 24;
   *r_shift             = 16;
   *g_shift             = 8;
   *b_shift             = 0;

   if (out_img->supports_rgba)
   {
      *r_shift = 0;
      *b_shift = 16;
      return true;
   }

   return false;
}

bool image_texture_color_convert(unsigned r_shift,
      unsigned g_shift, unsigned b_shift, unsigned a_shift,
      struct texture_image *out_img)
{
   /* This is quite uncommon. */
   if (a_shift != 24 || r_shift != 16 || g_shift != 8 || b_shift != 0)
   {
      uint32_t i;
      uint32_t num_pixels = out_img->width * out_img->height;
      uint32_t *pixels    = (uint32_t*)out_img->pixels;

      for (i = 0; i < num_pixels; i++)
      {
         uint32_t col = pixels[i];
         uint8_t a    = (uint8_t)(col >> 24);
         uint8_t r    = (uint8_t)(col >> 16);
         uint8_t g    = (uint8_t)(col >>  8);
         uint8_t b    = (uint8_t)(col >>  0);
         /* Explicitly cast these to uint32_t to prevent
          * ASAN runtime error: left shift of 255 by 24 places
          * cannot be represented in type 'int' */
         pixels[i]    = ((uint32_t)a << a_shift) |
                        ((uint32_t)r << r_shift) |
                        ((uint32_t)g << g_shift) |
                        ((uint32_t)b << b_shift);
      }

      return true;
   }

   return false;
}

#ifdef GEKKO

#define GX_BLIT_LINE_32(off) \
{ \
   unsigned x; \
   const uint16_t *tmp_src = src; \
   uint16_t       *tmp_dst = dst; \
   for (x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \
   { \
      tmp_dst[  0 + off] = tmp_src[0]; \
      tmp_dst[ 16 + off] = tmp_src[1]; \
      tmp_dst[  1 + off] = tmp_src[2]; \
      tmp_dst[ 17 + off] = tmp_src[3]; \
      tmp_dst[  2 + off] = tmp_src[4]; \
      tmp_dst[ 18 + off] = tmp_src[5]; \
      tmp_dst[  3 + off] = tmp_src[6]; \
      tmp_dst[ 19 + off] = tmp_src[7]; \
   } \
   src += tmp_pitch; \
}

static bool image_texture_internal_gx_convert_texture32(
      struct texture_image *image)
{
   unsigned tmp_pitch, width2, i;
   const uint16_t *src = NULL;
   uint16_t *dst       = NULL;
   /* Memory allocation in libogc is extremely primitive so try
    * to avoid gaps in memory when converting by copying over to
    * a temporary buffer first, then converting over into
    * main buffer again. */
   void *tmp           = malloc(image->width
         * image->height * sizeof(uint32_t));

   if (!tmp)
      return false;

   memcpy(tmp, image->pixels, image->width
         * image->height * sizeof(uint32_t));
   tmp_pitch = (image->width * sizeof(uint32_t)) >> 1;

   image->width       &= ~3;
   image->height      &= ~3;
   width2              = image->width << 1;
   src                 = (uint16_t*)tmp;
   dst                 = (uint16_t*)image->pixels;

   for (i = 0; i < image->height; i += 4, dst += 4 * width2)
   {
      GX_BLIT_LINE_32(0)
      GX_BLIT_LINE_32(4)
      GX_BLIT_LINE_32(8)
      GX_BLIT_LINE_32(12)
   }

   free(tmp);
   return true;
}
#endif

static bool image_texture_load_internal(
      enum image_type_enum type,
      void *ptr,
      size_t len,
      struct texture_image *out_img,
      unsigned a_shift, unsigned r_shift,
      unsigned g_shift, unsigned b_shift)
{
   int ret;
   void *img    = image_transfer_new(type);

   if (!img)
      return false;

   image_transfer_set_buffer_ptr(img, type, (uint8_t*)ptr, len);

   if (!image_transfer_start(img, type))
   {
      image_transfer_free(img, type);
      return false;
   }

   while (image_transfer_iterate(img, type));

   if (!image_transfer_is_valid(img, type))
   {
      image_transfer_free(img, type);
      return false;
   }

   do
   {
      ret = image_transfer_process(img, type,
            (uint32_t**)&out_img->pixels, len, &out_img->width,
            &out_img->height);
   } while (ret == IMAGE_PROCESS_NEXT);

   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
   {
      image_transfer_free(img, type);
      return false;
   }

   image_texture_color_convert(r_shift, g_shift, b_shift,
         a_shift, out_img);

#ifdef GEKKO
   if (!image_texture_internal_gx_convert_texture32(out_img))
   {
      image_texture_free(out_img);
      image_transfer_free(img, type);
      return false;
   }
#endif

   image_transfer_free(img, type);
   return true;
}

void image_texture_free(struct texture_image *img)
{
   if (!img)
      return;

   if (img->pixels)
      free(img->pixels);
   img->width  = 0;
   img->height = 0;
   img->pixels = NULL;
}

bool image_texture_load_buffer(struct texture_image *out_img,
   enum image_type_enum type, void *buffer, size_t buffer_len)
{
   unsigned r_shift, g_shift, b_shift, a_shift;
   image_texture_set_color_shifts(&r_shift, &g_shift, &b_shift,
      &a_shift, out_img);

   if (type != IMAGE_TYPE_NONE)
   {
      if (image_texture_load_internal(
         type, buffer, buffer_len, out_img,
         a_shift, r_shift, g_shift, b_shift))
         return true;
   }

   out_img->supports_rgba = false;
   out_img->pixels = NULL;
   out_img->width = 0;
   out_img->height = 0;

   return false;
}

bool image_texture_load(struct texture_image *out_img,
      const char *path)
{
   enum image_type_enum type  = image_texture_get_type(path);

   if (type != IMAGE_TYPE_NONE)
   {
      struct nbio_t *handle = (struct nbio_t*)
         nbio_open(path, NBIO_READ);
      if (handle)
      {
         void *ptr       = NULL;
         size_t file_len = 0;

         nbio_begin_read(handle);

         while (!nbio_iterate(handle));

         if ((ptr = nbio_get_ptr(handle, &file_len)))
         {
            unsigned r_shift, g_shift, b_shift, a_shift;
            image_texture_set_color_shifts(&r_shift,
                  &g_shift, &b_shift, &a_shift, out_img);

            if (image_texture_load_internal(
                     type,
                     ptr, file_len, out_img,
                     a_shift, r_shift, g_shift, b_shift))
            {
               nbio_free(handle);
               return true;
            }
         }
         nbio_free(handle);
      }
   }

   out_img->supports_rgba = false;
   out_img->pixels        = NULL;
   out_img->width         = 0;
   out_img->height        = 0;

   return false;
}

./include/libretro-common/formats/image_transfer.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (image_transfer.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <string.h>

#include <boolean.h>

#ifdef HAVE_RPNG
#include <formats/rpng.h>
#endif
#ifdef HAVE_RJPEG
#include <formats/rjpeg.h>
#endif
#ifdef HAVE_RTGA
#include <formats/rtga.h>
#endif
#ifdef HAVE_RBMP
#include <formats/rbmp.h>
#endif

#include <formats/image.h>

void image_transfer_free(void *data, enum image_type_enum type)
{
   switch (type)
   {
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         rtga_free((rtga_t*)data);
#endif
         break;
      case IMAGE_TYPE_PNG:
         {
#ifdef HAVE_RPNG
            rpng_t *rpng = (rpng_t*)data;
            if (rpng)
               rpng_free(rpng);
#endif
         }
         break;
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         rjpeg_free((rjpeg_t*)data);
#endif
         break;
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         rbmp_free((rbmp_t*)data);
#endif
         break;
      case IMAGE_TYPE_NONE:
         break;
   }
}

void *image_transfer_new(enum image_type_enum type)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         return rpng_alloc();
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return rjpeg_alloc();
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return rtga_alloc();
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         return rbmp_alloc();
#else
         break;
#endif
      default:
         break;
   }

   return NULL;
}

bool image_transfer_start(void *data, enum image_type_enum type)
{

   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         if (!rpng_start((rpng_t*)data))
            break;
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
         return true;
      case IMAGE_TYPE_NONE:
         break;
   }

   return false;
}

bool image_transfer_is_valid(
      void *data,
      enum image_type_enum type)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         return rpng_is_valid((rpng_t*)data);
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
         return true;
      case IMAGE_TYPE_NONE:
         break;
   }

   return false;
}

void image_transfer_set_buffer_ptr(
      void *data,
      enum image_type_enum type,
      void *ptr,
      size_t len)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         rpng_set_buf_ptr((rpng_t*)data, (uint8_t*)ptr, len);
#endif
         break;
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         rjpeg_set_buf_ptr((rjpeg_t*)data, (uint8_t*)ptr);
#endif
         break;
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         rtga_set_buf_ptr((rtga_t*)data, (uint8_t*)ptr);
#endif
         break;
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         rbmp_set_buf_ptr((rbmp_t*)data, (uint8_t*)ptr);
#endif
         break;
      case IMAGE_TYPE_NONE:
         break;
   }
}

int image_transfer_process(
      void *data,
      enum image_type_enum type,
      uint32_t **buf, size_t len,
      unsigned *width, unsigned *height)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         return rpng_process_image(
               (rpng_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return rjpeg_process_image((rjpeg_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return rtga_process_image((rtga_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         return rbmp_process_image((rbmp_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_NONE:
         break;
   }

   return 0;
}

bool image_transfer_iterate(void *data, enum image_type_enum type)
{

   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         if (!rpng_iterate_image((rpng_t*)data))
            return false;
#endif
         break;
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return false;
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return false;
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
         return false;
      case IMAGE_TYPE_NONE:
         return false;
   }

   return true;
}

./include/libretro-common/formats/jpeg/rjpeg.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjpeg.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Modified version of stb_image's JPEG sources. */

#include <stdint.h>
#include <stdarg.h>
#include <stddef.h> /* ptrdiff_t on osx */
#include <stdlib.h>
#include <string.h>

#include <retro_inline.h>
#include <boolean.h>
#include <formats/image.h>
#include <formats/rjpeg.h>
#include <features/features_cpu.h>

enum
{
   RJPEG_DEFAULT = 0, /* only used for req_comp */
   RJPEG_GREY,
   RJPEG_GREY_ALPHA,
   RJPEG_RGB,
   RJPEG_RGB_ALPHA
};

enum
{
   RJPEG_SCAN_LOAD = 0,
   RJPEG_SCAN_TYPE,
   RJPEG_SCAN_HEADER
};

typedef uint8_t *(*rjpeg_resample_row_func)(uint8_t *out, uint8_t *in0, uint8_t *in1,
                                    int w, int hs);

typedef struct
{
   rjpeg_resample_row_func resample;
   uint8_t *line0;
   uint8_t *line1;
   int hs,vs;   /* expansion factor in each axis */
   int w_lores; /* horizontal pixels pre-expansion */
   int ystep;   /* how far through vertical expansion we are */
   int ypos;    /* which pre-expansion row we're on */
} rjpeg_resample;

struct rjpeg
{
   uint8_t *buff_data;
};

#ifdef _MSC_VER
#define RJPEG_HAS_LROTL
#endif

#ifdef RJPEG_HAS_LROTL
   #define RJPEG_LROT(x,y)  _lrotl(x,y)
#else
   #define RJPEG_LROT(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
#endif

/* x86/x64 detection */
#if defined(__x86_64__) || defined(_M_X64)
#define RJPEG_X64_TARGET
#elif defined(__i386) || defined(_M_IX86)
#define RJPEG_X86_TARGET
#endif

#if defined(__GNUC__) && (defined(RJPEG_X86_TARGET) || defined(RJPEG_X64_TARGET)) && !defined(__SSE2__) && !defined(RJPEG_NO_SIMD)
/* NOTE: not clear do we actually need this for the 64-bit path?
 * gcc doesn't support sse2 intrinsics unless you compile with -msse2,
 * (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
 * this is just broken and gcc are jerks for not fixing it properly
 * http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
 */
#define RJPEG_NO_SIMD
#endif

#if defined(__MINGW32__) && defined(RJPEG_X86_TARGET) && !defined(RJPEG_MINGW_ENABLE_SSE2) && !defined(RJPEG_NO_SIMD)
/* Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid RJPEG_X64_TARGET
 *
 * 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
 * Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
 * As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
 * simultaneously enabling "-mstackrealign".
 *
 * See https://github.com/nothings/stb/issues/81 for more information.
 *
 * So default to no SSE2 on 32-bit MinGW. If you've read this far and added
 * -mstackrealign to your build settings, feel free to #define RJPEG_MINGW_ENABLE_SSE2.
 */
#define RJPEG_NO_SIMD
#endif

#if defined(__SSE2__)
#include <emmintrin.h>

#ifdef _MSC_VER
#define RJPEG_SIMD_ALIGN(type, name) __declspec(align(16)) type name
#else
#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
#endif

#endif

/* ARM NEON */
#if defined(RJPEG_NO_SIMD) && defined(RJPEG_NEON)
#undef RJPEG_NEON
#endif

#ifdef RJPEG_NEON
#include <arm_neon.h>
/* assume GCC or Clang on ARM targets */
#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
#endif

#ifndef RJPEG_SIMD_ALIGN
#define RJPEG_SIMD_ALIGN(type, name) type name
#endif

typedef struct
{
   uint8_t *img_buffer;
   uint8_t *img_buffer_end;
   uint8_t *img_buffer_original;
   int      img_n;
   int      img_out_n;
   int      buflen;
   uint32_t img_x;
   uint32_t img_y;
   uint8_t  buffer_start[128];
} rjpeg_context;

static INLINE uint8_t rjpeg_get8(rjpeg_context *s)
{
   if (s->img_buffer < s->img_buffer_end)
      return *s->img_buffer++;

   return 0;
}

#define RJPEG_AT_EOF(s)     ((s)->img_buffer >= (s)->img_buffer_end)

#define RJPEG_GET16BE(s)    ((rjpeg_get8((s)) << 8) + rjpeg_get8((s)))

/* huffman decoding acceleration */
#define FAST_BITS   9  /* larger handles more cases; smaller stomps less cache */

typedef struct
{
   unsigned int maxcode[18];
   int    delta[17];   /* old 'firstsymbol' - old 'firstcode' */
   /* weirdly, repacking this into AoS is a 10% speed loss, instead of a win */
   uint16_t code[256];
   uint8_t  fast[1 << FAST_BITS];
   uint8_t  values[256];
   uint8_t  size[257];
} rjpeg_huffman;

typedef struct
{
   rjpeg_context *s;
   /* kernels */
   void (*idct_block_kernel)(uint8_t *out, int out_stride, short data[64]);
   void (*YCbCr_to_RGB_kernel)(uint8_t *out, const uint8_t *y, const uint8_t *pcb,
         const uint8_t *pcr, int count, int step);
   uint8_t *(*resample_row_hv_2_kernel)(uint8_t *out, uint8_t *in_near,
         uint8_t *in_far, int w, int hs);

   /* definition of jpeg image component */
   struct
   {
      uint8_t *data;
      void *raw_data, *raw_coeff;
      uint8_t *linebuf;
      short   *coeff;            /* progressive only */
      int id;
      int h,v;
      int tq;
      int hd,ha;
      int dc_pred;

      int x,y,w2,h2;
      int      coeff_w;          /* number of 8x8 coefficient blocks */
      int      coeff_h;          /* number of 8x8 coefficient blocks */
   } img_comp[4];

   /* sizes for components, interleaved MCUs */
   int img_h_max, img_v_max;
   int img_mcu_x, img_mcu_y;
   int img_mcu_w, img_mcu_h;

   int            code_bits;     /* number of valid bits */
   int            nomore;        /* flag if we saw a marker so must stop */
   int            progressive;
   int            spec_start;
   int            spec_end;
   int            succ_high;
   int            succ_low;
   int            eob_run;
   int scan_n, order[4];
   int restart_interval, todo;
   uint32_t       code_buffer;   /* jpeg entropy-coded buffer */
   rjpeg_huffman huff_dc[4];     /* unsigned int alignment */
   rjpeg_huffman huff_ac[4];     /* unsigned int alignment */
   int16_t fast_ac[4][1 << FAST_BITS];
   unsigned char  marker;        /* marker seen while filling entropy buffer */
   uint8_t dequant[4][64];
} rjpeg_jpeg;

#define RJPEG_F2F(x)  ((int) (((x) * 4096 + 0.5)))
#define RJPEG_FSH(x)  ((x) << 12)

#define RJPEG_MARKER_NONE  0xff
/* if there's a pending marker from the entropy stream, return that
 * otherwise, fetch from the stream and get a marker. if there's no
 * marker, return 0xff, which is never a valid marker value
 */

/* in each scan, we'll have scan_n components, and the order
 * of the components is specified by order[]
 */
#define RJPEG_RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)

#define JPEG_MARKER           0xFF
#define JPEG_MARKER_SOI       0xD8
#define JPEG_MARKER_SOS       0xDA
#define JPEG_MARKER_EOI       0xD9
#define JPEG_MARKER_APP1      0xE1
#define JPEG_MARKER_APP2      0xE2

/* use comparisons since in some cases we handle more than one case (e.g. SOF) */
#define RJPEG_SOF(x)               ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)

#define RJPEG_SOF_PROGRESSIVE(x)   ((x) == 0xc2)
#define RJPEG_DIV4(x)              ((uint8_t) ((x) >> 2))
#define RJPEG_DIV16(x)             ((uint8_t) ((x) >> 4))

static int rjpeg_build_huffman(rjpeg_huffman *h, int *count)
{
   int i,j,k = 0,code;

   /* build size list for each symbol (from JPEG spec) */
   for (i = 0; i < 16; ++i)
      for (j = 0; j < count[i]; ++j)
         h->size[k++] = (uint8_t) (i+1);

   h->size[k] = 0;
   /* compute actual symbols (from jpeg spec) */
   code       = 0;
   k          = 0;

   for (j = 1; j <= 16; ++j)
   {
      /* compute delta to add to code to compute symbol id */
      h->delta[j] = k - code;
      if (h->size[k] == j)
      {
         while (h->size[k] == j)
            h->code[k++] = (uint16_t) (code++);

         /* Bad code lengths, corrupt JPEG? */
         if (code-1 >= (1 << j))
            return 0;
      }
      /* compute largest code + 1 for this size, preshifted as needed later */
      h->maxcode[j] = code << (16-j);
      code <<= 1;
   }
   h->maxcode[j] = 0xffffffff;

   /* build non-spec acceleration table; 255 is flag for not-accelerated */
   memset(h->fast, 255, 1 << FAST_BITS);
   for (i = 0; i < k; ++i)
   {
      int s = h->size[i];
      if (s <= FAST_BITS)
      {
         int c = h->code[i] << (FAST_BITS-s);
         int m = 1 << (FAST_BITS-s);
         for (j = 0; j < m; ++j)
            h->fast[c+j] = (uint8_t) i;
      }
   }
   return 1;
}

/* build a table that decodes both magnitude and value of small ACs in
 * one go. */
static void rjpeg_build_fast_ac(int16_t *fast_ac, rjpeg_huffman *h)
{
   int i;

   for (i = 0; i < (1 << FAST_BITS); ++i)
   {
      uint8_t fast = h->fast[i];

      fast_ac[i] = 0;

      if (fast < 255)
      {
         int rs      = h->values[fast];
         int run     = (rs >> 4) & 15;
         int magbits = rs & 15;
         int len     = h->size[fast];

         if (magbits && len + magbits <= FAST_BITS)
         {
            /* magnitude code followed by receive_extend code */
            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
            int m = 1 << (magbits - 1);
            if (k < m)
               k += (~0U << magbits) + 1;

            /* if the result is small enough, we can fit it in fast_ac table */
            if (k >= -128 && k <= 127)
               fast_ac[i] = (int16_t) ((k << 8) + (run << 4) + (len + magbits));
         }
      }
   }
}

static void rjpeg_grow_buffer_unsafe(rjpeg_jpeg *j)
{
   do
   {
      int b = j->nomore ? 0 : rjpeg_get8(j->s);
      if (b == 0xff)
      {
         int c = rjpeg_get8(j->s);

         if (c != 0)
         {
            j->marker = (unsigned char) c;
            j->nomore = 1;
            return;
         }
      }
      j->code_buffer |= b << (24 - j->code_bits);
      j->code_bits   += 8;
   } while (j->code_bits <= 24);
}

/* (1 << n) - 1 */
static uint32_t rjpeg_bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};

/* decode a JPEG huffman value from the bitstream */
static INLINE int rjpeg_jpeg_huff_decode(rjpeg_jpeg *j, rjpeg_huffman *h)
{
   unsigned int temp;
   int c,k;

   if (j->code_bits < 16)
      rjpeg_grow_buffer_unsafe(j);

   /* look at the top FAST_BITS and determine what symbol ID it is,
    * if the code is <= FAST_BITS */
   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
   k = h->fast[c];

   if (k < 255)
   {
      int s = h->size[k];
      if (s > j->code_bits)
         return -1;
      j->code_buffer <<= s;
      j->code_bits -= s;
      return h->values[k];
   }

   /* naive test is to shift the code_buffer down so k bits are
    * valid, then test against maxcode. To speed this up, we've
    * preshifted maxcode left so that it has (16-k) 0s at the
    * end; in other words, regardless of the number of bits, it
    * wants to be compared against something shifted to have 16;
    * that way we don't need to shift inside the loop. */
   temp = j->code_buffer >> 16;
   for (k=FAST_BITS+1 ; ; ++k)
      if (temp < h->maxcode[k])
         break;

   if (k == 17)
   {
      /* error! code not found */
      j->code_bits -= 16;
      return -1;
   }

   if (k > j->code_bits)
      return -1;

   /* convert the huffman code to the symbol id */
   c = ((j->code_buffer >> (32 - k)) & rjpeg_bmask[k]) + h->delta[k];

   /* convert the id to a symbol */
   j->code_bits -= k;
   j->code_buffer <<= k;
   return h->values[c];
}

/* bias[n] = (-1<<n) + 1 */
static int const rjpeg_jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};

/* combined JPEG 'receive' and JPEG 'extend', since baseline
 * always extends everything it receives. */
static INLINE int rjpeg_extend_receive(rjpeg_jpeg *j, int n)
{
   unsigned int k;
   int sgn;
   if (j->code_bits < n)
      rjpeg_grow_buffer_unsafe(j);

   sgn             = (int32_t)j->code_buffer >> 31; /* sign bit is always in MSB */
   k               = RJPEG_LROT(j->code_buffer, n);
   j->code_buffer  = k & ~rjpeg_bmask[n];
   k              &= rjpeg_bmask[n];
   j->code_bits   -= n;
   return k + (rjpeg_jbias[n] & ~sgn);
}

/* get some unsigned bits */
static INLINE int rjpeg_jpeg_get_bits(rjpeg_jpeg *j, int n)
{
   unsigned int k;
   if (j->code_bits < n)
      rjpeg_grow_buffer_unsafe(j);
   k              = RJPEG_LROT(j->code_buffer, n);
   j->code_buffer = k & ~rjpeg_bmask[n];
   k             &= rjpeg_bmask[n];
   j->code_bits  -= n;
   return k;
}

static INLINE int rjpeg_jpeg_get_bit(rjpeg_jpeg *j)
{
   unsigned int k;
   if (j->code_bits < 1)
      rjpeg_grow_buffer_unsafe(j);

   k                = j->code_buffer;
   j->code_buffer <<= 1;
   --j->code_bits;
   return k & 0x80000000;
}

/* given a value that's at position X in the zigzag stream,
 * where does it appear in the 8x8 matrix coded as row-major? */
static uint8_t rjpeg_jpeg_dezigzag[64+15] =
{
    0,  1,  8, 16,  9,  2,  3, 10,
   17, 24, 32, 25, 18, 11,  4,  5,
   12, 19, 26, 33, 40, 48, 41, 34,
   27, 20, 13,  6,  7, 14, 21, 28,
   35, 42, 49, 56, 57, 50, 43, 36,
   29, 22, 15, 23, 30, 37, 44, 51,
   58, 59, 52, 45, 38, 31, 39, 46,
   53, 60, 61, 54, 47, 55, 62, 63,
   /* let corrupt input sample past end */
   63, 63, 63, 63, 63, 63, 63, 63,
   63, 63, 63, 63, 63, 63, 63
};

/* decode one 64-entry block-- */
static int rjpeg_jpeg_decode_block(
      rjpeg_jpeg *j, short data[64],
      rjpeg_huffman *hdc,
      rjpeg_huffman *hac,
      int16_t *fac,
      int b,
      uint8_t *dequant)
{
   int dc,k;
   int t;
   int diff      = 0;

   if (j->code_bits < 16)
      rjpeg_grow_buffer_unsafe(j);
   t = rjpeg_jpeg_huff_decode(j, hdc);

   /* Bad huffman code. Corrupt JPEG? */
   if (t < 0)
      return 0;

   /* 0 all the ac values now so we can do it 32-bits at a time */
   memset(data,0,64*sizeof(data[0]));

   if (t)
      diff                = rjpeg_extend_receive(j, t);
   dc                     = j->img_comp[b].dc_pred + diff;
   j->img_comp[b].dc_pred = dc;
   data[0]                = (short) (dc * dequant[0]);

   /* decode AC components, see JPEG spec */
   k                      = 1;
   do
   {
      unsigned int zig;
      int c,r,s;
      if (j->code_bits < 16)
         rjpeg_grow_buffer_unsafe(j);
      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
      r = fac[c];
      if (r)
      {
         /* fast-AC path */
         k               += (r >> 4) & 15; /* run */
         s                = r & 15; /* combined length */
         j->code_buffer <<= s;
         j->code_bits    -= s;
         /* decode into unzigzag'd location */
         zig              = rjpeg_jpeg_dezigzag[k++];
         data[zig]        = (short) ((r >> 8) * dequant[zig]);
      }
      else
      {
         int rs = rjpeg_jpeg_huff_decode(j, hac);

         /* Bad huffman code. Corrupt JPEG? */
         if (rs < 0)
            return 0;

         s = rs & 15;
         r = rs >> 4;
         if (s == 0)
         {
            if (rs != 0xf0)
               break; /* end block */
            k += 16;
         }
         else
         {
            k += r;
            /* decode into unzigzag'd location */
            zig = rjpeg_jpeg_dezigzag[k++];
            data[zig] = (short) (rjpeg_extend_receive(j,s) * dequant[zig]);
         }
      }
   } while (k < 64);
   return 1;
}

static int rjpeg_jpeg_decode_block_prog_dc(
      rjpeg_jpeg *j,
      short data[64],
      rjpeg_huffman *hdc,
      int b)
{
   /* Can't merge DC and AC. Corrupt JPEG? */
   if (j->spec_end != 0)
      return 0;

   if (j->code_bits < 16)
      rjpeg_grow_buffer_unsafe(j);

   if (j->succ_high == 0)
   {
      int t;
      int dc;
      int diff = 0;

      /* first scan for DC coefficient, must be first */
      memset(data,0,64*sizeof(data[0])); /* 0 all the ac values now */
      t       = rjpeg_jpeg_huff_decode(j, hdc);
      if (t)
         diff = rjpeg_extend_receive(j, t);

      dc      = j->img_comp[b].dc_pred + diff;
      j->img_comp[b].dc_pred = dc;
      data[0] = (short) (dc << j->succ_low);
   }
   else
   {
      /* refinement scan for DC coefficient */
      if (rjpeg_jpeg_get_bit(j))
         data[0] += (short) (1 << j->succ_low);
   }
   return 1;
}

static int rjpeg_jpeg_decode_block_prog_ac(
      rjpeg_jpeg *j,
      short data[64],
      rjpeg_huffman *hac,
      int16_t *fac)
{
   int k;

   /* Can't merge DC and AC. Corrupt JPEG? */
   if (j->spec_start == 0)
      return 0;

   if (j->succ_high == 0)
   {
      int shift = j->succ_low;

      if (j->eob_run)
      {
         --j->eob_run;
         return 1;
      }

      k = j->spec_start;
      do
      {
         unsigned int zig;
         int c,r,s;
         if (j->code_bits < 16)
            rjpeg_grow_buffer_unsafe(j);
         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
         r = fac[c];
         if (r)
         {
            /* fast-AC path */
            k               += (r >> 4) & 15; /* run */
            s                = r & 15; /* combined length */
            j->code_buffer <<= s;
            j->code_bits    -= s;
            zig              = rjpeg_jpeg_dezigzag[k++];
            data[zig]        = (short) ((r >> 8) << shift);
         }
         else
         {
            int rs = rjpeg_jpeg_huff_decode(j, hac);

            /* Bad huffman code. Corrupt JPEG? */
            if (rs < 0)
               return 0;

            s = rs & 15;
            r = rs >> 4;
            if (s == 0)
            {
               if (r < 15)
               {
                  j->eob_run = (1 << r);
                  if (r)
                     j->eob_run += rjpeg_jpeg_get_bits(j, r);
                  --j->eob_run;
                  break;
               }
               k += 16;
            }
            else
            {
               k         += r;
               zig        = rjpeg_jpeg_dezigzag[k++];
               data[zig]  = (short) (rjpeg_extend_receive(j,s) << shift);
            }
         }
      } while (k <= j->spec_end);
   }
   else
   {
      /* refinement scan for these AC coefficients */

      short bit = (short) (1 << j->succ_low);

      if (j->eob_run)
      {
         --j->eob_run;
         for (k = j->spec_start; k <= j->spec_end; ++k)
         {
            short *p = &data[rjpeg_jpeg_dezigzag[k]];
            if (*p != 0)
               if (rjpeg_jpeg_get_bit(j))
                  if ((*p & bit) == 0)
                  {
                     if (*p > 0)
                        *p += bit;
                     else
                        *p -= bit;
                  }
         }
      }
      else
      {
         k = j->spec_start;
         do
         {
            int r,s;
            int rs = rjpeg_jpeg_huff_decode(j, hac);

            /* Bad huffman code. Corrupt JPEG? */
            if (rs < 0)
               return 0;

            s = rs & 15;
            r = rs >> 4;
            if (s == 0)
            {
               if (r < 15)
               {
                  j->eob_run = (1 << r) - 1;
                  if (r)
                     j->eob_run += rjpeg_jpeg_get_bits(j, r);
                  r = 64; /* force end of block */
               }
               else
               {
                  /* r=15 s=0 should write 16 0s, so we just do
                   * a run of 15 0s and then write s (which is 0),
                   * so we don't have to do anything special here */
               }
            }
            else
            {
               /* Bad huffman code. Corrupt JPEG? */
               if (s != 1)
                  return 0;

               /* sign bit */
               if (rjpeg_jpeg_get_bit(j))
                  s = bit;
               else
                  s = -bit;
            }

            /* advance by r */
            while (k <= j->spec_end)
            {
               short *p = &data[rjpeg_jpeg_dezigzag[k++]];
               if (*p != 0)
               {
                  if (rjpeg_jpeg_get_bit(j))
                     if ((*p & bit) == 0)
                     {
                        if (*p > 0)
                           *p += bit;
                        else
                           *p -= bit;
                     }
               }
               else
               {
                  if (r == 0)
                  {
                     *p = (short) s;
                     break;
                  }
                  --r;
               }
            }
         } while (k <= j->spec_end);
      }
   }
   return 1;
}

/* take a -128..127 value and rjpeg_clamp it and convert to 0..255 */
static INLINE uint8_t rjpeg_clamp(int x)
{
   /* trick to use a single test to catch both cases */
   if ((unsigned int) x > 255)
      return 255;
   return (uint8_t) x;
}

/* derived from jidctint -- DCT_ISLOW */
#define RJPEG_IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
   int t0,t1,p4,p5,x0,x1,x2,x3; \
   int p2 = s2;                                \
   int p3 = s6;                                \
   int p1 = (p2+p3) * RJPEG_F2F(0.5411961f);   \
   int t2 = p1 + p3 * RJPEG_F2F(-1.847759065f);\
   int t3 = p1 + p2 * RJPEG_F2F( 0.765366865f);\
   p2 = s0;                                    \
   p3 = s4;                                    \
   t0 = RJPEG_FSH(p2+p3);                      \
   t1 = RJPEG_FSH(p2-p3);                      \
   x0 = t0+t3;                                 \
   x3 = t0-t3;                                 \
   x1 = t1+t2;                                 \
   x2 = t1-t2;                                 \
   t0 = s7;                                    \
   t1 = s5;                                    \
   t2 = s3;                                    \
   t3 = s1;                                    \
   p3 = t0+t2;                                 \
   p4 = t1+t3;                                 \
   p1 = t0+t3;                                 \
   p2 = t1+t2;                                 \
   p5 = (p3+p4) * RJPEG_F2F( 1.175875602f);    \
   t0 = t0      * RJPEG_F2F( 0.298631336f);    \
   t1 = t1      * RJPEG_F2F( 2.053119869f);    \
   t2 = t2      * RJPEG_F2F( 3.072711026f);    \
   t3 = t3      * RJPEG_F2F( 1.501321110f);    \
   p1 = p5 + p1 * RJPEG_F2F(-0.899976223f);    \
   p2 = p5 + p2 * RJPEG_F2F(-2.562915447f);    \
   p3 = p3      * RJPEG_F2F(-1.961570560f);    \
   p4 = p4      * RJPEG_F2F(-0.390180644f);    \
   t3 += p1+p4;                                \
   t2 += p2+p3;                                \
   t1 += p2+p4;                                \
   t0 += p1+p3

static void rjpeg_idct_block(uint8_t *out, int out_stride, short data[64])
{
   int i,val[64],*v=val;
   uint8_t   *o = NULL;
   int16_t   *d = data;

   /* columns */
   for (i = 0; i < 8; ++i,++d, ++v)
   {
      /* if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing */
      if (     d[ 8] == 0
            && d[16] == 0
            && d[24] == 0
            && d[32] == 0
            && d[40] == 0
            && d[48] == 0
            && d[56] == 0)
      {
         /*    no shortcut                 0     seconds
          *    (1|2|3|4|5|6|7)==0          0     seconds
          *    all separate               -0.047 seconds
          *    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds */
         int dcterm = d[0] << 2;
         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
      }
      else
      {
         RJPEG_IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]);

         /* constants scaled things up by 1<<12; let's bring them back
          * down, but keep 2 extra bits of precision */
         x0 += 512;
         x1 += 512;
         x2 += 512;
         x3 += 512;

         v[ 0] = (x0+t3) >> 10;
         v[56] = (x0-t3) >> 10;
         v[ 8] = (x1+t2) >> 10;
         v[48] = (x1-t2) >> 10;
         v[16] = (x2+t1) >> 10;
         v[40] = (x2-t1) >> 10;
         v[24] = (x3+t0) >> 10;
         v[32] = (x3-t0) >> 10;
      }
   }

   for (i = 0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride)
   {
      /* no fast case since the first 1D IDCT spread components out */
      RJPEG_IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]);

      /* constants scaled things up by 1<<12, plus we had 1<<2 from first
       * loop, plus horizontal and vertical each scale by sqrt(8) so together
       * we've got an extra 1<<3, so 1<<17 total we need to remove.
       * so we want to round that, which means adding 0.5 * 1<<17,
       * aka 65536. Also, we'll end up with -128 to 127 that we want
       * to encode as 0..255 by adding 128, so we'll add that before the shift
       */
      x0 += 65536 + (128<<17);
      x1 += 65536 + (128<<17);
      x2 += 65536 + (128<<17);
      x3 += 65536 + (128<<17);

      /* Tried computing the shifts into temps, or'ing the temps to see
       * if any were out of range, but that was slower */
      o[0] = rjpeg_clamp((x0+t3) >> 17);
      o[7] = rjpeg_clamp((x0-t3) >> 17);
      o[1] = rjpeg_clamp((x1+t2) >> 17);
      o[6] = rjpeg_clamp((x1-t2) >> 17);
      o[2] = rjpeg_clamp((x2+t1) >> 17);
      o[5] = rjpeg_clamp((x2-t1) >> 17);
      o[3] = rjpeg_clamp((x3+t0) >> 17);
      o[4] = rjpeg_clamp((x3-t0) >> 17);
   }
}

#if defined(__SSE2__)
/* sse2 integer IDCT. not the fastest possible implementation but it
 * produces bit-identical results to the generic C version so it's
 * fully "transparent".
 */
static void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])
{
   /* This is constructed to match our regular (generic) integer IDCT exactly. */
   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
   __m128i tmp;

   /* dot product constant: even elems=x, odd elems=y */
   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))

   /* out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
    * out(1) = c1[even]*x + c1[odd]*y
    */
   #define dct_rot(out0,out1, x,y,c0,c1) \
      __m128i c0##lo   = _mm_unpacklo_epi16((x),(y)); \
      __m128i c0##hi   = _mm_unpackhi_epi16((x),(y)); \
      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)

   /* out = in << 12  (in 16-bit, out 32-bit) */
   #define dct_widen(out, in) \
      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)

   /* wide add */
   #define dct_wadd(out, a, b) \
      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)

   /* wide sub */
   #define dct_wsub(out, a, b) \
      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)

   /* butterfly a/b, add bias, then shift by "s" and pack */
   #define dct_bfly32o(out0, out1, a,b,bias,s) \
      { \
         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
         dct_wadd(sum, abiased, b); \
         dct_wsub(dif, abiased, b); \
         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
      }

   /* 8-bit interleave step (for transposes) */
   #define dct_interleave8(a, b) \
      tmp = a; \
      a = _mm_unpacklo_epi8(a, b); \
      b = _mm_unpackhi_epi8(tmp, b)

   /* 16-bit interleave step (for transposes) */
   #define dct_interleave16(a, b) \
      tmp = a; \
      a = _mm_unpacklo_epi16(a, b); \
      b = _mm_unpackhi_epi16(tmp, b)

   #define dct_pass(bias,shift) \
      { \
         /* even part */ \
         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
         __m128i sum04 = _mm_add_epi16(row0, row4); \
         __m128i dif04 = _mm_sub_epi16(row0, row4); \
         dct_widen(t0e, sum04); \
         dct_widen(t1e, dif04); \
         dct_wadd(x0, t0e, t3e); \
         dct_wsub(x3, t0e, t3e); \
         dct_wadd(x1, t1e, t2e); \
         dct_wsub(x2, t1e, t2e); \
         /* odd part */ \
         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
         __m128i sum17 = _mm_add_epi16(row1, row7); \
         __m128i sum35 = _mm_add_epi16(row3, row5); \
         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
         dct_wadd(x4, y0o, y4o); \
         dct_wadd(x5, y1o, y5o); \
         dct_wadd(x6, y2o, y5o); \
         dct_wadd(x7, y3o, y4o); \
         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
      }

   __m128i rot0_0 = dct_const(RJPEG_F2F(0.5411961f), RJPEG_F2F(0.5411961f) + RJPEG_F2F(-1.847759065f));
   __m128i rot0_1 = dct_const(RJPEG_F2F(0.5411961f) + RJPEG_F2F( 0.765366865f), RJPEG_F2F(0.5411961f));
   __m128i rot1_0 = dct_const(RJPEG_F2F(1.175875602f) + RJPEG_F2F(-0.899976223f), RJPEG_F2F(1.175875602f));
   __m128i rot1_1 = dct_const(RJPEG_F2F(1.175875602f), RJPEG_F2F(1.175875602f) + RJPEG_F2F(-2.562915447f));
   __m128i rot2_0 = dct_const(RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 0.298631336f), RJPEG_F2F(-1.961570560f));
   __m128i rot2_1 = dct_const(RJPEG_F2F(-1.961570560f), RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 3.072711026f));
   __m128i rot3_0 = dct_const(RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 2.053119869f), RJPEG_F2F(-0.390180644f));
   __m128i rot3_1 = dct_const(RJPEG_F2F(-0.390180644f), RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 1.501321110f));

   /* rounding biases in column/row passes, see rjpeg_idct_block for explanation. */
   __m128i bias_0 = _mm_set1_epi32(512);
   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));

   /* load */
   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
   row7 = _mm_load_si128((const __m128i *) (data + 7*8));

   /* column pass */
   dct_pass(bias_0, 10);

   {
      /* 16bit 8x8 transpose pass 1 */
      dct_interleave16(row0, row4);
      dct_interleave16(row1, row5);
      dct_interleave16(row2, row6);
      dct_interleave16(row3, row7);

      /* transpose pass 2 */
      dct_interleave16(row0, row2);
      dct_interleave16(row1, row3);
      dct_interleave16(row4, row6);
      dct_interleave16(row5, row7);

      /* transpose pass 3 */
      dct_interleave16(row0, row1);
      dct_interleave16(row2, row3);
      dct_interleave16(row4, row5);
      dct_interleave16(row6, row7);
   }

   /* row pass */
   dct_pass(bias_1, 17);

   {
      /* pack */
      __m128i p0 = _mm_packus_epi16(row0, row1); /* a0a1a2a3...a7b0b1b2b3...b7 */
      __m128i p1 = _mm_packus_epi16(row2, row3);
      __m128i p2 = _mm_packus_epi16(row4, row5);
      __m128i p3 = _mm_packus_epi16(row6, row7);

      /* 8bit 8x8 transpose pass 1 */
      dct_interleave8(p0, p2); /* a0e0a1e1... */
      dct_interleave8(p1, p3); /* c0g0c1g1... */

      /* transpose pass 2 */
      dct_interleave8(p0, p1); /* a0c0e0g0... */
      dct_interleave8(p2, p3); /* b0d0f0h0... */

      /* transpose pass 3 */
      dct_interleave8(p0, p2); /* a0b0c0d0... */
      dct_interleave8(p1, p3); /* a4b4c4d4... */

      /* store */
      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
   }

#undef dct_const
#undef dct_rot
#undef dct_widen
#undef dct_wadd
#undef dct_wsub
#undef dct_bfly32o
#undef dct_interleave8
#undef dct_interleave16
#undef dct_pass
}

#endif

#ifdef RJPEG_NEON

/* NEON integer IDCT. should produce bit-identical
 * results to the generic C version. */
static void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])
{
   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;

   int16x4_t rot0_0 = vdup_n_s16(RJPEG_F2F(0.5411961f));
   int16x4_t rot0_1 = vdup_n_s16(RJPEG_F2F(-1.847759065f));
   int16x4_t rot0_2 = vdup_n_s16(RJPEG_F2F( 0.765366865f));
   int16x4_t rot1_0 = vdup_n_s16(RJPEG_F2F( 1.175875602f));
   int16x4_t rot1_1 = vdup_n_s16(RJPEG_F2F(-0.899976223f));
   int16x4_t rot1_2 = vdup_n_s16(RJPEG_F2F(-2.562915447f));
   int16x4_t rot2_0 = vdup_n_s16(RJPEG_F2F(-1.961570560f));
   int16x4_t rot2_1 = vdup_n_s16(RJPEG_F2F(-0.390180644f));
   int16x4_t rot3_0 = vdup_n_s16(RJPEG_F2F( 0.298631336f));
   int16x4_t rot3_1 = vdup_n_s16(RJPEG_F2F( 2.053119869f));
   int16x4_t rot3_2 = vdup_n_s16(RJPEG_F2F( 3.072711026f));
   int16x4_t rot3_3 = vdup_n_s16(RJPEG_F2F( 1.501321110f));

#define dct_long_mul(out, inq, coeff) \
   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)

#define dct_long_mac(out, acc, inq, coeff) \
   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)

#define dct_widen(out, inq) \
   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)

/* wide add */
#define dct_wadd(out, a, b) \
   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)

/* wide sub */
#define dct_wsub(out, a, b) \
   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)

/* butterfly a/b, then shift using "shiftop" by "s" and pack */
#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
   { \
      dct_wadd(sum, a, b); \
      dct_wsub(dif, a, b); \
      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
   }

#define dct_pass(shiftop, shift) \
   { \
      /* even part */ \
      int16x8_t sum26 = vaddq_s16(row2, row6); \
      dct_long_mul(p1e, sum26, rot0_0); \
      dct_long_mac(t2e, p1e, row6, rot0_1); \
      dct_long_mac(t3e, p1e, row2, rot0_2); \
      int16x8_t sum04 = vaddq_s16(row0, row4); \
      int16x8_t dif04 = vsubq_s16(row0, row4); \
      dct_widen(t0e, sum04); \
      dct_widen(t1e, dif04); \
      dct_wadd(x0, t0e, t3e); \
      dct_wsub(x3, t0e, t3e); \
      dct_wadd(x1, t1e, t2e); \
      dct_wsub(x2, t1e, t2e); \
      /* odd part */ \
      int16x8_t sum15 = vaddq_s16(row1, row5); \
      int16x8_t sum17 = vaddq_s16(row1, row7); \
      int16x8_t sum35 = vaddq_s16(row3, row5); \
      int16x8_t sum37 = vaddq_s16(row3, row7); \
      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
      dct_long_mul(p5o, sumodd, rot1_0); \
      dct_long_mac(p1o, p5o, sum17, rot1_1); \
      dct_long_mac(p2o, p5o, sum35, rot1_2); \
      dct_long_mul(p3o, sum37, rot2_0); \
      dct_long_mul(p4o, sum15, rot2_1); \
      dct_wadd(sump13o, p1o, p3o); \
      dct_wadd(sump24o, p2o, p4o); \
      dct_wadd(sump23o, p2o, p3o); \
      dct_wadd(sump14o, p1o, p4o); \
      dct_long_mac(x4, sump13o, row7, rot3_0); \
      dct_long_mac(x5, sump24o, row5, rot3_1); \
      dct_long_mac(x6, sump23o, row3, rot3_2); \
      dct_long_mac(x7, sump14o, row1, rot3_3); \
      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
   }

   /* load */
   row0 = vld1q_s16(data + 0*8);
   row1 = vld1q_s16(data + 1*8);
   row2 = vld1q_s16(data + 2*8);
   row3 = vld1q_s16(data + 3*8);
   row4 = vld1q_s16(data + 4*8);
   row5 = vld1q_s16(data + 5*8);
   row6 = vld1q_s16(data + 6*8);
   row7 = vld1q_s16(data + 7*8);

   /* add DC bias */
   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));

   /* column pass */
   dct_pass(vrshrn_n_s32, 10);

   /* 16bit 8x8 transpose */
   {
/* these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
 * whether compilers actually get this is another story, sadly. */
#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }

      /* pass 1 */
      dct_trn16(row0, row1); /* a0b0a2b2a4b4a6b6 */
      dct_trn16(row2, row3);
      dct_trn16(row4, row5);
      dct_trn16(row6, row7);

      /* pass 2 */
      dct_trn32(row0, row2); /* a0b0c0d0a4b4c4d4 */
      dct_trn32(row1, row3);
      dct_trn32(row4, row6);
      dct_trn32(row5, row7);

      /* pass 3 */
      dct_trn64(row0, row4); /* a0b0c0d0e0f0g0h0 */
      dct_trn64(row1, row5);
      dct_trn64(row2, row6);
      dct_trn64(row3, row7);

#undef dct_trn16
#undef dct_trn32
#undef dct_trn64
   }

   /* row pass
    * vrshrn_n_s32 only supports shifts up to 16, we need
    * 17. so do a non-rounding shift of 16 first then follow
    * up with a rounding shift by 1. */
   dct_pass(vshrn_n_s32, 16);

   {
      /* pack and round */
      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);

      /* again, these can translate into one instruction, but often don't. */
#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }

      /* sadly can't use interleaved stores here since we only write
       * 8 bytes to each scan line! */

      /* 8x8 8-bit transpose pass 1 */
      dct_trn8_8(p0, p1);
      dct_trn8_8(p2, p3);
      dct_trn8_8(p4, p5);
      dct_trn8_8(p6, p7);

      /* pass 2 */
      dct_trn8_16(p0, p2);
      dct_trn8_16(p1, p3);
      dct_trn8_16(p4, p6);
      dct_trn8_16(p5, p7);

      /* pass 3 */
      dct_trn8_32(p0, p4);
      dct_trn8_32(p1, p5);
      dct_trn8_32(p2, p6);
      dct_trn8_32(p3, p7);

      /* store */
      vst1_u8(out, p0);
      out += out_stride;
      vst1_u8(out, p1);
      out += out_stride;
      vst1_u8(out, p2);
      out += out_stride;
      vst1_u8(out, p3);
      out += out_stride;
      vst1_u8(out, p4);
      out += out_stride;
      vst1_u8(out, p5);
      out += out_stride;
      vst1_u8(out, p6);
      out += out_stride;
      vst1_u8(out, p7);

#undef dct_trn8_8
#undef dct_trn8_16
#undef dct_trn8_32
   }

#undef dct_long_mul
#undef dct_long_mac
#undef dct_widen
#undef dct_wadd
#undef dct_wsub
#undef dct_bfly32o
#undef dct_pass
}

#endif /* RJPEG_NEON */

static uint8_t rjpeg_get_marker(rjpeg_jpeg *j)
{
   uint8_t x;

   if (j->marker != RJPEG_MARKER_NONE)
   {
      x = j->marker;
      j->marker = RJPEG_MARKER_NONE;
      return x;
   }

   x = rjpeg_get8(j->s);
   if (x != 0xff)
      return RJPEG_MARKER_NONE;
   while (x == 0xff)
      x = rjpeg_get8(j->s);
   return x;
}

/* after a restart interval, rjpeg_jpeg_reset the entropy decoder and
 * the dc prediction
 */
static void rjpeg_jpeg_reset(rjpeg_jpeg *j)
{
   j->code_bits           = 0;
   j->code_buffer         = 0;
   j->nomore              = 0;
   j->img_comp[0].dc_pred = 0;
   j->img_comp[1].dc_pred = 0;
   j->img_comp[2].dc_pred = 0;
   j->marker              = RJPEG_MARKER_NONE;
   j->todo                = j->restart_interval ? j->restart_interval : 0x7fffffff;
   j->eob_run             = 0;

   /* no more than 1<<31 MCUs if no restart_interval? that's plenty safe,
    * since we don't even allow 1<<30 pixels */
}

static int rjpeg_parse_entropy_coded_data(rjpeg_jpeg *z)
{
   rjpeg_jpeg_reset(z);

   if (z->scan_n == 1)
   {
      int i, j;
      int n = z->order[0];
      int w = (z->img_comp[n].x+7) >> 3;
      int h = (z->img_comp[n].y+7) >> 3;

      /* non-interleaved data, we just need to process one block at a time,
       * in trivial scanline order
       * number of blocks to do just depends on how many actual "pixels" this
       * component has, independent of interleaved MCU blocking and such */

      if (z->progressive)
      {
         for (j = 0; j < h; ++j)
         {
            for (i = 0; i < w; ++i)
            {
               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);

               if (z->spec_start == 0)
               {
                  if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
                     return 0;
               }
               else
               {
                  int ha = z->img_comp[n].ha;
                  if (!rjpeg_jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
                     return 0;
               }

               /* every data block is an MCU, so countdown the restart interval */
               if (--z->todo <= 0)
               {
                  if (z->code_bits < 24)
                     rjpeg_grow_buffer_unsafe(z);

                  if (!RJPEG_RESTART(z->marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
      else
      {
         RJPEG_SIMD_ALIGN(short, data[64]);

         for (j = 0; j < h; ++j)
         {
            for (i = 0; i < w; ++i)
            {
               int ha = z->img_comp[n].ha;
               if (!rjpeg_jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd,
                        z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq]))
                  return 0;

               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8,
                     z->img_comp[n].w2, data);

               /* every data block is an MCU, so countdown the restart interval */
               if (--z->todo <= 0)
               {
                  if (z->code_bits < 24)
                     rjpeg_grow_buffer_unsafe(z);

                  /* if it's NOT a restart, then just bail,
                   * so we get corrupt data rather than no data */
                  if (!RJPEG_RESTART(z->marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
   }
   else
   {
      /* interleaved */
      int i,j,k,x,y;

      if (z->progressive)
      {
         for (j = 0; j < z->img_mcu_y; ++j)
         {
            for (i = 0; i < z->img_mcu_x; ++i)
            {
               /* scan an interleaved MCU... process scan_n components in order */
               for (k = 0; k < z->scan_n; ++k)
               {
                  int n = z->order[k];
                  /* scan out an MCU's worth of this component; that's just determined
                   * by the basic H and V specified for the component */
                  for (y = 0; y < z->img_comp[n].v; ++y)
                  {
                     for (x = 0; x < z->img_comp[n].h; ++x)
                     {
                        int      x2 = (i*z->img_comp[n].h + x);
                        int      y2 = (j*z->img_comp[n].v + y);
                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
                        if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
                           return 0;
                     }
                  }
               }

               /* after all interleaved components, that's an interleaved MCU,
                * so now count down the restart interval */
               if (--z->todo <= 0)
               {
                  if (z->code_bits < 24)
                     rjpeg_grow_buffer_unsafe(z);
                  if (!RJPEG_RESTART(z->marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
      else
      {
         RJPEG_SIMD_ALIGN(short, data[64]);

         for (j = 0; j < z->img_mcu_y; ++j)
         {
            for (i = 0; i < z->img_mcu_x; ++i)
            {
               /* scan an interleaved MCU... process scan_n components in order */
               for (k = 0; k < z->scan_n; ++k)
               {
                  int n = z->order[k];
                  /* scan out an MCU's worth of this component; that's just determined
                   * by the basic H and V specified for the component */
                  for (y = 0; y < z->img_comp[n].v; ++y)
                  {
                     for (x = 0; x < z->img_comp[n].h; ++x)
                     {
                        int x2 = (i*z->img_comp[n].h + x)*8;
                        int y2 = (j*z->img_comp[n].v + y)*8;
                        int ha = z->img_comp[n].ha;

                        if (!rjpeg_jpeg_decode_block(z, data,
                                 z->huff_dc+z->img_comp[n].hd,
                                 z->huff_ac+ha, z->fast_ac[ha],
                                 n, z->dequant[z->img_comp[n].tq]))
                           return 0;

                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2,
                              z->img_comp[n].w2, data);
                     }
                  }
               }

               /* after all interleaved components, that's an interleaved MCU,
                * so now count down the restart interval */
               if (--z->todo <= 0)
               {
                  if (z->code_bits < 24)
                     rjpeg_grow_buffer_unsafe(z);
                  if (!RJPEG_RESTART(z->marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
   }

   return 1;
}

static void rjpeg_jpeg_dequantize(short *data, uint8_t *dequant)
{
   int i;
   for (i = 0; i < 64; ++i)
      data[i] *= dequant[i];
}

static void rjpeg_jpeg_finish(rjpeg_jpeg *z)
{
   int i,j,n;

   if (!z->progressive)
      return;

   /* dequantize and IDCT the data */
   for (n = 0; n < z->s->img_n; ++n)
   {
      int w = (z->img_comp[n].x+7) >> 3;
      int h = (z->img_comp[n].y+7) >> 3;
      for (j = 0; j < h; ++j)
      {
         for (i = 0; i < w; ++i)
         {
            short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
            rjpeg_jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
            z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8,
                  z->img_comp[n].w2, data);
         }
      }
   }
}

static int rjpeg_process_marker(rjpeg_jpeg *z, int m)
{
   int L;
   switch (m)
   {
      case RJPEG_MARKER_NONE: /* no marker found */
         /* Expected marker. Corrupt JPEG? */
         return 0;

      case 0xDD: /* DRI - specify restart interval */

         /* Bad DRI length. Corrupt JPEG? */
         if (RJPEG_GET16BE(z->s) != 4)
            return 0;

         z->restart_interval = RJPEG_GET16BE(z->s);
         return 1;

      case 0xDB: /* DQT - define quantization table */
         L = RJPEG_GET16BE(z->s)-2;
         while (L > 0)
         {
            int q = rjpeg_get8(z->s);
            int p = q >> 4;
            int t = q & 15,i;

            /* Bad DQT type. Corrupt JPEG? */
            if (p != 0)
               return 0;

            /* Bad DQT table. Corrupt JPEG? */
            if (t > 3)
               return 0;

            for (i = 0; i < 64; ++i)
               z->dequant[t][rjpeg_jpeg_dezigzag[i]] = rjpeg_get8(z->s);
            L -= 65;
         }
         return L == 0;

      case 0xC4: /* DHT - define huffman table */
         L = RJPEG_GET16BE(z->s)-2;
         while (L > 0)
         {
            int sizes[16],i,n = 0;
            uint8_t *v = NULL;
            int q      = rjpeg_get8(z->s);
            int tc     = q >> 4;
            int th     = q & 15;

            /* Bad DHT header. Corrupt JPEG? */
            if (tc > 1 || th > 3)
               return 0;

            for (i = 0; i < 16; ++i)
            {
               sizes[i] = rjpeg_get8(z->s);
               n += sizes[i];
            }
            L -= 17;

            if (tc == 0)
            {
               if (!rjpeg_build_huffman(z->huff_dc+th, sizes))
                  return 0;
               v = z->huff_dc[th].values;
            }
            else
            {
               if (!rjpeg_build_huffman(z->huff_ac+th, sizes))
                  return 0;
               v = z->huff_ac[th].values;
            }
            for (i = 0; i < n; ++i)
               v[i] = rjpeg_get8(z->s);
            if (tc != 0)
               rjpeg_build_fast_ac(z->fast_ac[th], z->huff_ac + th);
            L -= n;
         }
         return L == 0;
   }

   /* check for comment block or APP blocks */
   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE)
   {
      int n = RJPEG_GET16BE(z->s)-2;

      if (n < 0)
         z->s->img_buffer = z->s->img_buffer_end;
      else
         z->s->img_buffer += n;

      return 1;
   }
   return 0;
}

/* after we see SOS */
static int rjpeg_process_scan_header(rjpeg_jpeg *z)
{
   int i;
   int aa;
   int Ls    = RJPEG_GET16BE(z->s);

   z->scan_n = rjpeg_get8(z->s);

   /* Bad SOS component count. Corrupt JPEG? */
   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n)
      return 0;

   /* Bad SOS length. Corrupt JPEG? */
   if (Ls != 6+2*z->scan_n)
      return 0;

   for (i = 0; i < z->scan_n; ++i)
   {
      int which;
      int id = rjpeg_get8(z->s);
      int q  = rjpeg_get8(z->s);

      for (which = 0; which < z->s->img_n; ++which)
         if (z->img_comp[which].id == id)
            break;
      if (which == z->s->img_n)
         return 0; /* no match */

      /* Bad DC huff. Corrupt JPEG? */
      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3)
         return 0;

      /* Bad AC huff. Corrupt JPEG? */
      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3)
         return 0;

      z->order[i] = which;
   }

   z->spec_start = rjpeg_get8(z->s);
   z->spec_end   = rjpeg_get8(z->s); /* should be 63, but might be 0 */
   aa            = rjpeg_get8(z->s);
   z->succ_high  = (aa >> 4);
   z->succ_low   = (aa & 15);

   if (z->progressive)
   {
      /* Bad SOS. Corrupt JPEG? */
      if (  z->spec_start > 63 ||
            z->spec_end > 63   ||
            z->spec_start > z->spec_end ||
            z->succ_high > 13           ||
            z->succ_low > 13)
         return 0;
   }
   else
   {
      /* Bad SOS. Corrupt JPEG? */
      if (z->spec_start != 0)
         return 0;
      if (z->succ_high != 0 || z->succ_low != 0)
         return 0;

      z->spec_end = 63;
   }

   return 1;
}

static int rjpeg_process_frame_header(rjpeg_jpeg *z, int scan)
{
   rjpeg_context *s = z->s;
   int Lf,p,i,q, h_max=1,v_max=1,c;
   Lf = RJPEG_GET16BE(s);

   /* JPEG */

   /* Bad SOF len. Corrupt JPEG? */
   if (Lf < 11)
      return 0;

   p  = rjpeg_get8(s);

   /* JPEG baseline */

   /* Only 8-bit. JPEG format not supported? */
   if (p != 8)
      return 0;

   s->img_y = RJPEG_GET16BE(s);

   /* Legal, but we don't handle it--but neither does IJG */

   /* No header height, JPEG format not supported? */
   if (s->img_y == 0)
      return 0;

   s->img_x = RJPEG_GET16BE(s);

   /* No header width. Corrupt JPEG? */
   if (s->img_x == 0)
      return 0;

   c = rjpeg_get8(s);

   /* JFIF requires */

   /* Bad component count. Corrupt JPEG? */
   if (c != 3 && c != 1)
      return 0;

   s->img_n = c;

   for (i = 0; i < c; ++i)
   {
      z->img_comp[i].data = NULL;
      z->img_comp[i].linebuf = NULL;
   }

   /* Bad SOF length. Corrupt JPEG? */
   if (Lf != 8+3*s->img_n)
      return 0;

   for (i = 0; i < s->img_n; ++i)
   {
      z->img_comp[i].id = rjpeg_get8(s);
      if (z->img_comp[i].id != i+1)   /* JFIF requires */
         if (z->img_comp[i].id != i)  /* some version of jpegtran outputs non-JFIF-compliant files! */
            return 0;

      q                = rjpeg_get8(s);
      z->img_comp[i].h = (q >> 4);

      /* Bad H. Corrupt JPEG? */
      if (!z->img_comp[i].h || z->img_comp[i].h > 4)
         return 0;

      z->img_comp[i].v = q & 15;

      /* Bad V. Corrupt JPEG? */
      if (!z->img_comp[i].v || z->img_comp[i].v > 4)
         return 0;

      z->img_comp[i].tq = rjpeg_get8(s);

      /* Bad TQ. Corrupt JPEG? */
      if (z->img_comp[i].tq > 3)
         return 0;
   }

   if (scan != RJPEG_SCAN_LOAD)
      return 1;

   /* Image too large to decode? */
   if ((1 << 30) / s->img_x / s->img_n < s->img_y)
      return 0;

   for (i = 0; i < s->img_n; ++i)
   {
      if (z->img_comp[i].h > h_max)
         h_max = z->img_comp[i].h;
      if (z->img_comp[i].v > v_max)
         v_max = z->img_comp[i].v;
   }

   /* compute interleaved MCU info */
   z->img_h_max = h_max;
   z->img_v_max = v_max;
   z->img_mcu_w = h_max * 8;
   z->img_mcu_h = v_max * 8;
   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;

   if (z->progressive)
   {
      for (i = 0; i < s->img_n; ++i)
      {
         /* number of effective pixels (e.g. for non-interleaved MCU) */
         z->img_comp[i].x        = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
         z->img_comp[i].y        = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;

         /* to simplify generation, we'll allocate enough memory to decode
          * the bogus oversized data from using interleaved MCUs and their
          * big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
          * discard the extra data until colorspace conversion */
         z->img_comp[i].w2       = z->img_mcu_x * z->img_comp[i].h * 8;
         z->img_comp[i].h2       = z->img_mcu_y * z->img_comp[i].v * 8;
         z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);

         /* Out of memory? */
         if (!z->img_comp[i].raw_data)
         {
            for (--i; i >= 0; --i)
            {
               free(z->img_comp[i].raw_data);
               z->img_comp[i].data = NULL;
            }

            return 0;
         }

         /* align blocks for IDCT using MMX/SSE */
         z->img_comp[i].data      = (uint8_t*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
         z->img_comp[i].linebuf   = NULL;
         z->img_comp[i].coeff_w   = (z->img_comp[i].w2 + 7) >> 3;
         z->img_comp[i].coeff_h   = (z->img_comp[i].h2 + 7) >> 3;
         z->img_comp[i].raw_coeff = malloc(z->img_comp[i].coeff_w *
                                    z->img_comp[i].coeff_h * 64 * sizeof(short) + 15);
         z->img_comp[i].coeff     = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
      }
   }
   else
   {
      for (i = 0; i < s->img_n; ++i)
      {
         /* number of effective pixels (e.g. for non-interleaved MCU) */
         z->img_comp[i].x        = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
         z->img_comp[i].y        = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;

         /* to simplify generation, we'll allocate enough memory to decode
          * the bogus oversized data from using interleaved MCUs and their
          * big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
          * discard the extra data until colorspace conversion */
         z->img_comp[i].w2       = z->img_mcu_x * z->img_comp[i].h * 8;
         z->img_comp[i].h2       = z->img_mcu_y * z->img_comp[i].v * 8;
         z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);

         /* Out of memory? */
         if (!z->img_comp[i].raw_data)
         {
            for (--i; i >= 0; --i)
            {
               free(z->img_comp[i].raw_data);
               z->img_comp[i].data = NULL;
            }
         }

         /* align blocks for IDCT using MMX/SSE */
         z->img_comp[i].data      = (uint8_t*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
         z->img_comp[i].linebuf   = NULL;
         z->img_comp[i].coeff     = 0;
         z->img_comp[i].raw_coeff = 0;
      }
   }

   return 1;
}

static int rjpeg_decode_jpeg_header(rjpeg_jpeg *z, int scan)
{
   int m;
   z->marker = RJPEG_MARKER_NONE; /* initialize cached marker to empty */
   m         = rjpeg_get_marker(z);

   /* No SOI. Corrupt JPEG? */
   if (m != JPEG_MARKER_SOI)
      return 0;

   if (scan == RJPEG_SCAN_TYPE)
      return 1;

   m = rjpeg_get_marker(z);
   while (!RJPEG_SOF(m))
   {
      if (!rjpeg_process_marker(z,m))
         return 0;
      m = rjpeg_get_marker(z);
      while (m == RJPEG_MARKER_NONE)
      {
         /* some files have extra padding after their blocks, so ok, we'll scan */

         /* No SOF. Corrupt JPEG? */
         if (RJPEG_AT_EOF(z->s))
            return 0;

         m = rjpeg_get_marker(z);
      }
   }
   z->progressive = RJPEG_SOF_PROGRESSIVE(m);
   if (!rjpeg_process_frame_header(z, scan))
      return 0;
   return 1;
}

/* decode image to YCbCr format */
static int rjpeg_decode_jpeg_image(rjpeg_jpeg *j)
{
   int m;
   for (m = 0; m < 4; m++)
   {
      j->img_comp[m].raw_data = NULL;
      j->img_comp[m].raw_coeff = NULL;
   }
   j->restart_interval = 0;
   if (!rjpeg_decode_jpeg_header(j, RJPEG_SCAN_LOAD))
      return 0;
   m = rjpeg_get_marker(j);

   while (m != JPEG_MARKER_EOI)
   {
      if (m == JPEG_MARKER_SOS)
      {
         if (!rjpeg_process_scan_header(j))
            return 0;
         if (!rjpeg_parse_entropy_coded_data(j))
            return 0;

         if (j->marker == RJPEG_MARKER_NONE )
         {
            /* handle 0s at the end of image data from IP Kamera 9060 */

            while (!RJPEG_AT_EOF(j->s))
            {
               int x = rjpeg_get8(j->s);
               if (x == 255)
               {
                  j->marker = rjpeg_get8(j->s);
                  break;
               }
               else if (x != 0) /* Junk before marker. Corrupt JPEG? */
                  return 0;
            }

            /* if we reach eof without hitting a marker,
             * rjpeg_get_marker() below will fail and we'll eventually return 0 */
         }
      }
      else
      {
         if (!rjpeg_process_marker(j, m))
            return 0;
      }
      m = rjpeg_get_marker(j);
   }

   if (j->progressive)
      rjpeg_jpeg_finish(j);
   return 1;
}

/* static jfif-centered resampling (across block boundaries) */

static uint8_t *rjpeg_resample_row_1(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   (void)out;
   (void)in_far;
   (void)w;
   (void)hs;
   return in_near;
}

static uint8_t* rjpeg_resample_row_v_2(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate two samples vertically for every one in input */
   int i;
   (void)hs;
   for (i = 0; i < w; ++i)
      out[i] = RJPEG_DIV4(3*in_near[i] + in_far[i] + 2);
   return out;
}

static uint8_t*  rjpeg_resample_row_h_2(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate two samples horizontally for every one in input */
   int i;
   uint8_t *input = in_near;

   if (w == 1)
   {
      /* if only one sample, can't do any interpolation */
      out[0] = out[1] = input[0];
      return out;
   }

   out[0] = input[0];
   out[1] = RJPEG_DIV4(input[0]*3 + input[1] + 2);

   for (i=1; i < w-1; ++i)
   {
      int n      = 3 * input[i] + 2;
      out[i*2+0] = RJPEG_DIV4(n+input[i-1]);
      out[i*2+1] = RJPEG_DIV4(n+input[i+1]);
   }
   out[i*2+0] = RJPEG_DIV4(input[w-2]*3 + input[w-1] + 2);
   out[i*2+1] = input[w-1];

   (void)in_far;
   (void)hs;

   return out;
}

static uint8_t *rjpeg_resample_row_hv_2(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate 2x2 samples for every one in input */
   int i,t0,t1;
   if (w == 1)
   {
      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);
      return out;
   }

   t1     = 3*in_near[0] + in_far[0];
   out[0] = RJPEG_DIV4(t1+2);

   for (i = 1; i < w; ++i)
   {
      t0         = t1;
      t1         = 3*in_near[i]+in_far[i];
      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);
      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);
   }
   out[w*2-1] = RJPEG_DIV4(t1+2);

   (void)hs;

   return out;
}

#if defined(__SSE2__) || defined(RJPEG_NEON)
static uint8_t *rjpeg_resample_row_hv_2_simd(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate 2x2 samples for every one in input */
   int i = 0,t0,t1;

   if (w == 1)
   {
      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);
      return out;
   }

   t1 = 3*in_near[0] + in_far[0];
   /* process groups of 8 pixels for as long as we can.
    * note we can't handle the last pixel in a row in this loop
    * because we need to handle the filter boundary conditions.
    */
   for (; i < ((w-1) & ~7); i += 8)
   {
#if defined(__SSE2__)
      /* load and perform the vertical filtering pass
       * this uses 3*x + y = 4*x + (y - x) */
      __m128i zero  = _mm_setzero_si128();
      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
      __m128i diff  = _mm_sub_epi16(farw, nearw);
      __m128i nears = _mm_slli_epi16(nearw, 2);
      __m128i curr  = _mm_add_epi16(nears, diff); /* current row */

      /* horizontal filter works the same based on shifted vers of current
       * row. "prev" is current row shifted right by 1 pixel; we need to
       * insert the previous pixel value (from t1).
       * "next" is current row shifted left by 1 pixel, with first pixel
       * of next block of 8 pixels added in.
       */
      __m128i prv0 = _mm_slli_si128(curr, 2);
      __m128i nxt0 = _mm_srli_si128(curr, 2);
      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);

      /* horizontal filter, polyphase implementation since it's convenient:
       * even pixels = 3*cur + prev = cur*4 + (prev - cur)
       * odd  pixels = 3*cur + next = cur*4 + (next - cur)
       * note the shared term. */
      __m128i bias = _mm_set1_epi16(8);
      __m128i curs = _mm_slli_epi16(curr, 2);
      __m128i prvd = _mm_sub_epi16(prev, curr);
      __m128i nxtd = _mm_sub_epi16(next, curr);
      __m128i curb = _mm_add_epi16(curs, bias);
      __m128i even = _mm_add_epi16(prvd, curb);
      __m128i odd  = _mm_add_epi16(nxtd, curb);

      /* interleave even and odd pixels, then undo scaling. */
      __m128i int0 = _mm_unpacklo_epi16(even, odd);
      __m128i int1 = _mm_unpackhi_epi16(even, odd);
      __m128i de0  = _mm_srli_epi16(int0, 4);
      __m128i de1  = _mm_srli_epi16(int1, 4);

      /* pack and write output */
      __m128i outv = _mm_packus_epi16(de0, de1);
      _mm_storeu_si128((__m128i *) (out + i*2), outv);
#elif defined(RJPEG_NEON)
      /* load and perform the vertical filtering pass
       * this uses 3*x + y = 4*x + (y - x) */
      uint8x8_t farb  = vld1_u8(in_far + i);
      uint8x8_t nearb = vld1_u8(in_near + i);
      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
      int16x8_t curr  = vaddq_s16(nears, diff); /* current row */

      /* horizontal filter works the same based on shifted vers of current
       * row. "prev" is current row shifted right by 1 pixel; we need to
       * insert the previous pixel value (from t1).
       * "next" is current row shifted left by 1 pixel, with first pixel
       * of next block of 8 pixels added in. */
      int16x8_t prv0 = vextq_s16(curr, curr, 7);
      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);

      /* horizontal filter, polyphase implementation since it's convenient:
       * even pixels = 3*cur + prev = cur*4 + (prev - cur)
       * odd  pixels = 3*cur + next = cur*4 + (next - cur)
       * note the shared term.
       */
      int16x8_t curs = vshlq_n_s16(curr, 2);
      int16x8_t prvd = vsubq_s16(prev, curr);
      int16x8_t nxtd = vsubq_s16(next, curr);
      int16x8_t even = vaddq_s16(curs, prvd);
      int16x8_t odd  = vaddq_s16(curs, nxtd);

      /* undo scaling and round, then store with even/odd phases interleaved */
      uint8x8x2_t o;
      o.val[0] = vqrshrun_n_s16(even, 4);
      o.val[1] = vqrshrun_n_s16(odd,  4);
      vst2_u8(out + i*2, o);
#endif

      /* "previous" value for next iteration */
      t1 = 3*in_near[i+7] + in_far[i+7];
   }

   t0       = t1;
   t1       = 3*in_near[i] + in_far[i];
   out[i*2] = RJPEG_DIV16(3*t1 + t0 + 8);

   for (++i; i < w; ++i)
   {
      t0         = t1;
      t1         = 3*in_near[i]+in_far[i];
      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);
      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);
   }
   out[w*2-1]    = RJPEG_DIV4(t1+2);

   (void)hs;

   return out;
}
#endif

static uint8_t *rjpeg_resample_row_generic(uint8_t *out,
      uint8_t *in_near, uint8_t *in_far, int w, int hs)
{
   /* resample with nearest-neighbor */
   int i,j;
   (void)in_far;

   for (i = 0; i < w; ++i)
      for (j = 0; j < hs; ++j)
         out[i*hs+j] = in_near[i];
   return out;
}

/* this is a reduced-precision calculation of YCbCr-to-RGB introduced
 * to make sure the code produces the same results in both SIMD and scalar */
#ifndef FLOAT2FIXED
#define FLOAT2FIXED(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)
#endif

static void rjpeg_YCbCr_to_RGB_row(uint8_t *out, const uint8_t *y,
      const uint8_t *pcb, const uint8_t *pcr, int count, int step)
{
   int i;
   for (i = 0; i < count; ++i)
   {
      int y_fixed = (y[i] << 20) + (1<<19); /* rounding */
      int cr = pcr[i] - 128;
      int cb = pcb[i] - 128;
      int r = y_fixed +  cr* FLOAT2FIXED(1.40200f);
      int g = y_fixed + (cr*-FLOAT2FIXED(0.71414f)) + ((cb*-FLOAT2FIXED(0.34414f)) & 0xffff0000);
      int b = y_fixed                               +   cb* FLOAT2FIXED(1.77200f);
      r >>= 20;
      g >>= 20;
      b >>= 20;
      if ((unsigned) r > 255)
         r = 255;
      if ((unsigned) g > 255)
         g = 255;
      if ((unsigned) b > 255)
         b = 255;
      out[0] = (uint8_t)r;
      out[1] = (uint8_t)g;
      out[2] = (uint8_t)b;
      out[3] = 255;
      out += step;
   }
}

#if defined(__SSE2__) || defined(RJPEG_NEON)
static void rjpeg_YCbCr_to_RGB_simd(uint8_t *out, const uint8_t *y,
      const uint8_t *pcb, const uint8_t *pcr, int count, int step)
{
   int i = 0;

#if defined(__SSE2__)
   /* step == 3 is pretty ugly on the final interleave, and i'm not convinced
    * it's useful in practice (you wouldn't use it for textures, for example).
    * so just accelerate step == 4 case.
    */
   if (step == 4)
   {
      /* this is a fairly straightforward implementation and not super-optimized. */
      __m128i signflip  = _mm_set1_epi8(-0x80);
      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
      __m128i y_bias    = _mm_set1_epi8((char) (unsigned char) 128);
      __m128i xw        = _mm_set1_epi16(255); /* alpha channel */

      for (; i+7 < count; i += 8)
      {
         /* load */
         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); /* -128 */
         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); /* -128 */

         /* unpack to short (and left-shift cr, cb by 8) */
         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);

         /* color transform */
         __m128i yws = _mm_srli_epi16(yw, 4);
         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
         __m128i rws = _mm_add_epi16(cr0, yws);
         __m128i gwt = _mm_add_epi16(cb0, yws);
         __m128i bws = _mm_add_epi16(yws, cb1);
         __m128i gws = _mm_add_epi16(gwt, cr1);

         /* descale */
         __m128i rw = _mm_srai_epi16(rws, 4);
         __m128i bw = _mm_srai_epi16(bws, 4);
         __m128i gw = _mm_srai_epi16(gws, 4);

         /* back to byte, set up for transpose */
         __m128i brb = _mm_packus_epi16(rw, bw);
         __m128i gxb = _mm_packus_epi16(gw, xw);

         /* transpose to interleave channels */
         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
         __m128i o1 = _mm_unpackhi_epi16(t0, t1);

         /* store */
         _mm_storeu_si128((__m128i *) (out + 0), o0);
         _mm_storeu_si128((__m128i *) (out + 16), o1);
         out += 32;
      }
   }
#endif

#ifdef RJPEG_NEON
   /* in this version, step=3 support would be easy to add. but is there demand? */
   if (step == 4)
   {
      /* this is a fairly straightforward implementation and not super-optimized. */
      uint8x8_t signflip = vdup_n_u8(0x80);
      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));

      for (; i+7 < count; i += 8)
      {
         uint8x8x4_t o;

         /* load */
         uint8x8_t y_bytes  = vld1_u8(y + i);
         uint8x8_t cr_bytes = vld1_u8(pcr + i);
         uint8x8_t cb_bytes = vld1_u8(pcb + i);
         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));

         /* expand to s16 */
         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
         int16x8_t crw = vshll_n_s8(cr_biased, 7);
         int16x8_t cbw = vshll_n_s8(cb_biased, 7);

         /* color transform */
         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
         int16x8_t rws = vaddq_s16(yws, cr0);
         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
         int16x8_t bws = vaddq_s16(yws, cb1);

         /* undo scaling, round, convert to byte */
         o.val[0] = vqrshrun_n_s16(rws, 4);
         o.val[1] = vqrshrun_n_s16(gws, 4);
         o.val[2] = vqrshrun_n_s16(bws, 4);
         o.val[3] = vdup_n_u8(255);

         /* store, interleaving r/g/b/a */
         vst4_u8(out, o);
         out += 8*4;
      }
   }
#endif

   for (; i < count; ++i)
   {
      int y_fixed = (y[i] << 20) + (1<<19); /* rounding */
      int cr      = pcr[i] - 128;
      int cb      = pcb[i] - 128;
      int r       = y_fixed + cr* FLOAT2FIXED(1.40200f);
      int g       = y_fixed + cr*-FLOAT2FIXED(0.71414f) + ((cb*-FLOAT2FIXED(0.34414f)) & 0xffff0000);
      int b       = y_fixed                             +   cb* FLOAT2FIXED(1.77200f);
      r >>= 20;
      g >>= 20;
      b >>= 20;
      if ((unsigned) r > 255)
         r = 255;
      if ((unsigned) g > 255)
         g = 255;
      if ((unsigned) b > 255)
         b = 255;
      out[0] = (uint8_t)r;
      out[1] = (uint8_t)g;
      out[2] = (uint8_t)b;
      out[3] = 255;
      out += step;
   }
}
#endif

/* set up the kernels */
static void rjpeg_setup_jpeg(rjpeg_jpeg *j)
{
   uint64_t mask = cpu_features_get();

   (void)mask;

   j->idct_block_kernel        = rjpeg_idct_block;
   j->YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_row;
   j->resample_row_hv_2_kernel = rjpeg_resample_row_hv_2;

#if defined(__SSE2__)
   if (mask & RETRO_SIMD_SSE2)
   {
      j->idct_block_kernel        = rjpeg_idct_simd;
      j->YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_simd;
      j->resample_row_hv_2_kernel = rjpeg_resample_row_hv_2_simd;
   }
#endif

#ifdef RJPEG_NEON
   j->idct_block_kernel           = rjpeg_idct_simd;
   j->YCbCr_to_RGB_kernel         = rjpeg_YCbCr_to_RGB_simd;
   j->resample_row_hv_2_kernel    = rjpeg_resample_row_hv_2_simd;
#endif
}

/* clean up the temporary component buffers */
static void rjpeg_cleanup_jpeg(rjpeg_jpeg *j)
{
   int i;
   for (i = 0; i < j->s->img_n; ++i)
   {
      if (j->img_comp[i].raw_data)
      {
         free(j->img_comp[i].raw_data);
         j->img_comp[i].raw_data = NULL;
         j->img_comp[i].data = NULL;
      }

      if (j->img_comp[i].raw_coeff)
      {
         free(j->img_comp[i].raw_coeff);
         j->img_comp[i].raw_coeff = 0;
         j->img_comp[i].coeff = 0;
      }

      if (j->img_comp[i].linebuf)
      {
         free(j->img_comp[i].linebuf);
         j->img_comp[i].linebuf = NULL;
      }
   }
}

static uint8_t *rjpeg_load_jpeg_image(rjpeg_jpeg *z,
      unsigned *out_x, unsigned *out_y, int *comp, int req_comp)
{
   int n, decode_n;
   int k;
   unsigned int i,j;
   rjpeg_resample res_comp[4];
   uint8_t *coutput[4] = {0};
   uint8_t *output     = NULL;
   z->s->img_n         = 0;

   /* load a jpeg image from whichever source, but leave in YCbCr format */
   if (!rjpeg_decode_jpeg_image(z))
      goto error;

   /* determine actual number of components to generate */
   n = req_comp ? req_comp : z->s->img_n;

   if (z->s->img_n == 3 && n < 3)
      decode_n = 1;
   else
      decode_n = z->s->img_n;

   /* resample and color-convert */
   for (k = 0; k < decode_n; ++k)
   {
      rjpeg_resample *r = &res_comp[k];

      /* allocate line buffer big enough for upsampling off the edges
       * with upsample factor of 4 */
      z->img_comp[k].linebuf = (uint8_t *) malloc(z->s->img_x + 3);
      if (!z->img_comp[k].linebuf)
         goto error;

      r->hs       = z->img_h_max / z->img_comp[k].h;
      r->vs       = z->img_v_max / z->img_comp[k].v;
      r->ystep    = r->vs >> 1;
      r->w_lores  = (z->s->img_x + r->hs-1) / r->hs;
      r->ypos     = 0;
      r->line0    = r->line1 = z->img_comp[k].data;
      r->resample = rjpeg_resample_row_generic;

      if      (r->hs == 1 && r->vs == 1)
         r->resample = rjpeg_resample_row_1;
      else if (r->hs == 1 && r->vs == 2)
         r->resample = rjpeg_resample_row_v_2;
      else if (r->hs == 2 && r->vs == 1)
         r->resample = rjpeg_resample_row_h_2;
      else if (r->hs == 2 && r->vs == 2)
         r->resample = z->resample_row_hv_2_kernel;
   }

   /* can't error after this so, this is safe */
   output = (uint8_t *) malloc(n * z->s->img_x * z->s->img_y + 1);

   if (!output)
      goto error;

   /* now go ahead and resample */
   for (j = 0; j < z->s->img_y; ++j)
   {
      uint8_t *out = output + n * z->s->img_x * j;
      for (k = 0; k < decode_n; ++k)
      {
         rjpeg_resample *r = &res_comp[k];
         int         y_bot  = r->ystep >= (r->vs >> 1);

         coutput[k]         = r->resample(z->img_comp[k].linebuf,
               y_bot ? r->line1 : r->line0,
               y_bot ? r->line0 : r->line1,
               r->w_lores, r->hs);

         if (++r->ystep >= r->vs)
         {
            r->ystep = 0;
            r->line0 = r->line1;
            if (++r->ypos < z->img_comp[k].y)
               r->line1 += z->img_comp[k].w2;
         }
      }

      if (n >= 3)
      {
         uint8_t *y = coutput[0];
         if (y)
         {
            if (z->s->img_n == 3)
               z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
            else
               for (i = 0; i < z->s->img_x; ++i)
               {
                  out[0]  = out[1] = out[2] = y[i];
                  out[3]  = 255; /* not used if n==3 */
                  out    += n;
               }
         }
      }
      else
      {
         uint8_t *y = coutput[0];
         if (n == 1)
            for (i = 0; i < z->s->img_x; ++i)
               out[i] = y[i];
         else
            for (i = 0; i < z->s->img_x; ++i)
            {
               *out++ = y[i];
               *out++ = 255;
            }
      }
   }

   rjpeg_cleanup_jpeg(z);
   *out_x = z->s->img_x;
   *out_y = z->s->img_y;

   if (comp)
      *comp  = z->s->img_n; /* report original components, not output */
   return output;

error:
   rjpeg_cleanup_jpeg(z);
   return NULL;
}

int rjpeg_process_image(rjpeg_t *rjpeg, void **buf_data,
      size_t size, unsigned *width, unsigned *height)
{
   rjpeg_jpeg j;
   rjpeg_context s;
   int comp;
   uint32_t *img         = NULL;
   uint32_t *pixels      = NULL;
   unsigned size_tex     = 0;

   if (!rjpeg)
      return IMAGE_PROCESS_ERROR;

   s.img_buffer          = (uint8_t*)rjpeg->buff_data;
   s.img_buffer_original = (uint8_t*)rjpeg->buff_data;
   s.img_buffer_end      = (uint8_t*)rjpeg->buff_data + (int)size;

   j.s                   = &s;

   rjpeg_setup_jpeg(&j);

   img                   =  (uint32_t*)rjpeg_load_jpeg_image(&j, width, height, &comp, 4);

   if (!img)
      return IMAGE_PROCESS_ERROR;

   size_tex = (*width) * (*height);
   pixels   = (uint32_t*)malloc(size_tex * sizeof(uint32_t));

   if (!pixels)
   {
      free(img);
      return IMAGE_PROCESS_ERROR;
   }

   *buf_data = pixels;

   /* Convert RGBA to ARGB */
   while (size_tex--)
   {
      unsigned int texel = img[size_tex];
      unsigned int A     = texel & 0xFF000000;
      unsigned int B     = texel & 0x00FF0000;
      unsigned int G     = texel & 0x0000FF00;
      unsigned int R     = texel & 0x000000FF;
      ((unsigned int*)pixels)[size_tex] = A | (R << 16) | G | (B >> 16);
   }

   free(img);

   return IMAGE_PROCESS_END;
}

bool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data)
{
   if (!rjpeg)
      return false;

   rjpeg->buff_data = (uint8_t*)data;

   return true;
}

void rjpeg_free(rjpeg_t *rjpeg)
{
   if (!rjpeg)
      return;

   free(rjpeg);
}

rjpeg_t *rjpeg_alloc(void)
{
   rjpeg_t *rjpeg = (rjpeg_t*)calloc(1, sizeof(*rjpeg));
   if (!rjpeg)
      return NULL;
   return rjpeg;
}

./include/libretro-common/formats/json/rjson.c

/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjson.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* The parser is based on Public Domain JSON Parser for C by Christopher Wellons - https://github.com/skeeto/pdjson */

#include <stdio.h>  /* snprintf, vsnprintf */
#include <stdarg.h> /* va_list */
#include <string.h> /* memcpy */
#include <stdint.h> /* int64_t */
#include <stdlib.h> /* malloc, realloc, atof, atoi */

#include <formats/rjson.h>
#include <compat/posix_string.h>
#include <streams/interface_stream.h>
#include <streams/file_stream.h>

struct _rjson_stack { enum rjson_type type; size_t count; };

struct rjson
{
   /* Order of the top few struct elements have an impact on performance */
   /* Place most frequently accessed things on top */
   const unsigned char *input_p;
   struct _rjson_stack *stack_top;
   const unsigned char *input_end;
   const unsigned char* source_column_p;
   size_t source_line;

   char *string, *string_pass_through;
   size_t string_len, string_cap;

   struct _rjson_stack inline_stack[10];
   struct _rjson_stack *stack;

   rjson_io_t io;
   void *user_data;

   unsigned int stack_cap, stack_max;
   int input_len;

   char option_flags;
   char decimal_sep;
   char error_text[80];
   char inline_string[512];

   /* Must be at the end of the struct, can be allocated with custom size */
   unsigned char input_buf[512];
};

enum _rjson_token
{
   _rJSON_TOK_WHITESPACE, _rJSON_TOK_NEWLINE, _rJSON_TOK_OPTIONAL_SKIP,
   _rJSON_TOK_OBJECT, _rJSON_TOK_ARRAY, _rJSON_TOK_STRING, _rJSON_TOK_NUMBER,
   _rJSON_TOK_TRUE, _rJSON_TOK_FALSE, _rJSON_TOK_NULL,
   _rJSON_TOK_OBJECT_END, _rJSON_TOK_ARRAY_END, _rJSON_TOK_COLON,
   _rJSON_TOK_COMMA, _rJSON_TOK_ERROR, _rJSON_TOK_EOF, _rJSON_TOKCOUNT
};

/* The used char type is int and not short for better performance */
typedef unsigned int _rjson_char_t;
#define _rJSON_EOF ((_rjson_char_t)256)

/* Compiler branching hint for expression with high probability
 * Explicitly only have likely (and no unlikely) because compilers
 * that don't support it expect likely branches to come first. */
#if defined(__GNUC__) || defined(__clang__)
#define _rJSON_LIKELY(x) __builtin_expect(!!(x), 1)
#else
#define _rJSON_LIKELY(x) (x)
#endif

/* These 3 error functions return RJSON_ERROR for convenience */
static enum rjson_type _rjson_error(rjson_t *json, const char *fmt, ...)
{
   va_list ap;
   if (json->stack_top->type == RJSON_ERROR)
      return RJSON_ERROR;
   json->stack_top->type = RJSON_ERROR;
   va_start(ap, fmt);
   vsnprintf(json->error_text, sizeof(json->error_text), fmt, ap);
   va_end(ap);
   return RJSON_ERROR;
}

static enum rjson_type _rjson_error_char(rjson_t *json,
      const char *fmt, _rjson_char_t chr)
{
   char buf[16];
   if (json->stack_top->type == RJSON_ERROR)
      return RJSON_ERROR;
   snprintf(buf, sizeof(buf),
         (chr == _rJSON_EOF ? "end of stream" :
         (chr >= ' ' && chr <= '~' ? "'%c'" : "byte 0x%02X")), chr);
   return _rjson_error(json, fmt, buf);
}

static enum rjson_type _rjson_error_token(rjson_t *json,
   const char *fmt, enum _rjson_token tok)
{
   return _rjson_error_char(json, fmt,
         (tok == _rJSON_TOK_EOF ? _rJSON_EOF : json->input_p[-1]));
}

static bool _rjson_io_input(rjson_t *json)
{
   if (json->input_end == json->input_buf)
      return false;
   json->source_column_p -= (json->input_end - json->input_buf);
   json->input_p = json->input_buf;
   json->input_end = json->input_buf +
         json->io(json->input_buf, json->input_len, json->user_data);
   if (json->input_end < json->input_buf)
   {
      _rjson_error(json, "input stream read error");
      json->input_end = json->input_buf;
   }
   return (json->input_end != json->input_p);
}

static bool _rjson_grow_string(rjson_t *json)
{
   char *string;
   size_t new_string_cap = json->string_cap * 2;
   if (json->string != json->inline_string)
      string             = (char*)realloc(json->string, new_string_cap);
   else if ((string      = (char*)malloc(new_string_cap)) != NULL)
      memcpy(string, json->inline_string, sizeof(json->inline_string));
   if (!string)
   {
      _rjson_error(json, "out of memory");
      return false;
   }
   json->string_cap      = new_string_cap;
   json->string          = string;
   return true;
}

static INLINE bool _rjson_pushchar(rjson_t *json, _rjson_char_t c)
{
   json->string[json->string_len++] = (char)c;
   return (json->string_len != json->string_cap || _rjson_grow_string(json));
}

static INLINE bool _rjson_pushchars(rjson_t *json,
      const unsigned char *from, const unsigned char *to)
{
   unsigned char* string;
   size_t _len    = json->string_len;
   size_t new_len = _len + (to - from);
   while (new_len >= json->string_cap)
      if (!_rjson_grow_string(json))
         return false;
   string = (unsigned char *)json->string;
   while (_len != new_len)
      string[_len++] = *(from++);
   json->string_len = new_len;
   return true;
}

static INLINE _rjson_char_t _rjson_char_get(rjson_t *json)
{
   return (json->input_p != json->input_end || _rjson_io_input(json)
        ? *json->input_p++ : _rJSON_EOF);
}

static unsigned int _rjson_get_unicode_cp(rjson_t *json)
{
   unsigned int cp = 0, shift = 16;
   for (;;)
   {
      _rjson_char_t c = _rjson_char_get(json);
      switch (c)
      {
         case '0': case '1': case '2': case '3': case '4':
         case '5': case '6': case '7': case '8': case '9':
            c -= '0';
            break;
         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
            c -= ('a' - 10);
            break;
         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
            c -= ('A' - 10);
            break;
         case _rJSON_EOF:
            _rjson_error(json, "unterminated string literal in Unicode");
            return (unsigned int)-1;
         default:
            _rjson_error_char(json, "invalid Unicode escape hexadecimal %s", c);
            return (unsigned int)-1;
      }
      shift -= 4;
      cp |= ((unsigned int)c << shift);
      if (!shift)
         return cp;
   }
}

static bool _rjson_read_unicode(rjson_t *json)
{
   #define _rJSON_READ_UNICODE_REPLACE_OR_IGNORE \
      if (json->option_flags & (RJSON_OPTION_IGNORE_INVALID_ENCODING \
            | RJSON_OPTION_REPLACE_INVALID_ENCODING)) goto replace_or_ignore;

   unsigned int cp;

   if ((cp = _rjson_get_unicode_cp(json)) == (unsigned int)-1)
      return false;

   if (cp >= 0xd800 && cp <= 0xdbff)
   {
      /* This is the high portion of a surrogate pair; we need to read the
       * lower portion to get the codepoint */
      unsigned int l, h = cp;

      _rjson_char_t c = _rjson_char_get(json);
      if (c == _rJSON_EOF)
      {
         _rjson_error(json, "unterminated string literal in Unicode");
         return false;
      }
      if (c != '\\')
      {
         _rjson_error_char(json, "invalid continuation %s"
               " for surrogate pair, expected '\\'", c);
         return false;
      }

      c = _rjson_char_get(json);
      if (c == _rJSON_EOF)
      {
         _rjson_error(json, "unterminated string literal in Unicode");
         return false;
      }
      if (c != 'u')
      {
         _rjson_error_char(json, "invalid continuation %s"
               " for surrogate pair, expected 'u'", c);
         return false;
      }
      if ((l = _rjson_get_unicode_cp(json)) == (unsigned int)-1)
         return false;
      if (l < 0xdc00 || l > 0xdfff)
      {
         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
         _rjson_error(json, "surrogate pair continuation \\u%04x out "
            "of range (dc00-dfff)", l);
         return false;
      }
      cp = ((h - 0xd800) * 0x400) + ((l - 0xdc00) + 0x10000);
   }
   else if (cp >= 0xdc00 && cp <= 0xdfff)
   {
      _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
      _rjson_error(json, "dangling surrogate \\u%04x", cp);
      return false;
   }

   if (cp < 0x80UL)
      return _rjson_pushchar(json, cp);

   if (cp < 0x0800UL)
      return (_rjson_pushchar(json, (cp >> 6 & 0x1F) | 0xC0) &&
              _rjson_pushchar(json, (cp >> 0 & 0x3F) | 0x80));

   if (cp < 0x010000UL)
   {
      if (cp >= 0xd800 && cp <= 0xdfff)
      {
         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
         _rjson_error(json, "invalid codepoint %04x", cp);
         return false;
      }
      return (_rjson_pushchar(json, (cp >> 12 & 0x0F) | 0xE0) &&
              _rjson_pushchar(json, (cp >>  6 & 0x3F) | 0x80) &&
              _rjson_pushchar(json, (cp >>  0 & 0x3F) | 0x80));
   }
   if (cp < 0x110000UL)
      return (_rjson_pushchar(json, (cp >> 18 & 0x07) | 0xF0) &&
              _rjson_pushchar(json, (cp >> 12 & 0x3F) | 0x80) &&
              _rjson_pushchar(json, (cp >>  6 & 0x3F) | 0x80) &&
              _rjson_pushchar(json, (cp >>  0 & 0x3F) | 0x80));

   _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
   _rjson_error(json, "unable to encode %04x as UTF-8", cp);
   return false;

replace_or_ignore:
   return ((json->option_flags & RJSON_OPTION_IGNORE_INVALID_ENCODING) ||
         _rjson_pushchar(json, '?'));
   #undef _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
}

static bool _rjson_validate_utf8(rjson_t *json)
{
   unsigned char first, c;
   unsigned char *p;
   unsigned char *from = (unsigned char *)
         (json->string_pass_through ? json->string_pass_through : json->string);
   unsigned char *to = from + json->string_len;

   if (json->option_flags & RJSON_OPTION_IGNORE_INVALID_ENCODING)
      return true;

   for (;;)
   {
      if (from == to)
         return true;
      first = *from;
      if (first <= 0x7F) /* ASCII */
      {
         from++;
         continue;
      }
      p = from;
      /* Continuation or overlong encoding of an ASCII byte */
      if (first <= 0xC1)
         goto invalid_utf8;
      if (first <= 0xDF)
      {
         if ((from = p + 2) > to)
            goto invalid_utf8;
continue_length_2:
         c = p[1];
         switch (first)
         {
            case 0xE0:
               c = (c < 0xA0 || c > 0xBF);
               break;
            case 0xED:
               c = (c < 0x80 || c > 0x9F);
               break;
            case 0xF0:
               c = (c < 0x90 || c > 0xBF);
               break;
            case 0xF4:
               c = (c < 0x80 || c > 0x8F);
               break;
            default:
               c = (c < 0x80 || c > 0xBF);
               break;
         }
         if (c)
            goto invalid_utf8;
      }
      else if (first <= 0xEF)
      {
         if ((from = p + 3) > to)
            goto invalid_utf8;
continue_length_3:
         if ((c = p[2]) < 0x80 || c > 0xBF)
            goto invalid_utf8;
         goto continue_length_2;
      }
      else if (first <= 0xF4)
      {
         if ((from = p + 4) > to)
            goto invalid_utf8;
         if ((c = p[3]) < 0x80 || c > 0xBF)
            goto invalid_utf8;
         goto continue_length_3;
      }
      else
         goto invalid_utf8; /* length 5 or 6 or invalid UTF-8 */
      continue;
invalid_utf8:
      if (!(json->option_flags & RJSON_OPTION_REPLACE_INVALID_ENCODING))
      {
         _rjson_error(json, "invalid UTF-8 character in string");
         return false;
      }
      from    = p;
      *from++ = '?';
      while (from != to && (*from & 0x80))
         *from++ = '?';
   }
}

static enum rjson_type _rjson_read_string(rjson_t *json)
{
   const unsigned char *p    = json->input_p, *raw = p;
   const unsigned char *end  = json->input_end;
   unsigned char utf8mask    = 0;
   json->string_pass_through = NULL;
   json->string_len          = 0;

   for (;;)
   {
      if (_rJSON_LIKELY(p != end))
      {
         unsigned char c = *p;
         if (_rJSON_LIKELY(c != '"' && c != '\\' && c >= 0x20))
         {
            /* handle most common case first, it's faster */
            utf8mask |= c;
            p++;
         }
         else if (c == '"')
         {
            json->input_p = p + 1;
            if (json->string_len == 0 && p + 1 != end)
            {
               /* raw string fully inside input buffer, pass through */
               json->string_len          = p - raw;
               json->string_pass_through = (char*)raw;
            }
            else if (raw != p && !_rjson_pushchars(json, raw, p)) /* OOM */
               return RJSON_ERROR;
            /* Contains invalid UTF-8 byte sequences */
            if ((utf8mask & 0x80) && !_rjson_validate_utf8(json))
               return RJSON_ERROR;
            return RJSON_STRING;
         }
         else if (c == '\\')
         {
            _rjson_char_t esc;
            if (raw != p)
            {
               /* Can't pass through string with escapes, use string buffer */
               if (!_rjson_pushchars(json, raw, p))
                  return RJSON_ERROR;
            }
            json->input_p = p + 1;
            esc = _rjson_char_get(json);
            switch (esc)
            {
               case 'u':
                  if (!_rjson_read_unicode(json))
                     return RJSON_ERROR;
                  break;

               case 'b':
                  esc = '\b';
                  goto escape_pushchar;
               case 'f':
                  esc = '\f';
                  goto escape_pushchar;
               case 'n':
                  esc = '\n';
                  goto escape_pushchar;
               case 'r':
                  if (!(json->option_flags & RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN))
                  {
                     esc = '\r';
                     goto escape_pushchar;
                  }
                  break;
               case 't':
                  esc = '\t';
                  goto escape_pushchar;
               case '/':
               case '"':
               case '\\':
escape_pushchar:
                  if (!_rjson_pushchar(json, esc))
                     return RJSON_ERROR;
                  break;

               case _rJSON_EOF:
                  return _rjson_error(json, "unterminated string literal in escape");

               default:
                  return _rjson_error_char(json, "invalid escaped %s", esc);
            }
            raw = p = json->input_p;
            end     = json->input_end;
         }
         else if (!(json->option_flags & RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS))
            return _rjson_error_char(json, "unescaped control character %s in string", c);
         else
            p++;
      }
      else
      {
         if (raw != p)
         {
            /* not fully inside input buffer, copy to string buffer */
            if (!_rjson_pushchars(json, raw, p))
               return RJSON_ERROR;
         }
         if (!_rjson_io_input(json))
            return _rjson_error(json, "unterminated string literal");
         raw = p = json->input_p;
         end     = json->input_end;
      }
   }
}

static enum rjson_type _rjson_read_number(rjson_t *json)
{
   const unsigned char *p     = json->input_p - 1;
   const unsigned char *end   = json->input_end;
   const unsigned char *start = p;

   json->string_len = 0;
   json->string_pass_through = NULL;
   for (;;)
   {
      if (_rJSON_LIKELY(p != end))
      {
         switch (*p++)
         {
            case '+': case '-': case '.':
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
            case 'E': case 'e':
               continue;
         }
         p--;
         json->input_p = p;
         if (!_rjson_pushchars(json, start, p))
            return RJSON_ERROR; /* out of memory */
         break;
      }
      else
      {
         /* number sequences are always copied to the string buffer */
         if (!_rjson_pushchars(json, start, p))
            return RJSON_ERROR;
         if (!_rjson_io_input(json))
         {
            /* EOF here is not an error for a number */
            json->input_p = json->input_end;
            break;
         }
         start = p = json->input_p;
         end = json->input_end;
      }
   }

   p = (const unsigned char *)json->string;
   end = (p + json->string_len);

   /* validate json number */
   if (*p == '-' && ++p == end)
      goto invalid_number;
   if (*p == '0')
   {
      if (++p == end)
         return RJSON_NUMBER;
   }
   else
   {
      if (*p < '1' || *p > '9')
         goto invalid_number;
      do
      {
         if (++p == end)
            return RJSON_NUMBER;
      }
      while (*p >= '0' && *p <= '9');
   }
   if (*p == '.')
   {
      if (++p == end)
         goto invalid_number;
      if (*p < '0' || *p > '9')
         goto invalid_number;
      do
      {
         if (++p == end)
            return RJSON_NUMBER;
      }
      while (*p >= '0' && *p <= '9');
   }
   if (((*p)|0x20) == 'e')
   {
      if (++p == end)
         goto invalid_number;
      if ((*p == '-' || *p == '+') && ++p == end)
         goto invalid_number;
      if (*p < '0' || *p > '9')
         goto invalid_number;
      do
      {
         if (++p == end)
            return RJSON_NUMBER;
      }
      while (*p >= '0' && *p <= '9');
   }
invalid_number:
   return _rjson_error_char(json, "unexpected %s in number",
         (p == json->input_end ? _rJSON_EOF : p[p == end ? -1 : 0]));
}

static enum rjson_type _rjson_push_stack(rjson_t *json, enum _rjson_token t)
{
   if (json->stack_top + 1 == json->stack + json->stack_cap)
   {
      /* reached allocated stack size, either reallocate or abort */
      unsigned int new_stack_cap;
      struct _rjson_stack *new_stack;
      size_t stack_alloc;
      if (json->stack_cap == json->stack_max)
         return _rjson_error(json, "maximum depth of nesting reached");

      new_stack_cap = json->stack_cap + 4;
      if (new_stack_cap > json->stack_max)
         new_stack_cap = json->stack_max;
      stack_alloc = new_stack_cap * sizeof(struct _rjson_stack);
      if (json->stack != json->inline_stack)
         new_stack = (struct _rjson_stack *)realloc(json->stack, stack_alloc);
      else if ((new_stack = (struct _rjson_stack*)malloc(stack_alloc)) != NULL)
         memcpy(new_stack, json->inline_stack, sizeof(json->inline_stack));
      if (!new_stack)
         return _rjson_error(json, "out of memory");

      json->stack     = new_stack;
      json->stack_top = new_stack + json->stack_cap - 1;
      json->stack_cap = new_stack_cap;
   }
   json->stack_top++;
   json->stack_top->count = 0;
   return (json->stack_top->type =
            (t == _rJSON_TOK_ARRAY ? RJSON_ARRAY : RJSON_OBJECT));
}

static enum rjson_type _rjson_read_name(rjson_t *json, const char *pattern, enum rjson_type type)
{
   _rjson_char_t c;
   const char *p;
   for (p = pattern; *p; p++)
   {
      if ((_rjson_char_t)*p != (c = _rjson_char_get(json)))
         return _rjson_error_char(json, "unexpected %s in value", c);
   }
   return type;
}

static bool _rjson_optional_skip(rjson_t *json, const unsigned char **p, const unsigned char **end)
{
   unsigned char c, skip = (*p)[-1];
   int state = 0;

   if (skip == '/' && !(json->option_flags & RJSON_OPTION_ALLOW_COMMENTS))
      return false;

   if (     skip == 0xEF && (!(json->option_flags & RJSON_OPTION_ALLOW_UTF8BOM)
         || json->source_line != 1 || json->source_column_p != json->input_p))
      return false;

   for (;;)
   {
      if (*p == *end)
      {
         if (!_rjson_io_input(json))
         {
            _rjson_error(json, "unfinished %s",
                  (skip == '/' ? "comment" : "utf8 byte order mark"));
            break;
         }
         *p   = json->input_p;
         *end = json->input_end;
      }
      c = *(*p)++;
      if (skip == '/')
      {
         if      (state == 0 && c == '/')
            state = 1;
         else if (state == 0 && c == '*')
            state = 2;
         else if (state == 0)
            break;
         else if (state == 1 && c == '\n')
            return true;
         else if (state == 2 && c == '*')
            state = 3;
         else if (state == 3 && c == '/')
            return true;
         else if (state == 3 && c != '*')
            state = 2;
      }
      else if (skip == 0xEF)
      {
         /* Silence warning - state being set never used */
         if      (state == 0 && c == 0xBB)
            state = 1;
         else if (state == 1 && c == 0xBF)
            return true;
         else
            break;
      }
   }
   return false;
}

enum rjson_type rjson_next(rjson_t *json)
{
   unsigned char tok;
   struct _rjson_stack *stack = json->stack_top;
   const unsigned char *p     = json->input_p;
   const unsigned char *end   = json->input_end;
   unsigned char passed_token = false;

   /* JSON token look-up-table */
   static const unsigned char token_lut[256] =
   {
      #define i _rJSON_TOK_ERROR
      /*   0 | 0x00 |   */ i,i,i,i,i,i,i,i,i,
      /*   9 | 0x09 |\t */ _rJSON_TOK_WHITESPACE,
      /*  10 | 0x0A |\n */ _rJSON_TOK_NEWLINE, i,i,
      /*  13 | 0x0D |\r */ _rJSON_TOK_WHITESPACE, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /*  32 | 0x20 |   */ _rJSON_TOK_WHITESPACE, i,
      /*  34 | 0x22 | " */ _rJSON_TOK_STRING, i,i,i,i,i,i,i,i,i,
      /*  44 | 0x2C | , */ _rJSON_TOK_COMMA,
      /*  45 | 0x2D | - */ _rJSON_TOK_NUMBER, i,
      /*  47 | 0x2F | / */ _rJSON_TOK_OPTIONAL_SKIP,
      /*  48 | 0x30 | 0 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,
      /*  53 | 0x35 | 5 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,
      /*  58 | 0x3A | : */ _rJSON_TOK_COLON, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /*  91 | 0x5B | [ */ _rJSON_TOK_ARRAY, i,
      /*  93 | 0x5D | ] */ _rJSON_TOK_ARRAY_END, i,i,i,i,i,i,i,i,
      /* 102 | 0x66 | f */ _rJSON_TOK_FALSE, i,i,i,i,i,i,i,
      /* 110 | 0x6E | n */ _rJSON_TOK_NULL, i,i,i,i,i,
      /* 116 | 0x74 | t */ _rJSON_TOK_TRUE, i,i,i,i,i,i,
      /* 123 | 0x7B | { */ _rJSON_TOK_OBJECT, i,
      /* 125 | 0x7D | } */ _rJSON_TOK_OBJECT_END,
      /* 126 | 0x7E | ~ */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /* 164 | 0xA4 |   */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /* 202 | 0xCA |   */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /* 239 | 0xEF |   */ _rJSON_TOK_OPTIONAL_SKIP, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i
      #undef i
   };

   if (_rJSON_LIKELY(stack->type != RJSON_ERROR))
   {
      for (;;)
      {
         if (_rJSON_LIKELY(p != end))
         {
            tok = token_lut[*p++];
            if (_rJSON_LIKELY(tok > _rJSON_TOK_OPTIONAL_SKIP))
            {
               /* Actual JSON token, process below */
            }
            else if (_rJSON_LIKELY(tok == _rJSON_TOK_WHITESPACE))
               continue;
            else if (tok == _rJSON_TOK_NEWLINE)
            {
               json->source_line++;
               json->source_column_p = p;
               continue;
            }
            else if (tok == _rJSON_TOK_OPTIONAL_SKIP)
            {
               if (_rjson_optional_skip(json, &p, &end))
                  continue;
            }
         }
         else if (_rJSON_LIKELY(_rjson_io_input(json)))
         {
            p   = json->input_p;
            end = json->input_end;
            continue;
         }
         else
         {
            p   = json->input_end;
            tok = _rJSON_TOK_EOF;
         }

         if (stack->type == RJSON_OBJECT)
         {
            if (stack->count & 1)
            {
               /* Expecting colon followed by value. */
               if (passed_token)
                  goto read_value;
               if (_rJSON_LIKELY(tok == _rJSON_TOK_COLON))
               {
                  passed_token = true;
                  continue;
               }
               json->input_p = p;
               return _rjson_error_token(json,
                     "expected ':' not %s after member name", (enum _rjson_token)tok);
            }
            if (passed_token)
            {
               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))
                  goto read_value;
               json->input_p = p;
               return _rjson_error(json, "expected member name after ','");
            }
            if (tok == _rJSON_TOK_OBJECT_END)
            {
               json->input_p = p;
               json->stack_top--;
               return RJSON_OBJECT_END;
            }
            if (stack->count == 0)
            {
               /* No member name/value pairs yet. */
               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))
                  goto read_value;
               json->input_p = p;
               return _rjson_error(json, "expected member name or '}'");
            }
            /* Expecting comma followed by member name. */
            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))
            {
               passed_token = true;
               continue;
            }
            json->input_p = p;
            return _rjson_error_token(json,
                  "expected ',' or '}' not %s after member value", (enum _rjson_token)tok);
         }
         else if (stack->type == RJSON_ARRAY)
         {
            if (passed_token)
               goto read_value;
            if (tok == _rJSON_TOK_ARRAY_END)
            {
               json->input_p = p;
               json->stack_top--;
               return RJSON_ARRAY_END;
            }
            if (stack->count == 0)
               goto read_value;
            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))
            {
               passed_token = true;
               continue;
            }
            json->input_p = p;
            return _rjson_error_token(json,
                  "expected ',' or ']' not %s in array", (enum _rjson_token)tok);
         }
         else
         {
            if (_rJSON_LIKELY(!stack->count && tok != _rJSON_TOK_EOF))
               goto read_value;
            json->input_p = p;
            if (!stack->count)
               return _rjson_error(json, "reached end without any data");
            if (tok == _rJSON_TOK_EOF)
               return RJSON_DONE;
            if (!(json->option_flags & RJSON_OPTION_ALLOW_TRAILING_DATA))
               return _rjson_error_token(json,
                     "expected end of stream instead of %s", (enum _rjson_token)tok);
            json->input_p--;
            return RJSON_DONE;
         }

         /* read value for current token */
         read_value:
         json->input_p = p;
         stack->count++;
         /* This is optimal when there are many strings, otherwise a switch statement
          * or a function pointer table is better (depending on compiler/cpu) */
         if      (tok == _rJSON_TOK_STRING)
            return _rjson_read_string(json);
         else if (tok == _rJSON_TOK_NUMBER)
            return _rjson_read_number(json);
         else if (tok == _rJSON_TOK_OBJECT)
            return _rjson_push_stack(json, _rJSON_TOK_OBJECT);
         else if (tok == _rJSON_TOK_ARRAY)
            return _rjson_push_stack(json, _rJSON_TOK_ARRAY);
         else if (tok == _rJSON_TOK_TRUE)
            return _rjson_read_name(json, "rue", RJSON_TRUE);
         else if (tok == _rJSON_TOK_FALSE)
            return _rjson_read_name(json, "alse", RJSON_FALSE);
         else if (tok == _rJSON_TOK_NULL)
            return _rjson_read_name(json, "ull", RJSON_NULL);
         else return _rjson_error_token(json,
               "unexpected %s in value", (enum _rjson_token)tok);
      }
   }
   return RJSON_ERROR;
}

void _rjson_setup(rjson_t *json, rjson_io_t io, void *user_data, int input_len)
{
   json->io                  = io;
   json->user_data           = user_data;
   json->input_len           = input_len;
   json->input_p             = json->input_end = json->input_buf + input_len;

   json->stack               = json->inline_stack;
   json->stack_top           = json->stack;
   json->stack_top->type     = RJSON_DONE;
   json->stack_top->count    = 0;
   json->stack_cap           = (unsigned int)(sizeof(json->inline_stack) / sizeof(json->inline_stack[0]));
   json->stack_max           = (unsigned int)50;

   json->string              = json->inline_string;
   json->string_pass_through = NULL;
   json->string_len          = 0;
   json->string_cap          = sizeof(json->inline_string);

   json->source_line         = 1;
   json->source_column_p     = json->input_p;
   json->option_flags        = 0;
   json->decimal_sep         = 0;
}

rjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size)
{
   rjson_t* json = (rjson_t*)malloc(
         sizeof(rjson_t) - sizeof(((rjson_t*)0)->input_buf) + io_block_size);
   if (json) _rjson_setup(json, io, user_data, io_block_size);
   return json;
}

static int _rjson_buffer_io(void* buf, int len, void *user)
{
   const char **ud = (const char **)user;
   if (ud[1] - ud[0] < len) len = (int)(ud[1] - ud[0]);
   memcpy(buf, ud[0], len);
   ud[0] += len;
   return len;
}

rjson_t *rjson_open_buffer(const void *buffer, size_t len)
{
   rjson_t *json   = (rjson_t *)malloc(sizeof(rjson_t) + sizeof(const char *)*2);
   const char **ud = (const char **)(json + 1);
   if (!json)
      return NULL;
   ud[0] = (const char *)buffer;
   ud[1] = ud[0] + len;
   _rjson_setup(json, _rjson_buffer_io, (void*)ud, sizeof(json->input_buf));
   return json;
}

rjson_t *rjson_open_string(const char *string, size_t len)
{
   return rjson_open_buffer(string, len);
}

static int _rjson_stream_io(void* buf, int len, void *user)
{
   return (int)intfstream_read((intfstream_t*)user, buf, (uint64_t)len);
}

rjson_t *rjson_open_stream(struct intfstream_internal *stream)
{
   /* Allocate an input buffer based on the file size */
   int64_t size = intfstream_get_size(stream);
   int io_size  =
         (size > 1024*1024 ? 4096 :
         (size >  256*1024 ? 2048 : 1024));
   return rjson_open_user(_rjson_stream_io, stream, io_size);
}

static int _rjson_rfile_io(void* buf, int len, void *user)
{
   return (int)filestream_read((RFILE*)user, buf, (int64_t)len);
}

rjson_t *rjson_open_rfile(RFILE *rfile)
{
   /* Allocate an input buffer based on the file size */
   int64_t size = filestream_get_size(rfile);
   int io_size =
         (size > 1024*1024 ? 4096 :
         (size >  256*1024 ? 2048 : 1024));
   return rjson_open_user(_rjson_rfile_io, rfile, io_size);
}

void rjson_set_options(rjson_t *json, char rjson_option_flags)
{
   json->option_flags = rjson_option_flags;
}

void rjson_set_max_depth(rjson_t *json, unsigned int max_depth)
{
   json->stack_max = max_depth;
}

const char *rjson_get_string(rjson_t *json, size_t *len)
{
   char* str             = (json->string_pass_through
         ? json->string_pass_through : json->string);
   if (len)
      *len               = json->string_len;
   str[json->string_len] = '\0';
   return str;
}

double rjson_get_double(rjson_t *json)
{
   char* str = (json->string_pass_through ? json->string_pass_through : json->string);
   str[json->string_len] = '\0';
   if (json->decimal_sep != '.')
   {
      /* handle locale that uses a non-standard decimal separator */
      char *p;
      if (json->decimal_sep == 0)
      {
         char test[4];
         snprintf(test, sizeof(test), "%.1f", 0.0f);
         json->decimal_sep = test[1];
      }
      if (json->decimal_sep != '.' && (p = memchr(str, '.', strlen(str) + 1)) != NULL)
      {
         double res;
         *p  = json->decimal_sep;
         res = atof(str);
         *p  = '.';
         return res;
      }
   }
   return atof(str);
}

int rjson_get_int(rjson_t *json)
{
   char* str = (json->string_pass_through ? json->string_pass_through : json->string);
   str[json->string_len] = '\0';
   return atoi(str);
}

const char *rjson_get_error(rjson_t *json)
{
   return (json->stack_top->type == RJSON_ERROR ? json->error_text : "");
}

void rjson_set_error(rjson_t *json, const char* error)
{
   _rjson_error(json, "%s", error);
}

size_t rjson_get_source_line(rjson_t *json)
{
   return json->source_line;
}

size_t rjson_get_source_column(rjson_t *json)
{
   return (json->input_p == json->source_column_p ? 1 :
         json->input_p - json->source_column_p);
}

int rjson_get_source_context_len(rjson_t *json)
{
   const unsigned char *from = json->input_buf, *to = json->input_end, *p = json->input_p;
   return (int)(((p + 256 < to ? p + 256 : to) - (p > from + 256 ? p - 256 : from)));
}

const char* rjson_get_source_context_buf(rjson_t *json)
{
   /* inside the input buffer, some " may have been replaced with \0. */
   const unsigned char *p = json->input_p, *from = json->input_buf;
   unsigned char *i = json->input_buf;
   for (; i != json->input_end; i++)
   {
      if (*i == '\0')
         *i = '"';
   }
   return (const char*)(p > from + 256 ? p - 256 : from);
}

bool rjson_check_context(rjson_t *json, unsigned int depth, ...)
{
   va_list ap;
   const struct _rjson_stack *stack = json->stack, *stack_top = json->stack_top;
   if ((unsigned int)(stack_top - stack) != depth)
      return false;
   va_start(ap, depth);
   while (++stack <= stack_top)
   {
      if (va_arg(ap, int) == (int)stack->type) continue;
      va_end(ap);
      return false;
   }
   va_end(ap);
   return true;
}

unsigned int rjson_get_context_depth(rjson_t *json)
{
   return (unsigned int)(json->stack_top - json->stack);
}

size_t rjson_get_context_count(rjson_t *json)
{
   return json->stack_top->count;
}

enum rjson_type rjson_get_context_type(rjson_t *json)
{
   return json->stack_top->type;
}

void rjson_free(rjson_t *json)
{
   if (json->stack != json->inline_stack)
      free(json->stack);
   if (json->string != json->inline_string)
      free(json->string);
   free(json);
}

static bool _rjson_nop_default(void *context) { return true; }
static bool _rjson_nop_string(void *context, const char *value, size_t len) { return true; }
static bool _rjson_nop_bool(void *context, bool value) { return true; }

enum rjson_type rjson_parse(rjson_t *json, void* context,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context))
{
   bool in_object = false;
   size_t _len;
   const char* string;
   if (!object_member_handler) object_member_handler = _rjson_nop_string;
   if (!string_handler       ) string_handler        = _rjson_nop_string;
   if (!number_handler       ) number_handler        = _rjson_nop_string;
   if (!start_object_handler ) start_object_handler  = _rjson_nop_default;
   if (!end_object_handler   ) end_object_handler    = _rjson_nop_default;
   if (!start_array_handler  ) start_array_handler   = _rjson_nop_default;
   if (!end_array_handler    ) end_array_handler     = _rjson_nop_default;
   if (!boolean_handler      ) boolean_handler       = _rjson_nop_bool;
   if (!null_handler         ) null_handler          = _rjson_nop_default;
   for (;;)
   {
      switch (rjson_next(json))
      {
         case RJSON_STRING:
            string = rjson_get_string(json, &_len);
            if (_rJSON_LIKELY(
                  (in_object && (json->stack_top->count & 1) ?
                     object_member_handler : string_handler)
                     (context, string, _len)))
               continue;
            return RJSON_STRING;
         case RJSON_NUMBER:
            string = rjson_get_string(json, &_len);
            if (_rJSON_LIKELY(number_handler(context, string, _len)))
               continue;
            return RJSON_NUMBER;
         case RJSON_OBJECT:
            in_object = true;
            if (_rJSON_LIKELY(start_object_handler(context)))
               continue;
            return RJSON_OBJECT;
         case RJSON_ARRAY:
            in_object = false;
            if (_rJSON_LIKELY(start_array_handler(context)))
               continue;
            return RJSON_ARRAY;
         case RJSON_OBJECT_END:
            if (_rJSON_LIKELY(end_object_handler(context)))
            {
               in_object = (json->stack_top->type == RJSON_OBJECT);
               continue;
            }
            return RJSON_OBJECT_END;
         case RJSON_ARRAY_END:
            if (_rJSON_LIKELY(end_array_handler(context)))
            {
               in_object = (json->stack_top->type == RJSON_OBJECT);
               continue;
            }
            return RJSON_ARRAY_END;
         case RJSON_TRUE:
            if (_rJSON_LIKELY(boolean_handler(context, true)))
               continue;
            return RJSON_TRUE;
         case RJSON_FALSE:
            if (_rJSON_LIKELY(boolean_handler(context, false)))
               continue;
            return RJSON_FALSE;
         case RJSON_NULL:
            if (_rJSON_LIKELY(null_handler(context)))
               continue;
            return RJSON_NULL;
         case RJSON_ERROR:
            return RJSON_ERROR;
         case RJSON_DONE:
            return RJSON_DONE;
      }
   }
}

bool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context),
      void (*error_handler        )(void *context, int line, int col, const char* error))
{
   const char *user_data[2];
   rjson_t json;
   user_data[0] = string;
   user_data[1] = string + len;
   _rjson_setup(&json, _rjson_buffer_io, (void*)user_data, sizeof(json.input_buf));
   rjson_set_options(&json, option_flags);
   if (rjson_parse(&json, context,
         object_member_handler, string_handler, number_handler,
         start_object_handler, end_object_handler,
         start_array_handler, end_array_handler,
         boolean_handler, null_handler) == RJSON_DONE)
      return true;
   if (error_handler)
      error_handler(context,
            (int)rjson_get_source_line(&json),
            (int)rjson_get_source_column(&json),
            rjson_get_error(&json));
   return false;
}

struct rjsonwriter
{
   char* buf;
   int buf_num, buf_cap;

   rjsonwriter_io_t io;
   void *user_data;

   const char* error_text;
   char option_flags, decimal_sep;
   bool buf_is_output, final_flush;

   char inline_buf[1024];
};

rjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data)
{
   rjsonwriter_t* writer = (rjsonwriter_t*)malloc(sizeof(rjsonwriter_t));
   if (!writer)
      return NULL;

   writer->buf           = writer->inline_buf;
   writer->buf_num       = 0;
   writer->buf_cap       = sizeof(writer->inline_buf);

   writer->error_text    = NULL;
   writer->option_flags  = writer->decimal_sep = 0;
   writer->buf_is_output = writer->final_flush = false;

   writer->io            = io;
   writer->user_data     = user_data;

   return writer;
}

static int _rjsonwriter_stream_io(const void* buf, int len, void *user)
{
   return (int)intfstream_write((intfstream_t*)user, buf, (uint64_t)len);
}

rjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream)
{
   return rjsonwriter_open_user(_rjsonwriter_stream_io, stream);
}

static int _rjsonwriter_rfile_io(const void* buf, int len, void *user)
{
   return (int)filestream_write((RFILE*)user, buf, (int64_t)len);
}

rjsonwriter_t *rjsonwriter_open_rfile(RFILE *rfile)
{
   return rjsonwriter_open_user(_rjsonwriter_rfile_io, rfile);
}

static int _rjsonwriter_memory_io(const void* buf, int len, void *user)
{
   rjsonwriter_t *writer = (rjsonwriter_t *)user;
   bool is_append        = (buf != writer->buf);
   int new_cap           = writer->buf_num + (is_append ? len : 0) + 512;
   if (!writer->final_flush && (is_append || new_cap > writer->buf_cap))
   {
      bool can_realloc   = (writer->buf != writer->inline_buf);
      char* new_buf      = (char*)(can_realloc ? realloc(writer->buf, new_cap) : malloc(new_cap));
      if (!new_buf)
         return 0;
      if (!can_realloc)
         memcpy(new_buf, writer->buf, writer->buf_num);
      if (is_append)
      {
         memcpy(new_buf + writer->buf_num, buf, len);
         writer->buf_num += len;
      }
      writer->buf        = new_buf;
      writer->buf_cap    = new_cap;
   }
   return len;
}

rjsonwriter_t *rjsonwriter_open_memory(void)
{
   rjsonwriter_t *writer = rjsonwriter_open_user(_rjsonwriter_memory_io, NULL);
   if (!writer)
      return NULL;
   writer->user_data     = writer;
   writer->buf_is_output = true;
   return writer;
}

char* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len)
{
   if (writer->io != _rjsonwriter_memory_io || writer->error_text)
      return NULL;
   if (writer->buf_num == writer->buf_cap)
      rjsonwriter_flush(writer);
   writer->buf[writer->buf_num] = '\0';
   if (len)
      *len = writer->buf_num;
   return writer->buf;
}

int rjsonwriter_count_memory_buffer(rjsonwriter_t *writer)
{
   return writer->buf_num;
}

void rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len)
{
   if (keep_len <= writer->buf_num)
      writer->buf_num = (keep_len < 0 ? 0 : keep_len);
}

bool rjsonwriter_free(rjsonwriter_t *writer)
{
   bool res;
   writer->final_flush = true;
   res = rjsonwriter_flush(writer);
   if (writer->buf != writer->inline_buf)
      free(writer->buf);
   free(writer);
   return res;
}

void rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags)
{
   writer->option_flags = rjsonwriter_option_flags;
}

bool rjsonwriter_flush(rjsonwriter_t *writer)
{
   if (writer->buf_num && !writer->error_text && writer->io(writer->buf,
            writer->buf_num, writer->user_data) != writer->buf_num)
      writer->error_text = "output error";
   if (!writer->buf_is_output || writer->error_text)
      writer->buf_num = 0;
   return !writer->error_text;
}

const char *rjsonwriter_get_error(rjsonwriter_t *writer)
{
   return (writer->error_text ? writer->error_text : "");
}

void rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len)
{
   if (writer->buf_num + len > writer->buf_cap)
      rjsonwriter_flush(writer);
   if (len == 1)
   {
      if (buf[0] > ' ' ||
            !(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))
         writer->buf[writer->buf_num++] = buf[0];
   }
   else
   {
      int add = writer->buf_cap - writer->buf_num;
      if (add > len)
         add = len;
      memcpy(writer->buf + writer->buf_num, buf, add);
      writer->buf_num += add;
      if (len == add)
         return;
      rjsonwriter_flush(writer);
      len -= add;
      buf += add;
      if (writer->buf_num + len <= writer->buf_cap)
      {
         memcpy(writer->buf + writer->buf_num, buf, len);
         writer->buf_num += len;
      }
      else if (writer->io(buf, len, writer->user_data) != len)
         writer->error_text = "output error";
   }
}

void rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...)
{
   int available, need;
   va_list ap, ap2;
   if (writer->buf_num >= writer->buf_cap - 16)
      rjsonwriter_flush(writer);
   available = (writer->buf_cap - writer->buf_num);
   va_start(ap, fmt);
   need = vsnprintf(writer->buf + writer->buf_num, available, fmt, ap);
   va_end(ap);
   if (need <= 0)
      return;
   if (need < available)
   {
      writer->buf_num += need;
      return;
   }
   rjsonwriter_flush(writer);
   if (writer->buf_num + need >= writer->buf_cap)
   {
      int newcap   = writer->buf_num + need + 1;
      char* newbuf = (char*)malloc(newcap);
      if (!newbuf)
      {
         if (!writer->error_text)
            writer->error_text = "out of memory";
         return;
      }
      if (writer->buf_num)
         memcpy(newbuf, writer->buf, writer->buf_num);
      if (writer->buf != writer->inline_buf)
         free(writer->buf);
      writer->buf = newbuf;
      writer->buf_cap = newcap;
   }
   va_start(ap2, fmt);
   vsnprintf(writer->buf + writer->buf_num, writer->buf_cap - writer->buf_num, fmt, ap2);
   va_end(ap2);
   writer->buf_num += need;
}

void _rjsonwriter_add_escaped(rjsonwriter_t *writer, unsigned char c)
{
   char esc_buf[8], esc_len = 2;
   const char* esc;
   switch (c)
   {
      case '\b':
         esc = "\\b";
         break;
      case '\t':
         esc = "\\t";
         break;
      case '\n':
         esc = "\\n";
         break;
      case '\f':
         esc = "\\f";
         break;
      case '\r':
         esc = "\\r";
         break;
      case '\"':
         esc = "\\\"";
         break;
      case '\\':
         esc = "\\\\";
         break;
      case '/':
         esc = "\\/";
         break;
      default:
         snprintf(esc_buf, sizeof(esc_buf), "\\u%04x", c);
         esc     = esc_buf;
         esc_len = 6;
   }
   rjsonwriter_raw(writer, esc, esc_len);
}

void rjsonwriter_add_string(rjsonwriter_t *writer, const char *value)
{
   const char *p = (const char*)value, *raw = p;
   unsigned char c;
   rjsonwriter_raw(writer, "\"", 1);
   if (!p)
      goto string_end;
   while ((c = (unsigned char)*p++) != '\0')
   {
      /* forward slash is special, it should be escaped if the previous character
       * was a < (intended to avoid having </script> html tags in JSON files) */
      if (   c >= 0x20 && c != '\"' && c != '\\' &&
            (c != '/' || p < value + 2 || p[-2] != '<'))
         continue;
      if (raw != p - 1)
         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
      _rjsonwriter_add_escaped(writer, c);
      raw = p;
   }
   if (raw != p - 1)
      rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
string_end:
   rjsonwriter_raw(writer, "\"", 1);
}

void rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len)
{
   const char *p = (const char*)value, *raw = p, *end = p + len;
   rjsonwriter_raw(writer, "\"", 1);
   while (p != end)
   {
      unsigned char c = (unsigned char)*p++;
      if (      c >= 0x20 && c != '\"' && c != '\\'
            && (c != '/' || p < value + 2 || p[-2] != '<'))
         continue;
      if (raw != p - 1)
         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
      _rjsonwriter_add_escaped(writer, c);
      raw = p;
   }
   if (raw != end)
      rjsonwriter_raw(writer, raw, (int)(end - raw));
   rjsonwriter_raw(writer, "\"", 1);
}

void rjsonwriter_add_double(rjsonwriter_t *writer, double value)
{
   int old_buf_num = writer->buf_num;
   rjsonwriter_rawf(writer, "%G", value);
   if (writer->decimal_sep != '.')
   {
      /* handle locale that uses a non-standard decimal separator */
      char *p, *str;
      if (writer->decimal_sep == 0)
      {
         char test[4];
         snprintf(test, sizeof(test), "%.1f", 0.0f);
         if ((writer->decimal_sep = test[1]) == '.')
            return;
      }
      str = writer->buf + (old_buf_num > writer->buf_num ? 0 : old_buf_num);
      if ((p = strchr(str, writer->decimal_sep)) != NULL)
         *p = '.';
   }
}

void rjsonwriter_add_spaces(rjsonwriter_t *writer, int count)
{
   if (!(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))
      for (; count > 0; count -= 8)
         rjsonwriter_raw(writer, "        ", (count > 8 ? 8 : count));
}

void rjsonwriter_add_tabs(rjsonwriter_t *writer, int count)
{
   if (!(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))
      for (; count > 0; count -= 8)
         rjsonwriter_raw(writer, "\t\t\t\t\t\t\t\t", (count > 8 ? 8 : count));
}

#undef _rJSON_EOF
#undef _rJSON_LIKELY

./include/libretro-common/formats/libchdr/libchdr_bitstream.c

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    bitstream.c

    Helper classes for reading/writing at the bit level.

***************************************************************************/

#include <stdlib.h>
#include <libchdr/bitstream.h>

/***************************************************************************
 *  INLINE FUNCTIONS
 ***************************************************************************
 */

int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); }

/*-------------------------------------------------
 *  create_bitstream - constructor
 *-------------------------------------------------
 */

struct bitstream* create_bitstream(const void *src, uint32_t srclength)
{
	struct bitstream* bitstream = (struct bitstream*)malloc(sizeof(struct bitstream));
	bitstream->buffer = 0;
	bitstream->bits = 0;
	bitstream->read = (const uint8_t*)src;
	bitstream->doffset = 0;
	bitstream->dlength = srclength;
	return bitstream;
}


/*-----------------------------------------------------
 *  bitstream_peek - fetch the requested number of bits
 *  but don't advance the input pointer
 *-----------------------------------------------------
 */

uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
{
	if (numbits == 0)
		return 0;

	/* fetch data if we need more */
	if (numbits > bitstream->bits)
	{
		while (bitstream->bits <= 24)
		{
			if (bitstream->doffset < bitstream->dlength)
				bitstream->buffer |= bitstream->read[bitstream->doffset] << (24 - bitstream->bits);
			bitstream->doffset++;
			bitstream->bits += 8;
		}
	}

	/* return the data */
	return bitstream->buffer >> (32 - numbits);
}


/*-----------------------------------------------------
 *  bitstream_remove - advance the input pointer by the
 *  specified number of bits
 *-----------------------------------------------------
 */

void bitstream_remove(struct bitstream* bitstream, int numbits)
{
	bitstream->buffer <<= numbits;
	bitstream->bits -= numbits;
}


/*-----------------------------------------------------
 *  bitstream_read - fetch the requested number of bits
 *-----------------------------------------------------
 */

uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
{
	uint32_t result = bitstream_peek(bitstream, numbits);
	bitstream_remove(bitstream, numbits);
	return result;
}


/*-------------------------------------------------
 *  read_offset - return the current read offset
 *-------------------------------------------------
 */

uint32_t bitstream_read_offset(struct bitstream* bitstream)
{
	uint32_t result = bitstream->doffset;
	int bits = bitstream->bits;
	while (bits >= 8)
	{
		result--;
		bits -= 8;
	}
	return result;
}


/*-------------------------------------------------
 *  flush - flush to the nearest byte
 *-------------------------------------------------
 */

uint32_t bitstream_flush(struct bitstream* bitstream)
{
	while (bitstream->bits >= 8)
	{
		bitstream->doffset--;
		bitstream->bits -= 8;
	}
	bitstream->bits = bitstream->buffer = 0;
	return bitstream->doffset;
}

./include/libretro-common/formats/libchdr/libchdr_cdrom.c

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    cdrom.c

    Generic MAME CD-ROM utilities - build IDE and SCSI CD-ROMs on top of this

****************************************************************************

    IMPORTANT:
    "physical" block addresses are the actual addresses on the emulated CD.
    "chd" block addresses are the block addresses in the CHD file.
    Because we pad each track to a 4-frame boundary, these addressing
    schemes will differ after track 1!

***************************************************************************/

#include <string.h>

#include <libchdr/cdrom.h>

#ifdef WANT_RAW_DATA_SECTOR

/***************************************************************************
    DEBUGGING
***************************************************************************/

/** @brief  The verbose. */
#define VERBOSE (0)
#if VERBOSE

/**
 * @def LOG(x) do
 *
 * @brief   A macro that defines log.
 *
 * @param   x   The void to process.
 */

#define LOG(x) do { if (VERBOSE) logerror x; } while (0)

/**
 * @fn  void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
 *
 * @brief   Logerrors the given text.
 *
 * @param   text    The text.
 *
 * @return  A CLIB_DECL.
 */

void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
#else

/**
 * @def LOG(x);
 *
 * @brief   A macro that defines log.
 *
 * @param   x   The void to process.
 */

#define LOG(x)
#endif

/***************************************************************************
    CONSTANTS
***************************************************************************/

/** @brief  offset within sector. */
#define SYNC_OFFSET 0x000
/** @brief  12 bytes. */
#define SYNC_NUM_BYTES 12

/** @brief  offset within sector. */
#define MODE_OFFSET 0x00f

/** @brief  offset within sector. */
#define ECC_P_OFFSET 0x81c
/** @brief  2 lots of 86. */
#define ECC_P_NUM_BYTES 86
/** @brief  24 bytes each. */
#define ECC_P_COMP 24

/** @brief  The ECC q offset. */
#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES)
/** @brief  2 lots of 52. */
#define ECC_Q_NUM_BYTES 52
/** @brief  43 bytes each. */
#define ECC_Q_COMP 43

/**
 * @brief   -------------------------------------------------
 *            ECC lookup tables pre-calculated tables for ECC data calcs
 *          -------------------------------------------------.
 */

static const uint8_t ecclow[256] =
{
	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
	0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
	0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
	0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
	0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
	0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
	0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
	0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
	0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03,
	0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23,
	0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43,
	0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63,
	0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83,
	0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3,
	0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3,
	0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3
};

/** @brief  The ecchigh[ 256]. */
static const uint8_t ecchigh[256] =
{
	0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05,
	0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe,
	0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee,
	0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15,
	0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce,
	0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35,
	0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25,
	0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde,
	0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e,
	0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75,
	0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65,
	0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e,
	0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45,
	0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe,
	0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae,
	0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55
};

/**
 * @brief   -------------------------------------------------
 *            poffsets - each row represents the addresses used to calculate a byte of the ECC P
 *            data 86 (*2) ECC P bytes, 24 values represented by each
 *          -------------------------------------------------.
 */

static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] =
{
	{ 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba },
	{ 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb },
	{ 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc },
	{ 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd },
	{ 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be },
	{ 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf },
	{ 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 },
	{ 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 },
	{ 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 },
	{ 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 },
	{ 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 },
	{ 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 },
	{ 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 },
	{ 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 },
	{ 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 },
	{ 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 },
	{ 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca },
	{ 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb },
	{ 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc },
	{ 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd },
	{ 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce },
	{ 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf },
	{ 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 },
	{ 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 },
	{ 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 },
	{ 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 },
	{ 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 },
	{ 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 },
	{ 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 },
	{ 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 },
	{ 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 },
	{ 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 },
	{ 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da },
	{ 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db },
	{ 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc },
	{ 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd },
	{ 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de },
	{ 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df },
	{ 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 },
	{ 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 },
	{ 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 },
	{ 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 },
	{ 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 },
	{ 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 },
	{ 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 },
	{ 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 },
	{ 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 },
	{ 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 },
	{ 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea },
	{ 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb },
	{ 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec },
	{ 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed },
	{ 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee },
	{ 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef },
	{ 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 },
	{ 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 },
	{ 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 },
	{ 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 },
	{ 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 },
	{ 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 },
	{ 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 },
	{ 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 },
	{ 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 },
	{ 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 },
	{ 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa },
	{ 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb },
	{ 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc },
	{ 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd },
	{ 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe },
	{ 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff },
	{ 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 },
	{ 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 },
	{ 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 },
	{ 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 },
	{ 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 },
	{ 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 },
	{ 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 },
	{ 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 },
	{ 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 },
	{ 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 },
	{ 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a },
	{ 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b },
	{ 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c },
	{ 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d },
	{ 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e },
	{ 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f }
};

/**
 * @brief   -------------------------------------------------
 *            qoffsets - each row represents the addresses used to calculate a byte of the ECC Q
 *            data 52 (*2) ECC Q bytes, 43 values represented by each
 *          -------------------------------------------------.
 */

static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =
{
	{ 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 },
	{ 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 },
	{ 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a },
	{ 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b },
	{ 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 },
	{ 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 },
	{ 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 },
	{ 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 },
	{ 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c },
	{ 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d },
	{ 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 },
	{ 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 },
	{ 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 },
	{ 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 },
	{ 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e },
	{ 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f },
	{ 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 },
	{ 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 },
	{ 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba },
	{ 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb },
	{ 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 },
	{ 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 },
	{ 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa },
	{ 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab },
	{ 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 },
	{ 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 },
	{ 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 },
	{ 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 },
	{ 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac },
	{ 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad },
	{ 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 },
	{ 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 },
	{ 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 },
	{ 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 },
	{ 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae },
	{ 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af },
	{ 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 },
	{ 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 },
	{ 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a },
	{ 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b },
	{ 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 },
	{ 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 },
	{ 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 },
	{ 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 },
	{ 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c },
	{ 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d },
	{ 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 },
	{ 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 },
	{ 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 },
	{ 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 },
	{ 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e },
	{ 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f }
};

/*-------------------------------------------------
 *  ecc_source_byte - return data from the sector
 *  at the given offset, masking anything
 *  particular to a mode
 *-------------------------------------------------
 */

static INLINE uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
{
	/* in mode 2 always treat these as 0 bytes */
	return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];
}

/**
 * @fn  void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2)
 *
 * @brief   -------------------------------------------------
 *            ecc_compute_bytes - calculate an ECC value (P or Q)
 *          -------------------------------------------------.
 *
 * @param   sector          The sector.
 * @param   row             The row.
 * @param   rowlen          The rowlen.
 * @param [in,out]  val1    The first value.
 * @param [in,out]  val2    The second value.
 */

void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)
{
	int component;
	*val1 = *val2 = 0;
	for (component = 0; component < rowlen; component++)
	{
		*val1 ^= ecc_source_byte(sector, row[component]);
		*val2 ^= ecc_source_byte(sector, row[component]);
		*val1 = ecclow[*val1];
	}
	*val1 = ecchigh[ecclow[*val1] ^ *val2];
	*val2 ^= *val1;
}

/**
 * @fn  int ecc_verify(const uint8_t *sector)
 *
 * @brief   -------------------------------------------------
 *            ecc_verify - verify the P and Q ECC codes in a sector
 *          -------------------------------------------------.
 *
 * @param   sector  The sector.
 *
 * @return  true if it succeeds, false if it fails.
 */

int ecc_verify(const uint8_t *sector)
{
	int byte;
	/* first verify P bytes */
	for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
	{
		uint8_t val1, val2;
		ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2);
		if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2)
			return 0;
	}

	/* then verify Q bytes */
	for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
	{
		uint8_t val1, val2;
		ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2);
		if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2)
			return 0;
	}
	return 1;
}

/**
 * @fn  void ecc_generate(uint8_t *sector)
 *
 * @brief   -------------------------------------------------
 *            ecc_generate - generate the P and Q ECC codes for a sector, overwriting any
 *            existing codes
 *          -------------------------------------------------.
 *
 * @param [in,out]  sector  If non-null, the sector.
 */

void ecc_generate(uint8_t *sector)
{
	int byte;
	/* first verify P bytes */
	for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
		ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);

	/* then verify Q bytes */
	for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
		ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);
}

/**
 * @fn  void ecc_clear(uint8_t *sector)
 *
 * @brief   -------------------------------------------------
 *            ecc_clear - erase the ECC P and Q cods to 0 within a sector
 *          -------------------------------------------------.
 *
 * @param [in,out]  sector  If non-null, the sector.
 */

void ecc_clear(uint8_t *sector)
{
	memset(&sector[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES);
	memset(&sector[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES);
}

#endif /* WANT_RAW_DATA_SECTOR */

./include/libretro-common/formats/libchdr/libchdr_chd.c

/***************************************************************************

    chd.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <libchdr/chd.h>
#include <libchdr/cdrom.h>
#include <libchdr/huffman.h>
#include <libchdr/minmax.h>

#ifdef HAVE_FLAC
#include <libchdr/flac.h>
#endif

#ifdef HAVE_ZLIB
#include <libchdr/libchdr_zlib.h>
#endif

#ifdef HAVE_7ZIP
#include <libchdr/lzma.h>
#endif

#ifdef HAVE_ZSTD
#include <libchdr/libchdr_zstd.h>
#endif

#if defined(__PS3__) || defined(__PSL1GHT__)
#define __MACTYPES__
#endif

#define TRUE 1
#define FALSE 0
#define SHA1_DIGEST_SIZE 20

/***************************************************************************
    DEBUGGING
***************************************************************************/

#define PRINTF_MAX_HUNK				(0)

/***************************************************************************
    CONSTANTS
***************************************************************************/

#define MAP_STACK_ENTRIES			512			/* max number of entries to use on the stack */
#define MAP_ENTRY_SIZE				16			/* V3 and later */
#define OLD_MAP_ENTRY_SIZE			8			/* V1-V2 */
#define METADATA_HEADER_SIZE		16			/* metadata header size */

#define MAP_ENTRY_FLAG_TYPE_MASK	0x0f		/* what type of hunk */
#define MAP_ENTRY_FLAG_NO_CRC		0x10		/* no CRC is present */

#define CHD_V1_SECTOR_SIZE			512			/* size of a "sector" in the V1 header */

#define COOKIE_VALUE				0xbaadf00d
#define MAX_ZLIB_ALLOCS				64

#define END_OF_LIST_COOKIE			"EndOfListCookie"

#define NO_MATCH					(~0)

/* V3-V4 entry types */
enum
{
	V34_MAP_ENTRY_TYPE_INVALID = 0,             /* invalid type */
	V34_MAP_ENTRY_TYPE_COMPRESSED = 1,          /* standard compression */
	V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,        /* uncompressed data */
	V34_MAP_ENTRY_TYPE_MINI = 3,                /* mini: use offset as raw data */
	V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,           /* same as another hunk in this file */
	V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         /* same as a hunk in the parent file */
	V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6       /* compressed with secondary algorithm (usually FLAC CDDA) */
};

/* V5 compression types */
enum
{
	/* codec #0
	 * these types are live when running */
	COMPRESSION_TYPE_0 = 0,
	/* codec #1 */
	COMPRESSION_TYPE_1 = 1,
	/* codec #2 */
	COMPRESSION_TYPE_2 = 2,
	/* codec #3 */
	COMPRESSION_TYPE_3 = 3,
	/* no compression; implicit length = hunkbytes */
	COMPRESSION_NONE = 4,
	/* same as another block in this chd */
	COMPRESSION_SELF = 5,
	/* same as a hunk's worth of units in the parent chd */
	COMPRESSION_PARENT = 6,

	/* start of small RLE run (4-bit length)
	 * these additional pseudo-types are used for compressed encodings: */
	COMPRESSION_RLE_SMALL,
	/* start of large RLE run (8-bit length) */
	COMPRESSION_RLE_LARGE,
	/* same as the last COMPRESSION_SELF block */
	COMPRESSION_SELF_0,
	/* same as the last COMPRESSION_SELF block + 1 */
	COMPRESSION_SELF_1,
	/* same block in the parent */
	COMPRESSION_PARENT_SELF,
	/* same as the last COMPRESSION_PARENT block */
	COMPRESSION_PARENT_0,
	/* same as the last COMPRESSION_PARENT block + 1 */
	COMPRESSION_PARENT_1
};

/***************************************************************************
    MACROS
***************************************************************************/

#define EARLY_EXIT(x)				do { (void)(x); goto cleanup; } while (0)

/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

/* interface to a codec */
typedef struct _codec_interface codec_interface;
struct _codec_interface
{
	uint32_t		compression;								/* type of compression */
	const char *compname;									/* name of the algorithm */
	uint8_t		lossy;										/* is this a lossy algorithm? */
	chd_error	(*init)(void *codec, uint32_t hunkbytes);		/* codec initialize */
	void		(*free)(void *codec);						/* codec free */
	chd_error	(*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */
	chd_error	(*config)(void *codec, int param, void *config); /* configure */
};

/* a single map entry */
typedef struct _map_entry map_entry;
struct _map_entry
{
	uint64_t					offset;			/* offset within the file of the data */
	uint32_t					crc;			/* 32-bit CRC of the data */
	uint32_t					length;			/* length of the data */
	uint8_t					flags;			/* misc flags */
};

/* a single metadata entry */
typedef struct _metadata_entry metadata_entry;
struct _metadata_entry
{
	uint64_t					offset;			/* offset within the file of the header */
	uint64_t					next;			/* offset within the file of the next header */
	uint64_t					prev;			/* offset within the file of the previous header */
	uint32_t					length;			/* length of the metadata */
	uint32_t					metatag;		/* metadata tag */
	uint8_t					flags;			/* flag bits */
};


typedef struct _huff_codec_data huff_codec_data;
struct _huff_codec_data
{
	struct huffman_decoder* decoder;
};


/* internal representation of an open CHD file */
struct _chd_file
{
	uint32_t					cookie;			/* cookie, should equal COOKIE_VALUE */

	core_file *				file;			/* handle to the open core file */
	chd_header				header;			/* header, extracted from file */

	chd_file *				parent;			/* pointer to parent file, or NULL */

	map_entry *				map;			/* array of map entries */

#ifdef NEED_CACHE_HUNK
	uint8_t *					cache;			/* hunk cache pointer */
	uint32_t					cachehunk;		/* index of currently cached hunk */

	uint8_t *					compare;		/* hunk compare pointer */
	uint32_t					comparehunk;	/* index of current compare data */
#endif

	uint8_t *					compressed;		/* pointer to buffer for compressed data */
	const codec_interface *	codecintf[4];	/* interface to the codec */

	huff_codec_data			huff_codec_data;		/* huff codec data */
#ifdef HAVE_ZLIB
	zlib_codec_data			zlib_codec_data;		/* zlib codec data */
	cdzl_codec_data			cdzl_codec_data;		/* cdzl codec data */
#endif
#ifdef HAVE_7ZIP
	lzma_codec_data			lzma_codec_data;		/* lzma codec data */
	cdlz_codec_data			cdlz_codec_data;		/* cdlz codec data */
#endif
#ifdef HAVE_FLAC
	flac_codec_data			flac_codec_data;		/* flac codec data */
	cdfl_codec_data			cdfl_codec_data;		/* cdfl codec data */
#endif
#ifdef HAVE_ZSTD
	zstd_codec_data			zstd_codec_data;		/* zstd codec data */
	cdzs_codec_data			cdzs_codec_data;		/* cdzs codec data */
#endif

#ifdef NEED_CACHE_HUNK
	uint32_t					maxhunk;		/* maximum hunk accessed */
#endif

	uint8_t *					file_cache;		/* cache of underlying file */
};


/***************************************************************************
    GLOBAL VARIABLES
***************************************************************************/

static const uint8_t nullmd5[CHD_MD5_BYTES] = { 0 };
static const uint8_t nullsha1[CHD_SHA1_BYTES] = { 0 };

/***************************************************************************
    PROTOTYPES
***************************************************************************/

/* core_file wrappers over stdio */
static core_file *core_stdio_fopen(char const *path);
static uint64_t core_stdio_fsize(core_file *file);
static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file);
static int core_stdio_fclose(core_file *file);
static int core_stdio_fclose_nonowner(core_file *file); /* alternate fclose used by chd_open_file */
static int core_stdio_fseek(core_file* file, int64_t offset, int whence);

/* internal header operations */
static chd_error header_validate(const chd_header *header);
static chd_error header_read(chd_file *chd, chd_header *header);

/* internal hunk read/write */
#ifdef NEED_CACHE_HUNK
static chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum);
#endif
static chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest);

/* internal map access */
static chd_error map_read(chd_file *chd);

/* metadata management */
static chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry);

/* zlib compression codec */
chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
void zlib_codec_free(void *codec);
chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
void zlib_fast_free(voidpf opaque, voidpf address);
void zlib_allocator_free(voidpf opaque);

/* lzma compression codec */
chd_error lzma_codec_init(void *codec, uint32_t hunkbytes);
void lzma_codec_free(void *codec);
chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* huff compression codec */
static chd_error huff_codec_init(void *codec, uint32_t hunkbytes);
static void huff_codec_free(void *codec);
static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* flac compression codec */
chd_error flac_codec_init(void *codec, uint32_t hunkbytes);
void flac_codec_free(void *codec);
chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* zstd compression codec */
chd_error zstd_codec_init(void *codec, uint32_t hunkbytes);
void zstd_codec_free(void *codec);
chd_error zstd_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdzl compression codec */
chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);
void cdzl_codec_free(void* codec);
chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdlz compression codec */
chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);
void cdlz_codec_free(void* codec);
chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdfl compression codec */
chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
void cdfl_codec_free(void* codec);
chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdzs compression codec */
chd_error cdzs_codec_init(void *codec, uint32_t hunkbytes);
void cdzs_codec_free(void *codec);
chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);


/***************************************************************************
 *  HUFFMAN DECOMPRESSOR
 ***************************************************************************
 */

static chd_error huff_codec_init(void* codec, uint32_t hunkbytes)
{
	huff_codec_data* huff_codec = (huff_codec_data*) codec;
	huff_codec->decoder = create_huffman_decoder(256, 16);
	return CHDERR_NONE;
}

static void huff_codec_free(void *codec)
{
	huff_codec_data* huff_codec = (huff_codec_data*) codec;
	delete_huffman_decoder(huff_codec->decoder);
}

static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t cur;
	chd_error result;
	huff_codec_data* huff_codec = (huff_codec_data*) codec;
	struct bitstream* bitbuf = create_bitstream(src, complen);

	/* first import the tree */
	enum huffman_error err = huffman_import_tree_huffman(huff_codec->decoder, bitbuf);
	if (err != HUFFERR_NONE)
	{
		free(bitbuf);
		return CHDERR_DECOMPRESSION_ERROR;
	}

	/* then decode the data */
	for (cur = 0; cur < destlen; cur++)
		dest[cur] = huffman_decode_one(huff_codec->decoder, bitbuf);
	bitstream_flush(bitbuf);
	result = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE;

	free(bitbuf);
	return result;
}
 

/***************************************************************************
    CODEC INTERFACES
***************************************************************************/

static const codec_interface codec_interfaces[] =
{
	/* "none" or no compression */
	{
		CHDCOMPRESSION_NONE,
		"none",
		FALSE,
		NULL,
		NULL,
		NULL,
		NULL
	},

#ifdef HAVE_ZLIB
	/* standard zlib compression */
	{
		CHDCOMPRESSION_ZLIB,
		"zlib",
		FALSE,
		zlib_codec_init,
		zlib_codec_free,
		zlib_codec_decompress,
		NULL
	},

	/* zlib+ compression */
	{
		CHDCOMPRESSION_ZLIB_PLUS,
		"zlib+",
		FALSE,
		zlib_codec_init,
		zlib_codec_free,
		zlib_codec_decompress,
		NULL
	},

	/* V5 zlib compression */
	{
		CHD_CODEC_ZLIB,
		"zlib (Deflate)",
		FALSE,
		zlib_codec_init,
		zlib_codec_free,
		zlib_codec_decompress,
		NULL
	},
	/* V5 CD zlib compression */
	{
		CHD_CODEC_CD_ZLIB,
		"cdzl (CD Deflate)",
		FALSE,
		cdzl_codec_init,
		cdzl_codec_free,
		cdzl_codec_decompress,
		NULL
	},
#endif
#ifdef HAVE_7ZIP
	/* V5 lzma compression */
	{
		CHD_CODEC_LZMA,
		"lzma (LZMA)",
		FALSE,
		lzma_codec_init,
		lzma_codec_free,
		lzma_codec_decompress,
		NULL
	},
	/* V5 CD lzma compression */
	{
		CHD_CODEC_CD_LZMA,
		"cdlz (CD LZMA)",
		FALSE,
		cdlz_codec_init,
		cdlz_codec_free,
		cdlz_codec_decompress,
		NULL
	},
#endif
	/* V5 huffman compression */
	{
		CHD_CODEC_HUFFMAN,
		"Huffman",
		FALSE,
		huff_codec_init,
		huff_codec_free,
		huff_codec_decompress,
		NULL
	},
#ifdef HAVE_FLAC
	/* V5 flac compression */
	{
		CHD_CODEC_FLAC,
		"flac (FLAC)",
		FALSE,
		flac_codec_init,
		flac_codec_free,
		flac_codec_decompress,
		NULL
	},
	/* V5 CD flac compression */
	{
		CHD_CODEC_CD_FLAC,
		"cdfl (CD FLAC)",
		FALSE,
		cdfl_codec_init,
		cdfl_codec_free,
		cdfl_codec_decompress,
		NULL
	},
#endif
#ifdef HAVE_ZSTD
	/* V5 zstd compression */
	{
		CHD_CODEC_ZSTD,
		"zstd (Zstandard)",
		FALSE,
		zstd_codec_init,
		zstd_codec_free,
		zstd_codec_decompress,
		NULL
	},
	/* V5 CD zstd compression */
	{
		CHD_CODEC_CD_ZSTD,
		"cdzs (CD Zstandard)",
		FALSE,
		cdzs_codec_init,
		cdzs_codec_free,
		cdzs_codec_decompress,
		NULL
	}
#endif
	
};

/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

/*-------------------------------------------------
    get_bigendian_uint64_t - fetch a uint64_t from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint64_t get_bigendian_uint64_t(const uint8_t *base)
{
	return ((uint64_t)base[0] << 56) | ((uint64_t)base[1] << 48) | ((uint64_t)base[2] << 40) | ((uint64_t)base[3] << 32) |
			((uint64_t)base[4] << 24) | ((uint64_t)base[5] << 16) | ((uint64_t)base[6] << 8) | (uint64_t)base[7];
}

/*-------------------------------------------------
    put_bigendian_uint64_t - write a uint64_t to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint64_t(uint8_t *base, uint64_t value)
{
	base[0] = value >> 56;
	base[1] = value >> 48;
	base[2] = value >> 40;
	base[3] = value >> 32;
	base[4] = value >> 24;
	base[5] = value >> 16;
	base[6] = value >> 8;
	base[7] = value;
}

/*-------------------------------------------------
    get_bigendian_uint48 - fetch a UINT48 from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint64_t get_bigendian_uint48(const uint8_t *base)
{
	return  ((uint64_t)base[0] << 40) | ((uint64_t)base[1] << 32) |
			((uint64_t)base[2] << 24) | ((uint64_t)base[3] << 16) | ((uint64_t)base[4] << 8) | (uint64_t)base[5];
}

/*-------------------------------------------------
    put_bigendian_uint48 - write a UINT48 to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint48(uint8_t *base, uint64_t value)
{
	value &= 0xffffffffffff;
	base[0] = value >> 40;
	base[1] = value >> 32;
	base[2] = value >> 24;
	base[3] = value >> 16;
	base[4] = value >> 8;
	base[5] = value;
}
/*-------------------------------------------------
    get_bigendian_uint32_t - fetch a uint32_t from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint32_t get_bigendian_uint32_t(const uint8_t *base)
{
	return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
}

/*-------------------------------------------------
    put_bigendian_uint32_t - write a uint32_t to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint32_t(uint8_t *base, uint32_t value)
{
	base[0] = value >> 24;
	base[1] = value >> 16;
	base[2] = value >> 8;
	base[3] = value;
}

/*-------------------------------------------------
    put_bigendian_uint24 - write a UINT24 to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint24(uint8_t *base, uint32_t value)
{
	value &= 0xffffff;
	base[0] = value >> 16;
	base[1] = value >> 8;
	base[2] = value;
}

/*-------------------------------------------------
    get_bigendian_uint24 - fetch a UINT24 from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint32_t get_bigendian_uint24(const uint8_t *base)
{
	return (base[0] << 16) | (base[1] << 8) | base[2];
}

/*-------------------------------------------------
    get_bigendian_uint16 - fetch a uint16_t from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint16_t get_bigendian_uint16(const uint8_t *base)
{
	return (base[0] << 8) | base[1];
}

/*-------------------------------------------------
    put_bigendian_uint16 - write a uint16_t to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint16(uint8_t *base, uint16_t value)
{
	base[0] = value >> 8;
	base[1] = value;
}

/*-------------------------------------------------
    map_extract - extract a single map
    entry from the datastream
-------------------------------------------------*/

static INLINE void map_extract(const uint8_t *base, map_entry *entry)
{
	entry->offset = get_bigendian_uint64_t(&base[0]);
	entry->crc = get_bigendian_uint32_t(&base[8]);
	entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
	entry->flags = base[15];
}

/*-------------------------------------------------
    map_assemble - write a single map
    entry to the datastream
-------------------------------------------------*/

static INLINE void map_assemble(uint8_t *base, map_entry *entry)
{
	put_bigendian_uint64_t(&base[0], entry->offset);
	put_bigendian_uint32_t(&base[8], entry->crc);
	put_bigendian_uint16(&base[12], entry->length);
	base[14] = entry->length >> 16;
	base[15] = entry->flags;
}

/*-------------------------------------------------
    map_size_v5 - calculate CHDv5 map size
-------------------------------------------------*/
static INLINE int map_size_v5(chd_header* header)
{
	return header->hunkcount * header->mapentrybytes;
}

/*-------------------------------------------------
    crc16 - calculate CRC16 (from hashing.cpp)
-------------------------------------------------*/
uint16_t crc16(const void *data, uint32_t length)
{
	uint16_t crc = 0xffff;

	static const uint16_t s_table[256] =
	{
		0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
		0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
		0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
		0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
		0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
		0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
		0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
		0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
		0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
		0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
		0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
		0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
		0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
		0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
		0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
		0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
		0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
		0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
		0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
		0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
		0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
		0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
		0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
		0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
		0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
		0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
		0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
		0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
		0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
		0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
		0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
		0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
	};

	const uint8_t *src = (uint8_t*)data;

	/* fetch the current value into a local and rip through the source data */
	while (length-- != 0)
		crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
	return crc;
}

/*-------------------------------------------------
	compressed - test if CHD file is compressed
+-------------------------------------------------*/
static INLINE int chd_compressed(chd_header* header) {
	return header->compression[0] != CHD_CODEC_NONE;
}

/*-------------------------------------------------
	decompress_v5_map - decompress the v5 map
-------------------------------------------------*/

static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
{
	uint32_t hunknum;
	int repcount = 0;
	uint8_t lastcomp = 0;
	uint32_t last_self = 0;
	uint64_t last_parent = 0;
	struct bitstream* bitbuf;
	uint32_t mapbytes;
	uint64_t firstoffs;
	uint16_t mapcrc;
	uint8_t lengthbits;
	uint8_t selfbits;
	uint8_t parentbits;
	uint8_t *compressed_ptr;
	uint8_t rawbuf[16];
	struct huffman_decoder* decoder;
	enum huffman_error err;
	uint64_t curoffset;	
	int rawmapsize = map_size_v5(header);

	if (!chd_compressed(header))
	{
		header->rawmap = (uint8_t*)malloc(rawmapsize);
		if (header->rawmap == NULL)
			return CHDERR_OUT_OF_MEMORY;
		core_fseek(chd->file, header->mapoffset, SEEK_SET);
		core_fread(chd->file, header->rawmap, rawmapsize);
		return CHDERR_NONE;
	}

	/* read the reader */
	core_fseek(chd->file, header->mapoffset, SEEK_SET);
	core_fread(chd->file, rawbuf, sizeof(rawbuf));
	mapbytes = get_bigendian_uint32_t(&rawbuf[0]);
	firstoffs = get_bigendian_uint48(&rawbuf[4]);
	mapcrc = get_bigendian_uint16(&rawbuf[10]);
	lengthbits = rawbuf[12];
	selfbits = rawbuf[13];
	parentbits = rawbuf[14];

	/* now read the map */
	compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
	if (compressed_ptr == NULL)
		return CHDERR_OUT_OF_MEMORY;
	core_fseek(chd->file, header->mapoffset + 16, SEEK_SET);
	core_fread(chd->file, compressed_ptr, mapbytes);
	bitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes);
	header->rawmap = (uint8_t*)malloc(rawmapsize);
	if (header->rawmap == NULL)
	{
		free(compressed_ptr);
		free(bitbuf);
		return CHDERR_OUT_OF_MEMORY;
	}

	/* first decode the compression types */
	decoder = create_huffman_decoder(16, 8);
	if (decoder == NULL)
	{
		free(compressed_ptr);
		free(bitbuf);
		return CHDERR_OUT_OF_MEMORY;
	}

	err = huffman_import_tree_rle(decoder, bitbuf);
	if (err != HUFFERR_NONE)
	{
		free(compressed_ptr);
		free(bitbuf);
		delete_huffman_decoder(decoder);
		return CHDERR_DECOMPRESSION_ERROR;
	}

	for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
	{
		uint8_t *rawmap = header->rawmap + (hunknum * 12);
		if (repcount > 0)
			rawmap[0] = lastcomp, repcount--;
		else
		{
			uint8_t val = huffman_decode_one(decoder, bitbuf);
			if (val == COMPRESSION_RLE_SMALL)
				rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf);
			else if (val == COMPRESSION_RLE_LARGE)
				rawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4), repcount += huffman_decode_one(decoder, bitbuf);
			else
				rawmap[0] = lastcomp = val;
		}
	}

	/* then iterate through the hunks and extract the needed data */
	curoffset = firstoffs;
	for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
	{
		uint8_t *rawmap = header->rawmap + (hunknum * 12);
		uint64_t offset = curoffset;
		uint32_t length = 0;
		uint16_t crc = 0;
		switch (rawmap[0])
		{
			/* base types */
			case COMPRESSION_TYPE_0:
			case COMPRESSION_TYPE_1:
			case COMPRESSION_TYPE_2:
			case COMPRESSION_TYPE_3:
				curoffset += length = bitstream_read(bitbuf, lengthbits);
				crc = bitstream_read(bitbuf, 16);
				break;

			case COMPRESSION_NONE:
				curoffset += length = header->hunkbytes;
				crc = bitstream_read(bitbuf, 16);
				break;

			case COMPRESSION_SELF:
				last_self = offset = bitstream_read(bitbuf, selfbits);
				break;

			case COMPRESSION_PARENT:
				offset = bitstream_read(bitbuf, parentbits);
				last_parent = offset;
				break;

			/* pseudo-types; convert into base types */
			case COMPRESSION_SELF_1:
				last_self++;
			case COMPRESSION_SELF_0:
				rawmap[0] = COMPRESSION_SELF;
				offset = last_self;
				break;

			case COMPRESSION_PARENT_SELF:
				rawmap[0] = COMPRESSION_PARENT;
				last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;
				break;

			case COMPRESSION_PARENT_1:
				last_parent += header->hunkbytes / header->unitbytes;
			case COMPRESSION_PARENT_0:
				rawmap[0] = COMPRESSION_PARENT;
				offset = last_parent;
				break;
		}
		/* UINT24 length */
		put_bigendian_uint24(&rawmap[1], length);

		/* UINT48 offset */
		put_bigendian_uint48(&rawmap[4], offset);

		/* crc16 */
		put_bigendian_uint16(&rawmap[10], crc);
	}

	/* free memory */
	free(compressed_ptr);
	free(bitbuf);
	delete_huffman_decoder(decoder);

	/* verify the final CRC */
	if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
		return CHDERR_DECOMPRESSION_ERROR;

	return CHDERR_NONE;
}

/*-------------------------------------------------
    map_extract_old - extract a single map
    entry in old format from the datastream
-------------------------------------------------*/

static INLINE void map_extract_old(const uint8_t *base, map_entry *entry, uint32_t hunkbytes)
{
	entry->offset = get_bigendian_uint64_t(&base[0]);
	entry->crc = 0;
	entry->length = entry->offset >> 44;
	entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
#ifdef __MWERKS__
	entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
#else
	entry->offset = (entry->offset << 20) >> 20;
#endif
}

/***************************************************************************
    CHD FILE MANAGEMENT
***************************************************************************/

/*-------------------------------------------------
    chd_open_file - open a CHD file for access
-------------------------------------------------*/

CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd) {
	core_file *stream = malloc(sizeof(core_file));
	if (!stream)
		return CHDERR_OUT_OF_MEMORY;
	stream->argp = file;
	stream->fsize = core_stdio_fsize;
	stream->fread = core_stdio_fread;
	stream->fclose = core_stdio_fclose_nonowner;
	stream->fseek = core_stdio_fseek;

	return chd_open_core_file(stream, mode, parent, chd);
}

/*-------------------------------------------------
    chd_open_core_file - open a CHD file for access
-------------------------------------------------*/

CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd)
{
	chd_file *newchd = NULL;
	chd_error err;
	size_t intfnum;

	/* verify parameters */
	if (file == NULL)
		EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);

	/* punt if invalid parent */
	if (parent != NULL && parent->cookie != COOKIE_VALUE)
		EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);

	/* allocate memory for the final result */
	newchd = (chd_file *)malloc(sizeof(**chd));
	if (newchd == NULL)
		EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
	memset(newchd, 0, sizeof(*newchd));
	newchd->cookie = COOKIE_VALUE;
	newchd->parent = parent;
	newchd->file = file;

	/* now attempt to read the header */
	err = header_read(newchd, &newchd->header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

	/* validate the header */
	err = header_validate(&newchd->header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

	/* make sure we don't open a read-only file writeable */
	if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
		EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);

	/* also, never open an older version writeable */
	if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
		EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);

	/* if we need a parent, make sure we have one */
	if (parent == NULL)
	{
		/* Detect parent requirement for versions below 5 */
		if (newchd->header.version < 5 && newchd->header.flags & CHDFLAGS_HAS_PARENT)
			EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
		/* Detection for version 5 and above - if parentsha1 != 0, we have a parent */
		else if (newchd->header.version >= 5 && memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
			EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
	}

	/* make sure we have a valid parent */
	if (parent != NULL)
	{
		/* check MD5 if it isn't empty */
		if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
			memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
			memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
			EARLY_EXIT(err = CHDERR_INVALID_PARENT);

		/* check SHA1 if it isn't empty */
		if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
			memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
			memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
			EARLY_EXIT(err = CHDERR_INVALID_PARENT);
	}

	/* now read the hunk map */
	if (newchd->header.version < 5)
	{
		err = map_read(newchd);
		if (err != CHDERR_NONE)
			EARLY_EXIT(err);
	}
	else
	{
		err = decompress_v5_map(newchd, &(newchd->header));
	}
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

#ifdef NEED_CACHE_HUNK
	/* allocate and init the hunk cache */
	newchd->cache = (uint8_t *)malloc(newchd->header.hunkbytes);
	newchd->compare = (uint8_t *)malloc(newchd->header.hunkbytes);
	if (newchd->cache == NULL || newchd->compare == NULL)
		EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
	newchd->cachehunk = ~0;
	newchd->comparehunk = ~0;
#endif

	/* allocate the temporary compressed buffer */
	newchd->compressed = (uint8_t *)malloc(newchd->header.hunkbytes);
	if (newchd->compressed == NULL)
		EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);

	/* find the codec interface */
	if (newchd->header.version < 5)
	{
		for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
		{
			if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
			{
				newchd->codecintf[0] = &codec_interfaces[intfnum];
				break;
			}
		}

		if (intfnum == ARRAY_LENGTH(codec_interfaces))
			EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);

#ifdef HAVE_ZLIB
		/* initialize the codec */
		if (newchd->codecintf[0]->init != NULL)
		{
			err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
			if (err != CHDERR_NONE)
				EARLY_EXIT(err);
		}
#endif
	}
	else
	{
		size_t decompnum;
		/* verify the compression types and initialize the codecs */
		for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)
		{
			size_t i;
			for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)
			{
				if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
				{
					newchd->codecintf[decompnum] = &codec_interfaces[i];
					break;
				}
			}

			if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
				EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);

			/* initialize the codec */
			if (newchd->codecintf[decompnum]->init != NULL)
			{
				void* codec = NULL;
				switch (newchd->header.compression[decompnum])
				{
					case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
						codec = &newchd->zlib_codec_data;
#endif
						break;

					case CHD_CODEC_LZMA:
#ifdef HAVE_7ZIP
						codec = &newchd->lzma_codec_data;
#endif
						break;

					case CHD_CODEC_HUFFMAN:
						codec = &newchd->huff_codec_data;
						break;

					case CHD_CODEC_FLAC:
#ifdef HAVE_FLAC
						codec = &newchd->flac_codec_data;
#endif
						break;

					case CHD_CODEC_ZSTD:
#ifdef HAVE_ZSTD
						codec = &newchd->zstd_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
						codec = &newchd->cdzl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_LZMA:
#ifdef HAVE_7ZIP
						codec = &newchd->cdlz_codec_data;
#endif
						break;

					case CHD_CODEC_CD_FLAC:
#ifdef HAVE_FLAC
						codec = &newchd->cdfl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZSTD:
#ifdef HAVE_ZSTD
						codec = &newchd->cdzs_codec_data;
#endif
						break;
				}

				if (codec == NULL)
					EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);

				err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
				if (err != CHDERR_NONE)
					EARLY_EXIT(err);
			}
		}
	}

	/* all done */
	*chd = newchd;
	return CHDERR_NONE;

cleanup:
	if (newchd != NULL)
		chd_close(newchd);
	return err;
}

/*-------------------------------------------------
    chd_precache - precache underlying file in
    memory
-------------------------------------------------*/

CHD_EXPORT chd_error chd_precache(chd_file *chd)
{
	uint64_t count;
	uint64_t size;

	if (chd->file_cache == NULL)
	{
		size = core_fsize(chd->file);
		if ((int64_t)size <= 0)
			return CHDERR_INVALID_DATA;
		chd->file_cache = malloc(size);
		if (chd->file_cache == NULL)
			return CHDERR_OUT_OF_MEMORY;
		core_fseek(chd->file, 0, SEEK_SET);
		count = core_fread(chd->file, chd->file_cache, size);
		if (count != size)
		{
			free(chd->file_cache);
			chd->file_cache = NULL;
			return CHDERR_READ_ERROR;
		}
	}

	return CHDERR_NONE;
}

/*-------------------------------------------------
    chd_open - open a CHD file by
    filename
-------------------------------------------------*/

CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
{
	chd_error err;
	core_file *file = NULL;

	if (filename == NULL)
	{
		err = CHDERR_INVALID_PARAMETER;
		goto cleanup;
	}

	/* choose the proper mode */
	switch(mode)
	{
		case CHD_OPEN_READ:
			break;

		default:
			err = CHDERR_INVALID_PARAMETER;
			goto cleanup;
	}

	/* open the file */
	file = core_stdio_fopen(filename);
	if (file == 0)
	{
		err = CHDERR_FILE_NOT_FOUND;
		goto cleanup;
	}

	/* now open the CHD */
	return chd_open_core_file(file, mode, parent, chd);

cleanup:
	if ((err != CHDERR_NONE) && (file != NULL))
		core_fclose(file);
	return err;
}

/*-------------------------------------------------
    chd_close - close a CHD file for access
-------------------------------------------------*/

CHD_EXPORT void chd_close(chd_file *chd)
{
	/* punt if NULL or invalid */
	if (chd == NULL || chd->cookie != COOKIE_VALUE)
		return;

	/* deinit the codec */
	if (chd->header.version < 5)
	{
#ifdef HAVE_ZLIB
		if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
			(*chd->codecintf[0]->free)(&chd->zlib_codec_data);
#endif
	}
	else
	{
		size_t i;
		/* Free the codecs */
		for (i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++)
		{
			void* codec = NULL;

			if (chd->codecintf[i] == NULL)
				continue;

			switch (chd->codecintf[i]->compression)
			{
				case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
					codec = &chd->zlib_codec_data;
#endif
					break;

				case CHD_CODEC_LZMA:
#ifdef HAVE_7ZIP
					codec = &chd->lzma_codec_data;
#endif
					break;

				case CHD_CODEC_HUFFMAN:
					codec = &chd->huff_codec_data;
					break;

				case CHD_CODEC_FLAC:
#ifdef HAVE_FLAC
					codec = &chd->flac_codec_data;
#endif
					break;

				case CHD_CODEC_ZSTD:
#ifdef HAVE_ZSTD
					codec = &chd->zstd_codec_data;
#endif
					break;

				case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
					codec = &chd->cdzl_codec_data;
#endif
					break;

				case CHD_CODEC_CD_LZMA:
#ifdef HAVE_7ZIP
					codec = &chd->cdlz_codec_data;
#endif
					break;

				case CHD_CODEC_CD_FLAC:
#ifdef HAVE_FLAC
					codec = &chd->cdfl_codec_data;
#endif
					break;

				case CHD_CODEC_CD_ZSTD:
#ifdef HAVE_ZSTD
					codec = &chd->cdzs_codec_data;
#endif
					break;
			}

			if (codec)
			{
				(*chd->codecintf[i]->free)(codec);
			}
		}

		/* Free the raw map */
		if (chd->header.rawmap != NULL)
			free(chd->header.rawmap);
	}

	/* free the compressed data buffer */
	if (chd->compressed != NULL)
		free(chd->compressed);

#ifdef NEED_CACHE_HUNK
	/* free the hunk cache and compare data */
	if (chd->compare != NULL)
		free(chd->compare);
	if (chd->cache != NULL)
		free(chd->cache);
#endif

	/* free the hunk map */
	if (chd->map != NULL)
		free(chd->map);

	/* close the file */
	if (chd->file != NULL)
		core_fclose(chd->file);

#ifdef NEED_CACHE_HUNK
	if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
#endif
	if (chd->file_cache)
		free(chd->file_cache);

	if (chd->parent)
		chd_close(chd->parent);

	/* free our memory */
	free(chd);
}

/*-------------------------------------------------
    chd_core_file - return the associated
    core_file
-------------------------------------------------*/

CHD_EXPORT core_file *chd_core_file(chd_file *chd)
{
	return chd->file;
}

/*-------------------------------------------------
    chd_error_string - return an error string for
    the given CHD error
-------------------------------------------------*/

CHD_EXPORT const char *chd_error_string(chd_error err)
{
	switch (err)
	{
		case CHDERR_NONE:						return "no error";
		case CHDERR_NO_INTERFACE:				return "no drive interface";
		case CHDERR_OUT_OF_MEMORY:				return "out of memory";
		case CHDERR_INVALID_FILE:				return "invalid file";
		case CHDERR_INVALID_PARAMETER:			return "invalid parameter";
		case CHDERR_INVALID_DATA:				return "invalid data";
		case CHDERR_FILE_NOT_FOUND:				return "file not found";
		case CHDERR_REQUIRES_PARENT:			return "requires parent";
		case CHDERR_FILE_NOT_WRITEABLE:			return "file not writeable";
		case CHDERR_READ_ERROR:					return "read error";
		case CHDERR_WRITE_ERROR:				return "write error";
		case CHDERR_CODEC_ERROR:				return "codec error";
		case CHDERR_INVALID_PARENT:				return "invalid parent";
		case CHDERR_HUNK_OUT_OF_RANGE:			return "hunk out of range";
		case CHDERR_DECOMPRESSION_ERROR:		return "decompression error";
		case CHDERR_COMPRESSION_ERROR:			return "compression error";
		case CHDERR_CANT_CREATE_FILE:			return "can't create file";
		case CHDERR_CANT_VERIFY:				return "can't verify file";
		case CHDERR_NOT_SUPPORTED:				return "operation not supported";
		case CHDERR_METADATA_NOT_FOUND:			return "can't find metadata";
		case CHDERR_INVALID_METADATA_SIZE:		return "invalid metadata size";
		case CHDERR_UNSUPPORTED_VERSION:		return "unsupported CHD version";
		case CHDERR_VERIFY_INCOMPLETE:			return "incomplete verify";
		case CHDERR_INVALID_METADATA:			return "invalid metadata";
		case CHDERR_INVALID_STATE:				return "invalid state";
		case CHDERR_OPERATION_PENDING:			return "operation pending";
		case CHDERR_NO_ASYNC_OPERATION:			return "no async operation in progress";
		case CHDERR_UNSUPPORTED_FORMAT:			return "unsupported format";
		default:								return "undocumented error";
	}
}

/***************************************************************************
    CHD HEADER MANAGEMENT
***************************************************************************/

/*-------------------------------------------------
    chd_get_header - return a pointer to the
    extracted header data
-------------------------------------------------*/

CHD_EXPORT const chd_header *chd_get_header(chd_file *chd)
{
	/* punt if NULL or invalid */
	if (chd == NULL || chd->cookie != COOKIE_VALUE)
		return NULL;

	return &chd->header;
}

/*-------------------------------------------------
    chd_read_header - read CHD header data
	from file into the pointed struct
-------------------------------------------------*/
CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header)
{
	chd_error err = CHDERR_NONE;
	chd_file *chd = NULL;

	/* punt if NULL */
	if (filename == NULL || header == NULL)
		EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);

	/* open the file */
	chd->file = core_stdio_fopen(filename);
	if (chd->file == NULL)
		EARLY_EXIT(err = CHDERR_FILE_NOT_FOUND);

	/* attempt to read the header */
	err = header_read(chd, header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

	/* validate the header */
	err = header_validate(header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

cleanup:
	if (chd->file != NULL)
		core_fclose(chd->file);

	return err;
}

/***************************************************************************
    CORE DATA READ/WRITE
***************************************************************************/

/*-------------------------------------------------
    chd_read - read a single hunk from the CHD
    file
-------------------------------------------------*/

CHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer)
{
	/* punt if NULL or invalid */
	if (chd == NULL || chd->cookie != COOKIE_VALUE)
		return CHDERR_INVALID_PARAMETER;

	/* if we're past the end, fail */
	if (hunknum >= chd->header.totalhunks)
		return CHDERR_HUNK_OUT_OF_RANGE;

	/* perform the read */
	return hunk_read_into_memory(chd, hunknum, (uint8_t *)buffer);
}

/***************************************************************************
    METADATA MANAGEMENT
***************************************************************************/

/*-------------------------------------------------
    chd_get_metadata - get the indexed metadata
    of the given type
-------------------------------------------------*/

CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, uint32_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags)
{
	metadata_entry metaentry;
	chd_error err;
	uint32_t count;

	/* if we didn't find it, just return */
	err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
	if (err != CHDERR_NONE)
	{
		/* unless we're an old version and they are requesting hard disk metadata */
		if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
		{
			char faux_metadata[256];
			uint32_t faux_length;

			/* fill in the faux metadata */
			sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize);
			faux_length = (uint32_t)strlen(faux_metadata) + 1;

			/* copy the metadata itself */
			memcpy(output, faux_metadata, MIN(outputlen, faux_length));

			/* return the length of the data and the tag */
			if (resultlen != NULL)
				*resultlen = faux_length;
			if (resulttag != NULL)
				*resulttag = HARD_DISK_METADATA_TAG;
			return CHDERR_NONE;
		}
		return err;
	}

	/* read the metadata */
	outputlen = MIN(outputlen, metaentry.length);
	core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
	count = core_fread(chd->file, output, outputlen);
	if (count != outputlen)
		return CHDERR_READ_ERROR;

	/* return the length of the data and the tag */
	if (resultlen != NULL)
		*resultlen = metaentry.length;
	if (resulttag != NULL)
		*resulttag = metaentry.metatag;
	if (resultflags != NULL)
		*resultflags = metaentry.flags;
	return CHDERR_NONE;
}

/***************************************************************************
    CODEC INTERFACES
***************************************************************************/

/*-------------------------------------------------
    chd_codec_config - set internal codec
    parameters
-------------------------------------------------*/

CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config)
{
	return CHDERR_INVALID_PARAMETER;
}

/*-------------------------------------------------
    chd_get_codec_name - get the name of a
    particular codec
-------------------------------------------------*/

CHD_EXPORT const char *chd_get_codec_name(uint32_t codec)
{
	return "Unknown";
}

/***************************************************************************
    INTERNAL HEADER OPERATIONS
***************************************************************************/

/*-------------------------------------------------
    header_validate - check the validity of a
    CHD header
-------------------------------------------------*/

static chd_error header_validate(const chd_header *header)
{
	size_t intfnum;

	/* require a valid version */
	if (header->version == 0 || header->version > CHD_HEADER_VERSION)
		return CHDERR_UNSUPPORTED_VERSION;

	/* require a valid length */
	if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
		(header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
		(header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
		(header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
		(header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
		return CHDERR_INVALID_PARAMETER;

	/* Do not validate v5 header */
	if (header->version <= 4)
	{
		/* require valid flags */
		if (header->flags & CHDFLAGS_UNDEFINED)
			return CHDERR_INVALID_PARAMETER;

		/* require a supported compression mechanism */
		for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
			if (codec_interfaces[intfnum].compression == header->compression[0])
				break;

		if (intfnum == ARRAY_LENGTH(codec_interfaces))
			return CHDERR_INVALID_PARAMETER;

		/* require a valid hunksize */
		if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
			return CHDERR_INVALID_PARAMETER;

		/* require a valid hunk count */
		if (header->totalhunks == 0)
			return CHDERR_INVALID_PARAMETER;

		/* require a valid MD5 and/or SHA1 if we're using a parent */
		if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
			return CHDERR_INVALID_PARAMETER;

		/* if we're V3 or later, the obsolete fields must be 0 */
		if (header->version >= 3 &&
			(header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
			 header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
			return CHDERR_INVALID_PARAMETER;

		/* if we're pre-V3, the obsolete fields must NOT be 0 */
		if (header->version < 3 &&
			(header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
			 header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
			return CHDERR_INVALID_PARAMETER;
	}

	return CHDERR_NONE;
}

/*-------------------------------------------------
    header_guess_unitbytes - for older CHD formats,
    guess at the bytes/unit based on metadata
-------------------------------------------------*/

static uint32_t header_guess_unitbytes(chd_file *chd)
{
	/* look for hard disk metadata; if found, then the unit size == sector size */
	char metadata[512];
	int i0, i1, i2, i3;
	if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&
		sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
		return i3;

	/* look for CD-ROM metadata; if found, then the unit size == CD frame size */
	if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
		return CD_FRAME_SIZE;

	/* otherwise, just map 1:1 with the hunk size */
	return chd->header.hunkbytes;
}

/*-------------------------------------------------
    header_read - read a CHD header into the
    internal data structure
-------------------------------------------------*/

static chd_error header_read(chd_file *chd, chd_header *header)
{
	uint8_t rawheader[CHD_MAX_HEADER_SIZE];
	uint32_t count;

	/* punt if NULL */
	if (header == NULL)
		return CHDERR_INVALID_PARAMETER;

	/* punt if invalid file */
	if (chd->file == NULL)
		return CHDERR_INVALID_FILE;

	/* seek and read */
	core_fseek(chd->file, 0, SEEK_SET);
	count = core_fread(chd->file, rawheader, sizeof(rawheader));
	if (count != sizeof(rawheader))
		return CHDERR_READ_ERROR;

	/* verify the tag */
	if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
		return CHDERR_INVALID_DATA;

	/* extract the direct data */
	memset(header, 0, sizeof(*header));
	header->length        = get_bigendian_uint32_t(&rawheader[8]);
	header->version       = get_bigendian_uint32_t(&rawheader[12]);

	/* make sure it's a version we understand */
	if (header->version == 0 || header->version > CHD_HEADER_VERSION)
		return CHDERR_UNSUPPORTED_VERSION;

	/* make sure the length is expected */
	if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
		(header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
		(header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
		(header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
		(header->version == 5 && header->length != CHD_V5_HEADER_SIZE))

		return CHDERR_INVALID_DATA;

	/* extract the common data */
	header->flags         	= get_bigendian_uint32_t(&rawheader[16]);
	header->compression[0]	= get_bigendian_uint32_t(&rawheader[20]);
	header->compression[1]	= CHD_CODEC_NONE;
	header->compression[2]	= CHD_CODEC_NONE;
	header->compression[3]	= CHD_CODEC_NONE;

	/* extract the V1/V2-specific data */
	if (header->version < 3)
	{
		int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32_t(&rawheader[76]);
		header->obsolete_hunksize  = get_bigendian_uint32_t(&rawheader[24]);
		header->totalhunks         = get_bigendian_uint32_t(&rawheader[28]);
		header->obsolete_cylinders = get_bigendian_uint32_t(&rawheader[32]);
		header->obsolete_heads     = get_bigendian_uint32_t(&rawheader[36]);
		header->obsolete_sectors   = get_bigendian_uint32_t(&rawheader[40]);
		memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
		memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
		header->logicalbytes = (uint64_t)header->obsolete_cylinders * (uint64_t)header->obsolete_heads * (uint64_t)header->obsolete_sectors * (uint64_t)seclen;
		header->hunkbytes = seclen * header->obsolete_hunksize;
		header->unitbytes          = header_guess_unitbytes(chd);
		if (header->unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header->unitcount          = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
		header->metaoffset = 0;
	}

	/* extract the V3-specific data */
	else if (header->version == 3)
	{
		header->totalhunks   = get_bigendian_uint32_t(&rawheader[24]);
		header->logicalbytes = get_bigendian_uint64_t(&rawheader[28]);
		header->metaoffset   = get_bigendian_uint64_t(&rawheader[36]);
		memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
		memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
		header->hunkbytes    = get_bigendian_uint32_t(&rawheader[76]);
		header->unitbytes    = header_guess_unitbytes(chd);
		if (header->unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
		memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
		memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
	}

	/* extract the V4-specific data */
	else if (header->version == 4)
	{
		header->totalhunks   = get_bigendian_uint32_t(&rawheader[24]);
		header->logicalbytes = get_bigendian_uint64_t(&rawheader[28]);
		header->metaoffset   = get_bigendian_uint64_t(&rawheader[36]);
		header->hunkbytes    = get_bigendian_uint32_t(&rawheader[44]);
		header->unitbytes    = header_guess_unitbytes(chd);
		if (header->unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
		memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
		memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
		memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
	}

	/* extract the V5-specific data */
	else if (header->version == 5)
	{
		/* TODO */
		header->compression[0]  = get_bigendian_uint32_t(&rawheader[16]);
		header->compression[1]  = get_bigendian_uint32_t(&rawheader[20]);
		header->compression[2]  = get_bigendian_uint32_t(&rawheader[24]);
		header->compression[3]  = get_bigendian_uint32_t(&rawheader[28]);
		header->logicalbytes    = get_bigendian_uint64_t(&rawheader[32]);
		header->mapoffset       = get_bigendian_uint64_t(&rawheader[40]);
		header->metaoffset      = get_bigendian_uint64_t(&rawheader[48]);
		header->hunkbytes       = get_bigendian_uint32_t(&rawheader[56]);
		if (header->hunkbytes == 0)
			return CHDERR_INVALID_DATA;
		header->hunkcount       = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes;
		header->unitbytes       = get_bigendian_uint32_t(&rawheader[60]);
		if (header->unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header->unitcount       = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
		memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);
		memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
		memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);

		/* determine properties of map entries */
		header->mapentrybytes = chd_compressed(header) ? 12 : 4;

		/* hack */
		header->totalhunks 		= header->hunkcount;
	}

	/* Unknown version */
	else
	{
		/* TODO */
	}

	/* guess it worked */
	return CHDERR_NONE;
}

/***************************************************************************
    INTERNAL HUNK READ/WRITE
***************************************************************************/

/*-------------------------------------------------
    hunk_read_compressed - read a compressed
    hunk
-------------------------------------------------*/

static uint8_t* hunk_read_compressed(chd_file *chd, uint64_t offset, size_t size)
{
	size_t bytes;

	if (chd->file_cache != NULL)
	{
		return chd->file_cache + offset;
	}
	else
	{
		core_fseek(chd->file, offset, SEEK_SET);
		bytes = core_fread(chd->file, chd->compressed, size);
		if (bytes != size)
			return NULL;
		return chd->compressed;
	}
}

/*-------------------------------------------------
    hunk_read_uncompressed - read an uncompressed
    hunk
-------------------------------------------------*/

static chd_error hunk_read_uncompressed(chd_file *chd, uint64_t offset, size_t size, uint8_t *dest)
{
	size_t bytes;

	if (chd->file_cache != NULL)
	{
		memcpy(dest, chd->file_cache + offset, size);
	}
	else
	{
		core_fseek(chd->file, offset, SEEK_SET);
		bytes = core_fread(chd->file, dest, size);
		if (bytes != size)
			return CHDERR_READ_ERROR;
	}
	return CHDERR_NONE;
}

#ifdef NEED_CACHE_HUNK
/*-------------------------------------------------
    hunk_read_into_cache - read a hunk into
    the CHD's hunk cache
-------------------------------------------------*/

static chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum)
{
	chd_error err;

	/* track the max */
	if (hunknum > chd->maxhunk)
		chd->maxhunk = hunknum;

	/* if we're already in the cache, we're done */
	if (chd->cachehunk == hunknum)
		return CHDERR_NONE;
	chd->cachehunk = ~0;

	/* otherwise, read the data */
	err = hunk_read_into_memory(chd, hunknum, chd->cache);
	if (err != CHDERR_NONE)
		return err;

	/* mark the hunk successfully cached in */
	chd->cachehunk = hunknum;
	return CHDERR_NONE;
}
#endif

/*-------------------------------------------------
    hunk_read_into_memory - read a hunk into
    memory at the given location
-------------------------------------------------*/

static chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest)
{
	chd_error err;

	/* punt if no file */
	if (chd->file == NULL)
		return CHDERR_INVALID_FILE;

	/* return an error if out of range */
	if (hunknum >= chd->header.totalhunks)
		return CHDERR_HUNK_OUT_OF_RANGE;

	if (dest == NULL)
		return CHDERR_INVALID_PARAMETER;

	if (chd->header.version < 5)
	{
		map_entry *entry = &chd->map[hunknum];
		uint32_t bytes;
		uint8_t* compressed_bytes;

		/* switch off the entry type */
		switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
		{
			/* compressed data */
			case V34_MAP_ENTRY_TYPE_COMPRESSED:
            {
               void *codec = NULL;

				/* read it into the decompression buffer */
				compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length);
				if (compressed_bytes == NULL)
					{
					return CHDERR_READ_ERROR;
					}

#ifdef HAVE_ZLIB
				/* now decompress using the codec */
				err = CHDERR_NONE;
				codec = &chd->zlib_codec_data;
				if (chd->codecintf[0]->decompress != NULL)
					err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
				if (err != CHDERR_NONE)
					return err;
#endif
				break;
			}

			/* uncompressed data */
			case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
				err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
				if (err != CHDERR_NONE)
					return err;
				break;

			/* mini-compressed data */
			case V34_MAP_ENTRY_TYPE_MINI:
				put_bigendian_uint64_t(&dest[0], entry->offset);
				for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
					dest[bytes] = dest[bytes - 8];
				break;

			/* self-referenced data */
			case V34_MAP_ENTRY_TYPE_SELF_HUNK:
#ifdef NEED_CACHE_HUNK
				if (chd->cachehunk == entry->offset && dest == chd->cache)
					break;
#endif
				return hunk_read_into_memory(chd, entry->offset, dest);

			/* parent-referenced data */
			case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
				err = hunk_read_into_memory(chd->parent, entry->offset, dest);
				if (err != CHDERR_NONE)
					return err;
				break;
		}
		return CHDERR_NONE;
	}
	else
	{
		void* codec = NULL;
		/* get a pointer to the map entry */
		uint64_t blockoffs;
		uint32_t blocklen;
#ifdef VERIFY_BLOCK_CRC
		uint16_t blockcrc;
#endif
		uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
		uint8_t* compressed_bytes;

		/* uncompressed case */
		if (!chd_compressed(&chd->header))
		{
			blockoffs = (uint64_t)get_bigendian_uint32_t(rawmap) * (uint64_t)chd->header.hunkbytes;
			if (blockoffs != 0) {
				core_fseek(chd->file, blockoffs, SEEK_SET);
				/*int result =*/
				core_fread(chd->file, dest, chd->header.hunkbytes);
			/* TODO
			else if (m_parent_missing)
				throw CHDERR_REQUIRES_PARENT; */
			} else if (chd->parent) {
				err = hunk_read_into_memory(chd->parent, hunknum, dest);
				if (err != CHDERR_NONE)
					return err;
			} else {
				memset(dest, 0, chd->header.hunkbytes);
			}

			return CHDERR_NONE;
		}

		/* compressed case */
		blocklen = get_bigendian_uint24(&rawmap[1]);
		blockoffs = get_bigendian_uint48(&rawmap[4]);
#ifdef VERIFY_BLOCK_CRC
		blockcrc = get_bigendian_uint16(&rawmap[10]);
#endif
		codec = NULL;
		switch (rawmap[0])
		{
			case COMPRESSION_TYPE_0:
			case COMPRESSION_TYPE_1:
			case COMPRESSION_TYPE_2:
			case COMPRESSION_TYPE_3:
				compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
				if (compressed_bytes == NULL)
					return CHDERR_READ_ERROR;
				switch (chd->codecintf[rawmap[0]]->compression)
				{
					case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
						codec = &chd->zlib_codec_data;
#endif
						break;

					case CHD_CODEC_LZMA:
#ifdef HAVE_7ZIP
						codec = &chd->lzma_codec_data;
#endif
						break;

					case CHD_CODEC_HUFFMAN:
						codec = &chd->huff_codec_data;
						break;

					case CHD_CODEC_FLAC:
#ifdef HAVE_FLAC
						codec = &chd->flac_codec_data;
#endif
						break;

					case CHD_CODEC_ZSTD:
#ifdef HAVE_ZSTD
						codec = &chd->zstd_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
						codec = &chd->cdzl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_LZMA:
#ifdef HAVE_7ZIP
						codec = &chd->cdlz_codec_data;
#endif
						break;

					case CHD_CODEC_CD_FLAC:
#ifdef HAVE_FLAC
						codec = &chd->cdfl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZSTD:
#ifdef HAVE_ZSTD
						codec = &chd->cdzs_codec_data;
#endif
						break;
				}
				
				if (codec==NULL)
					return CHDERR_CODEC_ERROR;
				err = chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
				if (err != CHDERR_NONE)
					return err;
#ifdef VERIFY_BLOCK_CRC
				if (crc16(dest, chd->header.hunkbytes) != blockcrc)
					return CHDERR_DECOMPRESSION_ERROR;
#endif
				return CHDERR_NONE;

			case COMPRESSION_NONE:
				err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
				if (err != CHDERR_NONE)
					return err;
#ifdef VERIFY_BLOCK_CRC
				if (crc16(dest, chd->header.hunkbytes) != blockcrc)
					return CHDERR_DECOMPRESSION_ERROR;
#endif
				return CHDERR_NONE;

			case COMPRESSION_SELF:
				return hunk_read_into_memory(chd, blockoffs, dest);

			case COMPRESSION_PARENT:
			{
				uint8_t units_in_hunk = chd->header.hunkbytes / chd->header.unitbytes;

				if (chd->parent == NULL)
					return CHDERR_REQUIRES_PARENT;

				/* blockoffs is aligned to units_in_hunk */
				if (blockoffs % units_in_hunk == 0) {
					return hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, dest);
				/* blockoffs is not aligned to units_in_hunk */
				} else {
					uint32_t unit_in_hunk = blockoffs % units_in_hunk;
					uint8_t *buf = malloc(chd->header.hunkbytes);
					/* Read first half of hunk which contains blockoffs */
					err = hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, buf);
					if (err != CHDERR_NONE) {
						free(buf);
						return err;
					}
					memcpy(dest, buf + unit_in_hunk * chd->header.unitbytes, (units_in_hunk - unit_in_hunk) * chd->header.unitbytes);
					/* Read second half of hunk which contains blockoffs */
					err = hunk_read_into_memory(chd->parent, (blockoffs / units_in_hunk) + 1, buf);
					if (err != CHDERR_NONE) {
						free(buf);
						return err;
					}
					memcpy(dest + (units_in_hunk - unit_in_hunk) * chd->header.unitbytes, buf, unit_in_hunk * chd->header.unitbytes);
					free(buf);
				}
			}
		}
		return CHDERR_NONE;
	}

	/* We should not reach this code */
	return CHDERR_DECOMPRESSION_ERROR;
}

/***************************************************************************
    INTERNAL MAP ACCESS
***************************************************************************/

/*-------------------------------------------------
    map_read - read the initial sector map
-------------------------------------------------*/

static chd_error map_read(chd_file *chd)
{
	uint32_t entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
	uint8_t raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
	uint64_t fileoffset, maxoffset = 0;
	uint8_t cookie[MAP_ENTRY_SIZE];
	uint32_t count;
	chd_error err;
	uint32_t i;

	/* first allocate memory */
	chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
	if (!chd->map)
		return CHDERR_OUT_OF_MEMORY;

	/* read the map entries in in chunks and extract to the map list */
	fileoffset = chd->header.length;
	for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES)
	{
		/* compute how many entries this time */
		int entries = chd->header.totalhunks - i, j;
		if (entries > MAP_STACK_ENTRIES)
			entries = MAP_STACK_ENTRIES;

		/* read that many */
		core_fseek(chd->file, fileoffset, SEEK_SET);
		count = core_fread(chd->file, raw_map_entries, entries * entrysize);
		if (count != entries * entrysize)
		{
			err = CHDERR_READ_ERROR;
			goto cleanup;
		}
		fileoffset += entries * entrysize;

		/* process that many */
		if (entrysize == MAP_ENTRY_SIZE)
		{
			for (j = 0; j < entries; j++)
				map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
		}
		else
		{
			for (j = 0; j < entries; j++)
				map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
		}

		/* track the maximum offset */
		for (j = 0; j < entries; j++)
			if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
				(chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
				maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
	}

	/* verify the cookie */
	core_fseek(chd->file, fileoffset, SEEK_SET);
	count = core_fread(chd->file, &cookie, entrysize);
	if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
	{
		err = CHDERR_INVALID_FILE;
		goto cleanup;
	}

	/* verify the length */
	if (maxoffset > core_fsize(chd->file))
	{
		err = CHDERR_INVALID_FILE;
		goto cleanup;
	}
	return CHDERR_NONE;

cleanup:
	if (chd->map)
		free(chd->map);
	chd->map = NULL;
	return err;
}

/***************************************************************************
    INTERNAL METADATA ACCESS
***************************************************************************/

/*-------------------------------------------------
    metadata_find_entry - find a metadata entry
-------------------------------------------------*/

static chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry)
{
	/* start at the beginning */
	metaentry->offset = chd->header.metaoffset;
	metaentry->prev = 0;

	/* loop until we run out of options */
	while (metaentry->offset != 0)
	{
		uint8_t	raw_meta_header[METADATA_HEADER_SIZE];
		uint32_t	count;

		/* read the raw header */
		core_fseek(chd->file, metaentry->offset, SEEK_SET);
		count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
		if (count != sizeof(raw_meta_header))
			break;

		/* extract the data */
		metaentry->metatag = get_bigendian_uint32_t(&raw_meta_header[0]);
		metaentry->length = get_bigendian_uint32_t(&raw_meta_header[4]);
		metaentry->next = get_bigendian_uint64_t(&raw_meta_header[8]);

		/* flags are encoded in the high byte of length */
		metaentry->flags = metaentry->length >> 24;
		metaentry->length &= 0x00ffffff;

		/* if we got a match, proceed */
		if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
			if (metaindex-- == 0)
				return CHDERR_NONE;

		/* no match, fetch the next link */
		metaentry->prev = metaentry->offset;
		metaentry->offset = metaentry->next;
	}

	/* if we get here, we didn't find it */
	return CHDERR_METADATA_NOT_FOUND;
}

/*-------------------------------------------------
	core_stdio_fopen - core_file wrapper over fopen
-------------------------------------------------*/
static core_file *core_stdio_fopen(char const *path) {
	core_file *file = malloc(sizeof(core_file));
	if (!file)
		return NULL;
	if (!(file->argp = fopen(path, "rb"))) {
		free(file);
		return NULL;
	}
	file->fsize = core_stdio_fsize;
	file->fread = core_stdio_fread;
	file->fclose = core_stdio_fclose;
	file->fseek = core_stdio_fseek;
	return file;
}

/*-------------------------------------------------
	core_stdio_fsize - core_file function for
	getting file size with stdio
-------------------------------------------------*/
static uint64_t core_stdio_fsize(core_file *file) {
#if defined USE_LIBRETRO_VFS
	#define core_stdio_fseek_impl fseek
	#define core_stdio_ftell_impl ftell
#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WIN64__)
	#define core_stdio_fseek_impl _fseeki64
	#define core_stdio_ftell_impl _ftelli64
#elif defined(_LARGEFILE_SOURCE) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(fseeko64) && defined(ftello64)
	#define core_stdio_fseek_impl fseeko64
	#define core_stdio_ftell_impl ftello64
#elif defined(__PS3__) && !defined(__PSL1GHT__) || defined(__SWITCH__) || defined(__vita__)
	#define core_stdio_fseek_impl(x,y,z) fseek(x,(off_t)y,z)
	#define core_stdio_ftell_impl(x) (off_t)ftell(x)
#else
	#define core_stdio_fseek_impl fseeko
	#define core_stdio_ftell_impl ftello
#endif
	FILE *fp;
	uint64_t p, rv;
	fp = (FILE*)file->argp;

	p = core_stdio_ftell_impl(fp);
	core_stdio_fseek_impl(fp, 0, SEEK_END);
	rv = core_stdio_ftell_impl(fp);
	core_stdio_fseek_impl(fp, p, SEEK_SET);
	return rv;
}

/*-------------------------------------------------
	core_stdio_fread - core_file wrapper over fread
-------------------------------------------------*/
static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file) {
	return fread(ptr, size, nmemb, (FILE*)file->argp);
}

/*-------------------------------------------------
	core_stdio_fclose - core_file wrapper over fclose
-------------------------------------------------*/
static int core_stdio_fclose(core_file *file) {
	int err = fclose((FILE*)file->argp);
	if (err == 0)
		free(file);
	return err;
}

/*-------------------------------------------------
	core_stdio_fclose_nonowner - don't call fclose because
		we don't own the underlying file, but do free the
		core_file because libchdr did allocate that itself.
-------------------------------------------------*/
static int core_stdio_fclose_nonowner(core_file *file) {
	free(file);
	return 0;
}

/*-------------------------------------------------
	core_stdio_fseek - core_file wrapper over fclose
-------------------------------------------------*/
static int core_stdio_fseek(core_file* file, int64_t offset, int whence) {
	return core_stdio_fseek_impl((FILE*)file->argp, offset, whence);
}

./include/libretro-common/formats/libchdr/libchdr_flac.c

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    flac.c

    FLAC compression wrappers

***************************************************************************/

#include <string.h>
#include <stdbool.h>

#include <libchdr/flac.h>
#ifdef HAVE_DR_FLAC
#include <retro_inline.h>
#define DR_FLAC_IMPLEMENTATION
#define DRFLAC_API static INLINE
#include <dr/dr_flac.h>
#endif

/***************************************************************************
 *  FLAC DECODER
 ***************************************************************************
 */

static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes);
static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin);
static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata);
static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes);


/* getters (valid after reset) */
/*static uint32_t sample_rate(flac_decoder *decoder)  { return decoder->sample_rate; }*/
static uint8_t channels(flac_decoder *decoder)  { return decoder->channels; }
/*static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }*/

/*-------------------------------------------------
 *  flac_decoder - constructor
 *-------------------------------------------------
 */

int flac_decoder_init(flac_decoder *decoder)
{
	decoder->decoder = NULL;
	decoder->sample_rate = 0;
	decoder->channels = 0;
	decoder->bits_per_sample = 0;
	decoder->compressed_offset = 0;
	decoder->compressed_start = NULL;
	decoder->compressed_length = 0;
	decoder->compressed2_start = NULL;
	decoder->compressed2_length = 0;
	decoder->uncompressed_offset = 0;
	decoder->uncompressed_length = 0;
	decoder->uncompressed_swap = 0;
	return 0;
}

/*-------------------------------------------------
 *  flac_decoder - destructor
 *-------------------------------------------------
 */

void flac_decoder_free(flac_decoder* decoder)
{
	if ((decoder != NULL) && (decoder->decoder != NULL)) {
		drflac_close(decoder->decoder);
		decoder->decoder = NULL;
	}
}

/*-------------------------------------------------
 *  reset - reset state with the original
 *  parameters
 *-------------------------------------------------
 */

static int flac_decoder_internal_reset(flac_decoder* decoder)
{
	decoder->compressed_offset = 0;
	flac_decoder_free(decoder);
	decoder->decoder = drflac_open_with_metadata(
		flac_decoder_read_callback, flac_decoder_seek_callback,
		flac_decoder_metadata_callback, decoder, NULL);
	return (decoder->decoder != NULL);
}

/*-------------------------------------------------
 *  reset - reset state with new memory parameters
 *  and a custom-generated header
 *-------------------------------------------------
 */

int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)
{
	/* modify the template header with our parameters */
	static const uint8_t s_header_template[0x2a] =
	{
		0x66, 0x4C, 0x61, 0x43,                         /* +00: 'fLaC' stream header */
		0x80,                                           /* +04: metadata block type 0 (STREAMINFO), */
								/*      flagged as last block */
		0x00, 0x00, 0x22,                               /* +05: metadata block length = 0x22 */
		0x00, 0x00,                                     /* +08: minimum block size */
		0x00, 0x00,                                     /* +0A: maximum block size */
		0x00, 0x00, 0x00,                               /* +0C: minimum frame size (0 == unknown) */
		0x00, 0x00, 0x00,                               /* +0F: maximum frame size (0 == unknown) */
		0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */
								/*      numchannels (2), sample bits (16), */
								/*      samples in stream (0 == unknown) */
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* +2A: start of stream data */
	};
	memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));
	decoder->custom_header[0x08] = decoder->custom_header[0x0a] = (block_size*num_channels) >> 8;
	decoder->custom_header[0x09] = decoder->custom_header[0x0b] = (block_size*num_channels) & 0xff;
	decoder->custom_header[0x12] = sample_rate >> 12;
	decoder->custom_header[0x13] = sample_rate >> 4;
	decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);

	/* configure the header ahead of the provided buffer */
	decoder->compressed_start = (const uint8_t *)(decoder->custom_header);
	decoder->compressed_length = sizeof(decoder->custom_header);
	decoder->compressed2_start = (const uint8_t *)(buffer);
	decoder->compressed2_length = length;
	return flac_decoder_internal_reset(decoder);
}

/*-------------------------------------------------
 *  decode_interleaved - decode to an interleaved
 *  sound stream
 *-------------------------------------------------
 */

int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)
{
#define	BUFFER	2352	/* bytes per CD audio sector */
	int16_t buffer[BUFFER];
	uint32_t buf_samples = BUFFER / channels(decoder);

	/* configure the uncompressed buffer */
	memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));
	decoder->uncompressed_start[0] = samples;
	decoder->uncompressed_offset = 0;
	decoder->uncompressed_length = num_samples;
	decoder->uncompressed_swap = swap_endian;

	/* loop until we get everything we want */
	while (decoder->uncompressed_offset < decoder->uncompressed_length) {
		uint32_t frames = (num_samples < buf_samples ? num_samples : buf_samples);
		if (!drflac_read_pcm_frames_s16(decoder->decoder, frames, buffer))
			return 0;
		flac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder));
		num_samples -= frames;
	}
	return 1;
}

/*-------------------------------------------------
 *  finish - finish up the decode
 *-------------------------------------------------
 */

uint32_t flac_decoder_finish(flac_decoder* decoder)
{
	/* get the final decoding position and move forward */
	drflac *flac = decoder->decoder;
	uint64_t position = decoder->compressed_offset;

	/* ugh... there's no function to obtain bytes used in drflac :-/ */
	position -= DRFLAC_CACHE_L2_LINES_REMAINING(&flac->bs) * sizeof(drflac_cache_t);
	position -= DRFLAC_CACHE_L1_BITS_REMAINING(&flac->bs) / 8;
	position -= flac->bs.unalignedByteCount;

	/* adjust position if we provided the header */
	if (position == 0)
		return 0;
	if (decoder->compressed_start == (const uint8_t *)(decoder->custom_header))
		position -= decoder->compressed_length;

	flac_decoder_free(decoder);
	return position;
}

/*-------------------------------------------------
 *  read_callback - handle reads from the input
 *  stream
 *-------------------------------------------------
 */

static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes)
{
	flac_decoder* decoder = (flac_decoder*)userdata;
	uint8_t *dst = buffer;

	/* copy from primary buffer first */
	uint32_t outputpos = 0;
	if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length)
	{
		uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);
		memcpy(&dst[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);
		outputpos += bytes_to_copy;
		decoder->compressed_offset += bytes_to_copy;
	}

	/* once we're out of that, copy from the secondary buffer */
	if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)
	{
		uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));
		memcpy(&dst[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);
		outputpos += bytes_to_copy;
		decoder->compressed_offset += bytes_to_copy;
	}

	return outputpos;
}

/*-------------------------------------------------
 *  metadata_callback - handle STREAMINFO metadata
 *-------------------------------------------------
 */

static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata)
{
	flac_decoder *decoder = userdata;

	/* ignore all but STREAMINFO metadata */
	if (metadata->type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO)
		return;

	/* parse out the data we care about */
	decoder->sample_rate = metadata->data.streaminfo.sampleRate;
	decoder->bits_per_sample = metadata->data.streaminfo.bitsPerSample;
	decoder->channels = metadata->data.streaminfo.channels;
}

/*-------------------------------------------------
 *  write_callback - handle writes to the output
 *  stream
 *-------------------------------------------------
 */

static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes)
{
	int sampnum, chan;
	int shift, blocksize;
	flac_decoder * decoder = (flac_decoder *)userdata;
	int16_t *sampbuf = (int16_t *)buffer;
	int sampch = channels(decoder);
	uint32_t offset = decoder->uncompressed_offset;
	uint16_t usample;

	/* interleaved case */
	shift = decoder->uncompressed_swap ? 8 : 0;
	blocksize = bytes / (sampch * sizeof(sampbuf[0]));
	if (decoder->uncompressed_start[1] == NULL)
	{
		int16_t *dest = decoder->uncompressed_start[0] + offset * sampch;
		for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
			for (chan = 0; chan < sampch; chan++) {
				usample = (uint16_t)*sampbuf++;
				*dest++ = (int16_t)((usample << shift) | (usample >> shift));
			}
	}

	/* non-interleaved case */
	else
	{
		for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
			for (chan = 0; chan < sampch; chan++) {
				usample = (uint16_t)*sampbuf++;
				if (decoder->uncompressed_start[chan] != NULL)
					decoder->uncompressed_start[chan][offset] = (int16_t) ((usample << shift) | (usample >> shift));
			}
	}
	decoder->uncompressed_offset = offset;
}


/*-------------------------------------------------
 *  seek_callback - handle seeks on the output
 *  stream
 *-------------------------------------------------
 */

static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin)
{
	flac_decoder * decoder = (flac_decoder *)userdata;
	uint32_t length = decoder->compressed_length + decoder->compressed2_length;

	if (origin == drflac_seek_origin_start) {
		uint32_t pos = offset;
		if (pos <= length) {
			decoder->compressed_offset = pos;
			return 1;
		}
	} else if (origin == drflac_seek_origin_current) {
		uint32_t pos = decoder->compressed_offset + offset;
		if (pos <= length) {
			decoder->compressed_offset = pos;
			return 1;
		}
	}
	return 0;
}

./include/libretro-common/formats/libchdr/libchdr_flac_codec.c

/***************************************************************************

    libchdr_flac_codec.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libchdr/chd.h>
#include <libchdr/minmax.h>
#include <libchdr/cdrom.h>
#include <libchdr/flac.h>
#include <libchdr/huffman.h>
#include <libchdr/libchdr_zlib.h>
#include <zlib.h>

#include <retro_inline.h>
#include <streams/file_stream.h>

/***************************************************************************
 *  CD FLAC DECOMPRESSOR
 ***************************************************************************
 */

/*------------------------------------------------------
 *  flac_codec_blocksize - return the optimal block size
 *------------------------------------------------------
 */

static uint32_t flac_codec_blocksize(uint32_t bytes)
{
	/* determine FLAC block size, which must be 16-65535
	 * clamp to 2k since that's supposed to be the sweet spot */
	uint32_t blocksize = bytes / 4;
	while (blocksize > 2048)
		blocksize /= 2;
	return blocksize;
}

chd_error flac_codec_init(void *codec, uint32_t hunkbytes)
{
	uint16_t native_endian = 0;
	flac_codec_data *flac = (flac_codec_data*)codec;

	/* make sure the CHD's hunk size is an even multiple of the sample size */
	if (hunkbytes % 4 != 0)
		return CHDERR_CODEC_ERROR;

	/* determine whether we want native or swapped samples */
	*(uint8_t *)(&native_endian) = 1;
	flac->native_endian = (native_endian & 1);

	/* flac decoder init */
	if (flac_decoder_init(&flac->decoder))
		return CHDERR_OUT_OF_MEMORY;

	return CHDERR_NONE;
}

void flac_codec_free(void *codec)
{
	flac_codec_data *flac = (flac_codec_data*)codec;
	flac_decoder_free(&flac->decoder);
}

chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	flac_codec_data *flac = (flac_codec_data*)codec;
	int swap_endian;

	if (src[0] == 'L')
		swap_endian = !flac->native_endian;
	else if (src[0] == 'B')
		swap_endian = flac->native_endian;
	else
		return CHDERR_DECOMPRESSION_ERROR;

	if (!flac_decoder_reset(&flac->decoder, 44100, 2, flac_codec_blocksize(destlen), src + 1, complen - 1))
		return CHDERR_DECOMPRESSION_ERROR;
	if (!flac_decoder_decode_interleaved(&flac->decoder, (int16_t *)(dest), destlen/4, swap_endian))
		return CHDERR_DECOMPRESSION_ERROR;
	flac_decoder_finish(&flac->decoder);

	return CHDERR_NONE;
}

static uint32_t cdfl_codec_blocksize(uint32_t bytes)
{
	/* for CDs it seems that CD_MAX_SECTOR_DATA is the right target */
	uint32_t blocksize = bytes / 4;
	while (blocksize > CD_MAX_SECTOR_DATA)
		blocksize /= 2;
	return blocksize;
}

chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
{
#ifdef WANT_SUBCODE
	chd_error ret;
#endif
	uint16_t native_endian = 0;
	cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;

	/* make sure the CHD's hunk size is an even multiple of the frame size */
	if (hunkbytes % CD_FRAME_SIZE != 0)
		return CHDERR_CODEC_ERROR;

	cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
	if (cdfl->buffer == NULL)
		return CHDERR_OUT_OF_MEMORY;

	/* determine whether we want native or swapped samples */
	*(uint8_t *)(&native_endian) = 1;
	cdfl->swap_endian = (native_endian & 1);

#ifdef WANT_SUBCODE
	/* init zlib inflater */
	ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#endif

	/* flac decoder init */
	if (flac_decoder_init(&cdfl->decoder))
		return CHDERR_OUT_OF_MEMORY;

	return CHDERR_NONE;
}

void cdfl_codec_free(void *codec)
{
	cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
	flac_decoder_free(&cdfl->decoder);
#ifdef WANT_SUBCODE
	zlib_codec_free(&cdfl->subcode_decompressor);
#endif
	if (cdfl->buffer)
		free(cdfl->buffer);
}

chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t framenum;
	uint8_t *buffer;
#ifdef WANT_SUBCODE
	uint32_t offset;
	chd_error ret;
#endif
	cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;

	/* reset and decode */
	uint32_t frames = destlen / CD_FRAME_SIZE;

	if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
		return CHDERR_DECOMPRESSION_ERROR;
	buffer = &cdfl->buffer[0];
	if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
		return CHDERR_DECOMPRESSION_ERROR;

#ifdef WANT_SUBCODE
	/* inflate the subcode data */
	offset = flac_decoder_finish(&cdfl->decoder);
	ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#else
	flac_decoder_finish(&cdfl->decoder);
#endif

	/* reassemble the data */
	for (framenum = 0; framenum < frames; framenum++)
	{
		memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
		memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
#endif
	}

	return CHDERR_NONE;
}

./include/libretro-common/formats/libchdr/libchdr_huffman.c

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
****************************************************************************

    huffman.c

    Static Huffman compression and decompression helpers.

****************************************************************************

    Maximum codelength is officially (alphabetsize - 1). This would be 255 bits
    (since we use 1 byte values). However, it is also dependent upon the number
    of samples used, as follows:

         2 bits -> 3..4 samples
         3 bits -> 5..7 samples
         4 bits -> 8..12 samples
         5 bits -> 13..20 samples
         6 bits -> 21..33 samples
         7 bits -> 34..54 samples
         8 bits -> 55..88 samples
         9 bits -> 89..143 samples
        10 bits -> 144..232 samples
        11 bits -> 233..376 samples
        12 bits -> 377..609 samples
        13 bits -> 610..986 samples
        14 bits -> 987..1596 samples
        15 bits -> 1597..2583 samples
        16 bits -> 2584..4180 samples   -> note that a 4k data size guarantees codelength <= 16 bits
        17 bits -> 4181..6764 samples
        18 bits -> 6765..10945 samples
        19 bits -> 10946..17710 samples
        20 bits -> 17711..28656 samples
        21 bits -> 28657..46367 samples
        22 bits -> 46368..75024 samples
        23 bits -> 75025..121392 samples
        24 bits -> 121393..196417 samples
        25 bits -> 196418..317810 samples
        26 bits -> 317811..514228 samples
        27 bits -> 514229..832039 samples
        28 bits -> 832040..1346268 samples
        29 bits -> 1346269..2178308 samples
        30 bits -> 2178309..3524577 samples
        31 bits -> 3524578..5702886 samples
        32 bits -> 5702887..9227464 samples

    Looking at it differently, here is where powers of 2 fall into these buckets:

          256 samples -> 11 bits max
          512 samples -> 12 bits max
           1k samples -> 14 bits max
           2k samples -> 15 bits max
           4k samples -> 16 bits max
           8k samples -> 18 bits max
          16k samples -> 19 bits max
          32k samples -> 21 bits max
          64k samples -> 22 bits max
         128k samples -> 24 bits max
         256k samples -> 25 bits max
         512k samples -> 27 bits max
           1M samples -> 28 bits max
           2M samples -> 29 bits max
           4M samples -> 31 bits max
           8M samples -> 32 bits max

****************************************************************************

    Delta-RLE encoding works as follows:

    Starting value is assumed to be 0. All data is encoded as a delta
    from the previous value, such that final[i] = final[i - 1] + delta.
    Long runs of 0s are RLE-encoded as follows:

        0x100 = repeat count of 8
        0x101 = repeat count of 9
        0x102 = repeat count of 10
        0x103 = repeat count of 11
        0x104 = repeat count of 12
        0x105 = repeat count of 13
        0x106 = repeat count of 14
        0x107 = repeat count of 15
        0x108 = repeat count of 16
        0x109 = repeat count of 32
        0x10a = repeat count of 64
        0x10b = repeat count of 128
        0x10c = repeat count of 256
        0x10d = repeat count of 512
        0x10e = repeat count of 1024
        0x10f = repeat count of 2048

    Note that repeat counts are reset at the end of a row, so if a 0 run
    extends to the end of a row, a large repeat count may be used.

    The reason for starting the run counts at 8 is that 0 is expected to
    be the most common symbol, and is typically encoded in 1 or 2 bits.

***************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <libchdr/huffman.h>
#include <libchdr/minmax.h>

/***************************************************************************
 *  MACROS
 ***************************************************************************
 */

#define MAKE_LOOKUP(code,bits)  (((code) << 5) | ((bits) & 0x1f))

/***************************************************************************
 *  IMPLEMENTATION
 ***************************************************************************
 */

/*-------------------------------------------------
 *  huffman_context_base - create an encoding/
 *  decoding context
 *-------------------------------------------------
 */

struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
{
	struct huffman_decoder* decoder = NULL;

	/* limit to 24 bits */
	if (maxbits > 24)
		return NULL;

	decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));
	decoder->numcodes = numcodes;
	decoder->maxbits = maxbits;
	decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));
	decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);
	decoder->datahisto = NULL;
	decoder->prevdata = 0;
	decoder->rleremaining = 0;
	return decoder;
}

void delete_huffman_decoder(struct huffman_decoder* decoder)
{
	if (decoder != NULL)
	{
		if (decoder->lookup != NULL)
			free(decoder->lookup);
		if (decoder->huffnode != NULL)
			free(decoder->huffnode);
		free(decoder);
	}
}

/*-------------------------------------------------
 *  decode_one - decode a single code from the
 *  huffman stream
 *-------------------------------------------------
 */

uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{
	/* peek ahead to get maxbits worth of data */
	uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);

	/* look it up, then remove the actual number of bits for this code */
	lookup_value lookup = decoder->lookup[bits];
	bitstream_remove(bitbuf, lookup & 0x1f);

	/* return the value */
	return lookup >> 5;
}

/*-------------------------------------------------
 *  import_tree_rle - import an RLE-encoded
 *  huffman tree from a source data stream
 *-------------------------------------------------
 */

enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{
	int numbits;
	uint32_t curnode;
	enum huffman_error error;

	/* bits per entry depends on the maxbits */
	if (decoder->maxbits >= 16)
		numbits = 5;
	else if (decoder->maxbits >= 8)
		numbits = 4;
	else
		numbits = 3;

	/* loop until we read all the nodes */
	for (curnode = 0; curnode < decoder->numcodes; )
	{
		/* a non-one value is just raw */
		int nodebits = bitstream_read(bitbuf, numbits);
		if (nodebits != 1)
			decoder->huffnode[curnode++].numbits = nodebits;

		/* a one value is an escape code */
		else
		{
			/* a double 1 is just a single 1 */
			nodebits = bitstream_read(bitbuf, numbits);
			if (nodebits == 1)
				decoder->huffnode[curnode++].numbits = nodebits;

			/* otherwise, we need one for value for the repeat count */
			else
			{
				int repcount = bitstream_read(bitbuf, numbits) + 3;
				if (repcount + curnode > decoder->numcodes)
					return HUFFERR_INVALID_DATA;
				while (repcount--)
					decoder->huffnode[curnode++].numbits = nodebits;
			}
		}
	}

	/* make sure we ended up with the right number */
	if (curnode != decoder->numcodes)
		return HUFFERR_INVALID_DATA;

	/* assign canonical codes for all nodes based on their code lengths */
	error = huffman_assign_canonical_codes(decoder);
	if (error != HUFFERR_NONE)
		return error;

	/* build the lookup table */
	huffman_build_lookup_table(decoder);

	/* determine final input length and report errors */
	return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}


/*-------------------------------------------------
 *  import_tree_huffman - import a huffman-encoded
 *  huffman tree from a source data stream
 *-------------------------------------------------
 */

enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{
	int start;
	int last = 0;
	int count = 0;
	int index;
	uint32_t curcode;
	uint8_t rlefullbits = 0;
	uint32_t temp;
	enum huffman_error error;
	/* start by parsing the lengths for the small tree */
	struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
	smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
	start = bitstream_read(bitbuf, 3) + 1;
	for (index = 1; index < 24; index++)
	{
		if (index < start || count == 7)
			smallhuff->huffnode[index].numbits = 0;
		else
		{
			count = bitstream_read(bitbuf, 3);
			smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count;
		}
	}

	/* then regenerate the tree */
	error = huffman_assign_canonical_codes(smallhuff);
	if (error != HUFFERR_NONE)
		return error;
	huffman_build_lookup_table(smallhuff);

	/* determine the maximum length of an RLE count */
	temp = decoder->numcodes - 9;
	while (temp != 0)
		temp >>= 1, rlefullbits++;

	/* now process the rest of the data */
	for (curcode = 0; curcode < decoder->numcodes; )
	{
		int value = huffman_decode_one(smallhuff, bitbuf);
		if (value != 0)
			decoder->huffnode[curcode++].numbits = last = value - 1;
		else
		{
			int count = bitstream_read(bitbuf, 3) + 2;
			if (count == 7+2)
				count += bitstream_read(bitbuf, rlefullbits);
			for ( ; count != 0 && curcode < decoder->numcodes; count--)
				decoder->huffnode[curcode++].numbits = last;
		}
	}

    /* make sure we free the local huffman decoder */
    delete_huffman_decoder(smallhuff);

	/* make sure we ended up with the right number */
	if (curcode != decoder->numcodes)
		return HUFFERR_INVALID_DATA;

	/* assign canonical codes for all nodes based on their code lengths */
	error = huffman_assign_canonical_codes(decoder);
	if (error != HUFFERR_NONE)
		return error;

	/* build the lookup table */
	huffman_build_lookup_table(decoder);

	/* determine final input length and report errors */
	return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}

/*-------------------------------------------------
 *  compute_tree_from_histo - common backend for
 *  computing a tree based on the data histogram
 *-------------------------------------------------
 */

enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
{
	uint32_t i;
	uint32_t lowerweight;
	uint32_t upperweight;
	/* compute the number of data items in the histogram */
	uint32_t sdatacount = 0;
	for (i = 0; i < decoder->numcodes; i++)
		sdatacount += decoder->datahisto[i];

	/* binary search to achieve the optimum encoding */
	lowerweight = 0;
	upperweight = sdatacount * 2;
	while (1)
	{
		/* build a tree using the current weight */
		uint32_t curweight = (upperweight + lowerweight) / 2;
		int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);

		/* apply binary search here */
		if (curmaxbits <= decoder->maxbits)
		{
			lowerweight = curweight;

			/* early out if it worked with the raw weights, or if we're done searching */
			if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
				break;
		}
		else
			upperweight = curweight;
	}

	/* assign canonical codes for all nodes based on their code lengths */
	return huffman_assign_canonical_codes(decoder);
}

/***************************************************************************
 *  INTERNAL FUNCTIONS
 ***************************************************************************
 */

/*-------------------------------------------------
 *  tree_node_compare - compare two tree nodes
 *  by weight
 *-------------------------------------------------
 */

static int huffman_tree_node_compare(const void *item1, const void *item2)
{
	const struct node_t *node1 = *(const struct node_t **)item1;
	const struct node_t *node2 = *(const struct node_t **)item2;
	if (node2->weight != node1->weight)
		return node2->weight - node1->weight;
	if (node2->bits - node1->bits == 0)
		fprintf(stderr, "identical node sort keys, should not happen!\n");
	return (int)node1->bits - (int)node2->bits;
}

/*-------------------------------------------------
 *  build_tree - build a huffman tree based on the
 *  data distribution
 *-------------------------------------------------
 */

int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
{
	uint32_t curcode;
	int nextalloc;
	int listitems = 0;
	int maxbits = 0;
	/* make a list of all non-zero nodes */
	struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);
	memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));
	for (curcode = 0; curcode < decoder->numcodes; curcode++)
		if (decoder->datahisto[curcode] != 0)
		{
			list[listitems++] = &decoder->huffnode[curcode];
			decoder->huffnode[curcode].count = decoder->datahisto[curcode];
			decoder->huffnode[curcode].bits = curcode;

			/* scale the weight by the current effective length, ensuring we don't go to 0 */
			decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
			if (decoder->huffnode[curcode].weight == 0)
				decoder->huffnode[curcode].weight = 1;
		}

#if 0
        fprintf(stderr, "Pre-sort:\n");
        for (int i = 0; i < listitems; i++) {
            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
        }
#endif

	/* sort the list by weight, largest weight first */
	qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);

#if 0
        fprintf(stderr, "Post-sort:\n");
        for (int i = 0; i < listitems; i++) {
            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
        }
        fprintf(stderr, "===================\n");
#endif

	/* now build the tree */
	nextalloc = decoder->numcodes;
	while (listitems > 1)
	{
		int curitem;
		/* remove lowest two items */
		struct node_t* node1 = &(*list[--listitems]);
		struct node_t* node0 = &(*list[--listitems]);

		/* create new node */
		struct node_t* newnode = &decoder->huffnode[nextalloc++];
		newnode->parent = NULL;
		node0->parent = node1->parent = newnode;
		newnode->weight = node0->weight + node1->weight;

		/* insert into list at appropriate location */
		for (curitem = 0; curitem < listitems; curitem++)
			if (newnode->weight > list[curitem]->weight)
			{
				memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0]));
				break;
			}
		list[curitem] = newnode;
		listitems++;
	}

	/* compute the number of bits in each code, and fill in another histogram */
	for (curcode = 0; curcode < decoder->numcodes; curcode++)
	{
		struct node_t *curnode;
		struct node_t* node = &decoder->huffnode[curcode];
		node->numbits = 0;
		node->bits = 0;

		/* if we have a non-zero weight, compute the number of bits */
		if (node->weight > 0)
		{
			/* determine the number of bits for this node */
			for (curnode = node; curnode->parent != NULL; curnode = curnode->parent)
				node->numbits++;
			if (node->numbits == 0)
				node->numbits = 1;

			/* keep track of the max */
			maxbits = MAX(maxbits, ((int)node->numbits));
		}
	}
	return maxbits;
}

/*-------------------------------------------------
 *  assign_canonical_codes - assign canonical codes
 *  to all the nodes based on the number of bits
 *  in each
 *-------------------------------------------------
 */

enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
{
	uint32_t curcode;
	int codelen;
	uint32_t curstart = 0;
	/* build up a histogram of bit lengths */
	uint32_t bithisto[33] = { 0 };
	for (curcode = 0; curcode < decoder->numcodes; curcode++)
	{
		struct node_t* node = &decoder->huffnode[curcode];
		if (node->numbits > decoder->maxbits)
			return HUFFERR_INTERNAL_INCONSISTENCY;
		if (node->numbits <= 32)
			bithisto[node->numbits]++;
	}

	/* for each code length, determine the starting code number */
	for (codelen = 32; codelen > 0; codelen--)
	{
		uint32_t nextstart = (curstart + bithisto[codelen]) >> 1;
		if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))
			return HUFFERR_INTERNAL_INCONSISTENCY;
		bithisto[codelen] = curstart;
		curstart = nextstart;
	}

	/* now assign canonical codes */
	for (curcode = 0; curcode < decoder->numcodes; curcode++)
	{
		struct node_t* node = &decoder->huffnode[curcode];
		if (node->numbits > 0)
			node->bits = bithisto[node->numbits]++;
	}
	return HUFFERR_NONE;
}

/*-------------------------------------------------
 *  build_lookup_table - build a lookup table for
 *  fast decoding
 *-------------------------------------------------
 */

void huffman_build_lookup_table(struct huffman_decoder* decoder)
{
	uint32_t curcode;
	/* iterate over all codes */
	for (curcode = 0; curcode < decoder->numcodes; curcode++)
	{
		/* process all nodes which have non-zero bits */
		struct node_t* node = &decoder->huffnode[curcode];
		if (node->numbits > 0)
		{
         int shift;
         lookup_value *dest;
         lookup_value *destend;
			/* set up the entry */
			lookup_value value = MAKE_LOOKUP(curcode, node->numbits);

			/* fill all matching entries */
			shift = decoder->maxbits - node->numbits;
			dest = &decoder->lookup[node->bits << shift];
			destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
			while (dest <= destend)
				*dest++ = value;
		}
	}
}

./include/libretro-common/formats/libchdr/libchdr_lzma.c

/***************************************************************************

    libchdr_lzma_codec.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include <libchdr/chd.h>
#include <libchdr/minmax.h>
#include <libchdr/cdrom.h>
#include <libchdr/huffman.h>
#include <libchdr/lzma.h>

#include <retro_inline.h>
#include <streams/file_stream.h>

/***************************************************************************
 *  LZMA ALLOCATOR HELPER
 ***************************************************************************
 */

void *lzma_fast_alloc(void *p, size_t size);
void lzma_fast_free(void *p, void *address);

/*-------------------------------------------------
 *  lzma_allocator_init
 *-------------------------------------------------
 */

static void lzma_allocator_init(void* p)
{
	lzma_allocator *codec = (lzma_allocator *)(p);

	/* reset pointer list */
	memset(codec->allocptr, 0, sizeof(codec->allocptr));
	memset(codec->allocptr2, 0, sizeof(codec->allocptr2));
	codec->Alloc = lzma_fast_alloc;
	codec->Free = lzma_fast_free;
}

/*-------------------------------------------------
 *  lzma_allocator_free
 *-------------------------------------------------
 */

static void lzma_allocator_free(void* p )
{
	int i;
	lzma_allocator *codec = (lzma_allocator *)(p);

	/* free our memory */
	for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
	{
		if (codec->allocptr[i] != NULL)
			free(codec->allocptr[i]);
	}
}

/*-------------------------------------------------
 *  lzma_fast_alloc - fast malloc for lzma, which
 *  allocates and frees memory frequently
 *-------------------------------------------------
 */

/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define LZMA_MIN_ALIGNMENT_BITS 512
#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)

void *lzma_fast_alloc(void *p, size_t size)
{
	int scan;
	uint32_t *addr        = NULL;
	lzma_allocator *codec = (lzma_allocator *)(p);
	uintptr_t vaddr = 0;

	/* compute the size, rounding to the nearest 1k */
	size = (size + 0x3ff) & ~0x3ff;

	/* reuse a hunk if we can */
	for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
	{
		uint32_t *ptr = codec->allocptr[scan];
		if (ptr != NULL && size == *ptr)
		{
			/* set the low bit of the size so we don't match next time */
			*ptr |= 1;

			/* return aligned address of the block */
			return codec->allocptr2[scan];
		}
	}

	/* alloc a new one and put it into the list */
	addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
	if (addr==NULL)
		return NULL;
	for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
	{
		if (codec->allocptr[scan] == NULL)
		{
			/* store block address */
			codec->allocptr[scan] = addr;

			/* compute aligned address, store it */
			vaddr = (uintptr_t)addr;
			vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
			codec->allocptr2[scan] = (uint32_t*)vaddr;
			break;
		}
	}

	/* set the low bit of the size so we don't match next time */
	*addr = size | 1;

	/* return aligned address */
	return (void*)vaddr;
}

/*-------------------------------------------------
 *  lzma_fast_free - fast free for lzma, which
 *  allocates and frees memory frequently
 *-------------------------------------------------
 */

void lzma_fast_free(void *p, void *address)
{
	int scan;
	uint32_t *ptr = NULL;
	lzma_allocator *codec = NULL;

	if (address == NULL)
		return;

	codec = (lzma_allocator *)(p);

	/* find the hunk */
	ptr = (uint32_t *)address;
	for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
	{
		if (ptr == codec->allocptr2[scan])
		{
			/* clear the low bit of the size to allow matches */
			*codec->allocptr[scan] &= ~1;
			return;
		}
	}
}

/***************************************************************************
 *  LZMA DECOMPRESSOR
 ***************************************************************************
 */

/*-------------------------------------------------
 *  lzma_codec_init - constructor
 *-------------------------------------------------
 */

chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
{
	CLzmaEncHandle enc;
	CLzmaEncProps encoder_props;
	Byte decoder_props[LZMA_PROPS_SIZE];
	SizeT props_size;
	lzma_allocator* alloc;
	lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;

	/* construct the decoder */
	LzmaDec_Construct(&lzma_codec->decoder);

	/* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
	 * This code assumes that the current version of the encoder imposes the same requirements on the
	 * decoder as the encoder used to produce the file.  This is not necessarily true.  The format
	 * needs to be changed so the encoder properties are written to the file.

	 * configure the properties like the compressor did */
	LzmaEncProps_Init(&encoder_props);
	encoder_props.level = 9;
	encoder_props.reduceSize = hunkbytes;
	LzmaEncProps_Normalize(&encoder_props);

	/* convert to decoder properties */
	alloc = &lzma_codec->allocator;
	lzma_allocator_init(alloc);
	enc = LzmaEnc_Create((ISzAlloc*)alloc);
	if (!enc)
		return CHDERR_DECOMPRESSION_ERROR;
	if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
	{
		LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
		return CHDERR_DECOMPRESSION_ERROR;
	}
	props_size = sizeof(decoder_props);
	if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
	{
		LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
		return CHDERR_DECOMPRESSION_ERROR;
	}
	LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);

	/* do memory allocations */
	if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
		return CHDERR_DECOMPRESSION_ERROR;

	/* Okay */
	return CHDERR_NONE;
}

/*-------------------------------------------------
 *  lzma_codec_free
 *-------------------------------------------------
 */

void lzma_codec_free(void* codec)
{
	lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;

	/* free memory */
	LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);
	lzma_allocator_free(&lzma_codec->allocator);
}

/*-------------------------------------------------
 *  decompress - decompress data using the LZMA
 *  codec
 *-------------------------------------------------
 */

chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	ELzmaStatus status;
	SRes res;
	SizeT consumedlen, decodedlen;
	/* initialize */
	lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
	LzmaDec_Init(&lzma_codec->decoder);

	/* decode */
	consumedlen = complen;
	decodedlen = destlen;
	res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
	if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
		return CHDERR_DECOMPRESSION_ERROR;
	return CHDERR_NONE;
}

/* cdlz */
chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
{
	chd_error ret;
	cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;

	/* allocate buffer */
	cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
	if (cdlz->buffer == NULL)
		return CHDERR_OUT_OF_MEMORY;

	/* make sure the CHD's hunk size is an even multiple of the frame size */
	ret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
	if (ret != CHDERR_NONE)
		return ret;

#ifdef WANT_SUBCODE
	ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#endif

	if (hunkbytes % CD_FRAME_SIZE != 0)
		return CHDERR_CODEC_ERROR;

	return CHDERR_NONE;
}

void cdlz_codec_free(void* codec)
{
	cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
	free(cdlz->buffer);
	lzma_codec_free(&cdlz->base_decompressor);
#ifdef WANT_SUBCODE
	zlib_codec_free(&cdlz->subcode_decompressor);
#endif
}

chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t framenum;
	cdlz_codec_data* cdlz = (cdlz_codec_data*)codec;

	/* determine header bytes */
	uint32_t frames = destlen / CD_FRAME_SIZE;
	uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
	uint32_t ecc_bytes = (frames + 7) / 8;
	uint32_t header_bytes = ecc_bytes + complen_bytes;

	/* extract compressed length of base */
	uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
	if (complen_bytes > 2)
		complen_base = (complen_base << 8) | src[ecc_bytes + 2];

	/* reset and decode */
	lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
	zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
#endif

	/* reassemble the data */
	for (framenum = 0; framenum < frames; framenum++)
	{
		uint8_t *sector;

		memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
		memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
#endif

#ifdef WANT_RAW_DATA_SECTOR
		/* reconstitute the ECC data and sync header */
		sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
		if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
		{
			const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
			memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
			ecc_generate(sector);
		}
#endif
	}
	return CHDERR_NONE;
}

./include/libretro-common/formats/libchdr/libchdr_zlib.c

/***************************************************************************

    libchdr_zlib.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libchdr/chd.h>
#include <libchdr/minmax.h>
#include <libchdr/cdrom.h>
#include <libchdr/huffman.h>
#include <libchdr/libchdr_zlib.h>
#include <zlib.h>

#include <retro_inline.h>
#include <streams/file_stream.h>

/***************************************************************************
    ZLIB COMPRESSION CODEC
***************************************************************************/

/*-------------------------------------------------
    zlib_codec_init - initialize the ZLIB codec
-------------------------------------------------*/

chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
{
	int zerr;
	chd_error err;
	zlib_codec_data *data = (zlib_codec_data*)codec;

	/* clear the buffers */
	memset(data, 0, sizeof(zlib_codec_data));

	/* init the inflater first */
	data->inflater.next_in = (Bytef *)data;	/* bogus, but that's ok */
	data->inflater.avail_in = 0;
	data->inflater.zalloc = zlib_fast_alloc;
	data->inflater.zfree = zlib_fast_free;
	data->inflater.opaque = &data->allocator;
	zerr = inflateInit2(&data->inflater, -MAX_WBITS);

	/* convert errors */
	if (zerr == Z_MEM_ERROR)
		err = CHDERR_OUT_OF_MEMORY;
	else if (zerr != Z_OK)
		err = CHDERR_CODEC_ERROR;
	else
		err = CHDERR_NONE;

	return err;
}

/*-------------------------------------------------
    zlib_codec_free - free data for the ZLIB
    codec
-------------------------------------------------*/

void zlib_codec_free(void *codec)
{
	zlib_codec_data *data = (zlib_codec_data *)codec;

	/* deinit the streams */
	if (data != NULL)
	{
		inflateEnd(&data->inflater);

		/* free our fast memory */
		zlib_allocator_free(&data->allocator);
	}
}

/*-------------------------------------------------
    zlib_codec_decompress - decompress data using
    the ZLIB codec
-------------------------------------------------*/

chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	zlib_codec_data *data = (zlib_codec_data *)codec;
	int zerr;

	/* reset the decompressor */
	data->inflater.next_in = (Bytef *)src;
	data->inflater.avail_in = complen;
	data->inflater.total_in = 0;
	data->inflater.next_out = (Bytef *)dest;
	data->inflater.avail_out = destlen;
	data->inflater.total_out = 0;
	zerr = inflateReset(&data->inflater);
	if (zerr != Z_OK)
		return CHDERR_DECOMPRESSION_ERROR;

	/* do it */
	zerr = inflate(&data->inflater, Z_FINISH);
	if (data->inflater.total_out != destlen)
		return CHDERR_DECOMPRESSION_ERROR;

	return CHDERR_NONE;
}

/*-------------------------------------------------
    zlib_fast_alloc - fast malloc for ZLIB, which
    allocates and frees memory frequently
-------------------------------------------------*/

/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define ZLIB_MIN_ALIGNMENT_BITS 512
#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)

voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
	zlib_allocator *alloc = (zlib_allocator *)opaque;
	uintptr_t paddr = 0;
	uint32_t *ptr;
	int i;

	/* compute the size, rounding to the nearest 1k */
	size = (size * items + 0x3ff) & ~0x3ff;

	/* reuse a hunk if we can */
	for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
	{
		ptr = alloc->allocptr[i];
		if (ptr && size == *ptr)
		{
			/* set the low bit of the size so we don't match next time */
			*ptr |= 1;

			/* return aligned block address */
			return (voidpf)(alloc->allocptr2[i]);
		}
	}

	/* alloc a new one */
    ptr = (uint32_t *)malloc(size + sizeof(uint32_t) + ZLIB_MIN_ALIGNMENT_BYTES);
	if (!ptr)
		return NULL;

	/* put it into the list */
	for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
		if (!alloc->allocptr[i])
		{
			alloc->allocptr[i] = ptr;
			paddr = (((uintptr_t)ptr) + sizeof(uint32_t) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
			alloc->allocptr2[i] = (uint32_t*)paddr;
			break;
		}

	/* set the low bit of the size so we don't match next time */
	*ptr = size | 1;

	/* return aligned block address */
	return (voidpf)paddr;
}

/*-------------------------------------------------
    zlib_fast_free - fast free for ZLIB, which
    allocates and frees memory frequently
-------------------------------------------------*/

void zlib_fast_free(voidpf opaque, voidpf address)
{
	zlib_allocator *alloc = (zlib_allocator *)opaque;
	uint32_t *ptr = (uint32_t *)address;
	int i;

	/* find the hunk */
	for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
		if (ptr == alloc->allocptr2[i])
		{
			/* clear the low bit of the size to allow matches */
			*(alloc->allocptr[i]) &= ~1;
			return;
		}
}

/*-------------------------------------------------
    zlib_allocator_free
-------------------------------------------------*/
void zlib_allocator_free(voidpf opaque)
{
	zlib_allocator *alloc = (zlib_allocator *)opaque;
	int i;

	for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
		if (alloc->allocptr[i])
			free(alloc->allocptr[i]);
}


/* cdzl */

chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
{
	chd_error ret;
	cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;

	/* make sure the CHD's hunk size is an even multiple of the frame size */
	if (hunkbytes % CD_FRAME_SIZE != 0)
		return CHDERR_CODEC_ERROR;

	cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
	if (cdzl->buffer == NULL)
		return CHDERR_OUT_OF_MEMORY;

	ret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
	if (ret != CHDERR_NONE)
		return ret;

#ifdef WANT_SUBCODE
	ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#endif

	return CHDERR_NONE;
}

void cdzl_codec_free(void *codec)
{
	cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
	zlib_codec_free(&cdzl->base_decompressor);
#ifdef WANT_SUBCODE
	zlib_codec_free(&cdzl->subcode_decompressor);
#endif
	free(cdzl->buffer);
}

chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t framenum;
	cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;

	/* determine header bytes */
	uint32_t frames = destlen / CD_FRAME_SIZE;
	uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
	uint32_t ecc_bytes = (frames + 7) / 8;
	uint32_t header_bytes = ecc_bytes + complen_bytes;

	/* extract compressed length of base */
	uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
	if (complen_bytes > 2)
		complen_base = (complen_base << 8) | src[ecc_bytes + 2];

	/* reset and decode */
	zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
	zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
#endif

	/* reassemble the data */
	for (framenum = 0; framenum < frames; framenum++)
	{
		uint8_t *sector;

		memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
		memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
#endif

#ifdef WANT_RAW_DATA_SECTOR
		/* reconstitute the ECC data and sync header */
		sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
		if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
		{
			const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
			memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
			ecc_generate(sector);
		}
#endif
	}
	return CHDERR_NONE;
}

./include/libretro-common/formats/logiqx_dat/logiqx_dat.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (logiqx_dat.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <file/file_path.h>
#include <string/stdstring.h>
#include <formats/rxml.h>

#include <formats/logiqx_dat.h>

/* Holds all internal DAT file data */
struct logiqx_dat
{
   rxml_document_t *data;
   rxml_node_t *current_node;
};

/* List of HTML formatting codes that must
 * be replaced when parsing XML data */
const char *logiqx_dat_html_code_list[][2] = {
   {"&amp;",  "&"},
   {"&apos;", "'"},
   {"&gt;",   ">"},
   {"&lt;",   "<"},
   {"&quot;", "\""}
};

#define LOGIQX_DAT_HTML_CODE_LIST_SIZE 5

/* Validation */

/* Performs rudimentary validation of the specified
 * Logiqx XML DAT file path (not rigorous - just
 * enough to prevent obvious errors).
 * Also provides access to file size (DAT files can
 * be very large, so it is useful to have this information
 * on hand - i.e. so we can check that the system has
 * enough free memory to load the file). */
bool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size)
{
   const char *file_ext = NULL;
   int32_t file_size_int;

   if (string_is_empty(path))
      return false;

   /* Check file extension */
   file_ext = path_get_extension(path);

   if (string_is_empty(file_ext))
      return false;

   if (!string_is_equal_noncase(file_ext, "dat") &&
       !string_is_equal_noncase(file_ext, "xml"))
      return false;

   /* Ensure file exists */
   if (!path_is_valid(path))
      return false;

   /* Get file size */
   file_size_int = path_get_size(path);

   if (file_size_int <= 0)
      return false;

   if (file_size)
      *file_size = (uint64_t)file_size_int;

   return true;
}

/* File initialisation/de-initialisation */

/* Loads specified Logiqx XML DAT file from disk.
 * Returned logiqx_dat_t object must be free'd using
 * logiqx_dat_free().
 * Returns NULL if file is invalid or a read error
 * occurs. */
logiqx_dat_t *logiqx_dat_init(const char *path)
{
   logiqx_dat_t *dat_file = NULL;
   rxml_node_t *root_node = NULL;

   /* Check file path */
   if (!logiqx_dat_path_is_valid(path, NULL))
      goto error;

   /* Create logiqx_dat_t object */
   dat_file = (logiqx_dat_t*)calloc(1, sizeof(*dat_file));

   if (!dat_file)
      goto error;

   /* Read file from disk */
   dat_file->data = rxml_load_document(path);

   if (!dat_file->data)
      goto error;

   /* Ensure root node has the correct name */
   root_node = rxml_root_node(dat_file->data);

   if (!root_node)
      goto error;

   if (string_is_empty(root_node->name))
      goto error;

   /* > Logiqx XML uses:           'datafile'
    * > MAME List XML uses:        'mame'
    * > MAME 'Software List' uses: 'softwarelist' */
   if (!string_is_equal(root_node->name, "datafile") &&
       !string_is_equal(root_node->name, "mame") &&
       !string_is_equal(root_node->name, "softwarelist"))
      goto error;

   /* Get pointer to initial child node */
   dat_file->current_node = root_node->children;

   if (!dat_file->current_node)
      goto error;

   /* All is well - return logiqx_dat_t object */
   return dat_file;

error:
   logiqx_dat_free(dat_file);
   return NULL;
}

/* Frees specified DAT file */
void logiqx_dat_free(logiqx_dat_t *dat_file)
{
   if (!dat_file)
      return;

   dat_file->current_node = NULL;

   if (dat_file->data)
   {
      rxml_free_document(dat_file->data);
      dat_file->data = NULL;
   }

   free(dat_file);
   dat_file = NULL;
}

/* Game information access */

/* Returns true if specified node is a 'game' entry */
static bool logiqx_dat_is_game_node(rxml_node_t *node)
{
   const char *node_name = NULL;

   if (!node)
      return false;

   /* Check node name */
   node_name = node->name;

   if (string_is_empty(node_name))
      return false;

   /* > Logiqx XML uses:           'game'
    * > MAME List XML uses:        'machine'
    * > MAME 'Software List' uses: 'software' */
   return string_is_equal(node_name, "game") ||
          string_is_equal(node_name, "machine") ||
          string_is_equal(node_name, "software");
}

/* Returns true if specified node is a game
 * node containing information for a game with
 * the specified name */
static bool logiqx_dat_game_node_matches_name(
      rxml_node_t *node, const char *game_name)
{
   const char *node_game_name = NULL;

   if (!logiqx_dat_is_game_node(node) ||
       string_is_empty(game_name))
      return false;

   /* Get 'name' attribute of XML node */
   node_game_name = rxml_node_attrib(node, "name");

   if (string_is_empty(node_game_name))
      return false;

   return string_is_equal(node_game_name, game_name);
}

/* The XML element data strings returned from
 * DAT files are very 'messy'. This function
 * removes all cruft, replaces formatting strings
 * and copies the result (if valid) to 'str' */
static void logiqx_dat_sanitise_element_data(
      const char *data, char *str, size_t len)
{
   char sanitised_data[PATH_MAX_LENGTH];
   size_t i;

   sanitised_data[0] = '\0';

   if (string_is_empty(data))
      return;

   strlcpy(sanitised_data, data, sizeof(sanitised_data));

   /* Element data includes leading/trailing
    * newline characters - trim them away */
   string_trim_whitespace_right(sanitised_data);
   string_trim_whitespace_left(sanitised_data);

   if (string_is_empty(sanitised_data))
      return;

   /* XML has a number of special characters that
    * are handled using a HTML formatting codes.
    * All of these have to be replaced...
    * &amp;  -> &
    * &apos; -> '
    * &gt;   -> >
    * &lt;   -> <
    * &quot; -> "
    */
   for (i = 0; i < LOGIQX_DAT_HTML_CODE_LIST_SIZE; i++)
   {
      const char *find_string    = logiqx_dat_html_code_list[i][0];
      const char *replace_string = logiqx_dat_html_code_list[i][1];

      /* string_replace_substring() is expensive
       * > only invoke if element string contains
       *   HTML code */
      if (strstr(sanitised_data, find_string))
      {
         char *tmp = string_replace_substring(
               sanitised_data, strlen(sanitised_data),
               find_string,    strlen(find_string),
               replace_string, strlen(replace_string));

         if (!string_is_empty(tmp))
            strlcpy(sanitised_data, tmp, sizeof(sanitised_data));

         if (tmp)
            free(tmp);
      }
   }

   if (string_is_empty(sanitised_data))
      return;

   /* All is well - can copy result */
   strlcpy(str, sanitised_data, len);
}

/* Extracts game information from specified node.
 * Returns false if node is invalid */
static bool logiqx_dat_parse_game_node(
      rxml_node_t *node, logiqx_dat_game_info_t *game_info)
{
   const char *game_name   = NULL;
   const char *is_bios     = NULL;
   const char *is_runnable = NULL;
   rxml_node_t *info_node  = NULL;
   bool description_found  = false;
   bool year_found         = false;
   bool manufacturer_found = false;

   if (!logiqx_dat_is_game_node(node))
      return false;

   if (!game_info)
      return false;

   /* Initialise logiqx_dat_game_info_t object */
   game_info->name[0]         = '\0';
   game_info->description[0]  = '\0';
   game_info->year[0]         = '\0';
   game_info->manufacturer[0] = '\0';
   game_info->is_bios         = false;
   game_info->is_runnable     = true;

   /* Get game name */
   game_name = rxml_node_attrib(node, "name");

   if (!string_is_empty(game_name))
      strlcpy(game_info->name, game_name, sizeof(game_info->name));

   /* Get 'is bios' status */
   is_bios = rxml_node_attrib(node, "isbios");

   if (!string_is_empty(is_bios))
      game_info->is_bios = string_is_equal(is_bios, "yes");

   /* Get 'is runnable' status
    * > Note: This attribute only exists in MAME List
    *   XML files, but there is no harm in checking for
    *   it generally. For normal Logiqx XML files,
    *   'is runnable' is just the inverse of 'is bios' */
   is_runnable = rxml_node_attrib(node, "runnable");

   if (!string_is_empty(is_runnable))
      game_info->is_runnable = string_is_equal(is_runnable, "yes");
   else
      game_info->is_runnable = !game_info->is_bios;

   /* Loop over all game info nodes */
   for (info_node = node->children; info_node; info_node = info_node->next)
   {
      const char *info_node_name = info_node->name;
      const char *info_node_data = info_node->data;

      if (string_is_empty(info_node_name))
         continue;

      /* Check description */
      if (string_is_equal(info_node_name, "description"))
      {
         logiqx_dat_sanitise_element_data(
            info_node_data, game_info->description,
            sizeof(game_info->description));
         description_found = true;
      }
      /* Check year */
      else if (string_is_equal(info_node_name, "year"))
      {
         logiqx_dat_sanitise_element_data(
            info_node_data, game_info->year,
            sizeof(game_info->year));
         year_found = true;
      }
      /* Check manufacturer */
      else if (string_is_equal(info_node_name, "manufacturer"))
      {
         logiqx_dat_sanitise_element_data(
            info_node_data, game_info->manufacturer,
            sizeof(game_info->manufacturer));
         manufacturer_found = true;
      }

      /* If all required entries have been found,
       * can end loop */
      if (description_found && year_found && manufacturer_found)
         break;
   }

   return true;
}

/* Sets/resets internal node pointer to the first
 * entry in the DAT file */
void logiqx_dat_set_first(logiqx_dat_t *dat_file)
{
   rxml_node_t *root_node = NULL;

   if (!dat_file)
      return;

   if (!dat_file->data)
      return;

   /* Get root node */
   root_node = rxml_root_node(dat_file->data);

   if (!root_node)
   {
      dat_file->current_node = NULL;
      return;
   }

   /* Get pointer to initial child node */
   dat_file->current_node = root_node->children;
}

/* Fetches game information for the current entry
 * in the DAT file and increments the internal node
 * pointer.
 * Returns false if the end of the DAT file has been
 * reached (in which case 'game_info' will be invalid) */
bool logiqx_dat_get_next(
      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info)
{
   if (!dat_file || !game_info)
      return false;

   if (!dat_file->data)
      return false;

   while (dat_file->current_node)
   {
      rxml_node_t *current_node = dat_file->current_node;

      /* Whatever happens, internal node pointer must
       * be 'incremented' */
      dat_file->current_node = dat_file->current_node->next;

      /* If this is a game node, extract info
       * and return */
      if (logiqx_dat_is_game_node(current_node))
         return logiqx_dat_parse_game_node(current_node, game_info);
   }

   return false;
}

/* Fetches information for the specified game.
 * Returns false if game does not exist, or arguments
 * are invalid. */
bool logiqx_dat_search(
      logiqx_dat_t *dat_file, const char *game_name,
      logiqx_dat_game_info_t *game_info)
{
   rxml_node_t *root_node = NULL;
   rxml_node_t *game_node = NULL;

   if (!dat_file || !game_info || string_is_empty(game_name))
      return false;

   if (!dat_file->data)
      return false;

   /* Get root node */
   root_node = rxml_root_node(dat_file->data);

   if (!root_node)
      return false;

   /* Loop over all child nodes of the DAT file */
   for (game_node = root_node->children; game_node; game_node = game_node->next)
   {
      /* If this is the requested game, fetch info and return */
      if (logiqx_dat_game_node_matches_name(game_node, game_name))
         return logiqx_dat_parse_game_node(game_node, game_info);
   }

   return false;
}

./include/libretro-common/formats/m3u/m3u_file.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (m3u_file.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <retro_miscellaneous.h>

#include <string/stdstring.h>
#include <lists/string_list.h>
#include <file/file_path.h>
#include <streams/file_stream.h>
#include <array/rbuf.h>

#include <formats/m3u_file.h>

/* We parse the following types of entry label:
 * - '#LABEL:<label>' non-standard, but used by
 *   some cores
 * - '#EXTINF:<runtime>,<label>' standard extended
 *   M3U directive
 * - '<content path>|<label>' non-standard, but
 *   used by some cores
 * All other comments/directives are ignored */
#define M3U_FILE_COMMENT            '#'
#define M3U_FILE_NONSTD_LABEL       "#LABEL:"
#define M3U_FILE_EXTSTD_LABEL       "#EXTINF:"
#define M3U_FILE_EXTSTD_LABEL_TOKEN ','
#define M3U_FILE_RETRO_LABEL_TOKEN  '|'

/* Holds all internal M3U file data
 * > Note the awkward name: 'content_m3u_file'
 *   If we used just 'm3u_file' here, it would
 *   lead to conflicts elsewhere... */
struct content_m3u_file
{
   char *path;
   m3u_file_entry_t *entries;
};

/* File Initialisation / De-Initialisation */

/* Reads M3U file contents from disk
 * - Does nothing if file does not exist
 * - Returns false in the event of an error */
static bool m3u_file_load(m3u_file_t *m3u_file)
{
   size_t i;
   char entry_label[NAME_MAX_LENGTH];
   char entry_path[PATH_MAX_LENGTH];
   const char *file_ext      = NULL;
   int64_t file_len          = 0;
   uint8_t *file_buf         = NULL;
   struct string_list *lines = NULL;
   bool success              = false;

   entry_path[0]  = '\0';
   entry_label[0] = '\0';

   if (!m3u_file)
      goto end;

   /* Check whether file exists
    * > If path is empty, then an error
    *   has occurred... */
   if (string_is_empty(m3u_file->path))
      goto end;

   /* > File must have the correct extension */
   file_ext = path_get_extension(m3u_file->path);

   if (    string_is_empty(file_ext)
       || !string_is_equal_noncase(file_ext, M3U_FILE_EXT))
      goto end;

   /* > If file does not exist, no action
    *   is required */
   if (!path_is_valid(m3u_file->path))
   {
      success = true;
      goto end;
   }

   /* Read file from disk */
   if (filestream_read_file(m3u_file->path, (void**)&file_buf, &file_len) >= 0)
   {
      /* Split file into lines */
      if (file_len > 0)
         lines = string_split((const char*)file_buf, "\n");

      /* File buffer no longer required */
      if (file_buf)
      {
         free(file_buf);
         file_buf = NULL;
      }
   }
   /* File IO error... */
   else
      goto end;

   /* If file was empty, no action is required */
   if (!lines)
   {
      success = true;
      goto end;
   }

   /* Parse lines of file */
   for (i = 0; i < lines->size; i++)
   {
      const char *line = lines->elems[i].data;

      if (string_is_empty(line))
         continue;

      /* Determine line 'type' */

      /* > '#LABEL:' */
      if (string_starts_with_size(line, M3U_FILE_NONSTD_LABEL,
            STRLEN_CONST(M3U_FILE_NONSTD_LABEL)))
      {
         /* Label is the string to the right
          * of '#LABEL:' */
         const char *label = line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL);

         if (!string_is_empty(label))
         {
            strlcpy(
                  entry_label, line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL),
                  sizeof(entry_label));
            string_trim_whitespace_right(entry_label);
            string_trim_whitespace_left(entry_label);
         }
      }
      /* > '#EXTINF:' */
      else if (string_starts_with_size(line, M3U_FILE_EXTSTD_LABEL,
            STRLEN_CONST(M3U_FILE_EXTSTD_LABEL)))
      {
         /* Label is the string to the right
          * of the first comma */
         const char* label_ptr = strchr(
               line + STRLEN_CONST(M3U_FILE_EXTSTD_LABEL),
               M3U_FILE_EXTSTD_LABEL_TOKEN);

         if (!string_is_empty(label_ptr))
         {
            label_ptr++;
            if (!string_is_empty(label_ptr))
            {
               strlcpy(entry_label, label_ptr, sizeof(entry_label));
               string_trim_whitespace_right(entry_label);
               string_trim_whitespace_left(entry_label);
            }
         }
      }
      /* > Ignore other comments/directives */
      else if (line[0] == M3U_FILE_COMMENT)
         continue;
      /* > An actual 'content' line */
      else
      {
         /* This is normally a file name/path, but may
          * have the format <content path>|<label> */
         const char *token_ptr = strchr(line, M3U_FILE_RETRO_LABEL_TOKEN);

         if (token_ptr)
         {
            size_t _len = (size_t)(1 + token_ptr - line);

            /* Get entry_path segment */
            if (_len > 0)
            {
               memset(entry_path, 0, sizeof(entry_path));
               strlcpy(
                     entry_path, line,
                     ((_len < PATH_MAX_LENGTH ?
                       _len : PATH_MAX_LENGTH) * sizeof(char)));
               string_trim_whitespace_right(entry_path);
               string_trim_whitespace_left(entry_path);
            }

            /* Get entry_label segment */
            token_ptr++;
            if (*token_ptr != '\0')
            {
               strlcpy(entry_label, token_ptr, sizeof(entry_label));
               string_trim_whitespace_right(entry_label);
               string_trim_whitespace_left(entry_label);
            }
         }
         else
         {
            /* Just a normal file name/path */
            strlcpy(entry_path, line, sizeof(entry_path));
            string_trim_whitespace_right(entry_path);
            string_trim_whitespace_left(entry_path);
         }

         /* Add entry to file
          * > Note: The only way that m3u_file_add_entry()
          *   can fail here is if we run out of memory.
          *   This is a critical error, and m3u_file must
          *   be considered invalid in this case */
         if (!string_is_empty(entry_path) &&
             !m3u_file_add_entry(m3u_file, entry_path, entry_label))
            goto end;

         /* Reset entry_path/entry_label */
         entry_path[0]  = '\0';
         entry_label[0] = '\0';
      }
   }

   success = true;

end:
   /* Clean up */
   if (lines)
   {
      string_list_free(lines);
      lines = NULL;
   }

   if (file_buf)
   {
      free(file_buf);
      file_buf = NULL;
   }

   return success;
}

/* Creates and initialises an M3U file
 * - If 'path' refers to an existing file,
 *   contents is parsed
 * - If path does not exist, an empty M3U file
 *   is created
 * - Returned m3u_file_t object must be free'd using
 *   m3u_file_free()
 * - Returns NULL in the event of an error */
m3u_file_t *m3u_file_init(const char *path)
{
   m3u_file_t *m3u_file = NULL;
   char m3u_path[PATH_MAX_LENGTH];

   /* Sanity check */
   if (string_is_empty(path))
      return NULL;

   /* Get 'real' file path */
   strlcpy(m3u_path, path, sizeof(m3u_path));
   path_resolve_realpath(m3u_path, sizeof(m3u_path), false);

   if (string_is_empty(m3u_path))
      return NULL;

   /* Create m3u_file_t object */
   if (!(m3u_file = (m3u_file_t*)malloc(sizeof(*m3u_file))))
      return NULL;

   /* Initialise members */
   m3u_file->path    = NULL;
   m3u_file->entries = NULL;

   /* Copy file path */
   m3u_file->path    = strdup(m3u_path);

   /* Read existing file contents from
    * disk, if required */
   if (!m3u_file_load(m3u_file))
   {
      m3u_file_free(m3u_file);
      return NULL;
   }

   return m3u_file;
}

/* Frees specified M3U file entry */
static void m3u_file_free_entry(m3u_file_entry_t *entry)
{
   if (!entry)
      return;

   if (entry->path)
      free(entry->path);

   if (entry->full_path)
      free(entry->full_path);

   if (entry->label)
      free(entry->label);

   entry->path      = NULL;
   entry->full_path = NULL;
   entry->label     = NULL;
}

/* Frees specified M3U file */
void m3u_file_free(m3u_file_t *m3u_file)
{
   size_t i;

   if (!m3u_file)
      return;

   if (m3u_file->path)
      free(m3u_file->path);

   m3u_file->path = NULL;

   /* Free entries */
   if (m3u_file->entries)
   {
      for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
      {
         m3u_file_entry_t *entry = &m3u_file->entries[i];
         m3u_file_free_entry(entry);
      }

      RBUF_FREE(m3u_file->entries);
   }

   free(m3u_file);
}

/* Getters */

/* Returns M3U file path */
char *m3u_file_get_path(m3u_file_t *m3u_file)
{
   if (!m3u_file)
      return NULL;

   return m3u_file->path;
}

/* Returns number of entries in M3U file */
size_t m3u_file_get_size(m3u_file_t *m3u_file)
{
   if (!m3u_file)
      return 0;

   return RBUF_LEN(m3u_file->entries);
}

/* Fetches specified M3U file entry
 * - Returns false if 'idx' is invalid, or internal
 *   entry is NULL */
bool m3u_file_get_entry(
      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry)
{
   if (!m3u_file ||
       !entry ||
       (idx >= RBUF_LEN(m3u_file->entries)))
      return false;

   *entry = &m3u_file->entries[idx];

   if (!*entry)
      return false;

   return true;
}

/* Setters */

/* Adds specified entry to the M3U file
 * - Returns false if path is invalid, or
 *   memory could not be allocated for the
 *   entry */
bool m3u_file_add_entry(
      m3u_file_t *m3u_file, const char *path, const char *label)
{
   m3u_file_entry_t *entry = NULL;
   size_t num_entries;
   char full_path[PATH_MAX_LENGTH];

   full_path[0] = '\0';

   if (!m3u_file || string_is_empty(path))
      return false;

   /* Get current number of file entries */
   num_entries = RBUF_LEN(m3u_file->entries);

   /* Attempt to allocate memory for new entry */
   if (!RBUF_TRYFIT(m3u_file->entries, num_entries + 1))
      return false;

   /* Allocation successful - increment array size */
   RBUF_RESIZE(m3u_file->entries, num_entries + 1);

   /* Fetch entry at end of list, and zero-initialise
    * members */
   entry = &m3u_file->entries[num_entries];
   memset(entry, 0, sizeof(*entry));

   /* Copy path and label */
   entry->path = strdup(path);

   if (!string_is_empty(label))
      entry->label = strdup(label);

   /* Populate 'full_path' field */
   if (path_is_absolute(path))
   {
      strlcpy(full_path, path, sizeof(full_path));
      path_resolve_realpath(full_path, sizeof(full_path), false);
   }
   else
      fill_pathname_resolve_relative(
            full_path, m3u_file->path, path,
            sizeof(full_path));

   /* Handle unforeseen errors... */
   if (string_is_empty(full_path))
   {
      m3u_file_free_entry(entry);
      return false;
   }

   entry->full_path = strdup(full_path);

   return true;
}

/* Removes all entries in M3U file */
void m3u_file_clear(m3u_file_t *m3u_file)
{
   size_t i;

   if (!m3u_file)
      return;

   if (m3u_file->entries)
   {
      for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
      {
         m3u_file_entry_t *entry = &m3u_file->entries[i];
         m3u_file_free_entry(entry);
      }

      RBUF_FREE(m3u_file->entries);
   }
}

/* Saving */

/* Saves M3U file to disk
 * - Setting 'label_type' to M3U_FILE_LABEL_NONE
 *   just outputs entry paths - this the most
 *   common format supported by most cores
 * - Returns false in the event of an error */
bool m3u_file_save(
      m3u_file_t *m3u_file, enum m3u_file_label_type label_type)
{
   size_t i;
   char base_dir[DIR_MAX_LENGTH];
   RFILE *file      = NULL;

   if (!m3u_file || !m3u_file->entries)
      return false;

   /* This should never happen */
   if (string_is_empty(m3u_file->path))
      return false;

   /* Get M3U file base directory */
   if (find_last_slash(m3u_file->path))
      fill_pathname_basedir(base_dir, m3u_file->path, sizeof(base_dir));
   else
      base_dir[0]   = '\0';

   /* Open file for writing */
   if (!(file = filestream_open(m3u_file->path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return false;

   /* Loop over entries */
   for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
   {
      m3u_file_entry_t *entry = &m3u_file->entries[i];
      char entry_path[PATH_MAX_LENGTH];

      entry_path[0] = '\0';

      if (!entry || string_is_empty(entry->full_path))
         continue;

      /* When writing M3U files, entry paths are
       * always relative */
      if (string_is_empty(base_dir))
         strlcpy(
               entry_path, entry->full_path,
               sizeof(entry_path));
      else
         path_relative_to(
               entry_path, entry->full_path, base_dir,
               sizeof(entry_path));

      if (string_is_empty(entry_path))
         continue;

      /* Check if we need to write a label */
      if (!string_is_empty(entry->label))
      {
         switch (label_type)
         {
            case M3U_FILE_LABEL_NONSTD:
               filestream_printf(
                     file, "%s%s\n%s\n",
                     M3U_FILE_NONSTD_LABEL, entry->label,
                     entry_path);
               break;
            case M3U_FILE_LABEL_EXTSTD:
               filestream_printf(
                     file, "%s%c%s\n%s\n",
                     M3U_FILE_EXTSTD_LABEL, M3U_FILE_EXTSTD_LABEL_TOKEN, entry->label,
                     entry_path);
               break;
            case M3U_FILE_LABEL_RETRO:
               filestream_printf(
                     file, "%s%c%s\n",
                     entry_path, M3U_FILE_RETRO_LABEL_TOKEN, entry->label);
               break;
            case M3U_FILE_LABEL_NONE:
            default:
               filestream_printf(
                     file, "%s\n", entry_path);
               break;
         }
      }
      /* No label - just write entry path */
      else
         filestream_printf(
               file, "%s\n", entry_path);
   }

   /* Close file */
   filestream_close(file);

   return true;
}

/* Utilities */

/* Internal qsort function */
static int m3u_file_qsort_func(
      const m3u_file_entry_t *a, const m3u_file_entry_t *b)
{
   if (!a || !b)
      return 0;

   if (string_is_empty(a->full_path) || string_is_empty(b->full_path))
      return 0;

   return strcasecmp(a->full_path, b->full_path);
}

/* Sorts M3U file entries in alphabetical order */
void m3u_file_qsort(m3u_file_t *m3u_file)
{
   size_t num_entries;

   if (!m3u_file)
      return;

   num_entries = RBUF_LEN(m3u_file->entries);

   if (num_entries < 2)
      return;

   qsort(
         m3u_file->entries, num_entries,
         sizeof(m3u_file_entry_t),
         (int (*)(const void *, const void *))m3u_file_qsort_func);
}

/* Returns true if specified path corresponds
 * to an M3U file (simple convenience function) */
bool m3u_file_is_m3u(const char *path)
{
   const char *file_ext = NULL;
   if (string_is_empty(path))
      return false;
   /* Check file extension */
   file_ext = path_get_extension(path);
   if (string_is_empty(file_ext))
      return false;
   if (!string_is_equal_noncase(file_ext, M3U_FILE_EXT))
      return false;
   /* Ensure file exists */
   if (!path_is_valid(path))
      return false;
   /* Ensure we have non-zero file size */
   if (path_get_size(path) <= 0)
      return false;
   return true;
}

./include/libretro-common/formats/png/rpng.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef DEBUG
#include <stdio.h>
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#ifdef GEKKO
#include <malloc.h>
#endif

#include <boolean.h>
#include <formats/image.h>
#include <formats/rpng.h>
#include <streams/trans_stream.h>
#include <string/stdstring.h>

#include "rpng_internal.h"

enum png_ihdr_color_type
{
   PNG_IHDR_COLOR_GRAY       = 0,
   PNG_IHDR_COLOR_RGB        = 2,
   PNG_IHDR_COLOR_PLT        = 3,
   PNG_IHDR_COLOR_GRAY_ALPHA = 4,
   PNG_IHDR_COLOR_RGBA       = 6
};

enum png_line_filter
{
   PNG_FILTER_NONE = 0,
   PNG_FILTER_SUB,
   PNG_FILTER_UP,
   PNG_FILTER_AVERAGE,
   PNG_FILTER_PAETH
};

enum png_chunk_type
{
   PNG_CHUNK_NOOP = 0,
   PNG_CHUNK_ERROR,
   PNG_CHUNK_IHDR,
   PNG_CHUNK_IDAT,
   PNG_CHUNK_PLTE,
   PNG_CHUNK_tRNS,
   PNG_CHUNK_IEND
};

struct adam7_pass
{
   unsigned x;
   unsigned y;
   unsigned stride_x;
   unsigned stride_y;
};

struct idat_buffer
{
   uint8_t *data;
   size_t size;
};

enum rpng_process_flags
{
   RPNG_PROCESS_FLAG_INFLATE_INITIALIZED    = (1 << 0),
   RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED = (1 << 1),
   RPNG_PROCESS_FLAG_PASS_INITIALIZED       = (1 << 2)
};

struct rpng_process
{
   uint32_t *data;
   uint32_t *palette;
   void *stream;
   const struct trans_stream_backend *stream_backend;
   uint8_t *prev_scanline;
   uint8_t *decoded_scanline;
   uint8_t *inflate_buf;
   size_t restore_buf_size;
   size_t adam7_restore_buf_size;
   size_t data_restore_buf_size;
   size_t inflate_buf_size;
   size_t avail_in;
   size_t avail_out;
   size_t total_out;
   size_t pass_size;
   struct png_ihdr ihdr; /* uint32_t alignment */
   unsigned bpp;
   unsigned pitch;
   unsigned h;
   unsigned pass_width;
   unsigned pass_height;
   unsigned pass_pos;
   uint8_t flags;
};

enum rpng_flags
{
   RPNG_FLAG_HAS_IHDR = (1 << 0),
   RPNG_FLAG_HAS_IDAT = (1 << 1),
   RPNG_FLAG_HAS_IEND = (1 << 2),
   RPNG_FLAG_HAS_PLTE = (1 << 3),
   RPNG_FLAG_HAS_TRNS = (1 << 4)
};

struct rpng
{
   struct rpng_process *process;
   uint8_t *buff_data;
   uint8_t *buff_end;
   struct idat_buffer idat_buf; /* ptr alignment */
   struct png_ihdr ihdr; /* uint32 alignment */
   uint32_t palette[256];
   uint8_t flags;
};

static const struct adam7_pass rpng_passes[] = {
   { 0, 0, 8, 8 },
   { 4, 0, 8, 8 },
   { 0, 4, 4, 8 },
   { 2, 0, 4, 4 },
   { 0, 2, 2, 4 },
   { 1, 0, 2, 2 },
   { 0, 1, 1, 2 },
};

static INLINE uint32_t rpng_dword_be(const uint8_t *buf)
{
   return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
}

#if defined(DEBUG) || defined(RPNG_TEST)
static bool rpng_process_ihdr(struct png_ihdr *ihdr)
{
   uint8_t ihdr_depth = ihdr->depth;

   switch (ihdr->color_type)
   {
      case PNG_IHDR_COLOR_RGB:
      case PNG_IHDR_COLOR_GRAY_ALPHA:
      case PNG_IHDR_COLOR_RGBA:
         if (ihdr_depth != 8 && ihdr_depth != 16)
         {
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
            return false;
         }
         break;
      case PNG_IHDR_COLOR_GRAY:
         /* Valid bitdepths are: 1, 2, 4, 8, 16 */
         if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
         {
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
            return false;
         }
         break;
      case PNG_IHDR_COLOR_PLT:
         /* Valid bitdepths are: 1, 2, 4, 8 */
         if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)
         {
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
            return false;
         }
         break;
      default:
         fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
         return false;
   }

#ifdef RPNG_TEST
   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
         ihdr->width, ihdr->height,
         ihdr_depth, (ihdr->color_type == PNG_IHDR_COLOR_PLT) ? "yes" : "no",
         (ihdr->color_type & PNG_IHDR_COLOR_RGB)              ? "yes" : "no",
         (ihdr->color_type & PNG_IHDR_COLOR_GRAY_ALPHA)       ? "yes" : "no",
         ihdr->interlace == 1 ? "yes" : "no");
#endif

   return true;
}
#else
static bool rpng_process_ihdr(struct png_ihdr *ihdr)
{
   uint8_t ihdr_depth = ihdr->depth;

   switch (ihdr->color_type)
   {
      case PNG_IHDR_COLOR_RGB:
      case PNG_IHDR_COLOR_GRAY_ALPHA:
      case PNG_IHDR_COLOR_RGBA:
         if (ihdr_depth != 8 && ihdr_depth != 16)
            return false;
         break;
      case PNG_IHDR_COLOR_GRAY:
         /* Valid bitdepths are: 1, 2, 4, 8, 16 */
         if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
            return false;
         break;
      case PNG_IHDR_COLOR_PLT:
         /* Valid bitdepths are: 1, 2, 4, 8 */
         if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)
            return false;
         break;
      default:
         return false;
   }

   return true;
}
#endif

static void rpng_reverse_filter_copy_line_rgb(uint32_t *data,
      const uint8_t *decoded, unsigned width, unsigned bpp)
{
   int i;

   bpp /= 8;

   for (i = 0; i < (int)width; i++)
   {
      uint32_t r, g, b;

      r        = *decoded;
      decoded += bpp;
      g        = *decoded;
      decoded += bpp;
      b        = *decoded;
      decoded += bpp;
      data[i]  = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
   }
}

static void rpng_reverse_filter_copy_line_rgba(uint32_t *data,
      const uint8_t *decoded, unsigned width, unsigned bpp)
{
   int i;

   bpp /= 8;

   for (i = 0; i < (int)width; i++)
   {
      uint32_t r, g, b, a;
      r        = *decoded;
      decoded += bpp;
      g        = *decoded;
      decoded += bpp;
      b        = *decoded;
      decoded += bpp;
      a        = *decoded;
      decoded += bpp;
      data[i]  = (a << 24) | (r << 16) | (g << 8) | (b << 0);
   }
}

static void rpng_reverse_filter_copy_line_bw(uint32_t *data,
      const uint8_t *decoded, unsigned width, unsigned depth)
{
   int i;
   unsigned bit;
   static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
   unsigned mul, mask;

   if (depth == 16)
   {
      for (i = 0; i < (int)width; i++)
      {
         uint32_t val = decoded[i << 1];
         data[i]      = (val * 0x010101) | (0xffu << 24);
      }
      return;
   }

   mul  = mul_table[depth];
   mask = (1 << depth) - 1;
   bit  = 0;

   for (i = 0; i < (int)width; i++, bit += depth)
   {
      unsigned byte = bit >> 3;
      unsigned val  = decoded[byte] >> (8 - depth - (bit & 7));

      val          &= mask;
      val          *= mul;
      data[i]       = (val * 0x010101) | (0xffu << 24);
   }
}

static void rpng_reverse_filter_copy_line_gray_alpha(uint32_t *data,
      const uint8_t *decoded, unsigned width,
      unsigned bpp)
{
   int i;

   bpp /= 8;

   for (i = 0; i < (int)width; i++)
   {
      uint32_t gray, alpha;

      gray     = *decoded;
      decoded += bpp;
      alpha    = *decoded;
      decoded += bpp;

      data[i]  = (gray * 0x010101) | (alpha << 24);
   }
}

static void rpng_reverse_filter_copy_line_plt(uint32_t *data,
      const uint8_t *decoded, unsigned width,
      unsigned depth, const uint32_t *palette)
{
   switch (depth)
   {
      case 1:
         {
            int i;
            unsigned w = width / 8;
            for (i = 0; i < (int)w; i++, decoded++)
            {
               *data++ = palette[(*decoded >> 7) & 1];
               *data++ = palette[(*decoded >> 6) & 1];
               *data++ = palette[(*decoded >> 5) & 1];
               *data++ = palette[(*decoded >> 4) & 1];
               *data++ = palette[(*decoded >> 3) & 1];
               *data++ = palette[(*decoded >> 2) & 1];
               *data++ = palette[(*decoded >> 1) & 1];
               *data++ = palette[*decoded & 1];
            }

            switch (width & 7)
            {
               case 7:
                  data[6] = palette[(*decoded >> 1) & 1];
               case 6:
                  data[5] = palette[(*decoded >> 2) & 1];
               case 5:
                  data[4] = palette[(*decoded >> 3) & 1];
               case 4:
                  data[3] = palette[(*decoded >> 4) & 1];
               case 3:
                  data[2] = palette[(*decoded >> 5) & 1];
               case 2:
                  data[1] = palette[(*decoded >> 6) & 1];
               case 1:
                  data[0] = palette[(*decoded >> 7) & 1];
                  break;
            }
         }
         break;

      case 2:
         {
            int i;
            unsigned w = width / 4;
            for (i = 0; i < (int)w; i++, decoded++)
            {
               *data++ = palette[(*decoded >> 6) & 3];
               *data++ = palette[(*decoded >> 4) & 3];
               *data++ = palette[(*decoded >> 2) & 3];
               *data++ = palette[*decoded & 3];
            }

            switch (width & 3)
            {
               case 3:
                  data[2] = palette[(*decoded >> 2) & 3];
               case 2:
                  data[1] = palette[(*decoded >> 4) & 3];
               case 1:
                  data[0] = palette[(*decoded >> 6) & 3];
                  break;
            }
         }
         break;

      case 4:
         {
            int i;
            unsigned w = width / 2;
            for (i = 0; i < (int)w; i++, decoded++)
            {
               *data++ = palette[*decoded >> 4];
               *data++ = palette[*decoded & 0x0f];
            }

            if (width & 1)
               *data = palette[*decoded >> 4];
         }
         break;

      case 8:
         {
            int i;
            for (i = 0; i < (int)width; i++, decoded++, data++)
               *data = palette[*decoded];
         }
         break;
   }
}

static void rpng_pass_geom(const struct png_ihdr *ihdr,
      unsigned width, unsigned height,
      unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size)
{
   unsigned bpp   = 0;
   unsigned pitch = 0;

   switch (ihdr->color_type)
   {
      case PNG_IHDR_COLOR_GRAY:
         bpp   = (ihdr->depth + 7) / 8;
         pitch = (ihdr->width * ihdr->depth + 7) / 8;
         break;
      case PNG_IHDR_COLOR_RGB:
         bpp   = (ihdr->depth * 3 + 7) / 8;
         pitch = (ihdr->width * ihdr->depth * 3 + 7) / 8;
         break;
      case PNG_IHDR_COLOR_PLT:
         bpp   = (ihdr->depth + 7) / 8;
         pitch = (ihdr->width * ihdr->depth + 7) / 8;
         break;
      case PNG_IHDR_COLOR_GRAY_ALPHA:
         bpp   = (ihdr->depth * 2 + 7) / 8;
         pitch = (ihdr->width * ihdr->depth * 2 + 7) / 8;
         break;
      case PNG_IHDR_COLOR_RGBA:
         bpp   = (ihdr->depth * 4 + 7) / 8;
         pitch = (ihdr->width * ihdr->depth * 4 + 7) / 8;
         break;
      default:
         break;
   }

   if (pass_size)
      *pass_size = (pitch + 1) * ihdr->height;
   if (bpp_out)
      *bpp_out   = bpp;
   if (pitch_out)
      *pitch_out = pitch;
}

static void rpng_reverse_filter_adam7_deinterlace_pass(uint32_t *data,
      const struct png_ihdr *ihdr,
      const uint32_t *input, unsigned pass_width, unsigned pass_height,
      const struct adam7_pass *pass)
{
   unsigned x, y;

   data += pass->y * ihdr->width + pass->x;

   for (y = 0; y < pass_height;
         y++, data += ihdr->width * pass->stride_y, input += pass_width)
   {
      uint32_t *out = data;

      for (x = 0; x < pass_width; x++, out += pass->stride_x)
         *out = input[x];
   }
}

static void rpng_reverse_filter_deinit(struct rpng_process *pngp)
{
   if (!pngp)
      return;
   if (pngp->decoded_scanline)
      free(pngp->decoded_scanline);
   pngp->decoded_scanline = NULL;
   if (pngp->prev_scanline)
      free(pngp->prev_scanline);
   pngp->prev_scanline    = NULL;

   pngp->flags           &= ~RPNG_PROCESS_FLAG_PASS_INITIALIZED;
   pngp->h                = 0;
}

static int rpng_reverse_filter_init(const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   size_t pass_size;

   if (   !(pngp->flags & RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED)
         && ihdr->interlace)
   {
      if (     ihdr->width  <= rpng_passes[pngp->pass_pos].x
            || ihdr->height <= rpng_passes[pngp->pass_pos].y) /* Empty pass */
         return 1;

      pngp->pass_width  = (ihdr->width -
            rpng_passes[pngp->pass_pos].x + rpng_passes[pngp->pass_pos].stride_x
- 1) / rpng_passes[pngp->pass_pos].stride_x;
      pngp->pass_height = (ihdr->height - rpng_passes[pngp->pass_pos].y +
            rpng_passes[pngp->pass_pos].stride_y - 1) / rpng_passes[pngp->pass_pos].stride_y;

      if (!(pngp->data = (uint32_t*)malloc(
            pngp->pass_width * pngp->pass_height * sizeof(uint32_t))))
         return -1;

      pngp->ihdr        = *ihdr;
      pngp->ihdr.width  = pngp->pass_width;
      pngp->ihdr.height = pngp->pass_height;

      rpng_pass_geom(&pngp->ihdr, pngp->pass_width,
            pngp->pass_height, NULL, NULL, &pngp->pass_size);

      if (pngp->pass_size > pngp->total_out)
      {
         free(pngp->data);
         pngp->data = NULL;
         return -1;
      }

      pngp->flags |= RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;

      return 0;
   }

   if (pngp->flags & RPNG_PROCESS_FLAG_PASS_INITIALIZED)
      return 0;

   rpng_pass_geom(ihdr, ihdr->width, ihdr->height, &pngp->bpp, &pngp->pitch, &pass_size);

   if (pngp->total_out < pass_size)
      return -1;

   pngp->restore_buf_size      = 0;
   pngp->data_restore_buf_size = 0;
   pngp->prev_scanline         = (uint8_t*)calloc(1, pngp->pitch);
   pngp->decoded_scanline      = (uint8_t*)calloc(1, pngp->pitch);

   if (!pngp->prev_scanline || !pngp->decoded_scanline)
      goto error;

   pngp->h                    = 0;
   pngp->flags               |= RPNG_PROCESS_FLAG_PASS_INITIALIZED;

   return 0;

error:
   rpng_reverse_filter_deinit(pngp);
   return -1;
}

static int rpng_reverse_filter_copy_line(uint32_t *data,
      const struct png_ihdr *ihdr,
      struct rpng_process *pngp, unsigned filter)
{
   unsigned i;

   switch (filter)
   {
      case PNG_FILTER_NONE:
         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
         break;
      case PNG_FILTER_SUB:
         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
         for (i = pngp->bpp; i < pngp->pitch; i++)
            pngp->decoded_scanline[i] += pngp->decoded_scanline[i - pngp->bpp];
         break;
      case PNG_FILTER_UP:
         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
         for (i = 0; i < pngp->pitch; i++)
            pngp->decoded_scanline[i] += pngp->prev_scanline[i];
         break;
      case PNG_FILTER_AVERAGE:
         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
         for (i = 0; i < pngp->bpp; i++)
         {
            uint8_t avg = pngp->prev_scanline[i] >> 1;
            pngp->decoded_scanline[i] += avg;
         }
         for (i = pngp->bpp; i < pngp->pitch; i++)
         {
            uint8_t avg = (pngp->decoded_scanline[i - pngp->bpp] + pngp->prev_scanline[i]) >> 1;
            pngp->decoded_scanline[i] += avg;
         }
         break;
      case PNG_FILTER_PAETH:
         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
         for (i = 0; i < pngp->bpp; i++)
            pngp->decoded_scanline[i] += pngp->prev_scanline[i];
         for (i = pngp->bpp; i < pngp->pitch; i++)
            pngp->decoded_scanline[i] += paeth(pngp->decoded_scanline[i - pngp->bpp],
                  pngp->prev_scanline[i], pngp->prev_scanline[i - pngp->bpp]);
         break;
      default:
         return IMAGE_PROCESS_ERROR_END;
   }

   switch (ihdr->color_type)
   {
      case PNG_IHDR_COLOR_GRAY:
         rpng_reverse_filter_copy_line_bw(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
         break;
      case PNG_IHDR_COLOR_RGB:
         rpng_reverse_filter_copy_line_rgb(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
         break;
      case PNG_IHDR_COLOR_PLT:
         rpng_reverse_filter_copy_line_plt(
               data, pngp->decoded_scanline, ihdr->width,
               ihdr->depth, pngp->palette);
         break;
      case PNG_IHDR_COLOR_GRAY_ALPHA:
         rpng_reverse_filter_copy_line_gray_alpha(data, pngp->decoded_scanline, ihdr->width,
               ihdr->depth);
         break;
      case PNG_IHDR_COLOR_RGBA:
         rpng_reverse_filter_copy_line_rgba(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
         break;
   }

   memcpy(pngp->prev_scanline, pngp->decoded_scanline, pngp->pitch);

   return IMAGE_PROCESS_NEXT;
}

static int rpng_reverse_filter_regular_iterate(
      uint32_t **data, const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   int ret = IMAGE_PROCESS_END;
   if (pngp->h < ihdr->height)
   {
      unsigned filter         = *pngp->inflate_buf++;
      pngp->restore_buf_size += 1;
      ret                     = rpng_reverse_filter_copy_line(*data,
            ihdr, pngp, filter);
      if (ret == IMAGE_PROCESS_END || ret == IMAGE_PROCESS_ERROR_END)
         goto end;
   }
   else
      goto end;

   pngp->h++;
   pngp->inflate_buf           += pngp->pitch;
   pngp->restore_buf_size      += pngp->pitch;

   *data                       += ihdr->width;
   pngp->data_restore_buf_size += ihdr->width;

   return IMAGE_PROCESS_NEXT;

end:
   rpng_reverse_filter_deinit(pngp);

   pngp->inflate_buf -= pngp->restore_buf_size;
   *data             -= pngp->data_restore_buf_size;
   pngp->data_restore_buf_size = 0;
   return ret;
}

static int rpng_reverse_filter_adam7_iterate(uint32_t **data_,
      const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   int        ret = 0;
   bool   to_next = pngp->pass_pos < ARRAY_SIZE(rpng_passes);
   uint32_t *data = *data_;

   if (!to_next)
      return IMAGE_PROCESS_END;

   if ((ret = rpng_reverse_filter_init(ihdr, pngp)) == 1)
      return IMAGE_PROCESS_NEXT;
   else if (ret == -1)
      return IMAGE_PROCESS_ERROR_END;

   if (rpng_reverse_filter_init(&pngp->ihdr, pngp) == -1)
      return IMAGE_PROCESS_ERROR;

   do
   {
      ret = rpng_reverse_filter_regular_iterate(&pngp->data,
            &pngp->ihdr, pngp);
   } while (ret == IMAGE_PROCESS_NEXT);

   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
      return IMAGE_PROCESS_ERROR;

   pngp->inflate_buf            += pngp->pass_size;
   pngp->adam7_restore_buf_size += pngp->pass_size;

   pngp->total_out              -= pngp->pass_size;

   rpng_reverse_filter_adam7_deinterlace_pass(data,
         ihdr, pngp->data, pngp->pass_width, pngp->pass_height,
         &rpng_passes[pngp->pass_pos]);

   free(pngp->data);

   pngp->data                   = NULL;
   pngp->pass_width             = 0;
   pngp->pass_height            = 0;
   pngp->pass_size              = 0;
   pngp->flags                 &= ~RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;

   return IMAGE_PROCESS_NEXT;
}

static int rpng_reverse_filter_adam7(uint32_t **data_,
      const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   int ret = rpng_reverse_filter_adam7_iterate(data_,
         ihdr, pngp);

   switch (ret)
   {
      case IMAGE_PROCESS_ERROR_END:
      case IMAGE_PROCESS_END:
         break;
      case IMAGE_PROCESS_NEXT:
         pngp->pass_pos++;
         return 0;
      case IMAGE_PROCESS_ERROR:
         if (pngp->data)
         {
            free(pngp->data);
            pngp->data = NULL;
         }
         pngp->inflate_buf -= pngp->adam7_restore_buf_size;
         pngp->adam7_restore_buf_size = 0;
         return -1;
   }

   pngp->inflate_buf            -= pngp->adam7_restore_buf_size;
   pngp->adam7_restore_buf_size  = 0;
   return ret;
}

static int rpng_load_image_argb_process_inflate_init(
      rpng_t *rpng, uint32_t **data)
{
   bool zstatus;
   enum trans_stream_error err;
   uint32_t rd, wn;
   struct rpng_process *process = (struct rpng_process*)rpng->process;
   bool to_continue        = (process->avail_in > 0
         && process->avail_out > 0);

   if (!to_continue)
      goto end;

   zstatus = process->stream_backend->trans(process->stream, false, &rd, &wn, &err);

   if (!zstatus && err != TRANS_STREAM_ERROR_BUFFER_FULL)
      goto error;

   process->avail_in -= rd;
   process->avail_out -= wn;
   process->total_out += wn;

   if (err)
      return 0;

end:
   process->stream_backend->stream_free(process->stream);
   process->stream = NULL;

#ifdef GEKKO
   /* we often use these in textures, make sure they're 32-byte aligned */
   *data = (uint32_t*)memalign(32, rpng->ihdr.width *
         rpng->ihdr.height * sizeof(uint32_t));
#else
   *data = (uint32_t*)malloc(rpng->ihdr.width *
         rpng->ihdr.height * sizeof(uint32_t));
#endif
   if (!*data)
      goto false_end;

   process->adam7_restore_buf_size = 0;
   process->restore_buf_size       = 0;
   process->palette                = rpng->palette;

   if (rpng->ihdr.interlace != 1)
      if (rpng_reverse_filter_init(&rpng->ihdr, process) == -1)
         goto false_end;

   process->flags              |=  RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;
   return 1;

error:
false_end:
   process->flags              &= ~RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;
   return -1;
}

static bool rpng_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)
{
   uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk_size);

   if (!new_buffer)
      return false;

   buf->data  = new_buffer;
   return true;
}

static struct rpng_process *rpng_process_init(rpng_t *rpng)
{
   uint8_t *inflate_buf            = NULL;
   struct rpng_process *process    = (struct rpng_process*)malloc(sizeof(*process));

   if (!process)
      return NULL;

   process->flags                  = 0;
   process->prev_scanline          = NULL;
   process->decoded_scanline       = NULL;
   process->inflate_buf            = NULL;

   process->ihdr.width             = 0;
   process->ihdr.height            = 0;
   process->ihdr.depth             = 0;
   process->ihdr.color_type        = 0;
   process->ihdr.compression       = 0;
   process->ihdr.filter            = 0;
   process->ihdr.interlace         = 0;

   process->restore_buf_size       = 0;
   process->adam7_restore_buf_size = 0;
   process->data_restore_buf_size  = 0;
   process->inflate_buf_size       = 0;
   process->avail_in               = 0;
   process->avail_out              = 0;
   process->total_out              = 0;
   process->pass_size              = 0;
   process->bpp                    = 0;
   process->pitch                  = 0;
   process->h                      = 0;
   process->pass_width             = 0;
   process->pass_height            = 0;
   process->pass_pos               = 0;
   process->data                   = 0;
   process->palette                = 0;
   process->stream                 = NULL;
   process->stream_backend         = trans_stream_get_zlib_inflate_backend();

   rpng_pass_geom(&rpng->ihdr, rpng->ihdr.width,
         rpng->ihdr.height, NULL, NULL, &process->inflate_buf_size);
   if (rpng->ihdr.interlace == 1) /* To be sure. */
      process->inflate_buf_size *= 2;

   process->stream = process->stream_backend->stream_new();

   if (!process->stream)
   {
      free(process);
      return NULL;
   }

   inflate_buf = (uint8_t*)malloc(process->inflate_buf_size);
   if (!inflate_buf)
      goto error;

   process->inflate_buf = inflate_buf;
   process->avail_in    = rpng->idat_buf.size;
   process->avail_out   = process->inflate_buf_size;

   process->stream_backend->set_in(
         process->stream,
         rpng->idat_buf.data,
         (uint32_t)rpng->idat_buf.size);
   process->stream_backend->set_out(
         process->stream,
         process->inflate_buf,
         (uint32_t)process->inflate_buf_size);

   return process;

error:
   if (process)
   {
      if (process->stream)
         process->stream_backend->stream_free(process->stream);
      free(process);
   }
   return NULL;
}

/**
 * rpng_read_chunk_header:
 *
 * Leaf function.
 *
 * @return The PNG type of the memory chunk (i.e. IHDR, IDAT, IEND,
   PLTE, and/or tRNS)
 **/
static enum png_chunk_type rpng_read_chunk_header(
      uint8_t *buf, uint32_t chunk_size)
{
   int i;
   char type[4];

   for (i = 0; i < 4; i++)
   {
      uint8_t byte = buf[i + 4];

      /* All four bytes of the chunk type must be
       * ASCII letters (codes 65-90 and 97-122) */
      if ((byte < 65) || ((byte > 90) && (byte < 97)) || (byte > 122))
         return PNG_CHUNK_ERROR;
      type[i]      = byte;
   }

   if (
            type[0] == 'I'
         && type[1] == 'H'
         && type[2] == 'D'
         && type[3] == 'R'
      )
      return PNG_CHUNK_IHDR;
   else if
      (
          type[0] == 'I'
       && type[1] == 'D'
       && type[2] == 'A'
       && type[3] == 'T'
      )
         return PNG_CHUNK_IDAT;
   else if
      (
          type[0] == 'I'
       && type[1] == 'E'
       && type[2] == 'N'
       && type[3] == 'D'
      )
         return PNG_CHUNK_IEND;
   else if
      (
          type[0] == 'P'
       && type[1] == 'L'
       && type[2] == 'T'
       && type[3] == 'E'
      )
         return PNG_CHUNK_PLTE;
   else if
      (
          type[0] == 't'
       && type[1] == 'R'
       && type[2] == 'N'
       && type[3] == 'S'
      )
         return PNG_CHUNK_tRNS;

   return PNG_CHUNK_NOOP;
}

bool rpng_iterate_image(rpng_t *rpng)
{
   unsigned i;
   uint8_t *buf             = (uint8_t*)rpng->buff_data;
   uint32_t chunk_size      = 0;

   /* Check whether data buffer pointer is valid */
   if (buf > rpng->buff_end)
      return false;

   /* Check whether reading the header will overflow
    * the data buffer */
   if (rpng->buff_end - buf < 8)
      return false;

   chunk_size = rpng_dword_be(buf);

   /* Check whether chunk will overflow the data buffer */
   if (buf + 8 + chunk_size > rpng->buff_end)
      return false;

   switch (rpng_read_chunk_header(buf, chunk_size))
   {
      case PNG_CHUNK_NOOP:
      default:
         break;

      case PNG_CHUNK_ERROR:
         return false;

      case PNG_CHUNK_IHDR:
         if (     (rpng->flags & RPNG_FLAG_HAS_IHDR)
               || (rpng->flags & RPNG_FLAG_HAS_IDAT)
               || (rpng->flags & RPNG_FLAG_HAS_IEND))
            return false;

         if (chunk_size != 13)
            return false;

         buf                    += 4 + 4;

         rpng->ihdr.width        = rpng_dword_be(buf + 0);
         rpng->ihdr.height       = rpng_dword_be(buf + 4);
         rpng->ihdr.depth        = buf[8];
         rpng->ihdr.color_type   = buf[9];
         rpng->ihdr.compression  = buf[10];
         rpng->ihdr.filter       = buf[11];
         rpng->ihdr.interlace    = buf[12];

         if (     rpng->ihdr.width  == 0
               || rpng->ihdr.height == 0
               /* ensure multiplications don't overflow and wrap around, that'd give buffer overflow crashes */
               || (uint64_t)rpng->ihdr.width*rpng->ihdr.height*sizeof(uint32_t) >= 0x80000000)
            return false;

         if (!rpng_process_ihdr(&rpng->ihdr))
            return false;

         if (rpng->ihdr.compression != 0)
         {
#if defined(DEBUG) || defined(RPNG_TEST)
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
#endif
            return false;
         }

         rpng->flags   |= RPNG_FLAG_HAS_IHDR;
         break;

      case PNG_CHUNK_PLTE:
         {
            int i;
            unsigned entries = chunk_size / 3;

            if (entries > 256)
               return false;
            if (chunk_size % 3)
               return false;

            if (     !(rpng->flags & RPNG_FLAG_HAS_IHDR)
                  ||  (rpng->flags & RPNG_FLAG_HAS_PLTE)
                  ||  (rpng->flags & RPNG_FLAG_HAS_IEND)
                  ||  (rpng->flags & RPNG_FLAG_HAS_IDAT)
                  ||  (rpng->flags & RPNG_FLAG_HAS_TRNS))
               return false;

            buf += 8;

            for (i = 0; i < (int)entries; i++)
            {
               uint32_t r       = buf[3 * i + 0];
               uint32_t g       = buf[3 * i + 1];
               uint32_t b       = buf[3 * i + 2];
               rpng->palette[i] = (r << 16) | (g << 8) | (b << 0) | (0xffu << 24);
            }

            rpng->flags        |= RPNG_FLAG_HAS_PLTE;
         }
         break;

      case PNG_CHUNK_tRNS:
         if (rpng->flags & RPNG_FLAG_HAS_IDAT)
            return false;

         if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT)
         {
            int i;
            uint32_t *palette;
            /* we should compare with the number of palette entries */
            if (chunk_size > 256)
               return false;

            buf    += 8;
            palette = rpng->palette;

            for (i = 0; i < (int)chunk_size; i++, buf++, palette++)
               *palette = (*palette & 0x00ffffff) | (unsigned)*buf << 24;
         }
         /* TODO: support colorkey in grayscale and truecolor images */

         rpng->flags         |= RPNG_FLAG_HAS_TRNS;
         break;

      case PNG_CHUNK_IDAT:
         if (     !(rpng->flags & RPNG_FLAG_HAS_IHDR)
               ||  (rpng->flags & RPNG_FLAG_HAS_IEND)
               ||  (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT
                  &&
                  !(rpng->flags & RPNG_FLAG_HAS_PLTE)))
            return false;

         if (!rpng_realloc_idat(&rpng->idat_buf, chunk_size))
            return false;

         buf += 8;

         for (i = 0; i < chunk_size; i++)
            rpng->idat_buf.data[i + rpng->idat_buf.size] = buf[i];

         rpng->idat_buf.size += chunk_size;

         rpng->flags         |= RPNG_FLAG_HAS_IDAT;
         break;

      case PNG_CHUNK_IEND:
         if (     !(rpng->flags & RPNG_FLAG_HAS_IHDR)
               || !(rpng->flags & RPNG_FLAG_HAS_IDAT))
            return false;

         rpng->flags         |= RPNG_FLAG_HAS_IEND;
         return false;
   }

   rpng->buff_data += chunk_size + 12;

   /* Check whether data buffer pointer is valid */
   if (rpng->buff_data > rpng->buff_end)
      return false;
   return true;
}

int rpng_process_image(rpng_t *rpng,
      void **_data, size_t len, unsigned *width, unsigned *height)
{
   uint32_t **data = (uint32_t**)_data;

   if (!rpng->process)
   {
      struct rpng_process *process = rpng_process_init(rpng);

      if (!process)
         goto error;

      rpng->process = process;
      return IMAGE_PROCESS_NEXT;
   }

   if (!(rpng->process->flags & RPNG_PROCESS_FLAG_INFLATE_INITIALIZED))
   {
      if (rpng_load_image_argb_process_inflate_init(rpng, data) == -1)
         goto error;
      return IMAGE_PROCESS_NEXT;
   }

   *width  = rpng->ihdr.width;
   *height = rpng->ihdr.height;

   if (rpng->ihdr.interlace && rpng->process)
      return rpng_reverse_filter_adam7(data, &rpng->ihdr, rpng->process);
   return rpng_reverse_filter_regular_iterate(data, &rpng->ihdr, rpng->process);

error:
   if (rpng->process)
   {
      if (rpng->process->inflate_buf)
         free(rpng->process->inflate_buf);
      if (rpng->process->stream)
         rpng->process->stream_backend->stream_free(rpng->process->stream);
      free(rpng->process);
      rpng->process = NULL;
   }
   return IMAGE_PROCESS_ERROR;
}

void rpng_free(rpng_t *rpng)
{
   if (!rpng)
      return;

   if (rpng->idat_buf.data)
      free(rpng->idat_buf.data);
   if (rpng->process)
   {
      if (rpng->process->inflate_buf)
         free(rpng->process->inflate_buf);
      if (rpng->process->stream)
      {
         if (rpng->process->stream_backend && rpng->process->stream_backend->stream_free)
            rpng->process->stream_backend->stream_free(rpng->process->stream);
         else
            free(rpng->process->stream);
      }
      free(rpng->process);
   }

   free(rpng);
}

bool rpng_start(rpng_t *rpng)
{
   if (!rpng)
      return false;

   /* Check whether reading the header will overflow
    * the data buffer */
   if (rpng->buff_end - rpng->buff_data < 8)
      return false;

   if (memcmp(rpng->buff_data, png_magic, sizeof(png_magic)) != 0)
      return false;

   rpng->buff_data += 8;

   return true;
}

/**
 * rpng_is_valid:
 *
 * Check if @rpng is a valid PNG image.
 * Must contain an IHDR chunk, one or more IDAT
 * chunks, and an IEND chunk.
 *
 * Leaf function.
 *
 * @return true if it's a valid PNG image, otherwise false.
 **/
bool rpng_is_valid(rpng_t *rpng)
{
   return (rpng && ((rpng->flags & (RPNG_FLAG_HAS_IHDR | RPNG_FLAG_HAS_IDAT |
RPNG_FLAG_HAS_IEND)) > 0));
}

bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len)
{
   if (!rpng || (len < 1))
      return false;

   rpng->buff_data = (uint8_t*)data;
   rpng->buff_end  = rpng->buff_data + (len - 1);

   return true;
}

rpng_t *rpng_alloc(void)
{
   rpng_t *rpng = (rpng_t*)calloc(1, sizeof(*rpng));
   if (!rpng)
      return NULL;
   return rpng;
}

./include/libretro-common/formats/png/rpng_encode.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng_encode.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libretro.h>
#include <encodings/crc32.h>
#include <streams/interface_stream.h>
#include <streams/trans_stream.h>

#include "rpng_internal.h"

#undef GOTO_END_ERROR
#define GOTO_END_ERROR() do { \
   fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__); \
   ret = false; \
   goto end; \
} while (0)

double DEFLATE_PADDING = 1.1;
int PNG_ROUGH_HEADER = 100;

static void dword_write_be(uint8_t *buf, uint32_t val)
{
   *buf++ = (uint8_t)(val >> 24);
   *buf++ = (uint8_t)(val >> 16);
   *buf++ = (uint8_t)(val >>  8);
   *buf++ = (uint8_t)(val >>  0);
}

static bool png_write_crc_string(intfstream_t *intf_s, const uint8_t *data, size_t len)
{
   uint8_t crc_raw[4] = {0};
   uint32_t crc       = encoding_crc32(0, data, len);

   dword_write_be(crc_raw, crc);
   return intfstream_write(intf_s, crc_raw, sizeof(crc_raw)) == sizeof(crc_raw);
}

static bool png_write_ihdr_string(intfstream_t *intf_s, const struct png_ihdr *ihdr)
{
   uint8_t ihdr_raw[21];

   ihdr_raw[0]  = '0';                 /* Size */
   ihdr_raw[1]  = '0';
   ihdr_raw[2]  = '0';
   ihdr_raw[3]  = '0';
   ihdr_raw[4]  = 'I';
   ihdr_raw[5]  = 'H';
   ihdr_raw[6]  = 'D';
   ihdr_raw[7]  = 'R';
   ihdr_raw[8]  =   0;                 /* Width */
   ihdr_raw[9]  =   0;
   ihdr_raw[10] =   0;
   ihdr_raw[11] =   0;
   ihdr_raw[12] =   0;                 /* Height */
   ihdr_raw[13] =   0;
   ihdr_raw[14] =   0;
   ihdr_raw[15] =   0;
   ihdr_raw[16] =   ihdr->depth;       /* Depth */
   ihdr_raw[17] =   ihdr->color_type;
   ihdr_raw[18] =   ihdr->compression;
   ihdr_raw[19] =   ihdr->filter;
   ihdr_raw[20] =   ihdr->interlace;

   dword_write_be(ihdr_raw +  0, sizeof(ihdr_raw) - 8);
   dword_write_be(ihdr_raw +  8, ihdr->width);
   dword_write_be(ihdr_raw + 12, ihdr->height);
   if (intfstream_write(intf_s, ihdr_raw, sizeof(ihdr_raw)) != sizeof(ihdr_raw))
      return false;

   return png_write_crc_string(intf_s, ihdr_raw + sizeof(uint32_t),
         sizeof(ihdr_raw) - sizeof(uint32_t));
}

static bool png_write_idat_string(intfstream_t* intf_s, const uint8_t *data, size_t len)
{
   if (intfstream_write(intf_s, data, len) != (ssize_t)len)
      return false;
   return png_write_crc_string(intf_s, data + sizeof(uint32_t), len - sizeof(uint32_t));
}

static bool png_write_iend_string(intfstream_t* intf_s)
{
   const uint8_t data[] = {
      0, 0, 0, 0,
      'I', 'E', 'N', 'D',
   };

   if (intfstream_write(intf_s, data, sizeof(data)) != sizeof(data))
      return false;

   return png_write_crc_string(intf_s, data + sizeof(uint32_t),
         sizeof(data) - sizeof(uint32_t));
}

static void copy_argb_line(uint8_t *dst, const uint32_t *src, unsigned width)
{
   unsigned i;
   for (i = 0; i < width; i++)
   {
      uint32_t col = src[i];
      *dst++ = (uint8_t)(col >> 16);
      *dst++ = (uint8_t)(col >>  8);
      *dst++ = (uint8_t)(col >>  0);
      *dst++ = (uint8_t)(col >> 24);
   }
}

static void copy_bgr24_line(uint8_t *dst, const uint8_t *src, unsigned width)
{
   unsigned i;
   for (i = 0; i < width; i++, dst += 3, src += 3)
   {
      dst[2] = src[0];
      dst[1] = src[1];
      dst[0] = src[2];
   }
}

static unsigned count_sad(const uint8_t *data, size_t len)
{
   size_t i;
   unsigned cnt = 0;
   for (i = 0; i < len; i++)
   {
      if (data[i])
         cnt += abs((int8_t)data[i]);
   }
   return cnt;
}

static unsigned filter_up(uint8_t *target, const uint8_t *line,
      const uint8_t *prev, unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i < width; i++)
      target[i] = line[i] - prev[i];

   return count_sad(target, width);
}

static unsigned filter_sub(uint8_t *target, const uint8_t *line,
      unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i < bpp; i++)
      target[i] = line[i];
   for (i = bpp; i < width; i++)
      target[i] = line[i] - line[i - bpp];

   return count_sad(target, width);
}

static unsigned filter_avg(uint8_t *target, const uint8_t *line,
      const uint8_t *prev, unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i < bpp; i++)
      target[i] = line[i] - (prev[i] >> 1);
   for (i = bpp; i < width; i++)
      target[i] = line[i] - ((line[i - bpp] + prev[i]) >> 1);

   return count_sad(target, width);
}

static unsigned filter_paeth(uint8_t *target,
      const uint8_t *line, const uint8_t *prev,
      unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i < bpp; i++)
      target[i] = line[i] - paeth(0, prev[i], 0);
   for (i = bpp; i < width; i++)
      target[i] = line[i] - paeth(line[i - bpp], prev[i], prev[i - bpp]);

   return count_sad(target, width);
}

bool rpng_save_image_stream(const uint8_t *data, intfstream_t* intf_s,
      unsigned width, unsigned height, signed pitch, unsigned bpp)
{
   unsigned h;
   struct png_ihdr ihdr = {0};
   bool ret = true;
   const struct trans_stream_backend *stream_backend = NULL;
   size_t encode_buf_size  = 0;
   uint8_t *encode_buf     = NULL;
   uint8_t *deflate_buf    = NULL;
   uint8_t *rgba_line      = NULL;
   uint8_t *up_filtered    = NULL;
   uint8_t *sub_filtered   = NULL;
   uint8_t *avg_filtered   = NULL;
   uint8_t *paeth_filtered = NULL;
   uint8_t *prev_encoded   = NULL;
   uint8_t *encode_target  = NULL;
   void *stream            = NULL;
   uint32_t total_in       = 0;
   uint32_t total_out      = 0;

   if (!intf_s)
      GOTO_END_ERROR();

   stream_backend = trans_stream_get_zlib_deflate_backend();

   if (intfstream_write(intf_s, png_magic, sizeof(png_magic)) != sizeof(png_magic))
      GOTO_END_ERROR();

   ihdr.width = width;
   ihdr.height = height;
   ihdr.depth = 8;
   ihdr.color_type = bpp == sizeof(uint32_t) ? 6 : 2; /* RGBA or RGB */
   if (!png_write_ihdr_string(intf_s, &ihdr))
      GOTO_END_ERROR();

   encode_buf_size = (width * bpp + 1) * height;
   encode_buf      = (uint8_t*)malloc(encode_buf_size);
   if (!encode_buf)
      GOTO_END_ERROR();

   prev_encoded = (uint8_t*)calloc(1, width * bpp);
   if (!prev_encoded)
      GOTO_END_ERROR();

   rgba_line      = (uint8_t*)malloc(width * bpp);
   up_filtered    = (uint8_t*)malloc(width * bpp);
   sub_filtered   = (uint8_t*)malloc(width * bpp);
   avg_filtered   = (uint8_t*)malloc(width * bpp);
   paeth_filtered = (uint8_t*)malloc(width * bpp);
   if (!rgba_line || !up_filtered || !sub_filtered || !avg_filtered || !paeth_filtered)
      GOTO_END_ERROR();

   encode_target = encode_buf;
   for (h = 0; h < height;
         h++, encode_target += width * bpp, data += pitch)
   {
      if (bpp == sizeof(uint32_t))
         copy_argb_line(rgba_line, (const uint32_t*)data, width);
      else
         copy_bgr24_line(rgba_line, data, width);

      /* Try every filtering method, and choose the method
       * which has most entries as zero.
       *
       * This is probably not very optimal, but it's very
       * simple to implement.
       */
      {
         unsigned none_score  = count_sad(rgba_line, width * bpp);
         unsigned up_score    = filter_up(up_filtered, rgba_line, prev_encoded, width, bpp);
         unsigned sub_score   = filter_sub(sub_filtered, rgba_line, width, bpp);
         unsigned avg_score   = filter_avg(avg_filtered, rgba_line, prev_encoded, width, bpp);
         unsigned paeth_score = filter_paeth(paeth_filtered, rgba_line, prev_encoded, width, bpp);

         uint8_t filter       = 0;
         unsigned min_sad     = none_score;
         const uint8_t *chosen_filtered = rgba_line;

         if (sub_score < min_sad)
         {
            filter = 1;
            chosen_filtered = sub_filtered;
            min_sad = sub_score;
         }

         if (up_score < min_sad)
         {
            filter = 2;
            chosen_filtered = up_filtered;
            min_sad = up_score;
         }

         if (avg_score < min_sad)
         {
            filter = 3;
            chosen_filtered = avg_filtered;
            min_sad = avg_score;
         }

         if (paeth_score < min_sad)
         {
            filter = 4;
            chosen_filtered = paeth_filtered;
         }

         *encode_target++ = filter;
         memcpy(encode_target, chosen_filtered, width * bpp);

         memcpy(prev_encoded, rgba_line, width * bpp);
      }
   }

   deflate_buf = (uint8_t*)malloc(encode_buf_size * 2); /* Just to be sure. */
   if (!deflate_buf)
      GOTO_END_ERROR();

   stream = stream_backend->stream_new();

   if (!stream)
      GOTO_END_ERROR();

   stream_backend->set_in(
         stream,
         encode_buf,
         (unsigned)encode_buf_size);
   stream_backend->set_out(
         stream,
         deflate_buf + 8,
         (unsigned)(encode_buf_size * 2));

   if (!stream_backend->trans(stream, true, &total_in, &total_out, NULL))
      GOTO_END_ERROR();

   memcpy(deflate_buf + 4, "IDAT", 4);
   dword_write_be(deflate_buf + 0,        ((uint32_t)total_out));
   if (!png_write_idat_string(intf_s, deflate_buf, ((size_t)total_out + 8)))
      GOTO_END_ERROR();

   if (!png_write_iend_string(intf_s))
      GOTO_END_ERROR();
end:
   free(encode_buf);
   free(deflate_buf);
   free(rgba_line);
   free(prev_encoded);
   free(up_filtered);
   free(sub_filtered);
   free(avg_filtered);
   free(paeth_filtered);

   if (stream_backend)
   {
      if (stream)
      {
         if (stream_backend->stream_free)
            stream_backend->stream_free(stream);
      }
   }
   return ret;
}

bool rpng_save_image_argb(const char *path, const uint32_t *data,
      unsigned width, unsigned height, unsigned pitch)
{
   bool ret                      = false;
   intfstream_t* intf_s          = NULL;

   intf_s = intfstream_open_file(path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   ret = rpng_save_image_stream((const uint8_t*) data, intf_s,
                                width, height,
                                (signed) pitch, sizeof(uint32_t));
   intfstream_close(intf_s);
   free(intf_s);
   return ret;
}

bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
      unsigned width, unsigned height, unsigned pitch)
{
   bool ret                      = false;
   intfstream_t* intf_s          = NULL;

   intf_s = intfstream_open_file(path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   ret = rpng_save_image_stream(data, intf_s, width, height,
                                (signed) pitch, 3);
   intfstream_close(intf_s);
   free(intf_s);
   return ret;
}


uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
      unsigned width, unsigned height, signed pitch, uint64_t* bytes)
{
   bool ret             = false;
   uint8_t *output      = NULL;
   intfstream_t *intf_s = NULL;
   size_t _len          = (width * height * 3 * DEFLATE_PADDING) + PNG_ROUGH_HEADER;
   uint8_t *buf         = (uint8_t*)malloc(_len * sizeof(uint8_t));
   if (!buf)
      GOTO_END_ERROR();

   intf_s = intfstream_open_memory(buf,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE,
         _len);

   ret    = rpng_save_image_stream((const uint8_t*)data,
            intf_s, width, height, pitch, 3);
   *bytes = intfstream_get_ptr(intf_s);
   intfstream_rewind(intf_s);
   output = (uint8_t*)malloc((size_t)((*bytes)*sizeof(uint8_t)));
   if (!output)
      GOTO_END_ERROR();
   intfstream_read(intf_s, output, *bytes);

end:
   if (buf)
      free(buf);
   if (intf_s)
   {
      intfstream_close(intf_s);
      free(intf_s);
   }
   if (ret == false)
   {
      if (output)
         free(output);
      return NULL;
   }
   return output;
}

./include/libretro-common/formats/png/rpng_internal.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng_internal.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _RPNG_COMMON_H
#define _RPNG_COMMON_H

#include <stdint.h>
#include <filters.h>
#include <formats/rpng.h>

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

static const uint8_t png_magic[8] = {
   0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a,
};

struct png_ihdr
{
   uint32_t width;
   uint32_t height;
   uint8_t depth;
   uint8_t color_type;
   uint8_t compression;
   uint8_t filter;
   uint8_t interlace;
};

#endif

./include/libretro-common/formats/tga/rtga.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtga.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Modified version of stb_image's TGA sources. */

#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h> /* ptrdiff_t on osx */
#include <stdlib.h>
#include <string.h>

#include <retro_inline.h>

#include <formats/image.h>
#include <formats/rtga.h>

#define RTGA_COMPUTE_Y(r, g, b) ((uint8_t)((((r) * 77) + ((g) * 150) +  (29 * (b))) >> 8))

struct rtga
{
   uint8_t *buff_data;
   uint32_t *output_image;
};

typedef struct
{
   uint8_t *img_buffer;
   uint8_t *img_buffer_end;
   uint8_t *img_buffer_original;
   int buflen;
   int img_n, img_out_n;
   uint32_t img_x, img_y;
   uint8_t buffer_start[128];
} rtga_context;

static INLINE uint8_t rtga_get8(rtga_context *s)
{
   if (s->img_buffer < s->img_buffer_end)
      return *s->img_buffer++;
   return 0;
}

static void rtga_skip(rtga_context *s, int n)
{
   if (n < 0)
   {
      s->img_buffer = s->img_buffer_end;
      return;
   }
   s->img_buffer += n;
}

static int rtga_get16le(rtga_context *s)
{
   return rtga_get8(s) + (rtga_get8(s) << 8);
}

static unsigned char *rtga_convert_format(
      unsigned char *data,
      int img_n,
      int req_comp,
      unsigned int x,
      unsigned int y)
{
   int i,j;
   unsigned char *good = (unsigned char *) malloc(req_comp * x * y);

   if (!good)
   {
      free(data);
      return NULL;
   }

   for (j=0; j < (int) y; ++j)
   {
      unsigned char *src  = data + j * x * img_n   ;
      unsigned char *dest = good + j * x * req_comp;

      switch (((img_n)*8+(req_comp)))
      {
         case ((1)*8+(2)):
            for (i=x-1; i >= 0; --i, src += 1, dest += 2)
            {
               dest[0]=src[0];
               dest[1]=255;
            }
            break;
         case ((1)*8+(3)):
            for (i=x-1; i >= 0; --i, src += 1, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case ((1)*8+(4)):
            for (i=x-1; i >= 0; --i, src += 1, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=255;
            }
            break;
         case ((2)*8+(1)):
            for (i=x-1; i >= 0; --i, src += 2, dest += 1)
               dest[0]=src[0];
            break;
         case ((2)*8+(3)):
            for (i=x-1; i >= 0; --i, src += 2, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case ((2)*8+(4)):
            for (i=x-1; i >= 0; --i, src += 2, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=src[1];
            }
            break;
         case ((3)*8+(4)):
            for (i=x-1; i >= 0; --i, src += 3, dest += 4)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
               dest[3]=255;
            }
            break;
         case ((3)*8+(1)):
            for (i=x-1; i >= 0; --i, src += 3, dest += 1)
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case ((3)*8+(2)):
            for (i=x-1; i >= 0; --i, src += 3, dest += 2)
            {
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = 255;
            }
            break;
         case ((4)*8+(1)):
            for (i=x-1; i >= 0; --i, src += 4, dest += 1)
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case ((4)*8+(2)):
            for (i=x-1; i >= 0; --i, src += 4, dest += 2)
            {
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = src[3];
            }
            break;
         case ((4)*8+(3)):
            for (i=x-1; i >= 0; --i, src += 4, dest += 3)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
            }
            break;
         default:
            break;
      }
   }

   free(data);
   return good;
}

static uint8_t *rtga_tga_load(rtga_context *s,
      unsigned *x, unsigned *y, int *comp, int req_comp)
{
   /* Read in the TGA header stuff */
   int tga_offset          = rtga_get8(s);
   int tga_indexed         = rtga_get8(s);
   int tga_image_type      = rtga_get8(s);
   int tga_is_RLE          = 0;
   int tga_palette_start   = rtga_get16le(s);
   int tga_palette_len     = rtga_get16le(s);
   int tga_palette_bits    = rtga_get8(s);
   int tga_x_origin        = rtga_get16le(s);
   int tga_y_origin        = rtga_get16le(s);
   int tga_width           = rtga_get16le(s);
   int tga_height          = rtga_get16le(s);
   int tga_bits_per_pixel  = rtga_get8(s);
   int tga_comp            = tga_bits_per_pixel / 8;
   int tga_inverted        = rtga_get8(s);

   /*   image data */
   unsigned char *tga_data = NULL;

   (void)tga_palette_start;
   (void)tga_x_origin;
   (void)tga_y_origin;

   /*   do a tiny bit of precessing */
   if (tga_image_type >= 8)
   {
      tga_image_type -= 8;
      tga_is_RLE = 1;
   }

   /* int tga_alpha_bits = tga_inverted & 15; */
   tga_inverted = 1 - ((tga_inverted >> 5) & 1);

   /*   error check */
   if (
         (tga_width < 1) || (tga_height < 1) ||
         (tga_image_type < 1) || (tga_image_type > 3) ||
         (
          (tga_bits_per_pixel != 8)  && (tga_bits_per_pixel != 16) &&
          (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)
         )
      )
      return NULL; /* we don't report this as a bad TGA because we don't even know if it's TGA */

   /*   If paletted, then we will use the number of bits from the palette */
   if (tga_indexed)
      tga_comp = tga_palette_bits / 8;

   /*   TGA info */
   *x = tga_width;
   *y = tga_height;
   if (comp)
      *comp = tga_comp;

   tga_data = (unsigned char*)malloc((size_t)tga_width * tga_height * tga_comp);
   if (!tga_data)
      return NULL;

   /* skip to the data's starting position (offset usually = 0) */
   rtga_skip(s, tga_offset );

   if (!tga_indexed && !tga_is_RLE)
   {
      int i;
      for (i=0; i < tga_height; ++i)
      {
         int _y           = tga_inverted ? (tga_height -i - 1) : i;
         uint8_t *tga_row = tga_data + _y * tga_width * tga_comp;
         int n            = tga_width * tga_comp;

         if (s->img_buffer + n <= s->img_buffer_end)
         {
            memcpy(tga_row, s->img_buffer, n);
            s->img_buffer += n;
         }
      }
   }
   else
   {
      int i, j;
      int RLE_repeating          = 0;
      int RLE_count              = 0;
      int read_next_pixel        = 1;
      unsigned char raw_data[4] = {0};
      unsigned char *tga_palette = NULL;

      /*   Do I need to load a palette? */
      if (tga_indexed)
      {
         int n;
         /* Any data to skip? (offset usually = 0) */
         rtga_skip(s, tga_palette_start );
         /* Load the palette */
         tga_palette = (unsigned char*)malloc(tga_palette_len * tga_palette_bits / 8);

         if (!tga_palette)
         {
            free(tga_data);
            return NULL;
         }

         n = tga_palette_len * tga_palette_bits / 8;

         if (s->img_buffer+n <= s->img_buffer_end)
         {
            memcpy(tga_palette, s->img_buffer, n);
            s->img_buffer += n;
         }
         else
         {
            free(tga_data);
            free(tga_palette);
            return NULL;
         }
      }

      /*   load the data */
      for (i=0; i < tga_width * tga_height; ++i)
      {
         /*   if I'm in RLE mode, do I need to get a RLE rtga_png chunk? */
         if (tga_is_RLE)
         {
            if (RLE_count == 0)
            {
               /*   yep, get the next byte as a RLE command */
               int RLE_cmd     = rtga_get8(s);
               RLE_count       = 1 + (RLE_cmd & 127);
               RLE_repeating   = RLE_cmd >> 7;
               read_next_pixel = 1;
            }
            else if (!RLE_repeating)
               read_next_pixel = 1;
         }
         else
            read_next_pixel = 1;

         /*   OK, if I need to read a pixel, do it now */
         if (read_next_pixel)
         {
            /*   load however much data we did have */
            if (tga_indexed)
            {
               /*   read in 1 byte, then perform the lookup */
               int pal_idx = rtga_get8(s);
               if (pal_idx >= tga_palette_len) /* invalid index */
                  pal_idx = 0;
               pal_idx *= tga_bits_per_pixel / 8;
               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
                  raw_data[j] = tga_palette[pal_idx+j];
            }
            else
            {
               /* read in the data raw */
               /* manually unroll, probably GCC bug 92955 */
               j = 0;
               switch (tga_bits_per_pixel)
               {
                  case 32:
                     raw_data[j++] = rtga_get8(s); /* fallthrough */
                  case 24:
                     raw_data[j++] = rtga_get8(s); /* fallthrough */
                  case 16:
                     raw_data[j++] = rtga_get8(s); /* fallthrough */
                  case  8:
                     raw_data[j++] = rtga_get8(s);
               }
            }

            /*   clear the reading flag for the next pixel */
            read_next_pixel = 0;
         } /* end of reading a pixel */

         /* copy data */
         for (j = 0; j < tga_comp; ++j)
            tga_data[i*tga_comp+j] = raw_data[j];

         /*   in case we're in RLE mode, keep counting down */
         --RLE_count;
      }

      /*   do I need to invert the image? */
      if (tga_inverted)
      {
         if (tga_data)
         {
            for (j = 0; j*2 < tga_height; ++j)
            {
               int index1 = j * tga_width * tga_comp;
               int index2 = (tga_height - 1 - j) * tga_width * tga_comp;

               for (i = tga_width * tga_comp; i > 0; --i)
               {
                  unsigned char temp = tga_data[index1];
                  tga_data[index1]   = tga_data[index2];
                  tga_data[index2]   = temp;
                  ++index1;
                  ++index2;
               }
            }
         }
      }

      /* Clear my palette, if I had one */
      if (tga_palette)
         free(tga_palette);
   }

   /* swap RGB */
   if (tga_comp >= 3)
   {
      int i;
      unsigned char* tga_pixel = tga_data;

      for (i = 0; i < tga_width * tga_height; ++i)
      {
         unsigned char temp  = tga_pixel[0];
         tga_pixel[0]        = tga_pixel[2];
         tga_pixel[2]        = temp;
         tga_pixel          += tga_comp;
      }
   }

   /* convert to target component count */
   if (     (req_comp)
         && (req_comp >= 1 && req_comp <= 4)
         && (req_comp != tga_comp))
   {
      tga_data = rtga_convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
   }

   return tga_data;
}

static uint8_t *rtga_load_from_memory(uint8_t const *buffer, int len,
      unsigned *x, unsigned *y, int *comp, int req_comp)
{
   rtga_context s;

   s.img_buffer          = (uint8_t *)buffer;
   s.img_buffer_original = (uint8_t *) buffer;
   s.img_buffer_end      = (uint8_t *) buffer+len;

   return rtga_tga_load(&s,x,y,comp,req_comp);
}

int rtga_process_image(rtga_t *rtga, void **buf_data,
      size_t size, unsigned *width, unsigned *height)
{
   int comp;
   unsigned size_tex     = 0;

   if (!rtga)
      return IMAGE_PROCESS_ERROR;

   rtga->output_image   = (uint32_t*)rtga_load_from_memory(rtga->buff_data,
                           (int)size, width, height, &comp, 4);
   *buf_data             = rtga->output_image;
   size_tex              = (*width) * (*height);

   /* Convert RGBA to ARGB */
   while (size_tex--)
   {
      unsigned int texel = rtga->output_image[size_tex];
      unsigned int A     = texel & 0xFF000000;
      unsigned int B     = texel & 0x00FF0000;
      unsigned int G     = texel & 0x0000FF00;
      unsigned int R     = texel & 0x000000FF;
      ((unsigned int*)rtga->output_image)[size_tex] = A | (R << 16) | G | (B >> 16);
   };

   return IMAGE_PROCESS_END;
}

bool rtga_set_buf_ptr(rtga_t *rtga, void *data)
{
   if (!rtga)
      return false;

   rtga->buff_data = (uint8_t*)data;

   return true;
}

void rtga_free(rtga_t *rtga)
{
   if (!rtga)
      return;

   free(rtga);
}

rtga_t *rtga_alloc(void)
{
   rtga_t *rtga = (rtga_t*)calloc(1, sizeof(*rtga));
   if (!rtga)
      return NULL;
   return rtga;
}

./include/libretro-common/formats/wav/rwav.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rwav.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h> /* ptrdiff_t on osx */
#include <stdlib.h>
#include <string.h>

#include <formats/rwav.h>

enum
{
   ITER_BEGIN,
   ITER_COPY_SAMPLES,
   ITER_COPY_SAMPLES_8,
   ITER_COPY_SAMPLES_16
};

struct rwav_iterator
{
   rwav_t *out;
   const uint8_t *data;
   size_t size;
   size_t i, j;
   int step;
};

void rwav_init(rwav_iterator_t* iter, rwav_t* out, const void *s, size_t len)
{
   iter->out    = out;
   iter->data   = (const uint8_t*)s;
   iter->size   = len;
   iter->step   = ITER_BEGIN;

   out->samples = NULL;
}

enum rwav_state rwav_iterate(rwav_iterator_t *iter)
{
   size_t s;
   uint16_t *u16       = NULL;
   void *samples       = NULL;
   rwav_t *rwav        = iter->out;
   const uint8_t *data = iter->data;

   switch (iter->step)
   {
      case ITER_BEGIN:
         if (iter->size < 44)
            return RWAV_ITERATE_ERROR; /* buffer is smaller than an empty wave file */

         if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F')
            return RWAV_ITERATE_ERROR;

         if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E')
            return RWAV_ITERATE_ERROR;

         if (data[12] != 'f' || data[13] != 'm' || data[14] != 't' || data[15] != ' ')
            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */

         if (data[16] != 16 || data[17] != 0 || data[18] != 0 || data[19] != 0)
            return RWAV_ITERATE_ERROR;

         if (data[20] != 1 || data[21] != 0)
            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */

         if (data[36] != 'd' || data[37] != 'a' || data[38] != 't' || data[39] != 'a')
            return RWAV_ITERATE_ERROR;

         rwav->bitspersample = data[34] | data[35] << 8;

         if (rwav->bitspersample != 8 && rwav->bitspersample != 16)
            return RWAV_ITERATE_ERROR; /* we only support 8 and 16 bps */

         rwav->subchunk2size = data[40] | data[41] << 8 | data[42] << 16 | data[43] << 24;

         if ((rwav->subchunk2size < 1) ||
             (rwav->subchunk2size > iter->size - 44))
            return RWAV_ITERATE_ERROR; /* too few bytes in buffer */

         samples = malloc(rwav->subchunk2size);

         if (!samples)
            return RWAV_ITERATE_ERROR;

         rwav->numchannels = data[22] | data[23] << 8;
         rwav->numsamples  = rwav->subchunk2size * 8 / rwav->bitspersample / rwav->numchannels;
         rwav->samplerate  = data[24] | data[25] << 8 | data[26] << 16 | data[27] << 24;
         rwav->samples     = samples;

         iter->step = ITER_COPY_SAMPLES;
         return RWAV_ITERATE_MORE;

      case ITER_COPY_SAMPLES:
         iter->i = 0;

         if (rwav->bitspersample == 8)
         {
            iter->step = ITER_COPY_SAMPLES_8;

            /* TODO/FIXME - what is going on here? */
            case ITER_COPY_SAMPLES_8:
            s = rwav->subchunk2size - iter->i;

            if (s > RWAV_ITERATE_BUF_SIZE)
               s = RWAV_ITERATE_BUF_SIZE;

            memcpy((void*)((uint8_t*)rwav->samples + iter->i), (void *)(iter->data + 44 + iter->i), s);
            iter->i += s;
         }
         else
         {
            iter->step = ITER_COPY_SAMPLES_16;
            iter->j    = 0;

            /* TODO/FIXME - what is going on here? */
            case ITER_COPY_SAMPLES_16:
            s = rwav->subchunk2size - iter->i;

            if (s > RWAV_ITERATE_BUF_SIZE)
               s = RWAV_ITERATE_BUF_SIZE;

            u16 = (uint16_t *)rwav->samples;

            while (s != 0)
            {
               u16[iter->j++] = iter->data[44 + iter->i] | iter->data[45 + iter->i] << 8;
               iter->i += 2;
               s -= 2;
            }
         }

         if (iter->i < rwav->subchunk2size)
            return RWAV_ITERATE_MORE;
         return RWAV_ITERATE_DONE;
   }

   return RWAV_ITERATE_ERROR;
}

enum rwav_state rwav_load(rwav_t* out, const void *s, size_t len)
{
   enum rwav_state res;
   rwav_iterator_t iter;

   iter.out             = NULL;
   iter.data            = NULL;
   iter.size            = 0;
   iter.i               = 0;
   iter.j               = 0;
   iter.step            = 0;

   rwav_init(&iter, out, s, len);

   do
   {
      res = rwav_iterate(&iter);
   }while (res == RWAV_ITERATE_MORE);

   return res;
}

void rwav_free(rwav_t *rwav)
{
   free((void*)rwav->samples);
}

./include/libretro-common/formats/xml/rxml.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <boolean.h>
#include <streams/file_stream.h>
#include <compat/posix_string.h>
#include <string/stdstring.h>

#include <formats/rxml.h>

#include "../../deps/yxml/yxml.h"

#define BUFSIZE 4096

struct rxml_parse_buffer
{
   rxml_node_t *stack[32];
   char xml[BUFSIZE];
   char val[BUFSIZE];
};

struct rxml_document
{
   struct rxml_node *root_node;
};

struct rxml_node *rxml_root_node(rxml_document_t *doc)
{
   if (doc)
      return doc->root_node;
   return NULL;
}

static void rxml_free_node(struct rxml_node *node)
{
   struct rxml_node *head = NULL;
   struct rxml_attrib_node *attrib_node_head = NULL;

   if (!node)
      return;

   for (head = node->children; head; )
   {
      struct rxml_node *next_node = (struct rxml_node*)head->next;
      rxml_free_node(head);
      head = next_node;
   }

   for (attrib_node_head = node->attrib; attrib_node_head; )
   {
      struct rxml_attrib_node *next_attrib =
            (struct rxml_attrib_node*)attrib_node_head->next;

      if (attrib_node_head->attrib)
         free(attrib_node_head->attrib);
      if (attrib_node_head->value)
         free(attrib_node_head->value);
      if (attrib_node_head)
         free(attrib_node_head);

      attrib_node_head = next_attrib;
   }

   if (node->name)
      free(node->name);
   if (node->data)
      free(node->data);
   if (node)
      free(node);
}

rxml_document_t *rxml_load_document(const char *path)
{
   rxml_document_t *doc    = NULL;
   char *memory_buffer     = NULL;
   int64_t len             = 0;
   RFILE *file             = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!file)
      return NULL;

   len                     = filestream_get_size(file);
   memory_buffer           = (char*)malloc((size_t)(len + 1));
   if (!memory_buffer)
      goto error;

   memory_buffer[len]      = '\0';
   if (filestream_read(file, memory_buffer, len) != len)
      goto error;

   filestream_close(file);
   file                    = NULL;

   doc                     = rxml_load_document_string(memory_buffer);

   free(memory_buffer);
   return doc;

error:
   free(memory_buffer);
   if (file)
      filestream_close(file);
   return NULL;
}

rxml_document_t *rxml_load_document_string(const char *str)
{
   yxml_t x;
   rxml_document_t *doc          = NULL;
   size_t stack_i                = 0;
   size_t level                  = 0;
   int i                         = 0;
   char *valptr                  = NULL;
   rxml_node_t *node             = NULL;
   struct rxml_attrib_node *attr = NULL;
   struct rxml_parse_buffer *buf = (struct rxml_parse_buffer*)
      malloc(sizeof(*buf));
   if (!buf)
      return NULL;

   valptr                        = buf->val;
   doc                           = (rxml_document_t*)malloc(sizeof(*doc));
   if (!doc)
      goto error;
   doc->root_node                = NULL;

   yxml_init(&x, buf->xml, BUFSIZE);

   for (; *str; ++str)
   {
      yxml_ret_t r = yxml_parse(&x, *str);

      if (r < 0)
         goto error;

      switch (r)
      {

         case YXML_ELEMSTART:
            if (node)
            {
               if (level > stack_i)
               {
                  buf->stack[stack_i]      = node;
                  ++stack_i;

                  node->children           = (rxml_node_t*)
                     malloc(sizeof(*node));

                  node->children->name     = NULL;
                  node->children->data     = NULL;
                  node->children->attrib   = NULL;
                  node->children->children = NULL;
                  node->children->next     = NULL;

                  node                     = node->children;
               }
               else
               {
                  node->next               = (rxml_node_t*)
                     malloc(sizeof(*node));

                  node->next->name         = NULL;
                  node->next->data         = NULL;
                  node->next->attrib       = NULL;
                  node->next->children     = NULL;
                  node->next->next         = NULL;

                  node                     = node->next;
               }
            }
            else
               node = doc->root_node       = (rxml_node_t*)
                  calloc(1, sizeof(*node));

            if (node->name)
               free(node->name);
            node->name                     = strdup(x.elem);

            attr                           = NULL;
            valptr                         = buf->val;

            ++level;
            break;

         case YXML_ELEMEND:
            --level;

            if (valptr > buf->val)
            {
               *valptr = '\0';

               /* Original code was broken here:
                * > If an element ended on two successive
                *   iterations, on the second iteration
                *   the 'data' for the *previous* node would
                *   get overwritten
                * > This effectively erased the data for the
                *   previous node, *and* caused a memory leak
                *   (due to the double strdup())
                * It seems the correct thing to do here is
                * only copy the data if the current 'level'
                * and 'stack index' are the same... */
               if (level == stack_i)
               {
                  if (node->data)
                     free(node->data);
                  node->data = strdup(buf->val);
               }

               valptr = buf->val;
            }

            if (level < stack_i)
            {
               --stack_i;
               node = buf->stack[stack_i];
            }
            break;

         case YXML_CONTENT:
            for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
            {
               *valptr = x.data[i];
               ++valptr;
            }
            break;

         case YXML_ATTRSTART:
            if (attr)
               attr = attr->next   = (struct rxml_attrib_node*)
                     calloc(1, sizeof(*attr));
            else
            {
               attr = (struct rxml_attrib_node*)calloc(1, sizeof(*attr));
               if (node && attr)
                  node->attrib = attr;
            }

            if (attr)
            {
               if (attr->attrib)
                  free(attr->attrib);
               attr->attrib = strdup(x.attr);
            }

            valptr       = buf->val;
            break;

         case YXML_ATTRVAL:
            for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
            {
               *valptr = x.data[i];
               ++valptr;
            }
            break;

         case YXML_ATTREND:
            if (valptr > buf->val)
            {
               *valptr = '\0';

               if (attr)
               {
                  if (attr->value)
                     free(attr->value);
                  attr->value = strdup(buf->val);
               }

               valptr      = buf->val;
            }
            break;

         default:
            break;
      }
   }

   free(buf);
   return doc;

error:
   rxml_free_document(doc);
   free(buf);
   return NULL;
}

void rxml_free_document(rxml_document_t *doc)
{
   if (!doc)
      return;

   if (doc->root_node)
      rxml_free_node(doc->root_node);

   free(doc);
}

const char *rxml_node_attrib(struct rxml_node *node, const char *attrib)
{
   struct rxml_attrib_node *attribs = NULL;
   for (attribs = node->attrib; attribs; attribs = attribs->next)
   {
      if (string_is_equal(attrib, attribs->attrib))
         return attribs->value;
   }

   return NULL;
}

./include/libretro-common/formats/xml/test/Makefile

TARGET := rxml

LIBRETRO_XML_DIR  := ..
LIBRETRO_COMM_DIR := ../../..
LIBRETRO_DEPS_DIR := ../../../../deps

SOURCES := \
	rxml_test.c \
	$(LIBRETRO_XML_DIR)/rxml.c \
	$(LIBRETRO_DEPS_DIR)/yxml/yxml.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -DRXML_TEST -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/formats/xml/test/rxml_test.c

/* Copyright  (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <formats/rxml.h>
#include <stdio.h>

static void print_siblings(struct rxml_node *node, unsigned level)
{
   fprintf(stderr, "\n%*sName: %s\n", level * 4, "", node->name);
   if (node->data)
      fprintf(stderr, "%*sData: %s\n", level * 4, "", node->data);

   for (const struct rxml_attrib_node *attrib =
         node->attrib; attrib; attrib = attrib->next)
      fprintf(stderr, "%*s  Attrib: %s = %s\n", level * 4, "",
            attrib->attrib, attrib->value);

   if (node->children)
      print_siblings(node->children, level + 1);

   if (node->next)
      print_siblings(node->next, level);
}

static void rxml_log_document(const char *path)
{
   rxml_document_t *doc = rxml_load_document(path);
   if (!doc)
   {
      fprintf(stderr, "rxml: Failed to load document: %s\n", path);
      return;
   }

   print_siblings(rxml_root_node(doc), 0);
   rxml_free_document(doc);
}

int main(int argc, char *argv[])
{
   if (argc != 2)
   {
      fprintf(stderr, "Usage: %s <path>\n", argv[0]);
      return 1;
   }

   rxml_log_document(argv[1]);
}

./include/libretro-common/gfx/gl_capabilities.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gl_capabilities.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <string.h>

#include <boolean.h>

#include <glsym/glsym.h>

#include <gfx/gl_capabilities.h>

static bool gl_core_context       = false;

bool gl_query_core_context_in_use(void)
{
   return gl_core_context;
}

void gl_query_core_context_set(bool set)
{
   gl_core_context     =  set;
}

void gl_query_core_context_unset(void)
{
   gl_core_context = false;
}

bool gl_query_extension(const char *ext)
{
   bool ret = false;

   if (gl_query_core_context_in_use())
   {
#ifdef GL_NUM_EXTENSIONS
      GLint i;
      GLint exts = 0;
      glGetIntegerv(GL_NUM_EXTENSIONS, &exts);
      for (i = 0; i < exts; i++)
      {
         const char *str = (const char*)glGetStringi(GL_EXTENSIONS, i);
         if (str && strstr(str, ext))
         {
            ret = true;
            break;
         }
      }
#endif
   }
   else
   {
      const char *str = (const char*)glGetString(GL_EXTENSIONS);
      ret = str && strstr(str, ext);
   }

   return ret;
}

bool gl_check_error(char **err_string)
{
   int err = glGetError();
   switch (err)
   {
      case GL_INVALID_ENUM:
         *err_string = strdup("GL: Invalid enum.");
         break;
      case GL_INVALID_VALUE:
         *err_string = strdup("GL: Invalid value.");
         break;
      case GL_INVALID_OPERATION:
         *err_string = strdup("GL: Invalid operation.");
         break;
      case GL_OUT_OF_MEMORY:
         *err_string = strdup("GL: Out of memory.");
         break;
      case GL_NO_ERROR:
         return true;
      default:
         *err_string = strdup("Non specified GL error.");
         break;
   }

   return false;
}

bool gl_check_capability(enum gl_capability_enum enum_idx)
{
   unsigned major       = 0;
   unsigned minor       = 0;
   const char *vendor   = (const char*)glGetString(GL_VENDOR);
   const char *renderer = (const char*)glGetString(GL_RENDERER);
   const char *version  = (const char*)glGetString(GL_VERSION);
#ifdef HAVE_OPENGLES
   if (version && sscanf(version, "OpenGL ES %u.%u", &major, &minor) != 2)
#else
   if (version && sscanf(version, "%u.%u", &major, &minor) != 2)
#endif
      major = minor = 0;

   (void)vendor;
   (void)renderer;

   switch (enum_idx)
   {
      case GL_CAPS_GLES3_SUPPORTED:
#if defined(HAVE_OPENGLES)
         if (major >= 3)
            return true;
#endif
         break;
      case GL_CAPS_EGLIMAGE:
#if defined(HAVE_EGL) && defined(HAVE_OPENGLES)
         if (glEGLImageTargetTexture2DOES != NULL)
            return true;
#endif
         break;
      case GL_CAPS_SYNC:
#ifdef HAVE_OPENGLES
         if (major >= 3)
            return true;
#else
         if (gl_query_extension("ARB_sync") &&
               glFenceSync && glDeleteSync && glClientWaitSync)
            return true;
#endif
         break;
      case GL_CAPS_MIPMAP:
         {
            static bool extension_queried = false;
            static bool extension         = false;

            if (!extension_queried)
            {
               extension         = gl_query_extension("ARB_framebuffer_object");
               extension_queried = true;
            }

            if (extension)
               return true;
         }
         break;
      case GL_CAPS_VAO:
#ifndef HAVE_OPENGLES
         if (!gl_query_core_context_in_use() && !gl_query_extension("ARB_vertex_array_object"))
            return false;

         if (glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays)
            return true;
#endif
         break;
      case GL_CAPS_FBO:
#if defined(HAVE_PSGL) || defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2)
         return true;
#else
         if (     !gl_query_core_context_in_use()
               && !gl_query_extension("ARB_framebuffer_object")
               && !gl_query_extension("EXT_framebuffer_object"))
            return false;

         if (gl_query_extension("ARB_framebuffer_object"))
            return true;

         if (gl_query_extension("EXT_framebuffer_object"))
            return true;

         if (major >= 3)
            return true;
         break;
#endif
      case GL_CAPS_ARGB8:
#if defined(HAVE_OPENGLES) && !defined(EMSCRIPTEN)
         if (gl_query_extension("OES_rgb8_rgba8")
               || gl_query_extension("ARM_rgba8")
                  || major >= 3)
            return true;
#elif defined(HAVE_OPENGLES) && defined(EMSCRIPTEN)
         if (gl_query_extension("EXT_sRGB")
               || major >= 3)
            return true;
#else
         /* TODO/FIXME - implement this for non-GLES? */
#endif
         break;
      case GL_CAPS_DEBUG:
         if (gl_query_extension("KHR_debug"))
            return true;
#ifndef HAVE_OPENGLES
         if (gl_query_extension("ARB_debug_output"))
            return true;
#endif
         break;
      case GL_CAPS_PACKED_DEPTH_STENCIL:
         if (major >= 3)
            return true;
         if (gl_query_extension("OES_packed_depth_stencil"))
            return true;
         if (gl_query_extension("EXT_packed_depth_stencil"))
            return true;
         break;
      case GL_CAPS_ES2_COMPAT:
#ifndef HAVE_OPENGLES
         /* ATI card detected, skipping check for GL_RGB565 support... */
         if (vendor && renderer && (strstr(vendor, "ATI") || strstr(renderer, "ATI")))
            return false;

         if (gl_query_extension("ARB_ES2_compatibility"))
            return true;
#endif
         break;
      case GL_CAPS_UNPACK_ROW_LENGTH:
#ifdef HAVE_OPENGLES
         if (major >= 3)
            return true;

         /* Extension GL_EXT_unpack_subimage, can copy textures faster
          * than using UNPACK_ROW_LENGTH */
         if (gl_query_extension("GL_EXT_unpack_subimage"))
            return true;
#endif
         break;
      case GL_CAPS_FULL_NPOT_SUPPORT:
         if (major >= 3)
            return true;
#ifdef HAVE_OPENGLES
         if (gl_query_extension("ARB_texture_non_power_of_two") ||
               gl_query_extension("OES_texture_npot"))
            return true;
#else
         {
            GLint max_texture_size = 0;
            GLint max_native_instr = 0;
            /* try to detect actual npot support. might fail for older cards. */
            bool  arb_npot         = gl_query_extension("ARB_texture_non_power_of_two");
            bool  arb_frag_program = gl_query_extension("ARB_fragment_program");

            glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);

#ifdef GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB
            if (arb_frag_program && glGetProgramivARB)
               glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
                     GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &max_native_instr);
#endif

            if (arb_npot && arb_frag_program &&
                  (max_texture_size >= 8192) && (max_native_instr >= 4096))
               return true;
         }
#endif
         break;
      case GL_CAPS_SRGB_FBO_ES3:
#ifdef HAVE_OPENGLES
         if (major >= 3)
            return true;
#else
         break;
#endif
      case GL_CAPS_SRGB_FBO:
#if defined(HAVE_OPENGLES)
         if (major >= 3 || gl_query_extension("EXT_sRGB"))
            return true;
#endif
         if (gl_check_capability(GL_CAPS_FBO))
         {
            if (   gl_query_core_context_in_use() ||
                  (gl_query_extension("EXT_texture_sRGB")
                   && gl_query_extension("ARB_framebuffer_sRGB"))
               )
               return true;
         }
         break;
      case GL_CAPS_FP_FBO:
         if (gl_check_capability(GL_CAPS_FBO))
         {
            /* Float FBO is core in 3.2. */
            if (gl_query_core_context_in_use() || gl_query_extension("ARB_texture_float") || gl_query_extension("OES_texture_float_linear"))
               return true;
         }
         break;
      case GL_CAPS_BGRA8888:
#ifdef HAVE_OPENGLES
         /* There are both APPLE and EXT variants. */
         if (gl_query_extension("BGRA8888"))
            return true;
#else
         return true;
#endif
         break;
      case GL_CAPS_TEX_STORAGE:
#ifdef HAVE_OPENGLES
         if (major >= 3)
            return true;
#else
         if (vendor && strstr(vendor, "ATI Technologies"))
            return false;
         if (gl_query_extension("ARB_texture_storage"))
            return true;
#endif
         break;
      case GL_CAPS_TEX_STORAGE_EXT:
#ifdef TARGET_OS_IPHONE
           /* Not working on iOS */
           return false;
#else
         if (gl_query_extension("EXT_texture_storage"))
            return true;
#endif
         break;
      case GL_CAPS_NONE:
      default:
         break;
   }

   return false;
}

./include/libretro-common/gfx/scaler/pixconv.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (pixconv.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include <retro_inline.h>

#include <gfx/scaler/pixconv.h>

#if _MSC_VER && _MSC_VER <= 1800
#define SCALER_NO_SIMD
#endif

#ifdef SCALER_NO_SIMD
#undef __SSE2__
#endif

#if defined(__SSE2__)
#include <emmintrin.h>
#elif defined(__MMX__)
#include <mmintrin.h>
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
#include <arm_neon.h>
#endif

void conv_rgb565_0rgb1555(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input   = (const uint16_t*)input_;
   uint16_t *output        = (uint16_t*)output_;

#if defined(__SSE2__)
   int max_width           = width - 7;
   const __m128i hi_mask   = _mm_set1_epi16(0x7fe0);
   const __m128i lo_mask   = _mm_set1_epi16(0x1f);
#endif

   for (h = 0; h < height;
         h++, output += out_stride >> 1, input += in_stride >> 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w < max_width; w += 8)
      {
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i hi = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);
         __m128i lo = _mm_and_si128(in, lo_mask);
         _mm_storeu_si128((__m128i*)(output + w), _mm_or_si128(hi, lo));
      }
#endif

      for (; w < width; w++)
      {
         uint16_t col = input[w];
         uint16_t hi  = (col >> 1) & 0x7fe0;
         uint16_t lo  = col & 0x1f;
         output[w]    = hi | lo;
      }
   }
}

void conv_0rgb1555_rgb565(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input   = (const uint16_t*)input_;
   uint16_t *output        = (uint16_t*)output_;

#if defined(__SSE2__)
   int max_width           = width - 7;

   const __m128i hi_mask   = _mm_set1_epi16(
         (int16_t)((0x1f << 11) | (0x1f << 6)));
   const __m128i lo_mask   = _mm_set1_epi16(0x1f);
   const __m128i glow_mask = _mm_set1_epi16(1 << 5);
#endif

   for (h = 0; h < height;
         h++, output += out_stride >> 1, input += in_stride >> 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w < max_width; w += 8)
      {
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i rg   = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);
         __m128i b    = _mm_and_si128(in, lo_mask);
         __m128i glow = _mm_and_si128(_mm_srli_epi16(in, 4), glow_mask);
         _mm_storeu_si128((__m128i*)(output + w),
               _mm_or_si128(rg, _mm_or_si128(b, glow)));
      }
#endif

      for (; w < width; w++)
      {
         uint16_t col  = input[w];
         uint16_t rg   = (col << 1) & ((0x1f << 11) | (0x1f << 6));
         uint16_t b    = col & 0x1f;
         uint16_t glow = (col >> 4) & (1 << 5);
         output[w]     = rg | b | glow;
      }
   }
}

void conv_0rgb1555_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input = (const uint16_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

#ifdef __SSE2__
   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f << 10);
   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f <<  5);
   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);
   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);
   const __m128i a           = _mm_set1_epi16(0x00ff);

   int max_width = width - 7;
#endif

   for (h = 0; h < height;
         h++, output += out_stride >> 2, input += in_stride >> 1)
   {
      int w = 0;
#ifdef __SSE2__
      for (; w < max_width; w += 8)
      {
         __m128i res_lo_bg, res_hi_bg;
         __m128i res_lo_ra, res_hi_ra;
         __m128i res_lo, res_hi;
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i r = _mm_and_si128(in, pix_mask_r);
         __m128i g = _mm_and_si128(in, pix_mask_gb);
         __m128i b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_gb);

         r = _mm_mulhi_epi16(r, mul15_hi);
         g = _mm_mulhi_epi16(g, mul15_mid);
         b = _mm_mulhi_epi16(b, mul15_mid);

         res_lo_bg = _mm_unpacklo_epi8(b, g);
         res_hi_bg = _mm_unpackhi_epi8(b, g);
         res_lo_ra = _mm_unpacklo_epi8(r, a);
         res_hi_ra = _mm_unpackhi_epi8(r, a);

         res_lo = _mm_or_si128(res_lo_bg,
               _mm_slli_si128(res_lo_ra, 2));
         res_hi = _mm_or_si128(res_hi_bg,
               _mm_slli_si128(res_hi_ra, 2));

         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
      }
#endif

      for (; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col >> 10) & 0x1f;
         uint32_t g   = (col >>  5) & 0x1f;
         uint32_t b   = (col >>  0) & 0x1f;
         r            = (r << 3) | (r >> 2);
         g            = (g << 3) | (g >> 2);
         b            = (b << 3) | (b >> 2);

         output[w]    = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
      }
   }
}

void conv_rgb565_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input    = (const uint16_t*)input_;
   uint32_t *output         = (uint32_t*)output_;

#if defined(__SSE2__)
   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);
   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);
   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);
   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
   const __m128i a          = _mm_set1_epi16(0x00ff);

   int max_width            = width - 7;
#elif defined(__MMX__)
   const __m64 pix_mask_r = _mm_set1_pi16(0x1f << 10);
   const __m64 pix_mask_g = _mm_set1_pi16(0x3f << 5);
   const __m64 pix_mask_b = _mm_set1_pi16(0x1f << 5);
   const __m64 mul16_r    = _mm_set1_pi16(0x0210);
   const __m64 mul16_g    = _mm_set1_pi16(0x2080);
   const __m64 mul16_b    = _mm_set1_pi16(0x4200);
   const __m64 a          = _mm_set1_pi16(0x00ff);

   int max_width            = width - 3;
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
   int max_width            = width - 7;
#endif

   for (h = 0; h < height;
         h++, output += out_stride >> 2, input += in_stride >> 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w < max_width; w += 8)
      {
         __m128i res_lo, res_hi;
         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);
         __m128i        g = _mm_and_si128(in, pix_mask_g);
         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);

         r                = _mm_mulhi_epi16(r, mul16_r);
         g                = _mm_mulhi_epi16(g, mul16_g);
         b                = _mm_mulhi_epi16(b, mul16_b);

         res_lo_bg        = _mm_unpacklo_epi8(b, g);
         res_hi_bg        = _mm_unpackhi_epi8(b, g);
         res_lo_ra        = _mm_unpacklo_epi8(r, a);
         res_hi_ra        = _mm_unpackhi_epi8(r, a);

         res_lo           = _mm_or_si128(res_lo_bg,
               _mm_slli_si128(res_lo_ra, 2));
         res_hi           = _mm_or_si128(res_hi_bg,
               _mm_slli_si128(res_hi_ra, 2));

         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
      }
#elif defined(__MMX__)
      for (; w < max_width; w += 4)
      {
         __m64 res_lo, res_hi;
         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m64 in = *((__m64*)(input + w));
         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 1), pix_mask_r);
         __m64          g = _mm_and_si64(in, pix_mask_g);
         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 5), pix_mask_b);

         r                = _mm_mulhi_pi16(r, mul16_r);
         g                = _mm_mulhi_pi16(g, mul16_g);
         b                = _mm_mulhi_pi16(b, mul16_b);

         res_lo_bg        = _mm_unpacklo_pi8(b, g);
         res_hi_bg        = _mm_unpackhi_pi8(b, g);
         res_lo_ra        = _mm_unpacklo_pi8(r, a);
         res_hi_ra        = _mm_unpackhi_pi8(r, a);

         res_lo           = _mm_or_si64(res_lo_bg,
               _mm_slli_si64(res_lo_ra, 16));
         res_hi           = _mm_or_si64(res_hi_bg,
               _mm_slli_si64(res_hi_ra, 16));

         *((__m64*)(output + w + 0)) = res_lo;
         *((__m64*)(output + w + 2)) = res_hi;
      }

      _mm_empty();
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
      for (; w < max_width; w += 8)
      {
         uint16x8_t in = vld1q_u16(input + w);

         uint16x8_t r = vsriq_n_u16(in, in, 5);
         uint16x8_t b = vsliq_n_u16(in, in, 5);
         uint16x8_t g = vsriq_n_u16(b,  b,  6);

         uint8x8x4_t res;
         res.val[3] = vdup_n_u8(0xffu);
         res.val[2] = vshrn_n_u16(r, 8);
         res.val[1] = vshrn_n_u16(g, 8);
         res.val[0] = vshrn_n_u16(b, 2);

         vst4_u8((uint8_t*)(output + w), res);
      }
#endif

      for (; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col >> 11) & 0x1f;
         uint32_t g   = (col >>  5) & 0x3f;
         uint32_t b   = (col >>  0) & 0x1f;
         r            = (r << 3) | (r >> 2);
         g            = (g << 2) | (g >> 4);
         b            = (b << 3) | (b >> 2);

         output[w]    = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
      }
   }
}

void conv_rgb565_abgr8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input    = (const uint16_t*)input_;
   uint32_t *output         = (uint32_t*)output_;
 #if defined(__SSE2__)
   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);
   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);
   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);
   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
   const __m128i a          = _mm_set1_epi16(0x00ff);
    int max_width            = width - 7;
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
   int max_width            = width - 7;
#endif
    for (h = 0; h < height;
         h++, output += out_stride >> 2, input += in_stride >> 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w < max_width; w += 8)
      {
         __m128i res_lo, res_hi;
         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);
         __m128i        g = _mm_and_si128(in, pix_mask_g);
         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);
         r                = _mm_mulhi_epi16(r, mul16_r);
         g                = _mm_mulhi_epi16(g, mul16_g);
         b                = _mm_mulhi_epi16(b, mul16_b);
         res_lo_bg        = _mm_unpacklo_epi8(b, g);
         res_hi_bg        = _mm_unpackhi_epi8(b, g);
         res_lo_ra        = _mm_unpacklo_epi8(r, a);
         res_hi_ra        = _mm_unpackhi_epi8(r, a);
         res_lo           = _mm_or_si128(res_lo_bg,
               _mm_slli_si128(res_lo_ra, 2));
         res_hi           = _mm_or_si128(res_hi_bg,
               _mm_slli_si128(res_hi_ra, 2));
         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
      }
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
      for (; w < max_width; w += 8)
      {
         uint16x8_t in = vld1q_u16(input + w);

         uint16x8_t r = vsriq_n_u16(in, in, 5);
         uint16x8_t b = vsliq_n_u16(in, in, 5);
         uint16x8_t g = vsriq_n_u16(b,  b,  6);

         uint8x8x4_t res;
         res.val[3] = vdup_n_u8(0xffu);
         res.val[2] = vshrn_n_u16(b, 2);
         res.val[1] = vshrn_n_u16(g, 8);
         res.val[0] = vshrn_n_u16(r, 8);

         vst4_u8((uint8_t*)(output + w), res);
      }
#endif
       for (; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col >> 11) & 0x1f;
         uint32_t g   = (col >>  5) & 0x3f;
         uint32_t b   = (col >>  0) & 0x1f;
         r            = (r << 3) | (r >> 2);
         g            = (g << 2) | (g >> 4);
         b            = (b << 3) | (b >> 2);
         output[w]    = (0xffu << 24) | (b << 16) | (g << 8) | (r << 0);
      }
   }
}

void conv_argb8888_rgba4444(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint32_t *input = (const uint32_t*)input_;
   uint16_t *output      = (uint16_t*)output_;

   for (h = 0; h < height;
         h++, output += out_stride >> 2, input += in_stride >> 1)
   {
      for (w = 0; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col >> 16) & 0xf;
         uint32_t g   = (col >>  8) & 0xf;
         uint32_t b   = (col) & 0xf;
         uint32_t a   = (col >>  24) & 0xf;
         r            = (r >> 4) | r;
         g            = (g >> 4) | g;
         b            = (b >> 4) | b;
         a            = (a >> 4) | a;

         output[w]    = (r << 12) | (g << 8) | (b << 4) | a;
      }
   }
}

void conv_rgba4444_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input = (const uint16_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

#if defined(__MMX__)
   const __m64 pix_mask_r = _mm_set1_pi16(0xf << 10);
   const __m64 pix_mask_g = _mm_set1_pi16(0xf << 8);
   const __m64 pix_mask_b = _mm_set1_pi16(0xf << 8);
   const __m64 mul16_r    = _mm_set1_pi16(0x0440);
   const __m64 mul16_g    = _mm_set1_pi16(0x1100);
   const __m64 mul16_b    = _mm_set1_pi16(0x1100);
   const __m64 a          = _mm_set1_pi16(0x00ff);

   int max_width            = width - 3;
#endif

   for (h = 0; h < height;
         h++, output += out_stride >> 2, input += in_stride >> 1)
   {
      int w = 0;
#if defined(__MMX__)
      for (; w < max_width; w += 4)
      {
         __m64 res_lo, res_hi;
         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m64 in = *((__m64*)(input + w));
         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 2), pix_mask_r);
         __m64          g = _mm_and_si64(in, pix_mask_g);
         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 4), pix_mask_b);

         r                = _mm_mulhi_pi16(r, mul16_r);
         g                = _mm_mulhi_pi16(g, mul16_g);
         b                = _mm_mulhi_pi16(b, mul16_b);

         res_lo_bg        = _mm_unpacklo_pi8(b, g);
         res_hi_bg        = _mm_unpackhi_pi8(b, g);
         res_lo_ra        = _mm_unpacklo_pi8(r, a);
         res_hi_ra        = _mm_unpackhi_pi8(r, a);

         res_lo           = _mm_or_si64(res_lo_bg,
               _mm_slli_si64(res_lo_ra, 16));
         res_hi           = _mm_or_si64(res_hi_bg,
               _mm_slli_si64(res_hi_ra, 16));

         *((__m64*)(output + w + 0)) = res_lo;
         *((__m64*)(output + w + 2)) = res_hi;
      }

      _mm_empty();
#endif

      for (; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col >> 12) & 0xf;
         uint32_t g   = (col >>  8) & 0xf;
         uint32_t b   = (col >>  4) & 0xf;
         uint32_t a   = (col >>  0) & 0xf;
         r            = (r << 4) | r;
         g            = (g << 4) | g;
         b            = (b << 4) | b;
         a            = (a << 4) | a;

         output[w]    = (a << 24) | (r << 16) | (g << 8) | (b << 0);
      }
   }
}

void conv_rgba4444_rgb565(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint16_t *input = (const uint16_t*)input_;
   uint16_t *output      = (uint16_t*)output_;

   for (h = 0; h < height;
         h++, output += out_stride >> 1, input += in_stride >> 1)
   {
      for (w = 0; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col >> 12) & 0xf;
         uint32_t g   = (col >>  8) & 0xf;
         uint32_t b   = (col >>  4) & 0xf;

         output[w]    = (r << 12) | (g << 7) | (b << 1);
      }
   }
}

#if defined(__SSE2__)
/* :( TODO: Make this saner. */
static INLINE void store_bgr24_sse2(void *output, __m128i a,
      __m128i b, __m128i c, __m128i d)
{
   const __m128i mask_0 = _mm_set_epi32(0, 0, 0, 0x00ffffff);
   const __m128i mask_1 = _mm_set_epi32(0, 0, 0x00ffffff, 0);
   const __m128i mask_2 = _mm_set_epi32(0, 0x00ffffff, 0, 0);
   const __m128i mask_3 = _mm_set_epi32(0x00ffffff, 0, 0, 0);

   __m128i a0 = _mm_and_si128(a, mask_0);
   __m128i a1 = _mm_srli_si128(_mm_and_si128(a, mask_1),  1);
   __m128i a2 = _mm_srli_si128(_mm_and_si128(a, mask_2),  2);
   __m128i a3 = _mm_srli_si128(_mm_and_si128(a, mask_3),  3);
   __m128i a4 = _mm_slli_si128(_mm_and_si128(b, mask_0), 12);
   __m128i a5 = _mm_slli_si128(_mm_and_si128(b, mask_1), 11);

   __m128i b0 = _mm_srli_si128(_mm_and_si128(b, mask_1), 5);
   __m128i b1 = _mm_srli_si128(_mm_and_si128(b, mask_2), 6);
   __m128i b2 = _mm_srli_si128(_mm_and_si128(b, mask_3), 7);
   __m128i b3 = _mm_slli_si128(_mm_and_si128(c, mask_0), 8);
   __m128i b4 = _mm_slli_si128(_mm_and_si128(c, mask_1), 7);
   __m128i b5 = _mm_slli_si128(_mm_and_si128(c, mask_2), 6);

   __m128i c0 = _mm_srli_si128(_mm_and_si128(c, mask_2), 10);
   __m128i c1 = _mm_srli_si128(_mm_and_si128(c, mask_3), 11);
   __m128i c2 = _mm_slli_si128(_mm_and_si128(d, mask_0),  4);
   __m128i c3 = _mm_slli_si128(_mm_and_si128(d, mask_1),  3);
   __m128i c4 = _mm_slli_si128(_mm_and_si128(d, mask_2),  2);
   __m128i c5 = _mm_slli_si128(_mm_and_si128(d, mask_3),  1);

   __m128i *out = (__m128i*)output;

   _mm_storeu_si128(out + 0,
         _mm_or_si128(a0, _mm_or_si128(a1, _mm_or_si128(a2,
                  _mm_or_si128(a3, _mm_or_si128(a4, a5))))));

   _mm_storeu_si128(out + 1,
         _mm_or_si128(b0, _mm_or_si128(b1, _mm_or_si128(b2,
                  _mm_or_si128(b3, _mm_or_si128(b4, b5))))));

   _mm_storeu_si128(out + 2,
         _mm_or_si128(c0, _mm_or_si128(c1, _mm_or_si128(c2,
                  _mm_or_si128(c3, _mm_or_si128(c4, c5))))));
}
#endif

void conv_0rgb1555_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input     = (const uint16_t*)input_;
   uint8_t *output           = (uint8_t*)output_;

#if defined(__SSE2__)
   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f << 10);
   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f <<  5);
   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);
   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);
   const __m128i a           = _mm_set1_epi16(0x00ff);

   int max_width             = width - 15;
#endif

   for (h = 0; h < height;
         h++, output += out_stride, input += in_stride >> 1)
   {
      uint8_t *out = output;
      int   w = 0;

#if defined(__SSE2__)
      for (; w < max_width; w += 16, out += 48)
      {
         __m128i res_lo_bg0, res_lo_bg1, res_hi_bg0, res_hi_bg1,
                 res_lo_ra0, res_lo_ra1, res_hi_ra0, res_hi_ra1,
                 res_lo0, res_lo1, res_hi0, res_hi1;
         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w + 0));
         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));
         __m128i r0        = _mm_and_si128(in0, pix_mask_r);
         __m128i r1        = _mm_and_si128(in1, pix_mask_r);
         __m128i g0        = _mm_and_si128(in0, pix_mask_gb);
         __m128i g1        = _mm_and_si128(in1, pix_mask_gb);
         __m128i b0        = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_gb);
         __m128i b1        = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_gb);

         r0                = _mm_mulhi_epi16(r0, mul15_hi);
         r1                = _mm_mulhi_epi16(r1, mul15_hi);
         g0                = _mm_mulhi_epi16(g0, mul15_mid);
         g1                = _mm_mulhi_epi16(g1, mul15_mid);
         b0                = _mm_mulhi_epi16(b0, mul15_mid);
         b1                = _mm_mulhi_epi16(b1, mul15_mid);

         res_lo_bg0        = _mm_unpacklo_epi8(b0, g0);
         res_lo_bg1        = _mm_unpacklo_epi8(b1, g1);
         res_hi_bg0        = _mm_unpackhi_epi8(b0, g0);
         res_hi_bg1        = _mm_unpackhi_epi8(b1, g1);
         res_lo_ra0        = _mm_unpacklo_epi8(r0, a);
         res_lo_ra1        = _mm_unpacklo_epi8(r1, a);
         res_hi_ra0        = _mm_unpackhi_epi8(r0, a);
         res_hi_ra1        = _mm_unpackhi_epi8(r1, a);

         res_lo0           = _mm_or_si128(res_lo_bg0,
               _mm_slli_si128(res_lo_ra0, 2));
         res_lo1           = _mm_or_si128(res_lo_bg1,
               _mm_slli_si128(res_lo_ra1, 2));
         res_hi0           = _mm_or_si128(res_hi_bg0,
               _mm_slli_si128(res_hi_ra0, 2));
         res_hi1           = _mm_or_si128(res_hi_bg1,
               _mm_slli_si128(res_hi_ra1, 2));

         /* Non-POT pixel sizes for the loss */
         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);
      }
#endif

      for (; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t b   = (col >>  0) & 0x1f;
         uint32_t g   = (col >>  5) & 0x1f;
         uint32_t r   = (col >> 10) & 0x1f;
         b            = (b << 3) | (b >> 2);
         g            = (g << 3) | (g >> 2);
         r            = (r << 3) | (r >> 2);

         *out++       = b;
         *out++       = g;
         *out++       = r;
      }
   }
}

void conv_rgb565_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input    = (const uint16_t*)input_;
   uint8_t *output          = (uint8_t*)output_;

#if defined(__SSE2__)
   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);
   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);
   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);
   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
   const __m128i a          = _mm_set1_epi16(0x00ff);

   int max_width            = width - 15;
#endif

   for (h = 0; h < height; h++, output += out_stride, input += in_stride >> 1)
   {
      uint8_t *out = output;
      int        w = 0;
#if defined(__SSE2__)
      for (; w < max_width; w += 16, out += 48)
      {
         __m128i res_lo_bg0, res_hi_bg0, res_lo_ra0, res_hi_ra0;
         __m128i res_lo_bg1, res_hi_bg1, res_lo_ra1, res_hi_ra1;
         __m128i res_lo0, res_hi0, res_lo1, res_hi1;
         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w));
         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));
         __m128i r0 = _mm_and_si128(_mm_srli_epi16(in0, 1), pix_mask_r);
         __m128i g0 = _mm_and_si128(in0, pix_mask_g);
         __m128i b0 = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_b);
         __m128i r1 = _mm_and_si128(_mm_srli_epi16(in1, 1), pix_mask_r);
         __m128i g1 = _mm_and_si128(in1, pix_mask_g);
         __m128i b1 = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_b);

         r0         = _mm_mulhi_epi16(r0, mul16_r);
         g0         = _mm_mulhi_epi16(g0, mul16_g);
         b0         = _mm_mulhi_epi16(b0, mul16_b);
         r1         = _mm_mulhi_epi16(r1, mul16_r);
         g1         = _mm_mulhi_epi16(g1, mul16_g);
         b1         = _mm_mulhi_epi16(b1, mul16_b);

         res_lo_bg0 = _mm_unpacklo_epi8(b0, g0);
         res_hi_bg0 = _mm_unpackhi_epi8(b0, g0);
         res_lo_ra0 = _mm_unpacklo_epi8(r0, a);
         res_hi_ra0 = _mm_unpackhi_epi8(r0, a);
         res_lo_bg1 = _mm_unpacklo_epi8(b1, g1);
         res_hi_bg1 = _mm_unpackhi_epi8(b1, g1);
         res_lo_ra1 = _mm_unpacklo_epi8(r1, a);
         res_hi_ra1 = _mm_unpackhi_epi8(r1, a);

         res_lo0    = _mm_or_si128(res_lo_bg0,
               _mm_slli_si128(res_lo_ra0, 2));
         res_hi0    = _mm_or_si128(res_hi_bg0,
               _mm_slli_si128(res_hi_ra0, 2));
         res_lo1    = _mm_or_si128(res_lo_bg1,
               _mm_slli_si128(res_lo_ra1, 2));
         res_hi1    = _mm_or_si128(res_hi_bg1,
               _mm_slli_si128(res_hi_ra1, 2));

         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);
      }
#endif

      for (; w < width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col >> 11) & 0x1f;
         uint32_t g   = (col >>  5) & 0x3f;
         uint32_t b   = (col >>  0) & 0x1f;
         r = (r << 3) | (r >> 2);
         g = (g << 2) | (g >> 4);
         b = (b << 3) | (b >> 2);

         *out++ = b;
         *out++ = g;
         *out++ = r;
      }
   }
}

void conv_bgr24_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint8_t *input = (const uint8_t*)input_;
   uint32_t *output     = (uint32_t*)output_;

   for (h = 0; h < height;
         h++, output += out_stride >> 2, input += in_stride)
   {
      const uint8_t *inp = input;
      for (w = 0; w < width; w++)
      {
         uint32_t b = *inp++;
         uint32_t g = *inp++;
         uint32_t r = *inp++;
         output[w]  = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
      }
   }
}

void conv_bgr24_rgb565(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint8_t *input = (const uint8_t*)input_;
   uint16_t *output     = (uint16_t*)output_;
   for (h = 0; h < height;
         h++, output += out_stride, input += in_stride)
   {
      const uint8_t *inp = input;
      for (w = 0; w < width; w++)
      {
         uint16_t b = *inp++;
         uint16_t g = *inp++;
         uint16_t r = *inp++;

         output[w] = ((r & 0x00F8) << 8) | ((g&0x00FC) << 3) | ((b&0x00F8) >> 3);
      }
   }
}

void conv_argb8888_0rgb1555(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint32_t *input = (const uint32_t*)input_;
   uint16_t *output      = (uint16_t*)output_;

   for (h = 0; h < height;
         h++, output += out_stride >> 1, input += in_stride >> 2)
   {
      for (w = 0; w < width; w++)
      {
         uint32_t col = input[w];
         uint16_t r   = (col >> 19) & 0x1f;
         uint16_t g   = (col >> 11) & 0x1f;
         uint16_t b   = (col >>  3) & 0x1f;
         output[w]    = (r << 10) | (g << 5) | (b << 0);
      }
   }
}

void conv_argb8888_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint32_t *input = (const uint32_t*)input_;
   uint8_t *output       = (uint8_t*)output_;

#if defined(__SSE2__)
   int max_width = width - 15;
#endif

   for (h = 0; h < height;
         h++, output += out_stride, input += in_stride >> 2)
   {
      uint8_t *out = output;
      int        w = 0;
#if defined(__SSE2__)
      for (; w < max_width; w += 16, out += 48)
      {
         __m128i l0 = _mm_loadu_si128((const __m128i*)(input + w +  0));
         __m128i l1 = _mm_loadu_si128((const __m128i*)(input + w +  4));
         __m128i l2 = _mm_loadu_si128((const __m128i*)(input + w +  8));
         __m128i l3 = _mm_loadu_si128((const __m128i*)(input + w + 12));
         store_bgr24_sse2(out, l0, l1, l2, l3);
      }
#endif

      for (; w < width; w++)
      {
         uint32_t col = input[w];
         *out++       = (uint8_t)(col >>  0);
         *out++       = (uint8_t)(col >>  8);
         *out++       = (uint8_t)(col >> 16);
      }
   }
}

#if defined(__SSE2__)
static INLINE __m128i conv_shuffle_rb_epi32(__m128i c)
{
   /* SSSE3 plz */
   const __m128i b_mask = _mm_set1_epi32(0x000000ff);
   const __m128i g_mask = _mm_set1_epi32(0x0000ff00);
   const __m128i r_mask = _mm_set1_epi32(0x00ff0000);
   __m128i sl = _mm_and_si128(_mm_slli_epi32(c, 16), r_mask);
   __m128i sr = _mm_and_si128(_mm_srli_epi32(c, 16), b_mask);
   __m128i g  = _mm_and_si128(c, g_mask);
   __m128i rb = _mm_or_si128(sl, sr);
   return _mm_or_si128(g, rb);
}
#endif

void conv_abgr8888_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint32_t *input = (const uint32_t*)input_;
   uint8_t *output       = (uint8_t*)output_;

#if defined(__SSE2__)
   int max_width = width - 15;
#endif

   for (h = 0; h < height;
         h++, output += out_stride, input += in_stride >> 2)
   {
      uint8_t *out = output;
      int        w = 0;
#if defined(__SSE2__)
      for (; w < max_width; w += 16, out += 48)
      {
		 __m128i a = _mm_loadu_si128((const __m128i*)(input + w +  0));
		 __m128i b = _mm_loadu_si128((const __m128i*)(input + w +  4));
		 __m128i c = _mm_loadu_si128((const __m128i*)(input + w +  8));
		 __m128i d = _mm_loadu_si128((const __m128i*)(input + w + 12));
         a = conv_shuffle_rb_epi32(a);
         b = conv_shuffle_rb_epi32(b);
         c = conv_shuffle_rb_epi32(c);
         d = conv_shuffle_rb_epi32(d);
         store_bgr24_sse2(out, a, b, c, d);
      }
#endif

      for (; w < width; w++)
      {
         uint32_t col = input[w];
         *out++       = (uint8_t)(col >> 16);
         *out++       = (uint8_t)(col >>  8);
         *out++       = (uint8_t)(col >>  0);
      }
   }
}

void conv_argb8888_abgr8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint32_t *input = (const uint32_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

   for (h = 0; h < height;
         h++, output += out_stride >> 2, input += in_stride >> 2)
   {
      for (w = 0; w < width; w++)
      {
         uint32_t col = input[w];
         output[w]    = ((col << 16) & 0xff0000) |
            ((col >> 16) & 0xff) | (col & 0xff00ff00);
      }
   }
}

#define YUV_SHIFT 6
#define YUV_OFFSET (1 << (YUV_SHIFT - 1))
#define YUV_MAT_Y (1 << 6)
#define YUV_MAT_U_G (-22)
#define YUV_MAT_U_B (113)
#define YUV_MAT_V_R (90)
#define YUV_MAT_V_G (-46)

void conv_yuyv_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint8_t *input        = (const uint8_t*)input_;
   uint32_t *output            = (uint32_t*)output_;

#if defined(__SSE2__)
   const __m128i mask_y        = _mm_set1_epi16(0xffu);
   const __m128i mask_u        = _mm_set1_epi32(0xffu << 8);
   const __m128i mask_v        = _mm_set1_epi32(0xffu << 24);
   const __m128i chroma_offset = _mm_set1_epi16(128);
   const __m128i round_offset  = _mm_set1_epi16(YUV_OFFSET);

   const __m128i yuv_mul       = _mm_set1_epi16(YUV_MAT_Y);
   const __m128i u_g_mul       = _mm_set1_epi16(YUV_MAT_U_G);
   const __m128i u_b_mul       = _mm_set1_epi16(YUV_MAT_U_B);
   const __m128i v_r_mul       = _mm_set1_epi16(YUV_MAT_V_R);
   const __m128i v_g_mul       = _mm_set1_epi16(YUV_MAT_V_G);
   const __m128i a             = _mm_cmpeq_epi16(
         _mm_setzero_si128(), _mm_setzero_si128());
#endif

   for (h = 0; h < height; h++, output += out_stride >> 2, input += in_stride)
   {
      const uint8_t *src = input;
      uint32_t      *dst = output;
      int              w = 0;

#if defined(__SSE2__)
      /* Each loop processes 16 pixels. */
      for (; w + 16 <= width; w += 16, src += 32, dst += 16)
      {
         __m128i u, v, u0_g, u1_g, u0_b, u1_b, v0_r, v1_r, v0_g, v1_g,
                 r0, g0, b0, r1, g1, b1;
         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         __m128i res0, res1, res2, res3;
         __m128i yuv0 = _mm_loadu_si128((const __m128i*)(src +  0)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */
         __m128i yuv1 = _mm_loadu_si128((const __m128i*)(src + 16)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */

         __m128i _y0 = _mm_and_si128(yuv0, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */
         __m128i u0 = _mm_and_si128(yuv0, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */
         __m128i v0 = _mm_and_si128(yuv0, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */
         __m128i _y1 = _mm_and_si128(yuv1, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */
         __m128i u1 = _mm_and_si128(yuv1, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */
         __m128i v1 = _mm_and_si128(yuv1, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */

         /* Juggle around to get U and V in the same 16-bit format as Y. */
         u0 = _mm_srli_si128(u0, 1);
         v0 = _mm_srli_si128(v0, 3);
         u1 = _mm_srli_si128(u1, 1);
         v1 = _mm_srli_si128(v1, 3);
         u = _mm_packs_epi32(u0, u1);
         v = _mm_packs_epi32(v0, v1);

         /* Apply YUV offsets (U, V) -= (-128, -128). */
         u = _mm_sub_epi16(u, chroma_offset);
         v = _mm_sub_epi16(v, chroma_offset);

         /* Upscale chroma horizontally (nearest). */
         u0 = _mm_unpacklo_epi16(u, u);
         u1 = _mm_unpackhi_epi16(u, u);
         v0 = _mm_unpacklo_epi16(v, v);
         v1 = _mm_unpackhi_epi16(v, v);

         /* Apply transformations. */
         _y0 = _mm_mullo_epi16(_y0, yuv_mul);
         _y1 = _mm_mullo_epi16(_y1, yuv_mul);
         u0_g   = _mm_mullo_epi16(u0, u_g_mul);
         u1_g   = _mm_mullo_epi16(u1, u_g_mul);
         u0_b   = _mm_mullo_epi16(u0, u_b_mul);
         u1_b   = _mm_mullo_epi16(u1, u_b_mul);
         v0_r   = _mm_mullo_epi16(v0, v_r_mul);
         v1_r   = _mm_mullo_epi16(v1, v_r_mul);
         v0_g   = _mm_mullo_epi16(v0, v_g_mul);
         v1_g   = _mm_mullo_epi16(v1, v_g_mul);

         /* Add contibutions from the transformed components. */
         r0 = _mm_srai_epi16(_mm_adds_epi16(_mm_adds_epi16(_y0, v0_r),
                  round_offset), YUV_SHIFT);
         g0 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_mm_adds_epi16(_y0, v0_g), u0_g), round_offset), YUV_SHIFT);
         b0 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_y0, u0_b), round_offset), YUV_SHIFT);

         r1 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_y1, v1_r), round_offset), YUV_SHIFT);
         g1 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_mm_adds_epi16(_y1, v1_g), u1_g), round_offset), YUV_SHIFT);
         b1 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_y1, u1_b), round_offset), YUV_SHIFT);

         /* Saturate into 8-bit. */
         r0 = _mm_packus_epi16(r0, r1);
         g0 = _mm_packus_epi16(g0, g1);
         b0 = _mm_packus_epi16(b0, b1);

         /* Interleave into ARGB. */
         res_lo_bg = _mm_unpacklo_epi8(b0, g0);
         res_hi_bg = _mm_unpackhi_epi8(b0, g0);
         res_lo_ra = _mm_unpacklo_epi8(r0, a);
         res_hi_ra = _mm_unpackhi_epi8(r0, a);
         res0 = _mm_unpacklo_epi16(res_lo_bg, res_lo_ra);
         res1 = _mm_unpackhi_epi16(res_lo_bg, res_lo_ra);
         res2 = _mm_unpacklo_epi16(res_hi_bg, res_hi_ra);
         res3 = _mm_unpackhi_epi16(res_hi_bg, res_hi_ra);

         _mm_storeu_si128((__m128i*)(dst +  0), res0);
         _mm_storeu_si128((__m128i*)(dst +  4), res1);
         _mm_storeu_si128((__m128i*)(dst +  8), res2);
         _mm_storeu_si128((__m128i*)(dst + 12), res3);
      }
#endif

      /* Finish off the rest (if any) in C. */
      for (; w < width; w += 2, src += 4, dst += 2)
      {
         int _y0    = src[0];
         int  u     = src[1] - 128;
         int _y1    = src[2];
         int  v     = src[3] - 128;

         uint8_t r0 = clamp_8bit((YUV_MAT_Y * _y0 +                   YUV_MAT_V_R * v + YUV_OFFSET) >> YUV_SHIFT);
         uint8_t g0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) >> YUV_SHIFT);
         uint8_t b0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_B * u                   + YUV_OFFSET) >> YUV_SHIFT);

         uint8_t r1 = clamp_8bit((YUV_MAT_Y * _y1 +                   YUV_MAT_V_R * v + YUV_OFFSET) >> YUV_SHIFT);
         uint8_t g1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) >> YUV_SHIFT);
         uint8_t b1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_B * u                   + YUV_OFFSET) >> YUV_SHIFT);

         dst[0]     = 0xff000000u | (r0 << 16) | (g0 << 8) | (b0 << 0);
         dst[1]     = 0xff000000u | (r1 << 16) | (g1 << 8) | (b1 << 0);
      }
   }
}

void conv_copy(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   int copy_len         = abs(out_stride);
   const uint8_t *input = (const uint8_t*)input_;
   uint8_t *output      = (uint8_t*)output_;

   if (abs(in_stride) < copy_len)
      copy_len          = abs(in_stride);

   for (h = 0; h < height;
         h++, output += out_stride, input += in_stride)
      memcpy(output, input, copy_len);
}

./include/libretro-common/gfx/scaler/scaler.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <gfx/scaler/scaler.h>
#include <gfx/scaler/scaler_int.h>
#include <gfx/scaler/filter.h>
#include <gfx/scaler/pixconv.h>

static bool allocate_frames(struct scaler_ctx *ctx)
{
   uint64_t *scaled_frame = NULL;
   ctx->scaled.stride     = ((ctx->out_width + 7) & ~7) * sizeof(uint64_t);
   ctx->scaled.width      = ctx->out_width;
   ctx->scaled.height     = ctx->in_height;
   scaled_frame           = (uint64_t*)calloc(
            (ctx->scaled.stride * ctx->scaled.height) >> 3,
            sizeof(uint64_t));

   if (!scaled_frame)
      return false;

   ctx->scaled.frame      = scaled_frame;

   if (ctx->in_fmt != SCALER_FMT_ARGB8888)
   {
      uint32_t *input_frame = NULL;
      ctx->input.stride     = ((ctx->in_width + 7) & ~7) * sizeof(uint32_t);
      input_frame           = (uint32_t*)calloc(
               (ctx->input.stride * ctx->in_height) >> 2,
               sizeof(uint32_t));

      if (!input_frame)
         return false;

      ctx->input.frame      = input_frame;
   }

   if (ctx->out_fmt != SCALER_FMT_ARGB8888)
   {
      uint32_t *output_frame = NULL;
      ctx->output.stride     = ((ctx->out_width + 7) & ~7) * sizeof(uint32_t);

      output_frame           = (uint32_t*)calloc(
               (ctx->output.stride * ctx->out_height) >> 2,
               sizeof(uint32_t));

      if (!output_frame)
         return false;

      ctx->output.frame      = output_frame;
   }

   return true;
}

bool scaler_ctx_gen_filter(struct scaler_ctx *ctx)
{
   scaler_ctx_gen_reset(ctx);

   ctx->scaler_special = NULL;
   ctx->unscaled       = false;

   if (!allocate_frames(ctx))
      return false;

   if (     ctx->in_width  == ctx->out_width
         && ctx->in_height == ctx->out_height)
   {
      ctx->unscaled     = true; /* Only pixel format conversion ... */

      if (ctx->in_fmt == ctx->out_fmt)
         ctx->direct_pixconv = conv_copy;
      else
      {
         /* Bind a pixel converter callback function to the
          * 'direct_pixconv' function pointer of the scaler context object. */
         switch (ctx->in_fmt)
         {
            case SCALER_FMT_0RGB1555:
               switch (ctx->out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx->direct_pixconv = conv_0rgb1555_argb8888;
                     break;
                  case SCALER_FMT_RGB565:
                     ctx->direct_pixconv = conv_0rgb1555_rgb565;
                     break;
                  case SCALER_FMT_BGR24:
                     ctx->direct_pixconv = conv_0rgb1555_bgr24;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_RGB565:
               switch (ctx->out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx->direct_pixconv = conv_rgb565_argb8888;
                     break;
                  case SCALER_FMT_ABGR8888:
                     ctx->direct_pixconv = conv_rgb565_abgr8888;
                     break;
                  case SCALER_FMT_BGR24:
                     ctx->direct_pixconv = conv_rgb565_bgr24;
                     break;
                  case SCALER_FMT_0RGB1555:
                     ctx->direct_pixconv = conv_rgb565_0rgb1555;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_BGR24:
               switch (ctx->out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx->direct_pixconv = conv_bgr24_argb8888;
                     break;
                  case SCALER_FMT_RGB565:
                     ctx->direct_pixconv = conv_bgr24_rgb565;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_ARGB8888:
               switch (ctx->out_fmt)
               {
                  case SCALER_FMT_0RGB1555:
                     ctx->direct_pixconv = conv_argb8888_0rgb1555;
                     break;
                  case SCALER_FMT_BGR24:
                     ctx->direct_pixconv = conv_argb8888_bgr24;
                     break;
                  case SCALER_FMT_ABGR8888:
                     ctx->direct_pixconv = conv_argb8888_abgr8888;
                     break;
                  case SCALER_FMT_RGBA4444:
                     ctx->direct_pixconv = conv_argb8888_rgba4444;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_YUYV:
               switch (ctx->out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx->direct_pixconv = conv_yuyv_argb8888;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_RGBA4444:
               switch (ctx->out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx->direct_pixconv = conv_rgba4444_argb8888;
                     break;
                  case SCALER_FMT_RGB565:
                     ctx->direct_pixconv = conv_rgba4444_rgb565;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_ABGR8888:
               switch (ctx->out_fmt)
               {
                  case SCALER_FMT_BGR24:
                     ctx->direct_pixconv = conv_abgr8888_bgr24;
                     break;
                  default:
                     break;
               }
               break;
         }

         if (!ctx->direct_pixconv)
            return false;
      }
   }
   else
   {
      ctx->scaler_horiz = scaler_argb8888_horiz;
      ctx->scaler_vert  = scaler_argb8888_vert;

      switch (ctx->in_fmt)
      {
         case SCALER_FMT_ARGB8888:
            /* No need to convert :D */
            break;

         case SCALER_FMT_0RGB1555:
            ctx->in_pixconv = conv_0rgb1555_argb8888;
            break;

         case SCALER_FMT_RGB565:
            ctx->in_pixconv = conv_rgb565_argb8888;
            break;

         case SCALER_FMT_BGR24:
            ctx->in_pixconv = conv_bgr24_argb8888;
            break;

         case SCALER_FMT_RGBA4444:
            ctx->in_pixconv = conv_rgba4444_argb8888;
            break;

         default:
            return false;
      }

      switch (ctx->out_fmt)
      {
         case SCALER_FMT_ARGB8888:
            /* No need to convert :D */
            break;

         case SCALER_FMT_RGBA4444:
            ctx->out_pixconv = conv_argb8888_rgba4444;
            break;

         case SCALER_FMT_0RGB1555:
            ctx->out_pixconv = conv_argb8888_0rgb1555;
            break;

         case SCALER_FMT_BGR24:
            ctx->out_pixconv = conv_argb8888_bgr24;
            break;

         case SCALER_FMT_ABGR8888:
            ctx->out_pixconv = conv_argb8888_abgr8888;
            break;

         default:
            return false;
      }

      if (!scaler_gen_filter(ctx))
         return false;
   }

   return true;
}

void scaler_ctx_gen_reset(struct scaler_ctx *ctx)
{
   if (ctx->horiz.filter)
      free(ctx->horiz.filter);
   if (ctx->horiz.filter_pos)
      free(ctx->horiz.filter_pos);
   if (ctx->vert.filter)
      free(ctx->vert.filter);
   if (ctx->vert.filter_pos)
      free(ctx->vert.filter_pos);
   if (ctx->scaled.frame)
      free(ctx->scaled.frame);
   if (ctx->input.frame)
      free(ctx->input.frame);
   if (ctx->output.frame)
      free(ctx->output.frame);

   ctx->horiz.filter        = NULL;
   ctx->horiz.filter_len    = 0;
   ctx->horiz.filter_stride = 0;
   ctx->horiz.filter_pos    = NULL;

   ctx->vert.filter         = NULL;
   ctx->vert.filter_len     = 0;
   ctx->vert.filter_stride  = 0;
   ctx->vert.filter_pos     = NULL;

   ctx->scaled.frame        = NULL;
   ctx->scaled.width        = 0;
   ctx->scaled.height       = 0;
   ctx->scaled.stride       = 0;

   ctx->input.frame         = NULL;
   ctx->input.stride        = 0;

   ctx->output.frame        = NULL;
   ctx->output.stride       = 0;
}

/**
 * scaler_ctx_scale:
 * @ctx          : pointer to scaler context object.
 * @output       : pointer to output image.
 * @input        : pointer to input image.
 *
 * Scales an input image to an output image.
 **/
void scaler_ctx_scale(struct scaler_ctx *ctx,
      void *output, const void *input)
{
   const void *input_frame = input;
   void *output_frame      = output;
   int input_stride        = ctx->in_stride;
   int output_stride       = ctx->out_stride;

   if (ctx->in_fmt != SCALER_FMT_ARGB8888)
   {
      ctx->in_pixconv(ctx->input.frame, input,
            ctx->in_width, ctx->in_height,
            ctx->input.stride, ctx->in_stride);

      input_frame       = ctx->input.frame;
      input_stride      = ctx->input.stride;
   }

   if (ctx->out_fmt != SCALER_FMT_ARGB8888)
   {
      output_frame  = ctx->output.frame;
      output_stride = ctx->output.stride;
   }

   /* Take some special, and (hopefully) more optimized path. */
   if (ctx->scaler_special)
      ctx->scaler_special(ctx, output_frame, input_frame,
            ctx->out_width, ctx->out_height,
            ctx->in_width, ctx->in_height,
            output_stride, input_stride);
   else
   {
      /* Take generic filter path. */
      if (ctx->scaler_horiz)
         ctx->scaler_horiz(ctx, input_frame, input_stride);
      if (ctx->scaler_vert)
         ctx->scaler_vert (ctx, output, output_stride);
   }

   if (ctx->out_fmt != SCALER_FMT_ARGB8888)
      ctx->out_pixconv(output, ctx->output.frame,
            ctx->out_width, ctx->out_height,
            ctx->out_stride, ctx->output.stride);
}

./include/libretro-common/gfx/scaler/scaler_filter.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler_filter.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <string.h>

#include <gfx/scaler/filter.h>
#include <gfx/scaler/scaler_int.h>
#include <retro_inline.h>
#include <filters.h>
#include <retro_math.h>

#define FILTER_UNITY (1 << 14)

static INLINE void gen_filter_point_sub(struct scaler_filter *filter,
      int len, int pos, int step)
{
   int i;
   for (i = 0; i < len; i++, pos += step)
   {
      filter->filter_pos[i] = pos >> 16;
      filter->filter[i]     = FILTER_UNITY;
   }
}

static INLINE void gen_filter_bilinear_sub(struct scaler_filter *filter,
      int len, int pos, int step)
{
   int i;
   for (i = 0; i < len; i++, pos += step)
   {
      filter->filter_pos[i]     = pos >> 16;
      filter->filter[i * 2 + 1] = (pos & 0xffff) >> 2;
      filter->filter[i * 2 + 0] = FILTER_UNITY - filter->filter[i * 2 + 1];
   }
}

static INLINE void gen_filter_sinc_sub(struct scaler_filter *filter,
      int len, int pos, int step, double phase_mul)
{
   int i, j;
   const int sinc_size = filter->filter_len;

   for (i = 0; i < len; i++, pos += step)
   {
      filter->filter_pos[i] = pos >> 16;

      for (j = 0; j < sinc_size; j++)
      {
         double sinc_phase    = M_PI * ((double)((sinc_size << 15) + (pos & 0xffff)) / 0x10000 - j);
         double lanczos_phase = sinc_phase / ((sinc_size >> 1));
         int16_t sinc_val     = FILTER_UNITY * sinc(sinc_phase * phase_mul) * sinc(lanczos_phase) * phase_mul;

         filter->filter[i * sinc_size + j] = sinc_val;
      }
   }
}

static bool validate_filter(struct scaler_ctx *ctx)
{
   int i;
   int max_h_pos;
   int max_w_pos = ctx->in_width - ctx->horiz.filter_len;

   for (i = 0; i < ctx->out_width; i++)
   {
      if (ctx->horiz.filter_pos[i] > max_w_pos || ctx->horiz.filter_pos[i] < 0)
         return false;
   }

   max_h_pos = ctx->in_height - ctx->vert.filter_len;

   for (i = 0; i < ctx->out_height; i++)
   {
      if (ctx->vert.filter_pos[i] > max_h_pos || ctx->vert.filter_pos[i] < 0)
         return false;
   }

   return true;
}

static void fixup_filter_sub(struct scaler_filter *filter,
      int out_len, int in_len)
{
   int i;
   int max_pos = in_len - filter->filter_len;

   for (i = 0; i < out_len; i++)
   {
      int postsample =  filter->filter_pos[i] - max_pos;
      int presample  = -filter->filter_pos[i];

      if (postsample > 0)
      {
         int16_t *base_filter   = NULL;

         filter->filter_pos[i] -= postsample;

         base_filter            = filter->filter + i * filter->filter_stride;

         if (postsample > (int)filter->filter_len)
            memset(base_filter, 0, filter->filter_len * sizeof(int16_t));
         else
         {
            memmove(base_filter + postsample, base_filter,
                  (filter->filter_len - postsample) * sizeof(int16_t));
            memset(base_filter, 0, postsample * sizeof(int16_t));
         }
      }

      if (presample > 0)
      {
         int16_t *base_filter   = NULL;

         filter->filter_pos[i] += presample;
         base_filter            = filter->filter + i * filter->filter_stride;

         if (presample > (int)filter->filter_len)
            memset(base_filter, 0, filter->filter_len * sizeof(int16_t));
         else
         {
            memmove(base_filter, base_filter + presample,
                  (filter->filter_len - presample) * sizeof(int16_t));
            memset(base_filter + (filter->filter_len - presample),
                  0, presample * sizeof(int16_t));
         }
      }
   }
}

bool scaler_gen_filter(struct scaler_ctx *ctx)
{
   int x_pos, x_step, y_pos, y_step;
   int sinc_size = 0;

   switch (ctx->scaler_type)
   {
      case SCALER_TYPE_POINT:
         ctx->horiz.filter_len    = 1;
         ctx->horiz.filter_stride = 1;
         ctx->vert.filter_len     = 1;
         ctx->vert.filter_stride  = 1;
         break;
      case SCALER_TYPE_BILINEAR:
         ctx->horiz.filter_len    = 2;
         ctx->horiz.filter_stride = 2;
         ctx->vert.filter_len     = 2;
         ctx->vert.filter_stride  = 2;
         break;
      case SCALER_TYPE_SINC:
         sinc_size                = 8 * ((ctx->in_width > ctx->out_width)
               ? next_pow2(ctx->in_width / ctx->out_width) : 1);
         ctx->horiz.filter_len    = sinc_size;
         ctx->horiz.filter_stride = sinc_size;
         ctx->vert.filter_len     = sinc_size;
         ctx->vert.filter_stride  = sinc_size;
         break;
      case SCALER_TYPE_UNKNOWN:
      default:
         return false;
   }

   ctx->horiz.filter     = (int16_t*)calloc(ctx->horiz.filter_stride * ctx->out_width, sizeof(int16_t));
   ctx->horiz.filter_pos = (int*)calloc(ctx->out_width, sizeof(int));

   ctx->vert.filter      = (int16_t*)calloc(ctx->vert.filter_stride * ctx->out_height, sizeof(int16_t));
   ctx->vert.filter_pos  = (int*)calloc(ctx->out_height, sizeof(int));

   if (!ctx->horiz.filter || !ctx->vert.filter)
      return false;

   x_step = (1 << 16) * ctx->in_width  / ctx->out_width;
   y_step = (1 << 16) * ctx->in_height / ctx->out_height;
   x_pos  = (1 << 15) * ctx->in_width  / ctx->out_width  - (1 << 15);
   y_pos  = (1 << 15) * ctx->in_height / ctx->out_height - (1 << 15);

   switch (ctx->scaler_type)
   {
      case SCALER_TYPE_POINT:
         gen_filter_point_sub(&ctx->horiz, ctx->out_width,  x_pos, x_step);
         gen_filter_point_sub(&ctx->vert,  ctx->out_height, y_pos, y_step);

         ctx->scaler_special = scaler_argb8888_point_special;
         break;

      case SCALER_TYPE_BILINEAR:
         gen_filter_bilinear_sub(&ctx->horiz, ctx->out_width,  x_pos, x_step);
         gen_filter_bilinear_sub(&ctx->vert,  ctx->out_height, y_pos, y_step);
         break;

      case SCALER_TYPE_SINC:
         /* Need to expand the filter when downsampling
          * to get a proper low-pass effect. */
         x_pos  -= (sinc_size << 15);
         y_pos  -= (sinc_size << 15);

         gen_filter_sinc_sub(&ctx->horiz, ctx->out_width, x_pos, x_step,
               ctx->in_width  > ctx->out_width  ? (double)ctx->out_width  / ctx->in_width  : 1.0);
         gen_filter_sinc_sub(&ctx->vert, ctx->out_height, y_pos, y_step,
               ctx->in_height > ctx->out_height ? (double)ctx->out_height / ctx->in_height : 1.0
               );
         break;
      case SCALER_TYPE_UNKNOWN:
         break;
   }

   /* Makes sure that we never sample outside our rectangle */
   fixup_filter_sub(&ctx->horiz, ctx->out_width,  ctx->in_width);
   fixup_filter_sub(&ctx->vert,  ctx->out_height, ctx->in_height);

   return validate_filter(ctx);
}

./include/libretro-common/gfx/scaler/scaler_int.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler_int.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <gfx/scaler/scaler_int.h>

#include <retro_inline.h>

#ifdef SCALER_NO_SIMD
#undef __SSE2__
#endif

#if defined(__SSE2__)
#include <emmintrin.h>
#ifdef _WIN32
#include <intrin.h>
#endif
#endif

/* ARGB8888 scaler is split in two:
 *
 * First, horizontal scaler is applied.
 * Here, all 8-bit channels are expanded to 16-bit. Values are then shifted 7
 * to left to occupy 15 bits.
 *
 * The sign bit is kept empty as we have to do signed multiplication for the
 * filter.
 *
 * A mulhi [(a * b) >> 16] is applied which loses some precision, but is
 * very efficient for SIMD.
 * It is accurate enough for 8-bit purposes.
 *
 * The fixed point 1.0 for filter is (1 << 14). After horizontal scale,
 * the output is kept with 16-bit channels, and will now have 13 bits
 * of precision as [(a * (1 << 14)) >> 16] is effectively a right shift by 2.
 *
 * Vertical scaler takes the 13 bit channels, and performs the
 * same mulhi steps.
 * Another 2 bits of precision is lost, which ends up as 11 bits.
 * Scaling is now complete. Channels are shifted right by 3, and saturated
 * into 8-bit values.
 *
 * The C version of scalers perform the exact same operations as the
 * SIMD code for testing purposes.
 */

void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)
{
   int h, w, y;
   const uint64_t      *input = ctx->scaled.frame;
   uint32_t           *output = (uint32_t*)output_;

   const int16_t *filter_vert = ctx->vert.filter;

   for (h = 0; h < ctx->out_height; h++,
         filter_vert += ctx->vert.filter_stride, output += stride >> 2)
   {
      const uint64_t *input_base = input + ctx->vert.filter_pos[h]
         * (ctx->scaled.stride >> 3);

      for (w = 0; w < ctx->out_width; w++)
      {
         const uint64_t *input_base_y = input_base + w;
#if defined(__SSE2__)
         __m128i final;
         __m128i res = _mm_setzero_si128();

         for (y = 0; (y + 1) < ctx->vert.filter_len; y += 2,
               input_base_y += (ctx->scaled.stride >> 2))
         {
            __m128i coeff = _mm_set_epi64x(filter_vert[y + 1] * 0x0001000100010001ll, filter_vert[y + 0] * 0x0001000100010001ll);
            __m128i col   = _mm_set_epi64x(input_base_y[ctx->scaled.stride >> 3], input_base_y[0]);

            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         for (; y < ctx->vert.filter_len; y++, input_base_y += (ctx->scaled.stride >> 3))
         {
            __m128i coeff = _mm_set_epi64x(0, filter_vert[y] * 0x0001000100010001ll);
            __m128i col   = _mm_set_epi64x(0, input_base_y[0]);

            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         res       = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
         res       = _mm_srai_epi16(res, (7 - 2 - 2));

         final     = _mm_packus_epi16(res, res);

         output[w] = _mm_cvtsi128_si32(final);
#else
         int16_t res_a = 0;
         int16_t res_r = 0;
         int16_t res_g = 0;
         int16_t res_b = 0;

         for (y = 0; y < ctx->vert.filter_len; y++,
               input_base_y += (ctx->scaled.stride >> 3))
         {
            uint64_t col   = *input_base_y;

            int16_t a      = (col >> 48) & 0xffff;
            int16_t r      = (col >> 32) & 0xffff;
            int16_t g      = (col >> 16) & 0xffff;
            int16_t b      = (col >>  0) & 0xffff;

            int16_t coeff  = filter_vert[y];

            res_a         += (a * coeff) >> 16;
            res_r         += (r * coeff) >> 16;
            res_g         += (g * coeff) >> 16;
            res_b         += (b * coeff) >> 16;
         }

         res_a           >>= (7 - 2 - 2);
         res_r           >>= (7 - 2 - 2);
         res_g           >>= (7 - 2 - 2);
         res_b           >>= (7 - 2 - 2);

         output[w]         =
            (clamp_8bit(res_a) << 24) |
            (clamp_8bit(res_r) << 16) |
            (clamp_8bit(res_g) << 8)  |
            (clamp_8bit(res_b) << 0);
#endif
      }
   }
}

void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)
{
   int h, w, x;
   const uint32_t *input = (uint32_t*)input_;
   uint64_t *output      = ctx->scaled.frame;

   for (h = 0; h < ctx->scaled.height; h++, input += stride >> 2,
         output += ctx->scaled.stride >> 3)
   {
      const int16_t *filter_horiz = ctx->horiz.filter;

      for (w = 0; w < ctx->scaled.width; w++,
            filter_horiz += ctx->horiz.filter_stride)
      {
         const uint32_t *input_base_x = input + ctx->horiz.filter_pos[w];
#if defined(__SSE2__)
         __m128i res = _mm_setzero_si128();
#ifndef __x86_64__
         union
         {
            uint32_t *u32;
            uint64_t *u64;
         } u;
#endif
         for (x = 0; (x + 1) < ctx->horiz.filter_len; x += 2)
         {
            __m128i coeff = _mm_set_epi64x(filter_horiz[x + 1] * 0x0001000100010001ll, filter_horiz[x + 0] * 0x0001000100010001ll);

            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi64x(0,
                     ((uint64_t)input_base_x[x + 1] << 32) | input_base_x[x + 0]), _mm_setzero_si128());

            col           = _mm_slli_epi16(col, 7);
            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         for (; x < ctx->horiz.filter_len; x++)
         {
            __m128i coeff = _mm_set_epi64x(0, filter_horiz[x] * 0x0001000100010001ll);
            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi32(0, 0, 0, input_base_x[x]), _mm_setzero_si128());

            col           = _mm_slli_epi16(col, 7);
            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         res              = _mm_adds_epi16(_mm_srli_si128(res, 8), res);

#ifdef __x86_64__
         output[w]        = _mm_cvtsi128_si64(res);
#else /* 32-bit doesn't have si64. Do it in two steps. */
         u.u64    = output + w;
         u.u32[0] = _mm_cvtsi128_si32(res);
         u.u32[1] = _mm_cvtsi128_si32(_mm_srli_si128(res, 4));
#endif
#else
         int16_t res_a = 0;
         int16_t res_r = 0;
         int16_t res_g = 0;
         int16_t res_b = 0;

         for (x = 0; x < ctx->horiz.filter_len; x++)
         {
            uint32_t col   = input_base_x[x];

            int16_t a      = (col >> (24 - 7)) & (0xff << 7);
            int16_t r      = (col >> (16 - 7)) & (0xff << 7);
            int16_t g      = (col >> ( 8 - 7)) & (0xff << 7);
            int16_t b      = (col << ( 0 + 7)) & (0xff << 7);

            int16_t coeff  = filter_horiz[x];

            res_a         += (a * coeff) >> 16;
            res_r         += (r * coeff) >> 16;
            res_g         += (g * coeff) >> 16;
            res_b         += (b * coeff) >> 16;
         }

         output[w]         = (
               (uint64_t)res_a  << 48)  |
               ((uint64_t)res_r << 32)  |
               ((uint64_t)res_g << 16)  |
               ((uint64_t)res_b << 0);
#endif
      }
   }
}

void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
      void *output_, const void *input_,
      int out_width, int out_height,
      int in_width, int in_height,
      int out_stride, int in_stride)
{
   int h, w;
   int x_pos             = (1 << 15) * in_width / out_width - (1 << 15);
   int x_step            = (1 << 16) * in_width / out_width;
   int y_pos             = (1 << 15) * in_height / out_height - (1 << 15);
   int y_step            = (1 << 16) * in_height / out_height;
   const uint32_t *input = (const uint32_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

   if (x_pos < 0)
      x_pos = 0;
   if (y_pos < 0)
      y_pos = 0;

   for (h = 0; h < out_height; h++, y_pos += y_step, output += out_stride >> 2)
   {
      int               x = x_pos;
      const uint32_t *inp = input + (y_pos >> 16) * (in_stride >> 2);

      for (w = 0; w < out_width; w++, x += x_step)
         output[w] = inp[x >> 16];
   }
}

./include/libretro-common/.gitignore

glsm/
*.[od]
*.dll
*.so
*.dylib
*.exe

./include/libretro-common/glsm/glsm.c

/* Copyright (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsm).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <glsym/glsym.h>
#include <glsm/glsm.h>

#ifndef GL_DEPTH_CLAMP
#define GL_DEPTH_CLAMP                    0x864F
#define GL_RASTERIZER_DISCARD             0x8C89
#define GL_SAMPLE_MASK                    0x8E51
#endif

#if 0
extern retro_log_printf_t log_cb;
#define GLSM_DEBUG
#endif

struct gl_cached_state
{
   struct
   {
      GLuint *ids;
   } bind_textures;

   struct
   {
      bool used[MAX_ATTRIB];
      GLint size[MAX_ATTRIB];
      GLenum type[MAX_ATTRIB];
      GLboolean normalized[MAX_ATTRIB];
      GLsizei stride[MAX_ATTRIB];
      const GLvoid *pointer[MAX_ATTRIB];
      GLuint buffer[MAX_ATTRIB];
   } attrib_pointer;

#ifndef HAVE_OPENGLES
   GLenum colorlogicop;
#endif

   struct
   {
      bool enabled[MAX_ATTRIB];
   } vertex_attrib_pointer;

   struct
   {
      GLenum pname;
      GLint param;
   } pixelstore_i;

   struct
   {
      GLuint r;
      GLuint g;
      GLuint b;
      GLuint a;
   } clear_color;

   struct
   {
      bool used;
      GLint x;
      GLint y;
      GLsizei w;
      GLsizei h;
   } scissor;

   struct
   {
      GLint x;
      GLint y;
      GLsizei w;
      GLsizei h;
   } viewport;

   struct
   {
      bool used;
      GLenum sfactor;
      GLenum dfactor;
   } blendfunc;

   struct
   {
      bool used;
      GLenum srcRGB;
      GLenum dstRGB;
      GLenum srcAlpha;
      GLenum dstAlpha;
   } blendfunc_separate;

   struct
   {
      bool used;
      GLboolean red;
      GLboolean green;
      GLboolean blue;
      GLboolean alpha;
   } colormask;

   struct
   {
      bool used;
      GLdouble depth;
   } cleardepth;

   struct
   {
      bool used;
      GLenum func;
   } depthfunc;

   struct
   {
      bool used;
      GLclampd zNear;
      GLclampd zFar;
   } depthrange;

   struct
   {
      bool used;
      GLfloat factor;
      GLfloat units;
   } polygonoffset;

   struct
   {
      bool used;
      GLenum func;
      GLint ref;
      GLuint mask;
   } stencilfunc;

   struct
   {
      bool used;
      GLenum sfail;
      GLenum dpfail;
      GLenum dppass;
   } stencilop;

   struct
   {
      bool used;
      GLenum mode;
   } frontface;

   struct
   {
      bool used;
      GLenum mode;
   } cullface;

   struct
   {
      bool used;
      GLuint mask;
   } stencilmask;

   struct
   {
      bool used;
      GLboolean mask;
   } depthmask;

   struct
   {
      GLenum mode;
   } readbuffer;

   GLuint vao;
   GLuint framebuf;
   GLuint array_buffer;
   GLuint program;
   GLenum active_texture;
   int cap_state[SGL_CAP_MAX];
   int cap_translate[SGL_CAP_MAX];
};

static GLuint default_framebuffer;
static GLint glsm_max_textures;
struct retro_hw_render_callback hw_render;
static struct gl_cached_state gl_state;

/* GL wrapper-side */

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
GLenum rglGetError(void)
{
   return glGetError();
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : N/A
 */

void rglProvokingVertex(	GLenum provokeMode)
{
#if defined(HAVE_OPENGL)
   glProvokingVertex(provokeMode);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglGetInteger64v(	GLenum pname, int64_t *data)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGetInteger64v(pname, (GLint64*)data);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglSamplerParameteri(	GLuint sampler,
 	GLenum pname,
 	GLint param)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glSamplerParameteri(sampler, pname, param);
#endif
}

void rglGenSamplers(	GLsizei n,
 	GLuint *samplers)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGenSamplers(n, samplers);
#endif
}

void rglBindSampler(	GLuint unit,
 	GLuint sampler)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glBindSampler(unit, sampler);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglClear(GLbitfield mask)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClear.\n");
#endif
   glClear(mask);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglValidateProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glValidateProgram.\n");
#endif
   glValidateProgram(program);
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 * OpenGLES  : N/A
 */
void rglPolygonMode(GLenum face, GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glPolygonMode.\n");
#endif
#ifndef HAVE_OPENGLES
   glPolygonMode(face, mode);
#endif
}

void rglTexSubImage2D(
      GLenum target,
  	GLint level,
  	GLint xoffset,
  	GLint yoffset,
  	GLsizei width,
  	GLsizei height,
  	GLenum format,
  	GLenum type,
  	const GLvoid * pixels)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexSubImage2D.\n");
#endif
   glTexSubImage2D(target, level, xoffset, yoffset,
         width, height, format, type, pixels);
}

void rglGetBufferSubData(	GLenum target,
 	GLintptr offset,
 	GLsizeiptr size,
 	GLvoid * data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetBufferSubData.\n");
#endif
#if defined(HAVE_OPENGL)
   glGetBufferSubData(target, offset, size, data);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglLineWidth(GLfloat width)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glLineWidth.\n");
#endif
   glLineWidth(width);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglBlitFramebuffer(
      GLint srcX0, GLint srcY0,
      GLint srcX1, GLint srcY1,
      GLint dstX0, GLint dstY0,
      GLint dstX1, GLint dstY1,
      GLbitfield mask, GLenum filter)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlitFramebuffer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
         dstX0, dstY0, dstX1, dstY1,
         mask, filter);
#endif
}

/*
 *
 * Core in:
 * OpenGLES  : 3.0
 */
void rglReadBuffer(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glReadBuffer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glReadBuffer(mode);
   gl_state.readbuffer.mode = mode;
#endif
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglClearDepth(GLdouble depth)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearDepth.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
#ifdef HAVE_OPENGLES
   glClearDepthf(depth);
#else
   glClearDepth(depth);
#endif
   gl_state.cleardepth.used  = true;
   gl_state.cleardepth.depth = depth;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglPixelStorei(GLenum pname, GLint param)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glPixelStorei.\n");
#endif
   glPixelStorei(pname, param);
   gl_state.pixelstore_i.pname = pname;
   gl_state.pixelstore_i.param = param;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglDepthRange(GLclampd zNear, GLclampd zFar)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDepthRange.\n");
#endif
#ifdef HAVE_OPENGLES
   glDepthRangef(zNear, zFar);
#else
   glDepthRange(zNear, zFar);
#endif
   gl_state.depthrange.used  = true;
   gl_state.depthrange.zNear = zNear;
   gl_state.depthrange.zFar  = zFar;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglFrontFace(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFrontFace.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glFrontFace(mode);
   gl_state.frontface.used = true;
   gl_state.frontface.mode = mode;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglDepthFunc(GLenum func)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDepthFunc.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.depthfunc.used = true;
   gl_state.depthfunc.func = func;
   glDepthFunc(func);
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglColorMask(GLboolean red, GLboolean green,
      GLboolean blue, GLboolean alpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glColorMask.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glColorMask(red, green, blue, alpha);
   gl_state.colormask.red   = red;
   gl_state.colormask.green = green;
   gl_state.colormask.blue  = blue;
   gl_state.colormask.alpha = alpha;
   gl_state.colormask.used  = true;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglCullFace(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCullFace.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glCullFace(mode);
   gl_state.cullface.used = true;
   gl_state.cullface.mode = mode;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glStencilOp.\n");
#endif
   glStencilOp(sfail, dpfail, dppass);
   gl_state.stencilop.used   = true;
   gl_state.stencilop.sfail  = sfail;
   gl_state.stencilop.dpfail = dpfail;
   gl_state.stencilop.dppass = dppass;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglStencilFunc(GLenum func, GLint ref, GLuint mask)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glStencilFunc.\n");
#endif
   glStencilFunc(func, ref, mask);
   gl_state.stencilfunc.used = true;
   gl_state.stencilfunc.func = func;
   gl_state.stencilfunc.ref  = ref;
   gl_state.stencilfunc.mask = mask;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
GLboolean rglIsEnabled(GLenum cap)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glIsEnabled.\n");
#endif
   return gl_state.cap_state[cap] ? GL_TRUE : GL_FALSE;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglClearColor(GLclampf red, GLclampf green,
      GLclampf blue, GLclampf alpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearColor.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glClearColor(red, green, blue, alpha);
   gl_state.clear_color.r = red;
   gl_state.clear_color.g = green;
   gl_state.clear_color.b = blue;
   gl_state.clear_color.a = alpha;
}

/*
 *
 * Core in:
 * OpenGLES    : 2.0 (maybe earlier?)
 */
void rglScissor(GLint x, GLint y, GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glScissor.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glScissor(x, y, width, height);
   gl_state.scissor.used = true;
   gl_state.scissor.x    = x;
   gl_state.scissor.y    = y;
   gl_state.scissor.w    = width;
   gl_state.scissor.h    = height;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglViewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glViewport.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glViewport(x, y, width, height);
   gl_state.viewport.x = x;
   gl_state.viewport.y = y;
   gl_state.viewport.w = width;
   gl_state.viewport.h = height;
}

void rglBlendFunc(GLenum sfactor, GLenum dfactor)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendFunc.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.blendfunc.used    = true;
   gl_state.blendfunc.sfactor = sfactor;
   gl_state.blendfunc.dfactor = dfactor;
   glBlendFunc(sfactor, dfactor);
}

/*
 * Category: Blending
 *
 * Core in:
 * OpenGL    : 1.4
 */
void rglBlendFuncSeparate(GLenum sfactor, GLenum dfactor)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendFuncSeparate.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.blendfunc_separate.used     = true;
   gl_state.blendfunc_separate.srcRGB   = sfactor;
   gl_state.blendfunc_separate.dstRGB   = dfactor;
   gl_state.blendfunc_separate.srcAlpha = sfactor;
   gl_state.blendfunc_separate.dstAlpha = dfactor;
   glBlendFunc(sfactor, dfactor);
}

/*
 * Category: Textures
 *
 * Core in:
 * OpenGL    : 1.3
 */
void rglActiveTexture(GLenum texture)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glActiveTexture.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glActiveTexture(texture);
   gl_state.active_texture = texture - GL_TEXTURE0;
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglBindTexture(GLenum target, GLuint texture)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindTexture.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glBindTexture(target, texture);
   gl_state.bind_textures.ids[gl_state.active_texture] = texture;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglDisable(GLenum cap)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDisable.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glDisable(gl_state.cap_translate[cap]);
   gl_state.cap_state[cap] = 0;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglEnable(GLenum cap)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glEnable.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glEnable(gl_state.cap_translate[cap]);
   gl_state.cap_state[cap] = 1;
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUseProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUseProgram.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.program = program;
   glUseProgram(program);
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglDepthMask(GLboolean flag)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDepthMask.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glDepthMask(flag);
   gl_state.depthmask.used = true;
   gl_state.depthmask.mask = flag;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglStencilMask(GLenum mask)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glStencilMask.\n");
#endif
   glStencilMask(mask);
   gl_state.stencilmask.used = true;
   gl_state.stencilmask.mask = mask;
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglBufferData(GLenum target, GLsizeiptr size,
      const GLvoid *data, GLenum usage)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBufferData.\n");
#endif
   glBufferData(target, size, data, usage);
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglBufferSubData(GLenum target, GLintptr offset,
      GLsizeiptr size, const GLvoid *data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBufferSubData.\n");
#endif
   glBufferSubData(target, offset, size, data);
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglBindBuffer(GLenum target, GLuint buffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindBuffer.\n");
#endif
   if (target == GL_ARRAY_BUFFER)
      gl_state.array_buffer = buffer;
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glBindBuffer(target, buffer);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglLinkProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glLinkProgram.\n");
#endif
   glLinkProgram(program);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 2.0
 */
void rglFramebufferTexture2D(GLenum target, GLenum attachment,
      GLenum textarget, GLuint texture, GLint level)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFramebufferTexture2D.\n");
#endif
   glFramebufferTexture2D(target, attachment, textarget, texture, level);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.2
 */
void rglFramebufferTexture(GLenum target, GLenum attachment,
  	GLuint texture, GLint level)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFramebufferTexture.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
   glFramebufferTexture(target, attachment, texture, level);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglDrawArrays(GLenum mode, GLint first, GLsizei count)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawArrays.\n");
#endif
   glDrawArrays(mode, first, count);
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglDrawElements(GLenum mode, GLsizei count, GLenum type,
                           const GLvoid * indices)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawElements.\n");
#endif
   glDrawElements(mode, count, type, indices);
}

void rglCompressedTexImage2D(GLenum target, GLint level,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLint border, GLsizei imageSize, const GLvoid *data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCompressedTexImage2D.\n");
#endif
   glCompressedTexImage2D(target, level, internalformat,
         width, height, border, imageSize, data);
}

void rglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteFramebuffers.\n");
#endif
   glDeleteFramebuffers(n, framebuffers);
}

void rglDeleteTextures(GLsizei n, const GLuint *textures)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteTextures.\n");
#endif
   glDeleteTextures(n, textures);
}

/*
 *
 * Core in:
 * OpenGLES    : 2.0
 */
void rglRenderbufferStorage(GLenum target, GLenum internalFormat,
      GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glRenderbufferStorage.\n");
#endif
   glRenderbufferStorage(target, internalFormat, width, height);
}

/*
 *
 * Core in:
 *
 * OpenGL      : 3.0
 * OpenGLES    : 2.0
 */
void rglBindRenderbuffer(GLenum target, GLuint renderbuffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindRenderbuffer.\n");
#endif
   glBindRenderbuffer(target, renderbuffer);
}

/*
 *
 * Core in:
 *
 * OpenGLES    : 2.0
 */
void rglDeleteRenderbuffers(GLsizei n, GLuint *renderbuffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteRenderbuffers.\n");
#endif
   glDeleteRenderbuffers(n, renderbuffers);
}

/*
 *
 * Core in:
 *
 * OpenGL      : 3.0
 * OpenGLES    : 2.0
 */
void rglGenRenderbuffers(GLsizei n, GLuint *renderbuffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenRenderbuffers.\n");
#endif
   glGenRenderbuffers(n, renderbuffers);
}

/*
 *
 * Core in:
 *
 * OpenGL      : 3.0
 * OpenGLES    : 2.0
 */
void rglGenerateMipmap(GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenerateMipmap.\n");
#endif
   glGenerateMipmap(target);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 */
GLenum rglCheckFramebufferStatus(GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCheckFramebufferStatus.\n");
#endif
   return glCheckFramebufferStatus(target);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 2.0
 */
void rglFramebufferRenderbuffer(GLenum target, GLenum attachment,
      GLenum renderbuffertarget, GLuint renderbuffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFramebufferRenderbuffer.\n");
#endif
   glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 3.0
 */
void rglBindFragDataLocation(GLuint program, GLuint colorNumber,
                                   const char * name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindFragDataLocation.\n");
#endif
#if !defined(HAVE_OPENGLES2)
   glBindFragDataLocation(program, colorNumber, name);
#endif
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetProgramiv(GLuint shader, GLenum pname, GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetProgramiv.\n");
#endif
   glGetProgramiv(shader, pname, params);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 4.1
 * OpenGLES  : 3.0
 */
void rglProgramParameteri( 	GLuint program,
  	GLenum pname,
  	GLint value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glProgramParameteri.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && (defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1))
   glProgramParameteri(program, pname, value);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
      GLsizei *length, GLint *size, GLenum *type, GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetActiveUniform.\n");
#endif
   glGetActiveUniform(program, index, bufsize, length, size, type, name);
}

void rglGenQueries(	GLsizei n,
 	GLuint * ids)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenQueries.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGenQueries(n, ids);
#endif
}

void rglGetQueryObjectuiv(	GLuint id,
 	GLenum pname,
 	GLuint * params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetQueryObjectuiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGetQueryObjectuiv(id, pname, params);
#endif
}

void rglDeleteQueries(	GLsizei n,
 	const GLuint * ids)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteQueries.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glDeleteQueries(n, ids);
#endif
}

void rglBeginQuery(	GLenum target,
 	GLuint id)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBeginQuery.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glBeginQuery(target, id);
#endif
}

void rglEndQuery(	GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glEndQuery.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glEndQuery(target);
#endif
}

/*
 * Category: UBO
 *
 * Core in:
 *
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglGetActiveUniformBlockiv(GLuint program,
  	GLuint uniformBlockIndex,
  	GLenum pname,
  	GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetActiveUniformBlockiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGetActiveUniformBlockiv(program, uniformBlockIndex,
         pname, params);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglGetActiveUniformsiv( 	GLuint program,
  	GLsizei uniformCount,
  	const GLuint *uniformIndices,
  	GLenum pname,
  	GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetActiveUniformsiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGetActiveUniformsiv(program, uniformCount,
         uniformIndices, pname, params);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglGetUniformIndices(GLuint program,
  	GLsizei uniformCount,
  	const GLchar **uniformNames,
  	GLuint *uniformIndices)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetUniformIndices.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGetUniformIndices(program, uniformCount,
         uniformNames, uniformIndices);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 * Category: UBO
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglBindBufferBase( 	GLenum target,
  	GLuint index,
  	GLuint buffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindBufferBase.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glBindBufferBase(target, index, buffer);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Category: UBO
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
GLuint rglGetUniformBlockIndex( 	GLuint program,
  	const GLchar *uniformBlockName)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetUniformBlockIndex.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   return glGetUniformBlockIndex(program, uniformBlockName);
#else
   printf("WARNING! Not implemented.\n");
   return 0;
#endif
}

/*
 * Category: UBO
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglUniformBlockBinding( 	GLuint program,
  	GLuint uniformBlockIndex,
  	GLuint uniformBlockBinding)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniformBlockBinding.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glUniformBlockBinding(program, uniformBlockIndex,
         uniformBlockBinding);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform1ui(GLint location, GLuint v)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glUniform1ui(location ,v);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform2ui(GLint location, GLuint v0, GLuint v1)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glUniform2ui(location, v0, v1);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform3ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glUniform3ui(location, v0, v1, v2);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glUniform4ui(location, v0, v1, v2, v3);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
      const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniformMatrix4fv.\n");
#endif
   glUniformMatrix4fv(location, count, transpose, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglDetachShader(GLuint program, GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDetachShader.\n");
#endif
   glDetachShader(program, shader);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetShaderiv(GLuint shader, GLenum pname, GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetShaderiv.\n");
#endif
   glGetShaderiv(shader, pname, params);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglAttachShader(GLuint program, GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glAttachShader.\n");
#endif
   glAttachShader(program, shader);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLint rglGetAttribLocation(GLuint program, const GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetAttribLocation.\n");
#endif
   return glGetAttribLocation(program, name);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglShaderSource(GLuint shader, GLsizei count,
      const GLchar **string, const GLint *length)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glShaderSource.\n");
#endif
   return glShaderSource(shader, count, string, length);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglCompileShader(GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCompileShader.\n");
#endif
   glCompileShader(shader);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLuint rglCreateProgram(void)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCreateProgram.\n");
#endif
   return glCreateProgram();
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglGenTextures(GLsizei n, GLuint *textures)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenTextures.\n");
#endif
   glGenTextures(n, textures);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetShaderInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetShaderInfoLog.\n");
#endif
   glGetShaderInfoLog(shader, maxLength, length, infoLog);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetProgramInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetProgramInfoLog.\n");
#endif
   glGetProgramInfoLog(shader, maxLength, length, infoLog);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLboolean rglIsProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glIsProgram.\n");
#endif
   return glIsProgram(program);
}

void rglTexCoord2f(GLfloat s, GLfloat t)
{
#ifdef HAVE_LEGACY_GL
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexCoord2f.\n");
#endif
   glTexCoord2f(s, t);
#endif
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 *
 */
void rglDisableVertexAttribArray(GLuint index)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDisableVertexAttribArray.\n");
#endif
   gl_state.vertex_attrib_pointer.enabled[index] = 0;
   glDisableVertexAttribArray(index);
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglEnableVertexAttribArray(GLuint index)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glEnableVertexAttribArray.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.vertex_attrib_pointer.enabled[index] = 1;
   glEnableVertexAttribArray(index);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttribIPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttribIPointer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glVertexAttribIPointer(index, size, type, stride, pointer);
#endif
}

void rglVertexAttribLPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttribLPointer.\n");
#endif
#if defined(HAVE_OPENGL)
   glVertexAttribLPointer(index, size, type, stride, pointer);
#endif
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttribPointer(GLuint name, GLint size,
      GLenum type, GLboolean normalized, GLsizei stride,
      const GLvoid* pointer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttribPointer.\n");
#endif
   gl_state.attrib_pointer.used[name] = 1;
   gl_state.attrib_pointer.size[name] = size;
   gl_state.attrib_pointer.type[name] = type;
   gl_state.attrib_pointer.normalized[name] = normalized;
   gl_state.attrib_pointer.stride[name] = stride;
   gl_state.attrib_pointer.pointer[name] = pointer;
   gl_state.attrib_pointer.buffer[name] = gl_state.array_buffer;
   glVertexAttribPointer(name, size, type, normalized, stride, pointer);
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglBindAttribLocation(GLuint program, GLuint index, const GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindAttribLocation.\n");
#endif
   glBindAttribLocation(program, index, name);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttrib4f(GLuint name, GLfloat x, GLfloat y,
      GLfloat z, GLfloat w)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttrib4f.\n");
#endif
   glVertexAttrib4f(name, x, y, z, w);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttrib4fv(GLuint name, GLfloat* v)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttrib4fv.\n");
#endif
   glVertexAttrib4fv(name, v);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLuint rglCreateShader(GLenum shaderType)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCreateShader.\n");
#endif
   return glCreateShader(shaderType);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglDeleteProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteProgram.\n");
#endif
   glDeleteProgram(program);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglDeleteShader(GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteShader.\n");
#endif
   glDeleteShader(shader);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLint rglGetUniformLocation(GLuint program, const GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetUniformLocation.\n");
#endif
   return glGetUniformLocation(program, name);
}

/*
 * Category: VBO and PBO
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglDeleteBuffers(GLsizei n, const GLuint *buffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteBuffers.\n");
#endif
   glDeleteBuffers(n, buffers);
}

/*
 * Category: VBO and PBO
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglGenBuffers(GLsizei n, GLuint *buffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenBuffers.\n");
#endif
   glGenBuffers(n, buffers);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1f(GLint location, GLfloat v0)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1f.\n");
#endif
   glUniform1f(location, v0);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1fv(GLint location,  GLsizei count,  const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1fv.\n");
#endif
   glUniform1fv(location, count, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1iv(GLint location,  GLsizei count,  const GLint *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1iv.\n");
#endif
   glUniform1iv(location, count, value);
}

void rglClearBufferfv( 	GLenum buffer,
  	GLint drawBuffer,
  	const GLfloat * value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearBufferfv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
   glClearBufferfv(buffer, drawBuffer, value);
#endif
}

void rglTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexBuffer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
   glTexBuffer(target, internalFormat, buffer);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
const GLubyte* rglGetStringi(GLenum name, GLuint index)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetString.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
   return glGetStringi(name, index);
#else
   return NULL;
#endif
}

void rglClearBufferfi( 	GLenum buffer,
  	GLint drawBuffer,
  	GLfloat depth,
  	GLint stencil)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearBufferfi.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
   glClearBufferfi(buffer, drawBuffer, depth, stencil);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglRenderbufferStorageMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glRenderbufferStorageMultisample.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
   glRenderbufferStorageMultisample(target, samples, internalformat, width, height);
#endif
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1i(GLint location, GLint v0)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1i.\n");
#endif
   glUniform1i(location, v0);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform2f(GLint location, GLfloat v0, GLfloat v1)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2f.\n");
#endif
   glUniform2f(location, v0, v1);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform2i(GLint location, GLint v0, GLint v1)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2i.\n");
#endif
   glUniform2i(location, v0, v1);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform2fv(GLint location, GLsizei count, const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2fv.\n");
#endif
   glUniform2fv(location, count, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform3f.\n");
#endif
   glUniform3f(location, v0, v1, v2);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform3fv(GLint location, GLsizei count, const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform3fv.\n");
#endif
   glUniform3fv(location, count, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4i.\n");
#endif
   glUniform4i(location, v0, v1, v2, v3);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4f.\n");
#endif
   glUniform4f(location, v0, v1, v2, v3);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform4fv(GLint location, GLsizei count, const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4fv.\n");
#endif
   glUniform4fv(location, count, value);
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglPolygonOffset(GLfloat factor, GLfloat units)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glPolygonOffset.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glPolygonOffset(factor, units);
   gl_state.polygonoffset.used   = true;
   gl_state.polygonoffset.factor = factor;
   gl_state.polygonoffset.units  = units;
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 */
void rglGenFramebuffers(GLsizei n, GLuint *ids)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenFramebuffers.\n");
#endif
   glGenFramebuffers(n, ids);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 */
void rglBindFramebuffer(GLenum target, GLuint framebuffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindFramebuffer.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glBindFramebuffer(target, framebuffer);
   gl_state.framebuf = framebuffer;
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglDrawBuffers(GLsizei n, const GLenum *bufs)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawBuffers.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glDrawBuffers(n, bufs);
#endif
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void *rglMapBufferRange( 	GLenum target,
  	GLintptr offset,
  	GLsizeiptr length,
  	GLbitfield access)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glMapBufferRange.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   return glMapBufferRange(target, offset, length, access);
#else
   printf("WARNING! Not implemented.\n");
   return NULL;
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.3
 * OpenGLES  : 3.1
 */
void rglTexStorage2DMultisample(GLenum target, GLsizei samples,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLboolean fixedsamplelocations)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexStorage2DMultisample.\n");
#endif
#if defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_1)
   glTexStorage2DMultisample(target, samples, internalformat,
         width, height, fixedsamplelocations);
#endif
}

/*
 *
 * Core in:
 * OpenGLES  : 3.0
 */
void rglTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
      GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexStorage2D.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glTexStorage2D(target, levels, internalFormat, width, height);
#endif
}
/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.2
 */
void rglDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
   glDrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.2
 * OpenGLES  : 3.1
 */
void rglMemoryBarrier( 	GLbitfield barriers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glMemoryBarrier.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3) && defined(HAVE_OPENGLES_3_1)
   glMemoryBarrier(barriers);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.2
 * OpenGLES  : 3.1
 */
void rglBindImageTexture( 	GLuint unit,
  	GLuint texture,
  	GLint level,
  	GLboolean layered,
  	GLint layer,
  	GLenum access,
  	GLenum format)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindImageTexture.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3) && defined(HAVE_OPENGLES_3_1)
   glBindImageTexture(unit, texture, level, layered, layer, access, format);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.1
 * OpenGLES  : 3.1
 */
void rglGetProgramBinary( 	GLuint program,
  	GLsizei bufsize,
  	GLsizei *length,
  	GLenum *binaryFormat,
  	void *binary)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetProgramBinary.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGetProgramBinary(program, bufsize, length, binaryFormat, binary);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.1
 * OpenGLES  : 3.1
 */
void rglProgramBinary(GLuint program,
  	GLenum binaryFormat,
  	const void *binary,
  	GLsizei length)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glProgramBinary.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_1)
   glProgramBinary(program, binaryFormat, binary, length);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

void rglTexImage2DMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height,
  	GLboolean fixedsamplelocations)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexImage2DMultisample.\n");
#endif
#ifndef HAVE_OPENGLES
   glTexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations);
#endif
}

void rglTexImage3D(	GLenum target,
 	GLint level,
 	GLint internalFormat,
 	GLsizei width,
 	GLsizei height,
 	GLsizei depth,
 	GLint border,
 	GLenum format,
 	GLenum type,
 	const GLvoid * data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexImage3D.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, data);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void * rglMapBuffer(	GLenum target, GLenum access)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glMapBuffer.\n");
#endif
#if defined(HAVE_OPENGLES)
   return glMapBufferOES(target, access);
#else
   return glMapBuffer(target, access);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
GLboolean rglUnmapBuffer( 	GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUnmapBuffer.\n");
#endif
#if defined(HAVE_OPENGLES)
   return glUnmapBufferOES(target);
#else
   return glUnmapBuffer(target);
#endif
}

void rglBlendEquation(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendEquation.\n");
#endif
   glBlendEquation(mode);
}

void rglBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendColor.\n");
#endif
   glBlendColor(red, green, blue, alpha);
}

/*
 * Category: Blending
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendEquationSeparate.\n");
#endif
   glBlendEquationSeparate(modeRGB, modeAlpha);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.2
 */
void rglCopyImageSubData( 	GLuint srcName,
  	GLenum srcTarget,
  	GLint srcLevel,
  	GLint srcX,
  	GLint srcY,
  	GLint srcZ,
  	GLuint dstName,
  	GLenum dstTarget,
  	GLint dstLevel,
  	GLint dstX,
  	GLint dstY,
  	GLint dstZ,
  	GLsizei srcWidth,
  	GLsizei srcHeight,
  	GLsizei srcDepth)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCopyImageSubData.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
   glCopyImageSubData(srcName,
         srcTarget,
         srcLevel,
         srcX,
         srcY,
         srcZ,
         dstName,
         dstTarget,
         dstLevel,
         dstX,
         dstY,
         dstZ,
         srcWidth,
         srcHeight,
         srcDepth);
#endif
}

/*
 * Category: VAO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglBindVertexArray(GLuint array)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindVertexArray.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glBindVertexArray(array);
#endif
}

/*
 * Category: VAO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglGenVertexArrays(GLsizei n, GLuint *arrays)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenVertexArrays.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glGenVertexArrays(n, arrays);
#endif
}

/*
 * Category: VAO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglDeleteVertexArrays(GLsizei n, const GLuint *arrays)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteVertexArrays.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glDeleteVertexArrays(n, arrays);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void *rglFenceSync(GLenum condition, GLbitfield flags)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFenceSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   return (GLsync)glFenceSync(condition, flags);
#else
   return NULL;
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglDeleteSync(void * sync)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
  glDeleteSync((GLsync)sync);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglWaitSync(void *sync, GLbitfield flags, uint64_t timeout)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glWaitSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glWaitSync((GLsync)sync, flags, (GLuint64)timeout);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.4
 * OpenGLES  : Not available
 */
void rglBufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GLbitfield flags)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBufferStorage.\n");
#endif
#if defined(HAVE_OPENGL)
   glBufferStorage(target, size, data, flags);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 2.0
 */

void rglUniform2iv(	GLint location,
 	GLsizei count,
 	const GLint *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2iv.\n");
#endif
   glUniform2iv(location, count, value);
}

/*
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : ?.?
 */

void rglUniform2uiv(	GLint location,
 	GLsizei count,
 	const GLuint *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2uiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
   glUniform2uiv(location, count, value);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.3
 * OpenGLES  : ?.?
 */
void rglTextureView(	GLuint texture,
 	GLenum target,
 	GLuint origtexture,
 	GLenum internalformat,
 	GLuint minlevel,
 	GLuint numlevels,
 	GLuint minlayer,
 	GLuint numlayers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTextureView.\n");
#endif
#if defined(HAVE_OPENGL)
   glTextureView(texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFlushMappedBufferRange.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
  glFlushMappedBufferRange(target, offset, length);
#endif
}

#ifndef GL_WAIT_FAILED
#define GL_WAIT_FAILED                                   0x911D
#endif

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
GLenum rglClientWaitSync(void *sync, GLbitfield flags, uint64_t timeout)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClientWaitSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
  return glClientWaitSync((GLsync)sync, flags, (GLuint64)timeout);
#else
  return GL_WAIT_FAILED;
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : Not available
 */
void rglDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
			       GLvoid *indices, GLint basevertex)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawElementsBaseVertex.\n");
#endif
#if defined(HAVE_OPENGL)
   glDrawElementsBaseVertex(mode, count, type, indices, basevertex);
#endif
}

/* GLSM-side */

static void glsm_state_setup(void)
{
   unsigned i;

   gl_state.cap_translate[SGL_DEPTH_TEST]           = GL_DEPTH_TEST;
   gl_state.cap_translate[SGL_BLEND]                = GL_BLEND;
   gl_state.cap_translate[SGL_POLYGON_OFFSET_FILL]  = GL_POLYGON_OFFSET_FILL;
   gl_state.cap_translate[SGL_FOG]                  = GL_FOG;
   gl_state.cap_translate[SGL_CULL_FACE]            = GL_CULL_FACE;
   gl_state.cap_translate[SGL_ALPHA_TEST]           = GL_ALPHA_TEST;
   gl_state.cap_translate[SGL_SCISSOR_TEST]         = GL_SCISSOR_TEST;
   gl_state.cap_translate[SGL_STENCIL_TEST]         = GL_STENCIL_TEST;

#ifndef HAVE_OPENGLES
   gl_state.cap_translate[SGL_COLOR_LOGIC_OP]       = GL_COLOR_LOGIC_OP;
   gl_state.cap_translate[SGL_CLIP_DISTANCE0]       = GL_CLIP_DISTANCE0;
   gl_state.cap_translate[SGL_DEPTH_CLAMP]          = GL_DEPTH_CLAMP;
#endif

   for (i = 0; i < MAX_ATTRIB; i++)
   {
      gl_state.vertex_attrib_pointer.enabled[i] = 0;
      gl_state.attrib_pointer.used[i] = 0;
   }

   glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &glsm_max_textures);

   gl_state.bind_textures.ids           = (GLuint*)calloc(glsm_max_textures, sizeof(GLuint));

   default_framebuffer                  = glsm_get_current_framebuffer();
   gl_state.framebuf                    = default_framebuffer;
   gl_state.cullface.mode               = GL_BACK;
   gl_state.frontface.mode              = GL_CCW;

   gl_state.blendfunc_separate.used     = false;
   gl_state.blendfunc_separate.srcRGB   = GL_ONE;
   gl_state.blendfunc_separate.dstRGB   = GL_ZERO;
   gl_state.blendfunc_separate.srcAlpha = GL_ONE;
   gl_state.blendfunc_separate.dstAlpha = GL_ZERO;

   gl_state.depthfunc.used              = false;

   gl_state.colormask.used              = false;
   gl_state.colormask.red               = GL_TRUE;
   gl_state.colormask.green             = GL_TRUE;
   gl_state.colormask.blue              = GL_TRUE;
   gl_state.colormask.alpha             = GL_TRUE;

   gl_state.polygonoffset.used          = false;

   gl_state.depthfunc.func              = GL_LESS;

#ifndef HAVE_OPENGLES
   gl_state.colorlogicop                = GL_COPY;
#endif

#ifdef CORE
   glGenVertexArrays(1, &gl_state.vao);
#endif
}

static void glsm_state_bind(void)
{
   unsigned i;
#ifdef CORE
   glBindVertexArray(gl_state.vao);
#endif
   glBindBuffer(GL_ARRAY_BUFFER, gl_state.array_buffer);

   for (i = 0; i < MAX_ATTRIB; i++)
   {
      if (gl_state.vertex_attrib_pointer.enabled[i])
         glEnableVertexAttribArray(i);
      else
         glDisableVertexAttribArray(i);

      if (gl_state.attrib_pointer.used[i] && gl_state.attrib_pointer.buffer[i] == gl_state.array_buffer)
      {
         glVertexAttribPointer(
               i,
               gl_state.attrib_pointer.size[i],
               gl_state.attrib_pointer.type[i],
               gl_state.attrib_pointer.normalized[i],
               gl_state.attrib_pointer.stride[i],
               gl_state.attrib_pointer.pointer[i]);
      }
   }

   glBindFramebuffer(RARCH_GL_FRAMEBUFFER, default_framebuffer);

   if (gl_state.blendfunc.used)
      glBlendFunc(
            gl_state.blendfunc.sfactor,
            gl_state.blendfunc.dfactor);

   if (gl_state.blendfunc_separate.used)
      glBlendFuncSeparate(
            gl_state.blendfunc_separate.srcRGB,
            gl_state.blendfunc_separate.dstRGB,
            gl_state.blendfunc_separate.srcAlpha,
            gl_state.blendfunc_separate.dstAlpha
            );

   glClearColor(
         gl_state.clear_color.r,
         gl_state.clear_color.g,
         gl_state.clear_color.b,
         gl_state.clear_color.a);

   if (gl_state.depthfunc.used)
      glDepthFunc(gl_state.depthfunc.func);

   if (gl_state.colormask.used)
      glColorMask(
            gl_state.colormask.red,
            gl_state.colormask.green,
            gl_state.colormask.blue,
            gl_state.colormask.alpha);

   if (gl_state.cullface.used)
      glCullFace(gl_state.cullface.mode);

   if (gl_state.depthmask.used)
      glDepthMask(gl_state.depthmask.mask);

   if (gl_state.polygonoffset.used)
      glPolygonOffset(
            gl_state.polygonoffset.factor,
            gl_state.polygonoffset.units);

   if (gl_state.scissor.used)
      glScissor(
            gl_state.scissor.x,
            gl_state.scissor.y,
            gl_state.scissor.w,
            gl_state.scissor.h);

   glUseProgram(gl_state.program);

   glViewport(
         gl_state.viewport.x,
         gl_state.viewport.y,
         gl_state.viewport.w,
         gl_state.viewport.h);

   for(i = 0; i < SGL_CAP_MAX; i ++)
   {
      if (gl_state.cap_state[i])
         glEnable(gl_state.cap_translate[i]);
   }

   if (gl_state.frontface.used)
      glFrontFace(gl_state.frontface.mode);

   if (gl_state.stencilmask.used)
      glStencilMask(gl_state.stencilmask.mask);

   if (gl_state.stencilop.used)
      glStencilOp(gl_state.stencilop.sfail,
            gl_state.stencilop.dpfail,
            gl_state.stencilop.dppass);

   if (gl_state.stencilfunc.used)
      glStencilFunc(
            gl_state.stencilfunc.func,
            gl_state.stencilfunc.ref,
            gl_state.stencilfunc.mask);

   for (i = 0; i < glsm_max_textures; i ++)
   {
      glActiveTexture(GL_TEXTURE0 + i);
      glBindTexture(GL_TEXTURE_2D, gl_state.bind_textures.ids[i]);
   }

   glActiveTexture(GL_TEXTURE0 + gl_state.active_texture);
}

static void glsm_state_unbind(void)
{
   unsigned i;
#ifdef CORE
   glBindVertexArray(0);
#endif
   for (i = 0; i < SGL_CAP_MAX; i ++)
   {
      if (gl_state.cap_state[i])
         glDisable(gl_state.cap_translate[i]);
   }

   glBlendFunc(GL_ONE, GL_ZERO);

   if (gl_state.colormask.used)
      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
   if (gl_state.blendfunc_separate.used)
      glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);

   if (gl_state.cullface.used)
      glCullFace(GL_BACK);

   if (gl_state.depthmask.used)
      glDepthMask(GL_TRUE);

   if (gl_state.polygonoffset.used)
      glPolygonOffset(0, 0);

   glUseProgram(0);
   glClearColor(0,0,0,0.0f);

   if (gl_state.depthrange.used)
      rglDepthRange(0, 1);

   glStencilMask(1);
   glFrontFace(GL_CCW);
   if (gl_state.depthfunc.used)
      glDepthFunc(GL_LESS);

   if (gl_state.stencilop.used)
      glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);

   if (gl_state.stencilfunc.used)
      glStencilFunc(GL_ALWAYS,0,1);

   /* Clear textures */
   for (i = 0; i < glsm_max_textures; i ++)
   {
      glActiveTexture(GL_TEXTURE0 + i);
      glBindTexture(GL_TEXTURE_2D, 0);
   }
   glActiveTexture(GL_TEXTURE0);

   for (i = 0; i < MAX_ATTRIB; i ++)
      glDisableVertexAttribArray(i);

   glBindFramebuffer(RARCH_GL_FRAMEBUFFER, 0);
}

static bool glsm_state_ctx_destroy(void *data)
{
   if (gl_state.bind_textures.ids)
      free(gl_state.bind_textures.ids);
   gl_state.bind_textures.ids = NULL;

   return true;
}

static bool glsm_state_ctx_init(glsm_ctx_params_t *params)
{
   if (!params || !params->environ_cb)
      return false;

#ifdef HAVE_OPENGLES
#if defined(HAVE_OPENGLES_3_1)
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES_VERSION;
   hw_render.version_major      = 3;
   hw_render.version_minor      = 1;
#elif defined(HAVE_OPENGLES3)
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES3;
#else
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES2;
#endif
#else
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGL;
   if (params->context_type != RETRO_HW_CONTEXT_NONE)
      hw_render.context_type    = params->context_type;
   if (params->major != 0)
      hw_render.version_major   = params->major;
   if (params->minor != 0)
      hw_render.version_minor   = params->minor;
#endif

   hw_render.context_reset      = params->context_reset;
   hw_render.context_destroy    = params->context_destroy;
   hw_render.stencil            = params->stencil;
   hw_render.depth              = true;
   hw_render.bottom_left_origin = true;
   hw_render.cache_context      = false;

   if (!params->environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render))
      return false;

   return true;
}

GLuint glsm_get_current_framebuffer(void)
{
   return hw_render.get_current_framebuffer();
}

bool glsm_ctl(enum glsm_state_ctl state, void *data)
{
   switch (state)
   {
      case GLSM_CTL_IMM_VBO_DRAW:
         return false;
      case GLSM_CTL_IMM_VBO_DISABLE:
         return false;
      case GLSM_CTL_IS_IMM_VBO:
         return false;
      case GLSM_CTL_SET_IMM_VBO:
         break;
      case GLSM_CTL_UNSET_IMM_VBO:
         break;
      case GLSM_CTL_PROC_ADDRESS_GET:
         {
            glsm_ctx_proc_address_t *proc = (glsm_ctx_proc_address_t*)data;
            if (!hw_render.get_proc_address)
               return false;
            proc->addr = hw_render.get_proc_address;
         }
         break;
      case GLSM_CTL_STATE_CONTEXT_RESET:
         rglgen_resolve_symbols(hw_render.get_proc_address);
         break;
      case GLSM_CTL_STATE_CONTEXT_DESTROY:
         glsm_state_ctx_destroy(data);
         break;
      case GLSM_CTL_STATE_CONTEXT_INIT:
         return glsm_state_ctx_init((glsm_ctx_params_t*)data);
      case GLSM_CTL_STATE_SETUP:
         glsm_state_setup();
         break;
      case GLSM_CTL_STATE_UNBIND:
         glsm_state_unbind();
         break;
      case GLSM_CTL_STATE_BIND:
         glsm_state_bind();
         break;
      case GLSM_CTL_NONE:
      default:
         break;
   }

   return true;
}

./include/libretro-common/glsym/glgen.py

#!/usr/bin/env python3

"""
   License statement applies to this file (glgen.py) only.

   Permission is hereby granted, free of charge,
   to any person obtaining a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import sys
import os
import re

banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]

def noext(sym):
   for ext in banned_ext:
      if sym.endswith(ext):
         return False
   return True

def fix_multiline_functions(lines):
   fixed_lines = []
   temp_lines = []
   for line in lines:
      if line.count('(') > line.count(')'):
         temp_lines.append(line)
      else:
         if len(temp_lines) > 0:
            if line.count(')') > line.count('('):
               temp_lines.append(line)
               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
               fixed_lines.append(fixed_line)
               temp_lines = []
            else:
               temp_lines.append(line)
         else:
            fixed_lines.append(line)
   return fixed_lines

def find_gl_symbols(lines):
   typedefs = []
   syms = []
   for line in lines:
      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
      g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
      if m and noext(m.group(1)):
         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
      if g and noext(g.group(1)):
         syms.append(g.group(1))
   return (typedefs, syms)

def generate_defines(gl_syms):
   res = []
   for line in gl_syms:
      res.append('#define {} __rglgen_{}'.format(line, line))
   return res

def generate_declarations(gl_syms):
   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]

def generate_macros(gl_syms):
   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]

def dump(f, lines):
   f.write('\n'.join(lines))
   f.write('\n\n')

if __name__ == '__main__':

   if len(sys.argv) > 4:
      for banned in sys.argv[4:]:
         banned_ext.append(banned)

   with open(sys.argv[1], 'r') as f:
      lines = fix_multiline_functions(f.readlines())
      typedefs, syms = find_gl_symbols(lines)

      overrides = generate_defines(syms)
      declarations = generate_declarations(syms)
      externs = ['extern ' + x for x in declarations]

      macros = generate_macros(syms)

   with open(sys.argv[2], 'w') as f:
      f.write('#ifndef RGLGEN_DECL_H__\n')
      f.write('#define RGLGEN_DECL_H__\n')

      f.write('#ifdef __cplusplus\n')
      f.write('extern "C" {\n')
      f.write('#endif\n')

      f.write('#ifdef GL_APIENTRY\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#else\n')
      f.write('#ifndef APIENTRY\n')
      f.write('#define APIENTRY\n')
      f.write('#endif\n')
      f.write('#ifndef APIENTRYP\n')
      f.write('#define APIENTRYP APIENTRY *\n')
      f.write('#endif\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#endif\n')

      f.write('#ifndef GL_OES_EGL_image\n')
      f.write('typedef void *GLeglImageOES;\n')
      f.write('#endif\n')

      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
      f.write('typedef GLint GLfixed;\n')
      f.write('#endif\n')

      f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\n')
      f.write('typedef long long int GLint64;\n')
      f.write('typedef unsigned long long int GLuint64;\n')
      f.write('typedef unsigned long long int GLuint64EXT;\n')
      f.write('typedef struct __GLsync *GLsync;\n')
      f.write('#endif\n')

      dump(f, typedefs)
      dump(f, overrides)
      dump(f, externs)

      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')

      f.write('#ifdef __cplusplus\n')
      f.write('}\n')
      f.write('#endif\n')

      f.write('#endif\n')

   with open(sys.argv[3], 'w') as f:
      f.write('#include "glsym/glsym.h"\n')
      f.write('#include <stddef.h>\n')
      f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
      dump(f, macros)
      f.write('    { NULL, NULL },\n')
      f.write('};\n')
      dump(f, declarations)

./include/libretro-common/glsym/glsym_es2.c

#include "glsym/glsym.h"
#include <stddef.h>
#define SYM(x) { "gl" #x, &(gl##x) }
const struct rglgen_sym_map rglgen_symbol_map[] = {
    SYM(BlendBarrierKHR),
    SYM(DebugMessageControlKHR),
    SYM(DebugMessageInsertKHR),
    SYM(DebugMessageCallbackKHR),
    SYM(GetDebugMessageLogKHR),
    SYM(PushDebugGroupKHR),
    SYM(PopDebugGroupKHR),
    SYM(ObjectLabelKHR),
    SYM(GetObjectLabelKHR),
    SYM(ObjectPtrLabelKHR),
    SYM(GetObjectPtrLabelKHR),
    SYM(GetPointervKHR),
    SYM(GetGraphicsResetStatusKHR),
    SYM(ReadnPixelsKHR),
    SYM(GetnUniformfvKHR),
    SYM(GetnUniformivKHR),
    SYM(GetnUniformuivKHR),
    SYM(EGLImageTargetTexture2DOES),
    SYM(EGLImageTargetRenderbufferStorageOES),
    SYM(CopyImageSubDataOES),
    SYM(EnableiOES),
    SYM(DisableiOES),
    SYM(BlendEquationiOES),
    SYM(BlendEquationSeparateiOES),
    SYM(BlendFunciOES),
    SYM(BlendFuncSeparateiOES),
    SYM(ColorMaskiOES),
    SYM(IsEnablediOES),
    SYM(DrawElementsBaseVertexOES),
    SYM(DrawRangeElementsBaseVertexOES),
    SYM(DrawElementsInstancedBaseVertexOES),
    SYM(MultiDrawElementsBaseVertexOES),
    SYM(FramebufferTextureOES),
    SYM(GetProgramBinaryOES),
    SYM(ProgramBinaryOES),
    SYM(MapBufferOES),
    SYM(UnmapBufferOES),
    SYM(GetBufferPointervOES),
    SYM(PrimitiveBoundingBoxOES),
    SYM(MinSampleShadingOES),
    SYM(PatchParameteriOES),
    SYM(TexImage3DOES),
    SYM(TexSubImage3DOES),
    SYM(CopyTexSubImage3DOES),
    SYM(CompressedTexImage3DOES),
    SYM(CompressedTexSubImage3DOES),
    SYM(FramebufferTexture3DOES),
    SYM(TexParameterIivOES),
    SYM(TexParameterIuivOES),
    SYM(GetTexParameterIivOES),
    SYM(GetTexParameterIuivOES),
    SYM(SamplerParameterIivOES),
    SYM(SamplerParameterIuivOES),
    SYM(GetSamplerParameterIivOES),
    SYM(GetSamplerParameterIuivOES),
    SYM(TexBufferOES),
    SYM(TexBufferRangeOES),
    SYM(TexStorage3DMultisampleOES),
    SYM(TextureViewOES),
    SYM(BindVertexArrayOES),
    SYM(DeleteVertexArraysOES),
    SYM(GenVertexArraysOES),
    SYM(IsVertexArrayOES),
    SYM(ViewportArrayvOES),
    SYM(ViewportIndexedfOES),
    SYM(ViewportIndexedfvOES),
    SYM(ScissorArrayvOES),
    SYM(ScissorIndexedOES),
    SYM(ScissorIndexedvOES),
    SYM(DepthRangeArrayfvOES),
    SYM(DepthRangeIndexedfOES),
    SYM(GetFloati_vOES),
    SYM(DrawArraysInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
    SYM(BindFragDataLocationIndexedEXT),
    SYM(BindFragDataLocationEXT),
    SYM(GetProgramResourceLocationIndexEXT),
    SYM(GetFragDataIndexEXT),
    SYM(BufferStorageEXT),
    SYM(ClearTexImageEXT),
    SYM(ClearTexSubImageEXT),
    SYM(CopyImageSubDataEXT),
    SYM(LabelObjectEXT),
    SYM(GetObjectLabelEXT),
    SYM(InsertEventMarkerEXT),
    SYM(PushGroupMarkerEXT),
    SYM(PopGroupMarkerEXT),
    SYM(DiscardFramebufferEXT),
    SYM(GenQueriesEXT),
    SYM(DeleteQueriesEXT),
    SYM(IsQueryEXT),
    SYM(BeginQueryEXT),
    SYM(EndQueryEXT),
    SYM(QueryCounterEXT),
    SYM(GetQueryivEXT),
    SYM(GetQueryObjectivEXT),
    SYM(GetQueryObjectuivEXT),
    SYM(DrawBuffersEXT),
    SYM(EnableiEXT),
    SYM(DisableiEXT),
    SYM(BlendEquationiEXT),
    SYM(BlendEquationSeparateiEXT),
    SYM(BlendFunciEXT),
    SYM(BlendFuncSeparateiEXT),
    SYM(ColorMaskiEXT),
    SYM(IsEnablediEXT),
    SYM(DrawElementsBaseVertexEXT),
    SYM(DrawRangeElementsBaseVertexEXT),
    SYM(DrawElementsInstancedBaseVertexEXT),
    SYM(MultiDrawElementsBaseVertexEXT),
    SYM(DrawArraysInstancedEXT),
    SYM(DrawElementsInstancedEXT),
    SYM(FramebufferTextureEXT),
    SYM(VertexAttribDivisorEXT),
    SYM(MapBufferRangeEXT),
    SYM(FlushMappedBufferRangeEXT),
    SYM(MultiDrawArraysEXT),
    SYM(MultiDrawElementsEXT),
    SYM(MultiDrawArraysIndirectEXT),
    SYM(MultiDrawElementsIndirectEXT),
    SYM(RenderbufferStorageMultisampleEXT),
    SYM(FramebufferTexture2DMultisampleEXT),
    SYM(ReadBufferIndexedEXT),
    SYM(DrawBuffersIndexedEXT),
    SYM(GetIntegeri_vEXT),
    SYM(PolygonOffsetClampEXT),
    SYM(PrimitiveBoundingBoxEXT),
    SYM(RasterSamplesEXT),
    SYM(GetGraphicsResetStatusEXT),
    SYM(ReadnPixelsEXT),
    SYM(GetnUniformfvEXT),
    SYM(GetnUniformivEXT),
    SYM(ActiveShaderProgramEXT),
    SYM(BindProgramPipelineEXT),
    SYM(CreateShaderProgramvEXT),
    SYM(DeleteProgramPipelinesEXT),
    SYM(GenProgramPipelinesEXT),
    SYM(GetProgramPipelineInfoLogEXT),
    SYM(GetProgramPipelineivEXT),
    SYM(IsProgramPipelineEXT),
    SYM(ProgramParameteriEXT),
    SYM(ProgramUniform1fEXT),
    SYM(ProgramUniform1fvEXT),
    SYM(ProgramUniform1iEXT),
    SYM(ProgramUniform1ivEXT),
    SYM(ProgramUniform2fEXT),
    SYM(ProgramUniform2fvEXT),
    SYM(ProgramUniform2iEXT),
    SYM(ProgramUniform2ivEXT),
    SYM(ProgramUniform3fEXT),
    SYM(ProgramUniform3fvEXT),
    SYM(ProgramUniform3iEXT),
    SYM(ProgramUniform3ivEXT),
    SYM(ProgramUniform4fEXT),
    SYM(ProgramUniform4fvEXT),
    SYM(ProgramUniform4iEXT),
    SYM(ProgramUniform4ivEXT),
    SYM(ProgramUniformMatrix2fvEXT),
    SYM(ProgramUniformMatrix3fvEXT),
    SYM(ProgramUniformMatrix4fvEXT),
    SYM(UseProgramStagesEXT),
    SYM(ValidateProgramPipelineEXT),
    SYM(ProgramUniform1uiEXT),
    SYM(ProgramUniform2uiEXT),
    SYM(ProgramUniform3uiEXT),
    SYM(ProgramUniform4uiEXT),
    SYM(ProgramUniform1uivEXT),
    SYM(ProgramUniform2uivEXT),
    SYM(ProgramUniform3uivEXT),
    SYM(ProgramUniform4uivEXT),
    SYM(ProgramUniformMatrix2x3fvEXT),
    SYM(ProgramUniformMatrix3x2fvEXT),
    SYM(ProgramUniformMatrix2x4fvEXT),
    SYM(ProgramUniformMatrix4x2fvEXT),
    SYM(ProgramUniformMatrix3x4fvEXT),
    SYM(ProgramUniformMatrix4x3fvEXT),
    SYM(FramebufferPixelLocalStorageSizeEXT),
    SYM(GetFramebufferPixelLocalStorageSizeEXT),
    SYM(ClearPixelLocalStorageuiEXT),
    SYM(TexPageCommitmentEXT),
    SYM(PatchParameteriEXT),
    SYM(TexParameterIivEXT),
    SYM(TexParameterIuivEXT),
    SYM(GetTexParameterIivEXT),
    SYM(GetTexParameterIuivEXT),
    SYM(SamplerParameterIivEXT),
    SYM(SamplerParameterIuivEXT),
    SYM(GetSamplerParameterIivEXT),
    SYM(GetSamplerParameterIuivEXT),
    SYM(TexBufferEXT),
    SYM(TexBufferRangeEXT),
    SYM(TexStorage1DEXT),
    SYM(TexStorage2DEXT),
    SYM(TexStorage3DEXT),
    SYM(TextureStorage1DEXT),
    SYM(TextureStorage2DEXT),
    SYM(TextureStorage3DEXT),
    SYM(TextureViewEXT),
    SYM(FramebufferTextureMultiviewOVR),
    SYM(FramebufferTextureMultisampleMultiviewOVR),

    { NULL, NULL },
};
RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;

./include/libretro-common/glsym/glsym_es3.c

#include "glsym/glsym.h"
#include <stddef.h>
#define SYM(x) { "gl" #x, &(gl##x) }
const struct rglgen_sym_map rglgen_symbol_map[] = {
    SYM(BlendBarrierKHR),
    SYM(DebugMessageControlKHR),
    SYM(DebugMessageInsertKHR),
    SYM(DebugMessageCallbackKHR),
    SYM(GetDebugMessageLogKHR),
    SYM(PushDebugGroupKHR),
    SYM(PopDebugGroupKHR),
    SYM(ObjectLabelKHR),
    SYM(GetObjectLabelKHR),
    SYM(ObjectPtrLabelKHR),
    SYM(GetObjectPtrLabelKHR),
    SYM(GetPointervKHR),
    SYM(GetGraphicsResetStatusKHR),
    SYM(ReadnPixelsKHR),
    SYM(GetnUniformfvKHR),
    SYM(GetnUniformivKHR),
    SYM(GetnUniformuivKHR),
    SYM(EGLImageTargetTexture2DOES),
    SYM(EGLImageTargetRenderbufferStorageOES),
    SYM(CopyImageSubDataOES),
    SYM(EnableiOES),
    SYM(DisableiOES),
    SYM(BlendEquationiOES),
    SYM(BlendEquationSeparateiOES),
    SYM(BlendFunciOES),
    SYM(BlendFuncSeparateiOES),
    SYM(ColorMaskiOES),
    SYM(IsEnablediOES),
    SYM(DrawElementsBaseVertexOES),
    SYM(DrawRangeElementsBaseVertexOES),
    SYM(DrawElementsInstancedBaseVertexOES),
    SYM(MultiDrawElementsBaseVertexOES),
    SYM(FramebufferTextureOES),
    SYM(GetProgramBinaryOES),
    SYM(ProgramBinaryOES),
    SYM(MapBufferOES),
    SYM(UnmapBufferOES),
    SYM(GetBufferPointervOES),
    SYM(PrimitiveBoundingBoxOES),
    SYM(MinSampleShadingOES),
    SYM(PatchParameteriOES),
    SYM(TexImage3DOES),
    SYM(TexSubImage3DOES),
    SYM(CopyTexSubImage3DOES),
    SYM(CompressedTexImage3DOES),
    SYM(CompressedTexSubImage3DOES),
    SYM(FramebufferTexture3DOES),
    SYM(TexParameterIivOES),
    SYM(TexParameterIuivOES),
    SYM(GetTexParameterIivOES),
    SYM(GetTexParameterIuivOES),
    SYM(SamplerParameterIivOES),
    SYM(SamplerParameterIuivOES),
    SYM(GetSamplerParameterIivOES),
    SYM(GetSamplerParameterIuivOES),
    SYM(TexBufferOES),
    SYM(TexBufferRangeOES),
    SYM(TexStorage3DMultisampleOES),
    SYM(TextureViewOES),
    SYM(BindVertexArrayOES),
    SYM(DeleteVertexArraysOES),
    SYM(GenVertexArraysOES),
    SYM(IsVertexArrayOES),
    SYM(ViewportArrayvOES),
    SYM(ViewportIndexedfOES),
    SYM(ViewportIndexedfvOES),
    SYM(ScissorArrayvOES),
    SYM(ScissorIndexedOES),
    SYM(ScissorIndexedvOES),
    SYM(DepthRangeArrayfvOES),
    SYM(DepthRangeIndexedfOES),
    SYM(GetFloati_vOES),
    SYM(DrawArraysInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
    SYM(BindFragDataLocationIndexedEXT),
    SYM(BindFragDataLocationEXT),
    SYM(GetProgramResourceLocationIndexEXT),
    SYM(GetFragDataIndexEXT),
    SYM(BufferStorageEXT),
    SYM(ClearTexImageEXT),
    SYM(ClearTexSubImageEXT),
    SYM(CopyImageSubDataEXT),
    SYM(LabelObjectEXT),
    SYM(GetObjectLabelEXT),
    SYM(InsertEventMarkerEXT),
    SYM(PushGroupMarkerEXT),
    SYM(PopGroupMarkerEXT),
    SYM(DiscardFramebufferEXT),
    SYM(GenQueriesEXT),
    SYM(DeleteQueriesEXT),
    SYM(IsQueryEXT),
    SYM(BeginQueryEXT),
    SYM(EndQueryEXT),
    SYM(QueryCounterEXT),
    SYM(GetQueryivEXT),
    SYM(GetQueryObjectivEXT),
    SYM(GetQueryObjectuivEXT),
    SYM(GetQueryObjecti64vEXT),
    SYM(GetQueryObjectui64vEXT),
    SYM(DrawBuffersEXT),
    SYM(EnableiEXT),
    SYM(DisableiEXT),
    SYM(BlendEquationiEXT),
    SYM(BlendEquationSeparateiEXT),
    SYM(BlendFunciEXT),
    SYM(BlendFuncSeparateiEXT),
    SYM(ColorMaskiEXT),
    SYM(IsEnablediEXT),
    SYM(DrawElementsBaseVertexEXT),
    SYM(DrawRangeElementsBaseVertexEXT),
    SYM(DrawElementsInstancedBaseVertexEXT),
    SYM(MultiDrawElementsBaseVertexEXT),
    SYM(DrawArraysInstancedEXT),
    SYM(DrawElementsInstancedEXT),
    SYM(FramebufferTextureEXT),
    SYM(VertexAttribDivisorEXT),
    SYM(MapBufferRangeEXT),
    SYM(FlushMappedBufferRangeEXT),
    SYM(MultiDrawArraysEXT),
    SYM(MultiDrawElementsEXT),
    SYM(MultiDrawArraysIndirectEXT),
    SYM(MultiDrawElementsIndirectEXT),
    SYM(RenderbufferStorageMultisampleEXT),
    SYM(FramebufferTexture2DMultisampleEXT),
    SYM(ReadBufferIndexedEXT),
    SYM(DrawBuffersIndexedEXT),
    SYM(GetIntegeri_vEXT),
    SYM(PolygonOffsetClampEXT),
    SYM(PrimitiveBoundingBoxEXT),
    SYM(RasterSamplesEXT),
    SYM(GetGraphicsResetStatusEXT),
    SYM(ReadnPixelsEXT),
    SYM(GetnUniformfvEXT),
    SYM(GetnUniformivEXT),
    SYM(ActiveShaderProgramEXT),
    SYM(BindProgramPipelineEXT),
    SYM(CreateShaderProgramvEXT),
    SYM(DeleteProgramPipelinesEXT),
    SYM(GenProgramPipelinesEXT),
    SYM(GetProgramPipelineInfoLogEXT),
    SYM(GetProgramPipelineivEXT),
    SYM(IsProgramPipelineEXT),
    SYM(ProgramParameteriEXT),
    SYM(ProgramUniform1fEXT),
    SYM(ProgramUniform1fvEXT),
    SYM(ProgramUniform1iEXT),
    SYM(ProgramUniform1ivEXT),
    SYM(ProgramUniform2fEXT),
    SYM(ProgramUniform2fvEXT),
    SYM(ProgramUniform2iEXT),
    SYM(ProgramUniform2ivEXT),
    SYM(ProgramUniform3fEXT),
    SYM(ProgramUniform3fvEXT),
    SYM(ProgramUniform3iEXT),
    SYM(ProgramUniform3ivEXT),
    SYM(ProgramUniform4fEXT),
    SYM(ProgramUniform4fvEXT),
    SYM(ProgramUniform4iEXT),
    SYM(ProgramUniform4ivEXT),
    SYM(ProgramUniformMatrix2fvEXT),
    SYM(ProgramUniformMatrix3fvEXT),
    SYM(ProgramUniformMatrix4fvEXT),
    SYM(UseProgramStagesEXT),
    SYM(ValidateProgramPipelineEXT),
    SYM(ProgramUniform1uiEXT),
    SYM(ProgramUniform2uiEXT),
    SYM(ProgramUniform3uiEXT),
    SYM(ProgramUniform4uiEXT),
    SYM(ProgramUniform1uivEXT),
    SYM(ProgramUniform2uivEXT),
    SYM(ProgramUniform3uivEXT),
    SYM(ProgramUniform4uivEXT),
    SYM(ProgramUniformMatrix2x3fvEXT),
    SYM(ProgramUniformMatrix3x2fvEXT),
    SYM(ProgramUniformMatrix2x4fvEXT),
    SYM(ProgramUniformMatrix4x2fvEXT),
    SYM(ProgramUniformMatrix3x4fvEXT),
    SYM(ProgramUniformMatrix4x3fvEXT),
    SYM(FramebufferPixelLocalStorageSizeEXT),
    SYM(GetFramebufferPixelLocalStorageSizeEXT),
    SYM(ClearPixelLocalStorageuiEXT),
    SYM(TexPageCommitmentEXT),
    SYM(PatchParameteriEXT),
    SYM(TexParameterIivEXT),
    SYM(TexParameterIuivEXT),
    SYM(GetTexParameterIivEXT),
    SYM(GetTexParameterIuivEXT),
    SYM(SamplerParameterIivEXT),
    SYM(SamplerParameterIuivEXT),
    SYM(GetSamplerParameterIivEXT),
    SYM(GetSamplerParameterIuivEXT),
    SYM(TexBufferEXT),
    SYM(TexBufferRangeEXT),
    SYM(TexStorage1DEXT),
    SYM(TexStorage2DEXT),
    SYM(TexStorage3DEXT),
    SYM(TextureStorage1DEXT),
    SYM(TextureStorage2DEXT),
    SYM(TextureStorage3DEXT),
    SYM(TextureViewEXT),
    SYM(FramebufferTextureMultiviewOVR),
    SYM(FramebufferTextureMultisampleMultiviewOVR),

    { NULL, NULL },
};
RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;
RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;
RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;

./include/libretro-common/glsym/glsym_gl.c

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stddef.h>

#include <glsym/glsym.h>

#define SYM(x) { "gl" #x, (void*)&(gl##x) }

const struct rglgen_sym_map rglgen_symbol_map[] = {
#ifdef HAVE_LIBNX
    SYM(ClearIndex),
    SYM(ClearColor),
    SYM(Clear),
    SYM(IndexMask),
    SYM(ColorMask),
    SYM(AlphaFunc),
    SYM(BlendFunc),
    SYM(LogicOp),
    SYM(CullFace),
    SYM(FrontFace),
    SYM(PointSize),
    SYM(LineWidth),
    SYM(LineStipple),
    SYM(PolygonMode),
    SYM(PolygonOffset),
    SYM(PolygonStipple),
    SYM(GetPolygonStipple),
    SYM(EdgeFlag),
    SYM(EdgeFlagv),
    SYM(Scissor),
    SYM(ClipPlane),
    SYM(GetClipPlane),
    SYM(DrawBuffer),
    SYM(ReadBuffer),
    SYM(Enable),
    SYM(Disable),
    SYM(IsEnabled),
    SYM(EnableClientState),
    SYM(DisableClientState),
    SYM(GetBooleanv),
    SYM(GetDoublev),
    SYM(GetFloatv),
    SYM(GetIntegerv),
    SYM(PushAttrib),
    SYM(PopAttrib),
    SYM(PushClientAttrib),
    SYM(PopClientAttrib),
    SYM(RenderMode),
    SYM(GetError),
    SYM(GetString),
    SYM(Finish),
    SYM(Flush),
    SYM(Hint),
    SYM(ClearDepth),
    SYM(DepthFunc),
    SYM(DepthMask),
    SYM(DepthRange),
    SYM(ClearAccum),
    SYM(Accum),
    SYM(MatrixMode),
    SYM(Ortho),
    SYM(Frustum),
    SYM(Viewport),
    SYM(PushMatrix),
    SYM(PopMatrix),
    SYM(LoadIdentity),
    SYM(LoadMatrixd),
    SYM(LoadMatrixf),
    SYM(MultMatrixd),
    SYM(MultMatrixf),
    SYM(Rotated),
    SYM(Rotatef),
    SYM(Scaled),
    SYM(Scalef),
    SYM(Translated),
    SYM(Translatef),
    SYM(IsList),
    SYM(DeleteLists),
    SYM(GenLists),
    SYM(NewList),
    SYM(EndList),
    SYM(CallList),
    SYM(CallLists),
    SYM(ListBase),
    SYM(Begin),
    SYM(End),
    SYM(Vertex2d),
    SYM(Vertex2f),
    SYM(Vertex2i),
    SYM(Vertex2s),
    SYM(Vertex3d),
    SYM(Vertex3f),
    SYM(Vertex3i),
    SYM(Vertex3s),
    SYM(Vertex4d),
    SYM(Vertex4f),
    SYM(Vertex4i),
    SYM(Vertex4s),
    SYM(Vertex2dv),
    SYM(Vertex2fv),
    SYM(Vertex2iv),
    SYM(Vertex2sv),
    SYM(Vertex3dv),
    SYM(Vertex3fv),
    SYM(Vertex3iv),
    SYM(Vertex3sv),
    SYM(Vertex4dv),
    SYM(Vertex4fv),
    SYM(Vertex4iv),
    SYM(Vertex4sv),
    SYM(Normal3b),
    SYM(Normal3d),
    SYM(Normal3f),
    SYM(Normal3i),
    SYM(Normal3s),
    SYM(Normal3bv),
    SYM(Normal3dv),
    SYM(Normal3fv),
    SYM(Normal3iv),
    SYM(Normal3sv),
    SYM(Indexd),
    SYM(Indexf),
    SYM(Indexi),
    SYM(Indexs),
    SYM(Indexub),
    SYM(Indexdv),
    SYM(Indexfv),
    SYM(Indexiv),
    SYM(Indexsv),
    SYM(Indexubv),
    SYM(Color3b),
    SYM(Color3d),
    SYM(Color3f),
    SYM(Color3i),
    SYM(Color3s),
    SYM(Color3ub),
    SYM(Color3ui),
    SYM(Color3us),
    SYM(Color4b),
    SYM(Color4d),
    SYM(Color4f),
    SYM(Color4i),
    SYM(Color4s),
    SYM(Color4ub),
    SYM(Color4ui),
    SYM(Color4us),
    SYM(Color3bv),
    SYM(Color3dv),
    SYM(Color3fv),
    SYM(Color3iv),
    SYM(Color3sv),
    SYM(Color3ubv),
    SYM(Color3uiv),
    SYM(Color3usv),
    SYM(Color4bv),
    SYM(Color4dv),
    SYM(Color4fv),
    SYM(Color4iv),
    SYM(Color4sv),
    SYM(Color4ubv),
    SYM(Color4uiv),
    SYM(Color4usv),
    SYM(TexCoord1d),
    SYM(TexCoord1f),
    SYM(TexCoord1i),
    SYM(TexCoord1s),
    SYM(TexCoord2d),
    SYM(TexCoord2f),
    SYM(TexCoord2i),
    SYM(TexCoord2s),
    SYM(TexCoord3d),
    SYM(TexCoord3f),
    SYM(TexCoord3i),
    SYM(TexCoord3s),
    SYM(TexCoord4d),
    SYM(TexCoord4f),
    SYM(TexCoord4i),
    SYM(TexCoord4s),
    SYM(TexCoord1dv),
    SYM(TexCoord1fv),
    SYM(TexCoord1iv),
    SYM(TexCoord1sv),
    SYM(TexCoord2dv),
    SYM(TexCoord2fv),
    SYM(TexCoord2iv),
    SYM(TexCoord2sv),
    SYM(TexCoord3dv),
    SYM(TexCoord3fv),
    SYM(TexCoord3iv),
    SYM(TexCoord3sv),
    SYM(TexCoord4dv),
    SYM(TexCoord4fv),
    SYM(TexCoord4iv),
    SYM(TexCoord4sv),
    SYM(RasterPos2d),
    SYM(RasterPos2f),
    SYM(RasterPos2i),
    SYM(RasterPos2s),
    SYM(RasterPos3d),
    SYM(RasterPos3f),
    SYM(RasterPos3i),
    SYM(RasterPos3s),
    SYM(RasterPos4d),
    SYM(RasterPos4f),
    SYM(RasterPos4i),
    SYM(RasterPos4s),
    SYM(RasterPos2dv),
    SYM(RasterPos2fv),
    SYM(RasterPos2iv),
    SYM(RasterPos2sv),
    SYM(RasterPos3dv),
    SYM(RasterPos3fv),
    SYM(RasterPos3iv),
    SYM(RasterPos3sv),
    SYM(RasterPos4dv),
    SYM(RasterPos4fv),
    SYM(RasterPos4iv),
    SYM(RasterPos4sv),
    SYM(Rectd),
    SYM(Rectf),
    SYM(Recti),
    SYM(Rects),
    SYM(Rectdv),
    SYM(Rectfv),
    SYM(Rectiv),
    SYM(Rectsv),
    SYM(VertexPointer),
    SYM(NormalPointer),
    SYM(ColorPointer),
    SYM(IndexPointer),
    SYM(TexCoordPointer),
    SYM(EdgeFlagPointer),
    SYM(GetPointerv),
    SYM(ArrayElement),
    SYM(DrawArrays),
    SYM(DrawElements),
    SYM(InterleavedArrays),
    SYM(ShadeModel),
    SYM(Lightf),
    SYM(Lighti),
    SYM(Lightfv),
    SYM(Lightiv),
    SYM(GetLightfv),
    SYM(GetLightiv),
    SYM(LightModelf),
    SYM(LightModeli),
    SYM(LightModelfv),
    SYM(LightModeliv),
    SYM(Materialf),
    SYM(Materiali),
    SYM(Materialfv),
    SYM(Materialiv),
    SYM(GetMaterialfv),
    SYM(GetMaterialiv),
    SYM(ColorMaterial),
    SYM(PixelZoom),
    SYM(PixelStoref),
    SYM(PixelStorei),
    SYM(PixelTransferf),
    SYM(PixelTransferi),
    SYM(PixelMapfv),
    SYM(PixelMapuiv),
    SYM(PixelMapusv),
    SYM(GetPixelMapfv),
    SYM(GetPixelMapuiv),
    SYM(GetPixelMapusv),
    SYM(Bitmap),
    SYM(ReadPixels),
    SYM(DrawPixels),
    SYM(CopyPixels),
    SYM(StencilFunc),
    SYM(StencilMask),
    SYM(StencilOp),
    SYM(ClearStencil),
    SYM(TexGend),
    SYM(TexGenf),
    SYM(TexGeni),
    SYM(TexGendv),
    SYM(TexGenfv),
    SYM(TexGeniv),
    SYM(GetTexGendv),
    SYM(GetTexGenfv),
    SYM(GetTexGeniv),
    SYM(TexEnvf),
    SYM(TexEnvi),
    SYM(TexEnvfv),
    SYM(TexEnviv),
    SYM(GetTexEnvfv),
    SYM(GetTexEnviv),
    SYM(TexParameterf),
    SYM(TexParameteri),
    SYM(TexParameterfv),
    SYM(TexParameteriv),
    SYM(GetTexParameterfv),
    SYM(GetTexParameteriv),
    SYM(GetTexLevelParameterfv),
    SYM(GetTexLevelParameteriv),
    SYM(TexImage1D),
    SYM(TexImage2D),
    SYM(GetTexImage),
    SYM(GenTextures),
    SYM(DeleteTextures),
    SYM(BindTexture),
    SYM(PrioritizeTextures),
    SYM(AreTexturesResident),
    SYM(IsTexture),
    SYM(TexSubImage1D),
    SYM(TexSubImage2D),
    SYM(CopyTexImage1D),
    SYM(CopyTexImage2D),
    SYM(CopyTexSubImage1D),
    SYM(CopyTexSubImage2D),
    SYM(Map1d),
    SYM(Map1f),
    SYM(Map2d),
    SYM(Map2f),
    SYM(GetMapdv),
    SYM(GetMapfv),
    SYM(GetMapiv),
    SYM(EvalCoord1d),
    SYM(EvalCoord1f),
    SYM(EvalCoord1dv),
    SYM(EvalCoord1fv),
    SYM(EvalCoord2d),
    SYM(EvalCoord2f),
    SYM(EvalCoord2dv),
    SYM(EvalCoord2fv),
    SYM(MapGrid1d),
    SYM(MapGrid1f),
    SYM(MapGrid2d),
    SYM(MapGrid2f),
    SYM(EvalPoint1),
    SYM(EvalPoint2),
    SYM(EvalMesh1),
    SYM(EvalMesh2),
    SYM(Fogf),
    SYM(Fogi),
    SYM(Fogfv),
    SYM(Fogiv),
    SYM(FeedbackBuffer),
    SYM(PassThrough),
    SYM(SelectBuffer),
    SYM(InitNames),
    SYM(LoadName),
    SYM(PushName),
    SYM(PopName),
    SYM(DrawRangeElements),
    SYM(TexImage3D),
    SYM(TexSubImage3D),
    SYM(CopyTexSubImage3D),
    SYM(ColorTable),
    SYM(ColorSubTable),
    SYM(ColorTableParameteriv),
    SYM(ColorTableParameterfv),
    SYM(CopyColorSubTable),
    SYM(CopyColorTable),
    SYM(GetColorTable),
    SYM(GetColorTableParameterfv),
    SYM(GetColorTableParameteriv),
    SYM(BlendEquation),
    SYM(BlendColor),
    SYM(Histogram),
    SYM(ResetHistogram),
    SYM(GetHistogram),
    SYM(GetHistogramParameterfv),
    SYM(GetHistogramParameteriv),
    SYM(Minmax),
    SYM(ResetMinmax),
    SYM(GetMinmax),
    SYM(GetMinmaxParameterfv),
    SYM(GetMinmaxParameteriv),
    SYM(ConvolutionFilter1D),
    SYM(ConvolutionFilter2D),
    SYM(ConvolutionParameterf),
    SYM(ConvolutionParameterfv),
    SYM(ConvolutionParameteri),
    SYM(ConvolutionParameteriv),
    SYM(CopyConvolutionFilter1D),
    SYM(CopyConvolutionFilter2D),
    SYM(GetConvolutionFilter),
    SYM(GetConvolutionParameterfv),
    SYM(GetConvolutionParameteriv),
    SYM(SeparableFilter2D),
    SYM(GetSeparableFilter),
    SYM(ActiveTexture),
    SYM(ClientActiveTexture),
    SYM(CompressedTexImage1D),
    SYM(CompressedTexImage2D),
    SYM(CompressedTexImage3D),
    SYM(CompressedTexSubImage1D),
    SYM(CompressedTexSubImage2D),
    SYM(CompressedTexSubImage3D),
    SYM(GetCompressedTexImage),
    SYM(MultiTexCoord1d),
    SYM(MultiTexCoord1dv),
    SYM(MultiTexCoord1f),
    SYM(MultiTexCoord1fv),
    SYM(MultiTexCoord1i),
    SYM(MultiTexCoord1iv),
    SYM(MultiTexCoord1s),
    SYM(MultiTexCoord1sv),
    SYM(MultiTexCoord2d),
    SYM(MultiTexCoord2dv),
    SYM(MultiTexCoord2f),
    SYM(MultiTexCoord2fv),
    SYM(MultiTexCoord2i),
    SYM(MultiTexCoord2iv),
    SYM(MultiTexCoord2s),
    SYM(MultiTexCoord2sv),
    SYM(MultiTexCoord3d),
    SYM(MultiTexCoord3dv),
    SYM(MultiTexCoord3f),
    SYM(MultiTexCoord3fv),
    SYM(MultiTexCoord3i),
    SYM(MultiTexCoord3iv),
    SYM(MultiTexCoord3s),
    SYM(MultiTexCoord3sv),
    SYM(MultiTexCoord4d),
    SYM(MultiTexCoord4dv),
    SYM(MultiTexCoord4f),
    SYM(MultiTexCoord4fv),
    SYM(MultiTexCoord4i),
    SYM(MultiTexCoord4iv),
    SYM(MultiTexCoord4s),
    SYM(MultiTexCoord4sv),
    SYM(LoadTransposeMatrixd),
    SYM(LoadTransposeMatrixf),
    SYM(MultTransposeMatrixd),
    SYM(MultTransposeMatrixf),
    SYM(SampleCoverage),
    SYM(ActiveTextureARB),
    SYM(ClientActiveTextureARB),
    SYM(MultiTexCoord1dARB),
    SYM(MultiTexCoord1dvARB),
    SYM(MultiTexCoord1fARB),
    SYM(MultiTexCoord1fvARB),
    SYM(MultiTexCoord1iARB),
    SYM(MultiTexCoord1ivARB),
    SYM(MultiTexCoord1sARB),
    SYM(MultiTexCoord1svARB),
    SYM(MultiTexCoord2dARB),
    SYM(MultiTexCoord2dvARB),
    SYM(MultiTexCoord2fARB),
    SYM(MultiTexCoord2fvARB),
    SYM(MultiTexCoord2iARB),
    SYM(MultiTexCoord2ivARB),
    SYM(MultiTexCoord2sARB),
    SYM(MultiTexCoord2svARB),
    SYM(MultiTexCoord3dARB),
    SYM(MultiTexCoord3dvARB),
    SYM(MultiTexCoord3fARB),
    SYM(MultiTexCoord3fvARB),
    SYM(MultiTexCoord3iARB),
    SYM(MultiTexCoord3ivARB),
    SYM(MultiTexCoord3sARB),
    SYM(MultiTexCoord3svARB),
    SYM(MultiTexCoord4dARB),
    SYM(MultiTexCoord4dvARB),
    SYM(MultiTexCoord4fARB),
    SYM(MultiTexCoord4fvARB),
    SYM(MultiTexCoord4iARB),
    SYM(MultiTexCoord4ivARB),
    SYM(MultiTexCoord4sARB),
    SYM(MultiTexCoord4svARB),
    SYM(EGLImageTargetTexture2DOES),
    SYM(EGLImageTargetRenderbufferStorageOES),
#endif

    SYM(DrawRangeElements),
    SYM(TexImage3D),
    SYM(TexSubImage3D),
    SYM(CopyTexSubImage3D),
    SYM(ActiveTexture),
    SYM(SampleCoverage),
    SYM(CompressedTexImage3D),
    SYM(CompressedTexImage2D),
    SYM(CompressedTexImage1D),
    SYM(CompressedTexSubImage3D),
    SYM(CompressedTexSubImage2D),
    SYM(CompressedTexSubImage1D),
    SYM(GetCompressedTexImage),
    SYM(ClientActiveTexture),
    SYM(MultiTexCoord1d),
    SYM(MultiTexCoord1dv),
    SYM(MultiTexCoord1f),
    SYM(MultiTexCoord1fv),
    SYM(MultiTexCoord1i),
    SYM(MultiTexCoord1iv),
    SYM(MultiTexCoord1s),
    SYM(MultiTexCoord1sv),
    SYM(MultiTexCoord2d),
    SYM(MultiTexCoord2dv),
    SYM(MultiTexCoord2f),
    SYM(MultiTexCoord2fv),
    SYM(MultiTexCoord2i),
    SYM(MultiTexCoord2iv),
    SYM(MultiTexCoord2s),
    SYM(MultiTexCoord2sv),
    SYM(MultiTexCoord3d),
    SYM(MultiTexCoord3dv),
    SYM(MultiTexCoord3f),
    SYM(MultiTexCoord3fv),
    SYM(MultiTexCoord3i),
    SYM(MultiTexCoord3iv),
    SYM(MultiTexCoord3s),
    SYM(MultiTexCoord3sv),
    SYM(MultiTexCoord4d),
    SYM(MultiTexCoord4dv),
    SYM(MultiTexCoord4f),
    SYM(MultiTexCoord4fv),
    SYM(MultiTexCoord4i),
    SYM(MultiTexCoord4iv),
    SYM(MultiTexCoord4s),
    SYM(MultiTexCoord4sv),
    SYM(LoadTransposeMatrixf),
    SYM(LoadTransposeMatrixd),
    SYM(MultTransposeMatrixf),
    SYM(MultTransposeMatrixd),
    SYM(BlendFuncSeparate),
    SYM(MultiDrawArrays),
    SYM(MultiDrawElements),
    SYM(PointParameterf),
    SYM(PointParameterfv),
    SYM(PointParameteri),
    SYM(PointParameteriv),
    SYM(FogCoordf),
    SYM(FogCoordfv),
    SYM(FogCoordd),
    SYM(FogCoorddv),
    SYM(FogCoordPointer),
    SYM(SecondaryColor3b),
    SYM(SecondaryColor3bv),
    SYM(SecondaryColor3d),
    SYM(SecondaryColor3dv),
    SYM(SecondaryColor3f),
    SYM(SecondaryColor3fv),
    SYM(SecondaryColor3i),
    SYM(SecondaryColor3iv),
    SYM(SecondaryColor3s),
    SYM(SecondaryColor3sv),
    SYM(SecondaryColor3ub),
    SYM(SecondaryColor3ubv),
    SYM(SecondaryColor3ui),
    SYM(SecondaryColor3uiv),
    SYM(SecondaryColor3us),
    SYM(SecondaryColor3usv),
    SYM(SecondaryColorPointer),
    SYM(WindowPos2d),
    SYM(WindowPos2dv),
    SYM(WindowPos2f),
    SYM(WindowPos2fv),
    SYM(WindowPos2i),
    SYM(WindowPos2iv),
    SYM(WindowPos2s),
    SYM(WindowPos2sv),
    SYM(WindowPos3d),
    SYM(WindowPos3dv),
    SYM(WindowPos3f),
    SYM(WindowPos3fv),
    SYM(WindowPos3i),
    SYM(WindowPos3iv),
    SYM(WindowPos3s),
    SYM(WindowPos3sv),
    SYM(BlendColor),
    SYM(BlendEquation),
    SYM(GenQueries),
    SYM(DeleteQueries),
    SYM(IsQuery),
    SYM(BeginQuery),
    SYM(EndQuery),
    SYM(GetQueryiv),
    SYM(GetQueryObjectiv),
    SYM(GetQueryObjectuiv),
    SYM(BindBuffer),
    SYM(DeleteBuffers),
    SYM(GenBuffers),
    SYM(IsBuffer),
    SYM(BufferData),
    SYM(BufferSubData),
    SYM(GetBufferSubData),
    SYM(MapBuffer),
    SYM(UnmapBuffer),
    SYM(GetBufferParameteriv),
    SYM(GetBufferPointerv),
    SYM(BlendEquationSeparate),
    SYM(DrawBuffers),
    SYM(StencilOpSeparate),
    SYM(StencilFuncSeparate),
    SYM(StencilMaskSeparate),
    SYM(AttachShader),
    SYM(BindAttribLocation),
    SYM(CompileShader),
    SYM(CreateProgram),
    SYM(CreateShader),
    SYM(DeleteProgram),
    SYM(DeleteShader),
    SYM(DetachShader),
    SYM(DisableVertexAttribArray),
    SYM(EnableVertexAttribArray),
    SYM(GetActiveAttrib),
    SYM(GetActiveUniform),
    SYM(GetAttachedShaders),
    SYM(GetAttribLocation),
    SYM(GetProgramiv),
    SYM(GetProgramInfoLog),
    SYM(GetShaderiv),
    SYM(GetShaderInfoLog),
    SYM(GetShaderSource),
    SYM(GetUniformLocation),
    SYM(GetUniformfv),
    SYM(GetUniformiv),
    SYM(GetVertexAttribdv),
    SYM(GetVertexAttribfv),
    SYM(GetVertexAttribiv),
    SYM(GetVertexAttribPointerv),
    SYM(IsProgram),
    SYM(IsShader),
    SYM(LinkProgram),
    SYM(ShaderSource),
    SYM(UseProgram),
    SYM(Uniform1f),
    SYM(Uniform2f),
    SYM(Uniform3f),
    SYM(Uniform4f),
    SYM(Uniform1i),
    SYM(Uniform2i),
    SYM(Uniform3i),
    SYM(Uniform4i),
    SYM(Uniform1fv),
    SYM(Uniform2fv),
    SYM(Uniform3fv),
    SYM(Uniform4fv),
    SYM(Uniform1iv),
    SYM(Uniform2iv),
    SYM(Uniform3iv),
    SYM(Uniform4iv),
    SYM(UniformMatrix2fv),
    SYM(UniformMatrix3fv),
    SYM(UniformMatrix4fv),
    SYM(ValidateProgram),
    SYM(VertexAttrib1d),
    SYM(VertexAttrib1dv),
    SYM(VertexAttrib1f),
    SYM(VertexAttrib1fv),
    SYM(VertexAttrib1s),
    SYM(VertexAttrib1sv),
    SYM(VertexAttrib2d),
    SYM(VertexAttrib2dv),
    SYM(VertexAttrib2f),
    SYM(VertexAttrib2fv),
    SYM(VertexAttrib2s),
    SYM(VertexAttrib2sv),
    SYM(VertexAttrib3d),
    SYM(VertexAttrib3dv),
    SYM(VertexAttrib3f),
    SYM(VertexAttrib3fv),
    SYM(VertexAttrib3s),
    SYM(VertexAttrib3sv),
    SYM(VertexAttrib4Nbv),
    SYM(VertexAttrib4Niv),
    SYM(VertexAttrib4Nsv),
    SYM(VertexAttrib4Nub),
    SYM(VertexAttrib4Nubv),
    SYM(VertexAttrib4Nuiv),
    SYM(VertexAttrib4Nusv),
    SYM(VertexAttrib4bv),
    SYM(VertexAttrib4d),
    SYM(VertexAttrib4dv),
    SYM(VertexAttrib4f),
    SYM(VertexAttrib4fv),
    SYM(VertexAttrib4iv),
    SYM(VertexAttrib4s),
    SYM(VertexAttrib4sv),
    SYM(VertexAttrib4ubv),
    SYM(VertexAttrib4uiv),
    SYM(VertexAttrib4usv),
    SYM(VertexAttribPointer),
    SYM(UniformMatrix2x3fv),
    SYM(UniformMatrix3x2fv),
    SYM(UniformMatrix2x4fv),
    SYM(UniformMatrix4x2fv),
    SYM(UniformMatrix3x4fv),
    SYM(UniformMatrix4x3fv),
    SYM(ColorMaski),
    SYM(GetBooleani_v),
    SYM(GetIntegeri_v),
    SYM(Enablei),
    SYM(Disablei),
    SYM(IsEnabledi),
    SYM(BeginTransformFeedback),
    SYM(EndTransformFeedback),
    SYM(BindBufferRange),
    SYM(BindBufferBase),
    SYM(TransformFeedbackVaryings),
    SYM(GetTransformFeedbackVarying),
    SYM(ClampColor),
    SYM(BeginConditionalRender),
    SYM(EndConditionalRender),
    SYM(VertexAttribIPointer),
    SYM(GetVertexAttribIiv),
    SYM(GetVertexAttribIuiv),
    SYM(VertexAttribI1i),
    SYM(VertexAttribI2i),
    SYM(VertexAttribI3i),
    SYM(VertexAttribI4i),
    SYM(VertexAttribI1ui),
    SYM(VertexAttribI2ui),
    SYM(VertexAttribI3ui),
    SYM(VertexAttribI4ui),
    SYM(VertexAttribI1iv),
    SYM(VertexAttribI2iv),
    SYM(VertexAttribI3iv),
    SYM(VertexAttribI4iv),
    SYM(VertexAttribI1uiv),
    SYM(VertexAttribI2uiv),
    SYM(VertexAttribI3uiv),
    SYM(VertexAttribI4uiv),
    SYM(VertexAttribI4bv),
    SYM(VertexAttribI4sv),
    SYM(VertexAttribI4ubv),
    SYM(VertexAttribI4usv),
    SYM(GetUniformuiv),
    SYM(BindFragDataLocation),
    SYM(GetFragDataLocation),
    SYM(Uniform1ui),
    SYM(Uniform2ui),
    SYM(Uniform3ui),
    SYM(Uniform4ui),
    SYM(Uniform1uiv),
    SYM(Uniform2uiv),
    SYM(Uniform3uiv),
    SYM(Uniform4uiv),
    SYM(TexParameterIiv),
    SYM(TexParameterIuiv),
    SYM(GetTexParameterIiv),
    SYM(GetTexParameterIuiv),
    SYM(ClearBufferiv),
    SYM(ClearBufferuiv),
    SYM(ClearBufferfv),
    SYM(ClearBufferfi),
    SYM(GetStringi),
    SYM(IsRenderbuffer),
    SYM(BindRenderbuffer),
    SYM(DeleteRenderbuffers),
    SYM(GenRenderbuffers),
    SYM(RenderbufferStorage),
    SYM(GetRenderbufferParameteriv),
    SYM(IsFramebuffer),
    SYM(BindFramebuffer),
    SYM(DeleteFramebuffers),
    SYM(GenFramebuffers),
    SYM(CheckFramebufferStatus),
    SYM(FramebufferTexture1D),
    SYM(FramebufferTexture2D),
    SYM(FramebufferTexture3D),
    SYM(FramebufferRenderbuffer),
    SYM(GetFramebufferAttachmentParameteriv),
    SYM(GenerateMipmap),
    SYM(BlitFramebuffer),
    SYM(RenderbufferStorageMultisample),
    SYM(FramebufferTextureLayer),
    SYM(MapBufferRange),
    SYM(FlushMappedBufferRange),
    SYM(BindVertexArray),
    SYM(DeleteVertexArrays),
    SYM(GenVertexArrays),
    SYM(IsVertexArray),
    SYM(DrawArraysInstanced),
    SYM(DrawElementsInstanced),
    SYM(TexBuffer),
    SYM(PrimitiveRestartIndex),
    SYM(CopyBufferSubData),
    SYM(GetUniformIndices),
    SYM(GetActiveUniformsiv),
    SYM(GetActiveUniformName),
    SYM(GetUniformBlockIndex),
    SYM(GetActiveUniformBlockiv),
    SYM(GetActiveUniformBlockName),
    SYM(UniformBlockBinding),
    SYM(DrawElementsBaseVertex),
    SYM(DrawRangeElementsBaseVertex),
    SYM(DrawElementsInstancedBaseVertex),
    SYM(MultiDrawElementsBaseVertex),
    SYM(ProvokingVertex),
    SYM(FenceSync),
    SYM(IsSync),
    SYM(DeleteSync),
    SYM(ClientWaitSync),
    SYM(WaitSync),
    SYM(GetInteger64v),
    SYM(GetSynciv),
    SYM(GetInteger64i_v),
    SYM(GetBufferParameteri64v),
    SYM(FramebufferTexture),
    SYM(TexImage2DMultisample),
    SYM(TexImage3DMultisample),
    SYM(GetMultisamplefv),
    SYM(SampleMaski),
    SYM(BindFragDataLocationIndexed),
    SYM(GetFragDataIndex),
    SYM(GenSamplers),
    SYM(DeleteSamplers),
    SYM(IsSampler),
    SYM(BindSampler),
    SYM(SamplerParameteri),
    SYM(SamplerParameteriv),
    SYM(SamplerParameterf),
    SYM(SamplerParameterfv),
    SYM(SamplerParameterIiv),
    SYM(SamplerParameterIuiv),
    SYM(GetSamplerParameteriv),
    SYM(GetSamplerParameterIiv),
    SYM(GetSamplerParameterfv),
    SYM(GetSamplerParameterIuiv),
    SYM(QueryCounter),
    SYM(GetQueryObjecti64v),
    SYM(GetQueryObjectui64v),
    SYM(VertexAttribDivisor),
    SYM(VertexAttribP1ui),
    SYM(VertexAttribP1uiv),
    SYM(VertexAttribP2ui),
    SYM(VertexAttribP2uiv),
    SYM(VertexAttribP3ui),
    SYM(VertexAttribP3uiv),
    SYM(VertexAttribP4ui),
    SYM(VertexAttribP4uiv),
    SYM(VertexP2ui),
    SYM(VertexP2uiv),
    SYM(VertexP3ui),
    SYM(VertexP3uiv),
    SYM(VertexP4ui),
    SYM(VertexP4uiv),
    SYM(TexCoordP1ui),
    SYM(TexCoordP1uiv),
    SYM(TexCoordP2ui),
    SYM(TexCoordP2uiv),
    SYM(TexCoordP3ui),
    SYM(TexCoordP3uiv),
    SYM(TexCoordP4ui),
    SYM(TexCoordP4uiv),
    SYM(MultiTexCoordP1ui),
    SYM(MultiTexCoordP1uiv),
    SYM(MultiTexCoordP2ui),
    SYM(MultiTexCoordP2uiv),
    SYM(MultiTexCoordP3ui),
    SYM(MultiTexCoordP3uiv),
    SYM(MultiTexCoordP4ui),
    SYM(MultiTexCoordP4uiv),
    SYM(NormalP3ui),
    SYM(NormalP3uiv),
    SYM(ColorP3ui),
    SYM(ColorP3uiv),
    SYM(ColorP4ui),
    SYM(ColorP4uiv),
    SYM(SecondaryColorP3ui),
    SYM(SecondaryColorP3uiv),
    SYM(MinSampleShading),
    SYM(BlendEquationi),
    SYM(BlendEquationSeparatei),
    SYM(BlendFunci),
    SYM(BlendFuncSeparatei),
    SYM(DrawArraysIndirect),
    SYM(DrawElementsIndirect),
    SYM(Uniform1d),
    SYM(Uniform2d),
    SYM(Uniform3d),
    SYM(Uniform4d),
    SYM(Uniform1dv),
    SYM(Uniform2dv),
    SYM(Uniform3dv),
    SYM(Uniform4dv),
    SYM(UniformMatrix2dv),
    SYM(UniformMatrix3dv),
    SYM(UniformMatrix4dv),
    SYM(UniformMatrix2x3dv),
    SYM(UniformMatrix2x4dv),
    SYM(UniformMatrix3x2dv),
    SYM(UniformMatrix3x4dv),
    SYM(UniformMatrix4x2dv),
    SYM(UniformMatrix4x3dv),
    SYM(GetUniformdv),
    SYM(GetSubroutineUniformLocation),
    SYM(GetSubroutineIndex),
    SYM(GetActiveSubroutineUniformiv),
    SYM(GetActiveSubroutineUniformName),
    SYM(GetActiveSubroutineName),
    SYM(UniformSubroutinesuiv),
    SYM(GetUniformSubroutineuiv),
    SYM(GetProgramStageiv),
    SYM(PatchParameteri),
    SYM(PatchParameterfv),
    SYM(BindTransformFeedback),
    SYM(DeleteTransformFeedbacks),
    SYM(GenTransformFeedbacks),
    SYM(IsTransformFeedback),
    SYM(PauseTransformFeedback),
    SYM(ResumeTransformFeedback),
    SYM(DrawTransformFeedback),
    SYM(DrawTransformFeedbackStream),
    SYM(BeginQueryIndexed),
    SYM(EndQueryIndexed),
    SYM(GetQueryIndexediv),
    SYM(ReleaseShaderCompiler),
    SYM(ShaderBinary),
    SYM(GetShaderPrecisionFormat),
    SYM(DepthRangef),
    SYM(ClearDepthf),
    SYM(GetProgramBinary),
    SYM(ProgramBinary),
    SYM(ProgramParameteri),
    SYM(UseProgramStages),
    SYM(ActiveShaderProgram),
    SYM(CreateShaderProgramv),
    SYM(BindProgramPipeline),
    SYM(DeleteProgramPipelines),
    SYM(GenProgramPipelines),
    SYM(IsProgramPipeline),
    SYM(GetProgramPipelineiv),
    SYM(ProgramUniform1i),
    SYM(ProgramUniform1iv),
    SYM(ProgramUniform1f),
    SYM(ProgramUniform1fv),
    SYM(ProgramUniform1d),
    SYM(ProgramUniform1dv),
    SYM(ProgramUniform1ui),
    SYM(ProgramUniform1uiv),
    SYM(ProgramUniform2i),
    SYM(ProgramUniform2iv),
    SYM(ProgramUniform2f),
    SYM(ProgramUniform2fv),
    SYM(ProgramUniform2d),
    SYM(ProgramUniform2dv),
    SYM(ProgramUniform2ui),
    SYM(ProgramUniform2uiv),
    SYM(ProgramUniform3i),
    SYM(ProgramUniform3iv),
    SYM(ProgramUniform3f),
    SYM(ProgramUniform3fv),
    SYM(ProgramUniform3d),
    SYM(ProgramUniform3dv),
    SYM(ProgramUniform3ui),
    SYM(ProgramUniform3uiv),
    SYM(ProgramUniform4i),
    SYM(ProgramUniform4iv),
    SYM(ProgramUniform4f),
    SYM(ProgramUniform4fv),
    SYM(ProgramUniform4d),
    SYM(ProgramUniform4dv),
    SYM(ProgramUniform4ui),
    SYM(ProgramUniform4uiv),
    SYM(ProgramUniformMatrix2fv),
    SYM(ProgramUniformMatrix3fv),
    SYM(ProgramUniformMatrix4fv),
    SYM(ProgramUniformMatrix2dv),
    SYM(ProgramUniformMatrix3dv),
    SYM(ProgramUniformMatrix4dv),
    SYM(ProgramUniformMatrix2x3fv),
    SYM(ProgramUniformMatrix3x2fv),
    SYM(ProgramUniformMatrix2x4fv),
    SYM(ProgramUniformMatrix4x2fv),
    SYM(ProgramUniformMatrix3x4fv),
    SYM(ProgramUniformMatrix4x3fv),
    SYM(ProgramUniformMatrix2x3dv),
    SYM(ProgramUniformMatrix3x2dv),
    SYM(ProgramUniformMatrix2x4dv),
    SYM(ProgramUniformMatrix4x2dv),
    SYM(ProgramUniformMatrix3x4dv),
    SYM(ProgramUniformMatrix4x3dv),
    SYM(ValidateProgramPipeline),
    SYM(GetProgramPipelineInfoLog),
    SYM(VertexAttribL1d),
    SYM(VertexAttribL2d),
    SYM(VertexAttribL3d),
    SYM(VertexAttribL4d),
    SYM(VertexAttribL1dv),
    SYM(VertexAttribL2dv),
    SYM(VertexAttribL3dv),
    SYM(VertexAttribL4dv),
    SYM(VertexAttribLPointer),
    SYM(GetVertexAttribLdv),
    SYM(ViewportArrayv),
    SYM(ViewportIndexedf),
    SYM(ViewportIndexedfv),
    SYM(ScissorArrayv),
    SYM(ScissorIndexed),
    SYM(ScissorIndexedv),
    SYM(DepthRangeArrayv),
    SYM(DepthRangeIndexed),
    SYM(GetFloati_v),
    SYM(GetDoublei_v),
    SYM(DrawArraysInstancedBaseInstance),
    SYM(DrawElementsInstancedBaseInstance),
    SYM(DrawElementsInstancedBaseVertexBaseInstance),
    SYM(GetInternalformativ),
    SYM(GetActiveAtomicCounterBufferiv),
    SYM(BindImageTexture),
    SYM(MemoryBarrier),
    SYM(TexStorage1D),
    SYM(TexStorage2D),
    SYM(TexStorage3D),
    SYM(DrawTransformFeedbackInstanced),
    SYM(DrawTransformFeedbackStreamInstanced),
    SYM(ClearBufferData),
    SYM(ClearBufferSubData),
    SYM(DispatchCompute),
    SYM(DispatchComputeIndirect),
    SYM(CopyImageSubData),
    SYM(FramebufferParameteri),
    SYM(GetFramebufferParameteriv),
    SYM(GetInternalformati64v),
    SYM(InvalidateTexSubImage),
    SYM(InvalidateTexImage),
    SYM(InvalidateBufferSubData),
    SYM(InvalidateBufferData),
    SYM(InvalidateFramebuffer),
    SYM(InvalidateSubFramebuffer),
    SYM(MultiDrawArraysIndirect),
    SYM(MultiDrawElementsIndirect),
    SYM(GetProgramInterfaceiv),
    SYM(GetProgramResourceIndex),
    SYM(GetProgramResourceName),
    SYM(GetProgramResourceiv),
    SYM(GetProgramResourceLocation),
    SYM(GetProgramResourceLocationIndex),
    SYM(ShaderStorageBlockBinding),
    SYM(TexBufferRange),
    SYM(TexStorage2DMultisample),
    SYM(TexStorage3DMultisample),
    SYM(TextureView),
    SYM(BindVertexBuffer),
    SYM(VertexAttribFormat),
    SYM(VertexAttribIFormat),
    SYM(VertexAttribLFormat),
    SYM(VertexAttribBinding),
    SYM(VertexBindingDivisor),
    SYM(DebugMessageControl),
    SYM(DebugMessageInsert),
    SYM(DebugMessageCallback),
    SYM(GetDebugMessageLog),
    SYM(PushDebugGroup),
    SYM(PopDebugGroup),
    SYM(ObjectLabel),
    SYM(GetObjectLabel),
    SYM(ObjectPtrLabel),
    SYM(GetObjectPtrLabel),
    SYM(BufferStorage),
    SYM(ClearTexImage),
    SYM(ClearTexSubImage),
    SYM(BindBuffersBase),
    SYM(BindBuffersRange),
    SYM(BindTextures),
    SYM(BindSamplers),
    SYM(BindImageTextures),
    SYM(BindVertexBuffers),
    SYM(GetTextureHandleARB),
    SYM(GetTextureSamplerHandleARB),
    SYM(MakeTextureHandleResidentARB),
    SYM(MakeTextureHandleNonResidentARB),
    SYM(GetImageHandleARB),
    SYM(MakeImageHandleResidentARB),
    SYM(MakeImageHandleNonResidentARB),
    SYM(UniformHandleui64ARB),
    SYM(UniformHandleui64vARB),
    SYM(ProgramUniformHandleui64ARB),
    SYM(ProgramUniformHandleui64vARB),
    SYM(IsTextureHandleResidentARB),
    SYM(IsImageHandleResidentARB),
    SYM(VertexAttribL1ui64ARB),
    SYM(VertexAttribL1ui64vARB),
    SYM(GetVertexAttribLui64vARB),
    SYM(CreateSyncFromCLeventARB),
    SYM(ClampColorARB),
    SYM(DispatchComputeGroupSizeARB),
    SYM(DebugMessageControlARB),
    SYM(DebugMessageInsertARB),
    SYM(DebugMessageCallbackARB),
    SYM(GetDebugMessageLogARB),
    SYM(DrawBuffersARB),
    SYM(BlendEquationiARB),
    SYM(BlendEquationSeparateiARB),
    SYM(BlendFunciARB),
    SYM(BlendFuncSeparateiARB),
    SYM(DrawArraysInstancedARB),
    SYM(DrawElementsInstancedARB),
    SYM(ProgramStringARB),
    SYM(BindProgramARB),
    SYM(DeleteProgramsARB),
    SYM(GenProgramsARB),
    SYM(ProgramEnvParameter4dARB),
    SYM(ProgramEnvParameter4dvARB),
    SYM(ProgramEnvParameter4fARB),
    SYM(ProgramEnvParameter4fvARB),
    SYM(ProgramLocalParameter4dARB),
    SYM(ProgramLocalParameter4dvARB),
    SYM(ProgramLocalParameter4fARB),
    SYM(ProgramLocalParameter4fvARB),
    SYM(GetProgramEnvParameterdvARB),
    SYM(GetProgramEnvParameterfvARB),
    SYM(GetProgramLocalParameterdvARB),
    SYM(GetProgramLocalParameterfvARB),
    SYM(GetProgramivARB),
    SYM(GetProgramStringARB),
    SYM(IsProgramARB),
    SYM(ProgramParameteriARB),
    SYM(FramebufferTextureARB),
    SYM(FramebufferTextureLayerARB),
    SYM(FramebufferTextureFaceARB),
    SYM(ColorTable),
    SYM(ColorTableParameterfv),
    SYM(ColorTableParameteriv),
    SYM(CopyColorTable),
    SYM(GetColorTable),
    SYM(GetColorTableParameterfv),
    SYM(GetColorTableParameteriv),
    SYM(ColorSubTable),
    SYM(CopyColorSubTable),
    SYM(ConvolutionFilter1D),
    SYM(ConvolutionFilter2D),
    SYM(ConvolutionParameterf),
    SYM(ConvolutionParameterfv),
    SYM(ConvolutionParameteri),
    SYM(ConvolutionParameteriv),
    SYM(CopyConvolutionFilter1D),
    SYM(CopyConvolutionFilter2D),
    SYM(GetConvolutionFilter),
    SYM(GetConvolutionParameterfv),
    SYM(GetConvolutionParameteriv),
    SYM(GetSeparableFilter),
    SYM(SeparableFilter2D),
    SYM(GetHistogram),
    SYM(GetHistogramParameterfv),
    SYM(GetHistogramParameteriv),
    SYM(GetMinmax),
    SYM(GetMinmaxParameterfv),
    SYM(GetMinmaxParameteriv),
    SYM(Histogram),
    SYM(Minmax),
    SYM(ResetHistogram),
    SYM(ResetMinmax),
    SYM(MultiDrawArraysIndirectCountARB),
    SYM(MultiDrawElementsIndirectCountARB),
    SYM(VertexAttribDivisorARB),
    SYM(CurrentPaletteMatrixARB),
    SYM(MatrixIndexubvARB),
    SYM(MatrixIndexusvARB),
    SYM(MatrixIndexuivARB),
    SYM(MatrixIndexPointerARB),
    SYM(SampleCoverageARB),
    SYM(ActiveTextureARB),
    SYM(ClientActiveTextureARB),
    SYM(MultiTexCoord1dARB),
    SYM(MultiTexCoord1dvARB),
    SYM(MultiTexCoord1fARB),
    SYM(MultiTexCoord1fvARB),
    SYM(MultiTexCoord1iARB),
    SYM(MultiTexCoord1ivARB),
    SYM(MultiTexCoord1sARB),
    SYM(MultiTexCoord1svARB),
    SYM(MultiTexCoord2dARB),
    SYM(MultiTexCoord2dvARB),
    SYM(MultiTexCoord2fARB),
    SYM(MultiTexCoord2fvARB),
    SYM(MultiTexCoord2iARB),
    SYM(MultiTexCoord2ivARB),
    SYM(MultiTexCoord2sARB),
    SYM(MultiTexCoord2svARB),
    SYM(MultiTexCoord3dARB),
    SYM(MultiTexCoord3dvARB),
    SYM(MultiTexCoord3fARB),
    SYM(MultiTexCoord3fvARB),
    SYM(MultiTexCoord3iARB),
    SYM(MultiTexCoord3ivARB),
    SYM(MultiTexCoord3sARB),
    SYM(MultiTexCoord3svARB),
    SYM(MultiTexCoord4dARB),
    SYM(MultiTexCoord4dvARB),
    SYM(MultiTexCoord4fARB),
    SYM(MultiTexCoord4fvARB),
    SYM(MultiTexCoord4iARB),
    SYM(MultiTexCoord4ivARB),
    SYM(MultiTexCoord4sARB),
    SYM(MultiTexCoord4svARB),
    SYM(GenQueriesARB),
    SYM(DeleteQueriesARB),
    SYM(IsQueryARB),
    SYM(BeginQueryARB),
    SYM(EndQueryARB),
    SYM(GetQueryivARB),
    SYM(GetQueryObjectivARB),
    SYM(GetQueryObjectuivARB),
    SYM(PointParameterfARB),
    SYM(PointParameterfvARB),
    SYM(GetGraphicsResetStatusARB),
    SYM(GetnTexImageARB),
    SYM(ReadnPixelsARB),
    SYM(GetnCompressedTexImageARB),
    SYM(GetnUniformfvARB),
    SYM(GetnUniformivARB),
    SYM(GetnUniformuivARB),
    SYM(GetnUniformdvARB),
    SYM(GetnMapdvARB),
    SYM(GetnMapfvARB),
    SYM(GetnMapivARB),
    SYM(GetnPixelMapfvARB),
    SYM(GetnPixelMapuivARB),
    SYM(GetnPixelMapusvARB),
    SYM(GetnPolygonStippleARB),
    SYM(GetnColorTableARB),
    SYM(GetnConvolutionFilterARB),
    SYM(GetnSeparableFilterARB),
    SYM(GetnHistogramARB),
    SYM(GetnMinmaxARB),
    SYM(MinSampleShadingARB),
    SYM(DeleteObjectARB),
    SYM(GetHandleARB),
    SYM(DetachObjectARB),
    SYM(CreateShaderObjectARB),
    SYM(ShaderSourceARB),
    SYM(CompileShaderARB),
    SYM(CreateProgramObjectARB),
    SYM(AttachObjectARB),
    SYM(LinkProgramARB),
    SYM(UseProgramObjectARB),
    SYM(ValidateProgramARB),
    SYM(Uniform1fARB),
    SYM(Uniform2fARB),
    SYM(Uniform3fARB),
    SYM(Uniform4fARB),
    SYM(Uniform1iARB),
    SYM(Uniform2iARB),
    SYM(Uniform3iARB),
    SYM(Uniform4iARB),
    SYM(Uniform1fvARB),
    SYM(Uniform2fvARB),
    SYM(Uniform3fvARB),
    SYM(Uniform4fvARB),
    SYM(Uniform1ivARB),
    SYM(Uniform2ivARB),
    SYM(Uniform3ivARB),
    SYM(Uniform4ivARB),
    SYM(UniformMatrix2fvARB),
    SYM(UniformMatrix3fvARB),
    SYM(UniformMatrix4fvARB),
    SYM(GetObjectParameterfvARB),
    SYM(GetObjectParameterivARB),
    SYM(GetInfoLogARB),
    SYM(GetAttachedObjectsARB),
    SYM(GetUniformLocationARB),
    SYM(GetActiveUniformARB),
    SYM(GetUniformfvARB),
    SYM(GetUniformivARB),
    SYM(GetShaderSourceARB),
    SYM(NamedStringARB),
    SYM(DeleteNamedStringARB),
    SYM(CompileShaderIncludeARB),
    SYM(IsNamedStringARB),
    SYM(GetNamedStringARB),
    SYM(GetNamedStringivARB),
    SYM(TexPageCommitmentARB),
    SYM(TexBufferARB),
    SYM(CompressedTexImage3DARB),
    SYM(CompressedTexImage2DARB),
    SYM(CompressedTexImage1DARB),
    SYM(CompressedTexSubImage3DARB),
    SYM(CompressedTexSubImage2DARB),
    SYM(CompressedTexSubImage1DARB),
    SYM(GetCompressedTexImageARB),
    SYM(LoadTransposeMatrixfARB),
    SYM(LoadTransposeMatrixdARB),
    SYM(MultTransposeMatrixfARB),
    SYM(MultTransposeMatrixdARB),
    SYM(WeightbvARB),
    SYM(WeightsvARB),
    SYM(WeightivARB),
    SYM(WeightfvARB),
    SYM(WeightdvARB),
    SYM(WeightubvARB),
    SYM(WeightusvARB),
    SYM(WeightuivARB),
    SYM(WeightPointerARB),
    SYM(VertexBlendARB),
    SYM(BindBufferARB),
    SYM(DeleteBuffersARB),
    SYM(GenBuffersARB),
    SYM(IsBufferARB),
    SYM(BufferDataARB),
    SYM(BufferSubDataARB),
    SYM(GetBufferSubDataARB),
    SYM(MapBufferARB),
    SYM(UnmapBufferARB),
    SYM(GetBufferParameterivARB),
    SYM(GetBufferPointervARB),
    SYM(VertexAttrib1dARB),
    SYM(VertexAttrib1dvARB),
    SYM(VertexAttrib1fARB),
    SYM(VertexAttrib1fvARB),
    SYM(VertexAttrib1sARB),
    SYM(VertexAttrib1svARB),
    SYM(VertexAttrib2dARB),
    SYM(VertexAttrib2dvARB),
    SYM(VertexAttrib2fARB),
    SYM(VertexAttrib2fvARB),
    SYM(VertexAttrib2sARB),
    SYM(VertexAttrib2svARB),
    SYM(VertexAttrib3dARB),
    SYM(VertexAttrib3dvARB),
    SYM(VertexAttrib3fARB),
    SYM(VertexAttrib3fvARB),
    SYM(VertexAttrib3sARB),
    SYM(VertexAttrib3svARB),
    SYM(VertexAttrib4NbvARB),
    SYM(VertexAttrib4NivARB),
    SYM(VertexAttrib4NsvARB),
    SYM(VertexAttrib4NubARB),
    SYM(VertexAttrib4NubvARB),
    SYM(VertexAttrib4NuivARB),
    SYM(VertexAttrib4NusvARB),
    SYM(VertexAttrib4bvARB),
    SYM(VertexAttrib4dARB),
    SYM(VertexAttrib4dvARB),
    SYM(VertexAttrib4fARB),
    SYM(VertexAttrib4fvARB),
    SYM(VertexAttrib4ivARB),
    SYM(VertexAttrib4sARB),
    SYM(VertexAttrib4svARB),
    SYM(VertexAttrib4ubvARB),
    SYM(VertexAttrib4uivARB),
    SYM(VertexAttrib4usvARB),
    SYM(VertexAttribPointerARB),
    SYM(EnableVertexAttribArrayARB),
    SYM(DisableVertexAttribArrayARB),
    SYM(GetVertexAttribdvARB),
    SYM(GetVertexAttribfvARB),
    SYM(GetVertexAttribivARB),
    SYM(GetVertexAttribPointervARB),
    SYM(BindAttribLocationARB),
    SYM(GetActiveAttribARB),
    SYM(GetAttribLocationARB),
    SYM(WindowPos2dARB),
    SYM(WindowPos2dvARB),
    SYM(WindowPos2fARB),
    SYM(WindowPos2fvARB),
    SYM(WindowPos2iARB),
    SYM(WindowPos2ivARB),
    SYM(WindowPos2sARB),
    SYM(WindowPos2svARB),
    SYM(WindowPos3dARB),
    SYM(WindowPos3dvARB),
    SYM(WindowPos3fARB),
    SYM(WindowPos3fvARB),
    SYM(WindowPos3iARB),
    SYM(WindowPos3ivARB),
    SYM(WindowPos3sARB),
    SYM(WindowPos3svARB),
    SYM(MultiTexCoord1bOES),
    SYM(MultiTexCoord1bvOES),
    SYM(MultiTexCoord2bOES),
    SYM(MultiTexCoord2bvOES),
    SYM(MultiTexCoord3bOES),
    SYM(MultiTexCoord3bvOES),
    SYM(MultiTexCoord4bOES),
    SYM(MultiTexCoord4bvOES),
    SYM(TexCoord1bOES),
    SYM(TexCoord1bvOES),
    SYM(TexCoord2bOES),
    SYM(TexCoord2bvOES),
    SYM(TexCoord3bOES),
    SYM(TexCoord3bvOES),
    SYM(TexCoord4bOES),
    SYM(TexCoord4bvOES),
    SYM(Vertex2bOES),
    SYM(Vertex2bvOES),
    SYM(Vertex3bOES),
    SYM(Vertex3bvOES),
    SYM(Vertex4bOES),
    SYM(Vertex4bvOES),
    SYM(AlphaFuncxOES),
    SYM(ClearColorxOES),
    SYM(ClearDepthxOES),
    SYM(ClipPlanexOES),
    SYM(Color4xOES),
    SYM(DepthRangexOES),
    SYM(FogxOES),
    SYM(FogxvOES),
    SYM(FrustumxOES),
    SYM(GetClipPlanexOES),
    SYM(GetFixedvOES),
    SYM(GetTexEnvxvOES),
    SYM(GetTexParameterxvOES),
    SYM(LightModelxOES),
    SYM(LightModelxvOES),
    SYM(LightxOES),
    SYM(LightxvOES),
    SYM(LineWidthxOES),
    SYM(LoadMatrixxOES),
    SYM(MaterialxOES),
    SYM(MaterialxvOES),
    SYM(MultMatrixxOES),
    SYM(MultiTexCoord4xOES),
    SYM(Normal3xOES),
    SYM(OrthoxOES),
    SYM(PointParameterxvOES),
    SYM(PointSizexOES),
    SYM(PolygonOffsetxOES),
    SYM(RotatexOES),
    SYM(SampleCoverageOES),
    SYM(ScalexOES),
    SYM(TexEnvxOES),
    SYM(TexEnvxvOES),
    SYM(TexParameterxOES),
    SYM(TexParameterxvOES),
    SYM(TranslatexOES),
    SYM(AccumxOES),
    SYM(BitmapxOES),
    SYM(BlendColorxOES),
    SYM(ClearAccumxOES),
    SYM(Color3xOES),
    SYM(Color3xvOES),
    SYM(Color4xvOES),
    SYM(ConvolutionParameterxOES),
    SYM(ConvolutionParameterxvOES),
    SYM(EvalCoord1xOES),
    SYM(EvalCoord1xvOES),
    SYM(EvalCoord2xOES),
    SYM(EvalCoord2xvOES),
    SYM(FeedbackBufferxOES),
    SYM(GetConvolutionParameterxvOES),
    SYM(GetHistogramParameterxvOES),
    SYM(GetLightxOES),
    SYM(GetMapxvOES),
    SYM(GetMaterialxOES),
    SYM(GetPixelMapxv),
    SYM(GetTexGenxvOES),
    SYM(GetTexLevelParameterxvOES),
    SYM(IndexxOES),
    SYM(IndexxvOES),
    SYM(LoadTransposeMatrixxOES),
    SYM(Map1xOES),
    SYM(Map2xOES),
    SYM(MapGrid1xOES),
    SYM(MapGrid2xOES),
    SYM(MultTransposeMatrixxOES),
    SYM(MultiTexCoord1xOES),
    SYM(MultiTexCoord1xvOES),
    SYM(MultiTexCoord2xOES),
    SYM(MultiTexCoord2xvOES),
    SYM(MultiTexCoord3xOES),
    SYM(MultiTexCoord3xvOES),
    SYM(MultiTexCoord4xvOES),
    SYM(Normal3xvOES),
    SYM(PassThroughxOES),
    SYM(PixelMapx),
    SYM(PixelStorex),
    SYM(PixelTransferxOES),
    SYM(PixelZoomxOES),
    SYM(PrioritizeTexturesxOES),
    SYM(RasterPos2xOES),
    SYM(RasterPos2xvOES),
    SYM(RasterPos3xOES),
    SYM(RasterPos3xvOES),
    SYM(RasterPos4xOES),
    SYM(RasterPos4xvOES),
    SYM(RectxOES),
    SYM(RectxvOES),
    SYM(TexCoord1xOES),
    SYM(TexCoord1xvOES),
    SYM(TexCoord2xOES),
    SYM(TexCoord2xvOES),
    SYM(TexCoord3xOES),
    SYM(TexCoord3xvOES),
    SYM(TexCoord4xOES),
    SYM(TexCoord4xvOES),
    SYM(TexGenxOES),
    SYM(TexGenxvOES),
    SYM(Vertex2xOES),
    SYM(Vertex2xvOES),
    SYM(Vertex3xOES),
    SYM(Vertex3xvOES),
    SYM(Vertex4xOES),
    SYM(Vertex4xvOES),
    SYM(QueryMatrixxOES),
    SYM(ClearDepthfOES),
    SYM(ClipPlanefOES),
    SYM(DepthRangefOES),
    SYM(FrustumfOES),
    SYM(GetClipPlanefOES),
    SYM(OrthofOES),
    SYM(ImageTransformParameteriHP),
    SYM(ImageTransformParameterfHP),
    SYM(ImageTransformParameterivHP),
    SYM(ImageTransformParameterfvHP),
    SYM(GetImageTransformParameterivHP),
    SYM(GetImageTransformParameterfvHP),

    { NULL, NULL },
};
RGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;
RGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;
RGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;
RGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;
RGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;
RGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;
RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;
RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;
RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;
RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;
RGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;
RGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;
RGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;
RGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;
RGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;
RGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;
RGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;
RGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;
RGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;
RGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;
RGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;
RGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;
RGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;
RGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;
RGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;
RGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;
RGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;
RGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;
RGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;
RGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;
RGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;
RGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;
RGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;
RGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;
RGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;
RGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;
RGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;
RGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;
RGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;
RGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;
RGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;
RGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;
RGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;
RGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;
RGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;
RGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;
RGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;
RGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;
RGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;
RGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;
RGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;
RGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;
RGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;
RGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;
RGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;
RGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;
RGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;
RGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;
RGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;
RGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;
RGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;
RGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;
RGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;
RGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;
RGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;
RGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;
RGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;
RGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;
RGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;
RGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;
RGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;
RGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;
RGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;
RGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;
RGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;
RGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;
RGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;
RGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;
RGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;
RGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;
RGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;
RGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;
RGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;
RGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;
RGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;
RGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;
RGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;
RGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;
RGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;
RGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;
RGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;
RGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;
RGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;
RGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;
RGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;
RGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;
RGLSYMGLISQUERYPROC __rglgen_glIsQuery;
RGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;
RGLSYMGLENDQUERYPROC __rglgen_glEndQuery;
RGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;
RGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;
RGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;
RGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;
RGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;
RGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;
RGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;
RGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;
RGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;
RGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;
RGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;
RGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;
RGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;
RGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;
RGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;
RGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;
RGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;
RGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;
RGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;
RGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;
RGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;
RGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;
RGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;
RGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;
RGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;
RGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;
RGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;
RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;
RGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;
RGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;
RGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;
RGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;
RGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;
RGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;
RGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;
RGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;
RGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;
RGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;
RGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;
RGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;
RGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;
RGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;
RGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;
RGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;
RGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;
RGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;
RGLSYMGLISSHADERPROC __rglgen_glIsShader;
RGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;
RGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;
RGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;
RGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;
RGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;
RGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;
RGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;
RGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;
RGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;
RGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;
RGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;
RGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;
RGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;
RGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;
RGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;
RGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;
RGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;
RGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;
RGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;
RGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;
RGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;
RGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;
RGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;
RGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;
RGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;
RGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;
RGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;
RGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;
RGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;
RGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;
RGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;
RGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;
RGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;
RGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;
RGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;
RGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;
RGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;
RGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;
RGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;
RGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;
RGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;
RGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;
RGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;
RGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;
RGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;
RGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;
RGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;
RGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;
RGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;
RGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;
RGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;
RGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;
RGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;
RGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;
RGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;
RGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;
RGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;
RGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;
RGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;
RGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;
RGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;
RGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;
RGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;
RGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;
RGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;
RGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;
RGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;
RGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;
RGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;
RGLSYMGLENABLEIPROC __rglgen_glEnablei;
RGLSYMGLDISABLEIPROC __rglgen_glDisablei;
RGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;
RGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;
RGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;
RGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;
RGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;
RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;
RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;
RGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;
RGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;
RGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;
RGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;
RGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;
RGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;
RGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;
RGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;
RGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;
RGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;
RGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;
RGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;
RGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;
RGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;
RGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;
RGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;
RGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;
RGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;
RGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;
RGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;
RGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;
RGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;
RGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;
RGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;
RGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;
RGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;
RGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;
RGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;
RGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;
RGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;
RGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;
RGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;
RGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;
RGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;
RGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;
RGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;
RGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;
RGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;
RGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;
RGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;
RGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;
RGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;
RGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;
RGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;
RGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;
RGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;
RGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;
RGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;
RGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;
RGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;
RGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;
RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;
RGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;
RGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;
RGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;
RGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;
RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;
RGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;
RGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;
RGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;
RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;
RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;
RGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;
RGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;
RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;
RGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;
RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;
RGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;
RGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;
RGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;
RGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;
RGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;
RGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;
RGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;
RGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;
RGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;
RGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;
RGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;
RGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;
RGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;
RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;
RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;
RGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;
RGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;
RGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;
RGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;
RGLSYMGLISSYNCPROC __rglgen_glIsSync;
RGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;
RGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;
RGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;
RGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;
RGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;
RGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;
RGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;
RGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;
RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;
RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;
RGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;
RGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;
RGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;
RGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;
RGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;
RGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;
RGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;
RGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;
RGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;
RGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;
RGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;
RGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;
RGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;
RGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;
RGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;
RGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;
RGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;
RGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;
RGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;
RGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;
RGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;
RGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;
RGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;
RGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;
RGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;
RGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;
RGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;
RGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;
RGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;
RGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;
RGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;
RGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;
RGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;
RGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;
RGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;
RGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;
RGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;
RGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;
RGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;
RGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;
RGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;
RGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;
RGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;
RGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;
RGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;
RGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;
RGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;
RGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;
RGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;
RGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;
RGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;
RGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;
RGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;
RGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;
RGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;
RGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;
RGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;
RGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;
RGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;
RGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;
RGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;
RGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;
RGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;
RGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;
RGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;
RGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;
RGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;
RGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;
RGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;
RGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;
RGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;
RGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;
RGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;
RGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;
RGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;
RGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;
RGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;
RGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;
RGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;
RGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;
RGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;
RGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;
RGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;
RGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;
RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;
RGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;
RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;
RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;
RGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;
RGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;
RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;
RGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;
RGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;
RGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;
RGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;
RGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;
RGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;
RGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;
RGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;
RGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;
RGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;
RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;
RGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;
RGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;
RGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;
RGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;
RGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;
RGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;
RGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;
RGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;
RGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;
RGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;
RGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;
RGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;
RGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;
RGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;
RGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;
RGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;
RGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;
RGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;
RGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;
RGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;
RGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;
RGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;
RGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;
RGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;
RGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;
RGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;
RGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;
RGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;
RGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;
RGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;
RGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;
RGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;
RGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;
RGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;
RGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;
RGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;
RGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;
RGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;
RGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;
RGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;
RGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;
RGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;
RGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;
RGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;
RGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;
RGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;
RGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;
RGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;
RGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;
RGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;
RGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;
RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;
RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;
RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;
RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;
RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;
RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;
RGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;
RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;
RGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;
RGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;
RGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;
RGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;
RGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;
RGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;
RGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;
RGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;
RGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;
RGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;
RGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;
RGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;
RGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;
RGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;
RGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;
RGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;
RGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;
RGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;
RGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;
RGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;
RGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;
RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;
RGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;
RGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;
RGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;
RGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;
RGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;
RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;
RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;
RGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;
RGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;
RGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;
RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;
RGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;
RGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;
RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;
RGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;
RGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;
RGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;
RGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;
RGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;
RGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;
RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;
RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;
RGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;
RGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;
RGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;
RGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;
RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;
RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;
RGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;
RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;
RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;
RGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;
RGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;
RGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;
RGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;
RGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;
RGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;
RGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;
RGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;
RGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;
RGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;
RGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;
RGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;
RGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;
RGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;
RGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;
RGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;
RGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;
RGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;
RGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;
RGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;
RGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;
RGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;
RGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;
RGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;
RGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;
RGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;
RGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;
RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;
RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;
RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;
RGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;
RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;
RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;
RGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;
RGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;
RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;
RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;
RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;
RGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;
RGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;
RGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;
RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;
RGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;
RGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;
RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;
RGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;
RGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;
RGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;
RGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;
RGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;
RGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;
RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;
RGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;
RGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;
RGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;
RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;
RGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;
RGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;
RGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;
RGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;
RGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;
RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;
RGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;
RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;
RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;
RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;
RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;
RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;
RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;
RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;
RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;
RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;
RGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;
RGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;
RGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;
RGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;
RGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;
RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;
RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;
RGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;
RGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;
RGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;
RGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;
RGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;
RGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;
RGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;
RGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;
RGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;
RGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;
RGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;
RGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;
RGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;
RGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;
RGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;
RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;
RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;
RGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;
RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;
RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;
RGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;
RGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;
RGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;
RGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;
RGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;
RGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;
RGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;
RGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;
RGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;
RGLSYMGLMINMAXPROC __rglgen_glMinmax;
RGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;
RGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;
RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;
RGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;
RGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;
RGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;
RGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;
RGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;
RGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;
RGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;
RGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;
RGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;
RGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;
RGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;
RGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;
RGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;
RGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;
RGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;
RGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;
RGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;
RGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;
RGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;
RGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;
RGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;
RGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;
RGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;
RGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;
RGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;
RGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;
RGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;
RGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;
RGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;
RGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;
RGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;
RGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;
RGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;
RGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;
RGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;
RGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;
RGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;
RGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;
RGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;
RGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;
RGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;
RGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;
RGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;
RGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;
RGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;
RGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;
RGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;
RGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;
RGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;
RGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;
RGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;
RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;
RGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;
RGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;
RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;
RGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;
RGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;
RGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;
RGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;
RGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;
RGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;
RGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;
RGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;
RGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;
RGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;
RGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;
RGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;
RGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;
RGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;
RGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;
RGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;
RGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;
RGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;
RGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;
RGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;
RGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;
RGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;
RGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;
RGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;
RGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;
RGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;
RGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;
RGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;
RGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;
RGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;
RGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;
RGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;
RGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;
RGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;
RGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;
RGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;
RGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;
RGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;
RGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;
RGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;
RGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;
RGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;
RGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;
RGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;
RGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;
RGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;
RGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;
RGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;
RGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;
RGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;
RGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;
RGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;
RGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;
RGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;
RGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;
RGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;
RGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;
RGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;
RGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;
RGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;
RGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;
RGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;
RGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;
RGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;
RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;
RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;
RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;
RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;
RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;
RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;
RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;
RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;
RGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;
RGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;
RGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;
RGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;
RGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;
RGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;
RGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;
RGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;
RGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;
RGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;
RGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;
RGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;
RGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;
RGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;
RGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;
RGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;
RGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;
RGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;
RGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;
RGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;
RGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;
RGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;
RGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;
RGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;
RGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;
RGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;
RGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;
RGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;
RGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;
RGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;
RGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;
RGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;
RGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;
RGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;
RGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;
RGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;
RGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;
RGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;
RGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;
RGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;
RGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;
RGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;
RGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;
RGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;
RGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;
RGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;
RGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;
RGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;
RGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;
RGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;
RGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;
RGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;
RGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;
RGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;
RGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;
RGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;
RGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;
RGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;
RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;
RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;
RGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;
RGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;
RGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;
RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;
RGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;
RGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;
RGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;
RGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;
RGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;
RGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;
RGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;
RGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;
RGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;
RGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;
RGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;
RGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;
RGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;
RGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;
RGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;
RGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;
RGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;
RGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;
RGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;
RGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;
RGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;
RGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;
RGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;
RGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;
RGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;
RGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;
RGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;
RGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;
RGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;
RGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;
RGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;
RGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;
RGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;
RGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;
RGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;
RGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;
RGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;
RGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;
RGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;
RGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;
RGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;
RGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;
RGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;
RGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;
RGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;
RGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;
RGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;
RGLSYMGLFOGXOESPROC __rglgen_glFogxOES;
RGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;
RGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;
RGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;
RGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;
RGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;
RGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;
RGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;
RGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;
RGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;
RGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;
RGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;
RGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;
RGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;
RGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;
RGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;
RGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;
RGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;
RGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;
RGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;
RGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;
RGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;
RGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;
RGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;
RGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;
RGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;
RGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;
RGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;
RGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;
RGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;
RGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;
RGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;
RGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;
RGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;
RGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;
RGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;
RGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;
RGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;
RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;
RGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;
RGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;
RGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;
RGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;
RGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;
RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;
RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;
RGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;
RGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;
RGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;
RGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;
RGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;
RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;
RGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;
RGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;
RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;
RGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;
RGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;
RGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;
RGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;
RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;
RGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;
RGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;
RGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;
RGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;
RGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;
RGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;
RGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;
RGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;
RGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;
RGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;
RGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;
RGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;
RGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;
RGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;
RGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;
RGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;
RGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;
RGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;
RGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;
RGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;
RGLSYMGLRECTXOESPROC __rglgen_glRectxOES;
RGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;
RGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;
RGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;
RGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;
RGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;
RGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;
RGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;
RGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;
RGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;
RGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;
RGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;
RGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;
RGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;
RGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;
RGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;
RGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;
RGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;
RGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;
RGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;
RGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;
RGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;
RGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;
RGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;
RGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;
RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;
RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;
RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;
RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;
RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;
RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;

./include/libretro-common/glsym/README.md

# Autogenerate GL extension loaders

## OpenGL desktop

Use Khronos' recent [header](www.opengl.org/registry/api/glext.h).

    ./glgen.py /usr/include/GL/glext.h glsym_gl.h glsym_gl.c

## OpenGL ES

    ./glgen.py /usr/include/GLES2/gl2ext.h glsym_es2.h glsym_es2.c

./include/libretro-common/glsym/rglgen.c

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <string.h>

#include <glsym/rglgen.h>
#include <glsym/glsym.h>

void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
      const struct rglgen_sym_map *map)
{
   for (; map->sym; map++)
   {
      rglgen_func_t func = proc(map->sym);
      memcpy(map->ptr, &func, sizeof(func));
   }
}

void rglgen_resolve_symbols(rglgen_proc_address_t proc)
{
   if (!proc)
      return;

   rglgen_resolve_symbols_custom(proc, rglgen_symbol_map);
}

./include/libretro-common/glsym/rglgen.py

#!/usr/bin/env python3

"""
   License statement applies to this file (glgen.py) only.

   Permission is hereby granted, free of charge,
   to any person obtaining a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import sys
import os
import re

banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]

def noext(sym):
   for ext in banned_ext:
      if sym.endswith(ext):
         return False
   return True

def fix_multiline_functions(lines):
   fixed_lines = []
   temp_lines = []
   for line in lines:
      if line.count('(') > line.count(')'):
         temp_lines.append(line)
      else:
         if len(temp_lines) > 0:
            if line.count(')') > line.count('('):
               temp_lines.append(line)
               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
               fixed_lines.append(fixed_line)
               temp_lines = []
            else:
               temp_lines.append(line)
         else:
            fixed_lines.append(line)
   return fixed_lines

def find_gl_symbols(lines):
   typedefs = []
   syms = []
   for line in lines:
      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
      g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
      if m and noext(m.group(1)):
         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
      if g and noext(g.group(1)):
         syms.append(g.group(1))
   return (typedefs, syms)

def generate_defines(gl_syms):
   res = []
   for line in gl_syms:
      res.append('#define {} __rglgen_{}'.format(line, line))
   return res

def generate_declarations(gl_syms):
   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]

def generate_macros(gl_syms):
   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]

def dump(f, lines):
   f.write('\n'.join(lines))
   f.write('\n\n')

if __name__ == '__main__':

   if len(sys.argv) > 4:
      for banned in sys.argv[4:]:
         banned_ext.append(banned)

   with open(sys.argv[1], 'r') as f:
      lines = fix_multiline_functions(f.readlines())
      typedefs, syms = find_gl_symbols(lines)

      overrides = generate_defines(syms)
      declarations = generate_declarations(syms)
      externs = ['extern ' + x for x in declarations]

      macros = generate_macros(syms)

   with open(sys.argv[2], 'w') as f:
      f.write('#ifndef RGLGEN_DECL_H__\n')
      f.write('#define RGLGEN_DECL_H__\n')

      f.write('#ifdef __cplusplus\n')
      f.write('extern "C" {\n')
      f.write('#endif\n')

      f.write('#ifdef GL_APIENTRY\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#else\n')
      f.write('#ifndef APIENTRY\n')
      f.write('#define APIENTRY\n')
      f.write('#endif\n')
      f.write('#ifndef APIENTRYP\n')
      f.write('#define APIENTRYP APIENTRY *\n')
      f.write('#endif\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#endif\n')

      f.write('#ifndef GL_OES_EGL_image\n')
      f.write('typedef void *GLeglImageOES;\n')
      f.write('#endif\n')

      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
      f.write('typedef GLint GLfixed;\n')
      f.write('#endif\n')

      dump(f, typedefs)
      dump(f, overrides)
      dump(f, externs)

      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')

      f.write('#ifdef __cplusplus\n')
      f.write('}\n')
      f.write('#endif\n')

      f.write('#endif\n')

   with open(sys.argv[3], 'w') as f:
      f.write('#include "glsym/glsym.h"\n')
      f.write('#include <stddef.h>\n')
      f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
      dump(f, macros)
      f.write('    { NULL, NULL },\n')
      f.write('};\n')
      dump(f, declarations)

./include/libretro-common/glsym/xglgen.py

#!/usr/bin/env python3

"""
   License statement applies to this file (xglgen.py) only.

   Permission is hereby granted, free of charge,
   to any person obtaining a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import sys
import os
import re

banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]

def noext(sym):
   for ext in banned_ext:
      if sym.endswith(ext):
         return False
   return True

def fix_multiline_functions(lines):
   fixed_lines = []
   temp_lines = []
   for line in lines:
      if line.count('(') > line.count(')'):
         temp_lines.append(line)
      else:
         if len(temp_lines) > 0:
            if line.count(')') > line.count('('):
               temp_lines.append(line)
               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
               fixed_lines.append(fixed_line)
               temp_lines = []
            else:
               temp_lines.append(line)
         else:
            fixed_lines.append(line)
   return fixed_lines

def find_gl_symbols(lines):
   typedefs = []
   syms = []
   for line in lines:
      # Note this doesn't work automated; this script is designed as a helper
      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
      g = re.search(r'^GLAPI\s(.+)\s(.+)\s(gl\S+)\W*\((.+)\).*', line)
      if g and noext(g.group(3)):
         typedefs.append('typedef ' + g.group(1) + ' (APIENTRYP RGLSYM' + g.group(3).upper() + 'PROC) (' + g.group(4) + ');')
         syms.append(g.group(3))

   return (typedefs, syms)

def generate_defines(gl_syms):
   res = []
   for line in gl_syms:
      res.append('#define {} __rglgen_{}'.format(line, line))
   return res

def generate_declarations(gl_syms):
   return ['RGLSYM' + x.upper() + 'PROC ' + x + ';' for x in gl_syms]

def generate_macros(gl_syms):
   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]

def dump(f, lines):
   f.write('\n'.join(lines))
   f.write('\n\n')

if __name__ == '__main__':

   if len(sys.argv) > 4:
      for banned in sys.argv[4:]:
         banned_ext.append(banned)

   with open(sys.argv[1], 'r') as f:
      lines = fix_multiline_functions(f.readlines())
      typedefs, syms = find_gl_symbols(lines)

      overrides = generate_defines(syms)
      declarations = generate_declarations(syms)
      externs = ['extern ' + x for x in declarations]

      macros = generate_macros(syms)

   with open(sys.argv[2], 'w') as f:
      f.write('#ifndef RGLGEN_DECL_H__\n')
      f.write('#define RGLGEN_DECL_H__\n')

      f.write('#ifdef __cplusplus\n')
      f.write('extern "C" {\n')
      f.write('#endif\n')

      f.write('#ifdef GL_APIENTRY\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#else\n')
      f.write('#ifndef APIENTRY\n')
      f.write('#define APIENTRY\n')
      f.write('#endif\n')
      f.write('#ifndef APIENTRYP\n')
      f.write('#define APIENTRYP APIENTRY *\n')
      f.write('#endif\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#endif\n')

      f.write('#ifndef GL_OES_EGL_image\n')
      f.write('typedef void *GLeglImageOES;\n')
      f.write('#endif\n')

      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
      f.write('typedef GLint GLfixed;\n')
      f.write('#endif\n')

      f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\n')
      f.write('typedef long long int GLint64;\n')
      f.write('typedef unsigned long long int GLuint64;\n')
      f.write('typedef unsigned long long int GLuint64EXT;\n')
      f.write('typedef struct __GLsync *GLsync;\n')
      f.write('#endif\n')

      dump(f, typedefs)
      dump(f, overrides)
      dump(f, externs)

      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')

      f.write('#ifdef __cplusplus\n')
      f.write('}\n')
      f.write('#endif\n')

      f.write('#endif\n')

   with open(sys.argv[3], 'w') as f:
      f.write('#include "glsym/glsym.h"\n')
      f.write('#include <stddef.h>\n')
      f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
      dump(f, macros)
      f.write('    { NULL, NULL },\n')
      f.write('};\n')
      dump(f, declarations)

./include/libretro-common/hash/lrc_hash.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (lrc_hash.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <lrc_hash.h>
#include <retro_miscellaneous.h>
#include <retro_endianness.h>
#include <streams/file_stream.h>

#define LSL32(x, n) ((uint32_t)(x) << (n))
#define LSR32(x, n) ((uint32_t)(x) >> (n))
#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))

/* First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19 */
static const uint32_t T_H[8] = {
   0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
};

/* First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311 */
static const uint32_t T_K[64] = {
   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
};

/* SHA256 implementation from bSNES. Written by valditx. */

struct sha256_ctx
{
   union
   {
      uint8_t u8[64];
      uint32_t u32[16];
   } in;
   unsigned inlen;

   uint32_t w[64];
   uint32_t h[8];
   uint64_t len;
};

static void sha256_init(struct sha256_ctx *p)
{
   memset(p, 0, sizeof(struct sha256_ctx));
   memcpy(p->h, T_H, sizeof(T_H));
}

static void sha256_block(struct sha256_ctx *p)
{
   unsigned i;
   uint32_t s0, s1;
   uint32_t a, b, c, d, e, f, g, h;

   for (i = 0; i < 16; i++)
      p->w[i] = load32be(p->in.u32 + i);

   for (i = 16; i < 64; i++)
   {
      s0 = ROR32(p->w[i - 15],  7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15],  3);
      s1 = ROR32(p->w[i -  2], 17) ^ ROR32(p->w[i -  2], 19) ^ LSR32(p->w[i -  2], 10);
      p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;
   }

   a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];
   e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];

   for (i = 0; i < 64; i++)
   {
      uint32_t t1, t2, maj, ch;

      s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
      maj = (a & b) ^ (a & c) ^ (b & c);
      t2  = s0 + maj;
      s1  = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
      ch  = (e & f) ^ (~e & g);
      t1  = h + s1 + ch + T_K[i] + p->w[i];

      h   = g;
      g   = f;
      f   = e;
      e   = d + t1;
      d   = c;
      c   = b;
      b   = a;
      a   = t1 + t2;
   }

   p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;
   p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;

   /* Next block */
   p->inlen = 0;
}

static void sha256_chunk(struct sha256_ctx *p,
      const uint8_t *s, size_t len)
{
   p->len += len;

   while (len)
   {
      size_t l   = 64 - p->inlen;

      if (len < l)
         l       = len;

      memcpy(p->in.u8 + p->inlen, s, l);

      s         += l;
      p->inlen  += l;
      len       -= l;

      if (p->inlen == 64)
         sha256_block(p);
   }
}

static void sha256_final(struct sha256_ctx *p)
{
   uint64_t len;
   p->in.u8[p->inlen++] = 0x80;

   if (p->inlen > 56)
   {
      memset(p->in.u8 + p->inlen, 0, 64 - p->inlen);
      sha256_block(p);
   }

   memset(p->in.u8 + p->inlen, 0, 56 - p->inlen);

   len = p->len << 3;
   store32be(p->in.u32 + 14, (uint32_t)(len >> 32));
   store32be(p->in.u32 + 15, (uint32_t)len);
   sha256_block(p);
}

static void sha256_subhash(struct sha256_ctx *p, uint32_t *t)
{
   unsigned i;
   for (i = 0; i < 8; i++)
      store32be(t++, p->h[i]);
}

/**
 * sha256_hash:
 * @s                 : Output.
 * @in                : Input.
 * @size              : Size of @s.
 *
 * Hashes SHA256 and outputs a human readable string.
 **/
void sha256_hash(char *s, const uint8_t *in, size_t len)
{
   unsigned i;
   struct sha256_ctx sha;

   union
   {
      uint32_t u32[8];
      uint8_t u8[32];
   } shahash;

   sha256_init(&sha);
   sha256_chunk(&sha, in, len);
   sha256_final(&sha);
   sha256_subhash(&sha, shahash.u32);

   for (i = 0; i < 32; i++)
      snprintf(s + 2 * i, 3, "%02x", (unsigned)shahash.u8[i]);
}

#ifndef HAVE_ZLIB
/* Zlib CRC32. */
static const uint32_t crc32_hash_table[256] = {
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

uint32_t crc32_adjust(uint32_t checksum, uint8_t input)
{
   return ((checksum >> 8) & 0x00ffffff) ^ crc32_hash_table[(checksum ^ input) & 0xff];
}

uint32_t crc32_calculate(const uint8_t *data, size_t len)
{
   size_t i;
   uint32_t checksum = ~0;
   for (i = 0; i < len; i++)
      checksum = crc32_adjust(checksum, data[i]);
   return ~checksum;
}
#endif

/* SHA-1 implementation. */

/*
 *  sha1.c
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones <paulej@packetizer.com>
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This file implements the Secure Hashing Standard as defined
 *      in FIPS PUB 180-1 published April 17, 1995.
 *
 *      The Secure Hashing Standard, which uses the Secure Hashing
 *      Algorithm (SHA), produces a 160-bit message digest for a
 *      given data stream.  In theory, it is highly improbable that
 *      two messages will produce the same message digest.  Therefore,
 *      this algorithm can serve as a means of providing a "fingerprint"
 *      for a message.
 *
 *  Portability Issues:
 *      SHA-1 is defined in terms of 32-bit "words".  This code was
 *      written with the expectation that the processor has at least
 *      a 32-bit machine word size.  If the machine word size is larger,
 *      the code should still function properly.  One caveat to that
 *      is that the input functions taking characters and character
 *      arrays assume that only 8 bits of information are stored in each
 *      character.
 *
 *  Caveats:
 *      SHA-1 is designed to work with messages less than 2^64 bits
 *      long. Although SHA-1 allows a message digest to be generated for
 *      messages of any number of bits less than 2^64, this
 *      implementation only works with messages with a length that is a
 *      multiple of the size of an 8-bit character.
 *
 */

/* Define the circular shift macro */
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))

struct sha1_context
{
   unsigned Message_Digest[5]; /* Message Digest (output)          */

   unsigned Length_Low;        /* Message length in bits           */
   unsigned Length_High;       /* Message length in bits           */

   unsigned char Message_Block[64]; /* 512-bit message blocks      */
   int Message_Block_Index;    /* Index into message block array   */

   int Computed;               /* Is the digest computed?          */
   int Corrupted;              /* Is the message digest corruped?  */
};


static void SHA1Reset(struct sha1_context *context)
{
   if (!context)
      return;

   context->Length_Low             = 0;
   context->Length_High            = 0;
   context->Message_Block_Index    = 0;

   context->Message_Digest[0]      = 0x67452301;
   context->Message_Digest[1]      = 0xEFCDAB89;
   context->Message_Digest[2]      = 0x98BADCFE;
   context->Message_Digest[3]      = 0x10325476;
   context->Message_Digest[4]      = 0xC3D2E1F0;

   context->Computed   = 0;
   context->Corrupted  = 0;
}

static void SHA1ProcessMessageBlock(struct sha1_context *context)
{
   const unsigned K[] =            /* Constants defined in SHA-1   */
   {
      0x5A827999,
      0x6ED9EBA1,
      0x8F1BBCDC,
      0xCA62C1D6
   };
   int         t;                  /* Loop counter                 */
   unsigned    temp;               /* Temporary word value         */
   unsigned    W[80];              /* Word sequence                */
   unsigned    A, B, C, D, E;      /* Word buffers                 */

   /* Initialize the first 16 words in the array W */
   for (t = 0; t < 16; t++)
   {
      W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
      W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
      W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
      W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
   }

   for (t = 16; t < 80; t++)
      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);

   A = context->Message_Digest[0];
   B = context->Message_Digest[1];
   C = context->Message_Digest[2];
   D = context->Message_Digest[3];
   E = context->Message_Digest[4];

   for (t = 0; t < 20; t++)
   {
      temp  =  SHA1CircularShift(5,A) +
         ((B & C) | ((~B) & D)) + E + W[t] + K[0];
      temp &= 0xFFFFFFFF;
      E     = D;
      D     = C;
      C     = SHA1CircularShift(30,B);
      B     = A;
      A     = temp;
   }

   for (t = 20; t < 40; t++)
   {
      temp  = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
      temp &= 0xFFFFFFFF;
      E     = D;
      D     = C;
      C     = SHA1CircularShift(30,B);
      B     = A;
      A     = temp;
   }

   for (t = 40; t < 60; t++)
   {
      temp  = SHA1CircularShift(5,A) +
         ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
      temp &= 0xFFFFFFFF;
      E     = D;
      D     = C;
      C     = SHA1CircularShift(30,B);
      B     = A;
      A     = temp;
   }

   for (t = 60; t < 80; t++)
   {
      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
      temp &= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   context->Message_Digest[0] =
      (context->Message_Digest[0] + A) & 0xFFFFFFFF;
   context->Message_Digest[1] =
      (context->Message_Digest[1] + B) & 0xFFFFFFFF;
   context->Message_Digest[2] =
      (context->Message_Digest[2] + C) & 0xFFFFFFFF;
   context->Message_Digest[3] =
      (context->Message_Digest[3] + D) & 0xFFFFFFFF;
   context->Message_Digest[4] =
      (context->Message_Digest[4] + E) & 0xFFFFFFFF;

   context->Message_Block_Index = 0;
}

static void SHA1PadMessage(struct sha1_context *context)
{
   if (!context)
      return;

   /*
    *  Check to see if the current message block is too small to hold
    *  the initial padding bits and length.  If so, we will pad the
    *  block, process it, and then continue padding into a second
    *  block.
    */
   context->Message_Block[context->Message_Block_Index++] = 0x80;

   if (context->Message_Block_Index > 55)
   {
      while (context->Message_Block_Index < 64)
         context->Message_Block[context->Message_Block_Index++] = 0;

      SHA1ProcessMessageBlock(context);
   }

   while (context->Message_Block_Index < 56)
      context->Message_Block[context->Message_Block_Index++] = 0;

   /*  Store the message length as the last 8 octets */
   context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
   context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
   context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
   context->Message_Block[59] = (context->Length_High) & 0xFF;
   context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
   context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
   context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
   context->Message_Block[63] = (context->Length_Low) & 0xFF;

   SHA1ProcessMessageBlock(context);
}

static int SHA1Result(struct sha1_context *context)
{
   if (context->Corrupted)
      return 0;

   if (!context->Computed)
   {
      SHA1PadMessage(context);
      context->Computed = 1;
   }

   return 1;
}

static void SHA1Input(struct sha1_context *context,
      const unsigned char *message_array,
      unsigned len)
{
   if (!len)
      return;

   if (context->Computed || context->Corrupted)
   {
      context->Corrupted = 1;
      return;
   }

   while (len-- && !context->Corrupted)
   {
      context->Message_Block[context->Message_Block_Index++] =
         (*message_array & 0xFF);

      context->Length_Low += 8;
      /* Force it to 32 bits */
      context->Length_Low &= 0xFFFFFFFF;
      if (context->Length_Low == 0)
      {
         context->Length_High++;
         /* Force it to 32 bits */
         context->Length_High &= 0xFFFFFFFF;
         if (context->Length_High == 0)
            context->Corrupted = 1; /* Message is too long */
      }

      if (context->Message_Block_Index == 64)
         SHA1ProcessMessageBlock(context);

      message_array++;
   }
}

int sha1_calculate(const char *path, char *result)
{
   struct sha1_context sha;
   unsigned char buff[4096];
   int rv    = 1;
   RFILE *fd = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fd)
      goto error;

   buff[0] = '\0';

   SHA1Reset(&sha);

   do
   {
      rv = (int)filestream_read(fd, buff, 4096);
      if (rv < 0)
         goto error;

      SHA1Input(&sha, buff, rv);
   } while (rv);

   if (!SHA1Result(&sha))
      goto error;

   sprintf(result, "%08X%08X%08X%08X%08X",
         sha.Message_Digest[0],
         sha.Message_Digest[1],
         sha.Message_Digest[2],
         sha.Message_Digest[3], sha.Message_Digest[4]);

   filestream_close(fd);
   return 0;

error:
   if (fd)
      filestream_close(fd);
   return -1;
}

uint32_t djb2_calculate(const char *str)
{
   const unsigned char *aux = (const unsigned char*)str;
   uint32_t            hash = 5381;

   while ( *aux )
      hash = ( hash << 5 ) + hash + *aux++;

   return hash;
}

./include/libretro-common/include/array/rbuf.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbuf.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ARRAY_RBUF_H__
#define __LIBRETRO_SDK_ARRAY_RBUF_H__

/*
 * This file implements stretchy buffers as invented (?) by Sean Barrett.
 * Based on the implementation from the public domain Bitwise project
 * by Per Vognsen - https://github.com/pervognsen/bitwise
 *
 * It's a super simple type safe dynamic array for C with no need
 * to predeclare any type or anything.
 * The first time an element is added, memory for 16 elements are allocated.
 * Then every time length is about to exceed capacity, capacity is doubled.
 *
 * Be careful not to supply modifying statements to the macro arguments.
 * Something like RBUF_REMOVE(buf, i--); would have unintended results.
 *
 * Sample usage:
 *
 * mytype_t* buf = NULL;
 * RBUF_PUSH(buf, some_element);
 * RBUF_PUSH(buf, other_element);
 * -- now RBUF_LEN(buf) == 2, buf[0] == some_element, buf[1] == other_element
 *
 * -- Free allocated memory:
 * RBUF_FREE(buf);
 * -- now buf == NULL, RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 0
 *
 * -- Explicitly increase allocated memory and set capacity:
 * RBUF_FIT(buf, 100);
 * -- now RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 100
 *
 * -- Resize buffer (does not initialize or zero memory!)
 * RBUF_RESIZE(buf, 200);
 * -- now RBUF_LEN(buf) == 200, RBUF_CAP(buf) == 200
 *
 * -- To handle running out of memory:
 * bool ran_out_of_memory = !RBUF_TRYFIT(buf, 1000);
 * -- before RESIZE or PUSH. When out of memory, buf will stay unmodified.
 */

#include <retro_math.h> /* for MAX */
#include <stdlib.h> /* for malloc, realloc */

#define RBUF__HDR(b) (((struct rbuf__hdr *)(b))-1)

#define RBUF_LEN(b) ((b) ? RBUF__HDR(b)->len : 0)
#define RBUF_CAP(b) ((b) ? RBUF__HDR(b)->cap : 0)
#define RBUF_END(b) ((b) + RBUF_LEN(b))
#define RBUF_SIZEOF(b) ((b) ? RBUF_LEN(b)*sizeof(*b) : 0)

#define RBUF_FREE(b) ((b) ? (free(RBUF__HDR(b)), (b) = NULL) : 0)
#define RBUF_FIT(b, n) ((size_t)(n) <= RBUF_CAP(b) ? 0 : (*(void**)(&(b)) = rbuf__grow((b), (n), sizeof(*(b)))))
#define RBUF_PUSH(b, val) (RBUF_FIT((b), 1 + RBUF_LEN(b)), (b)[RBUF__HDR(b)->len++] = (val))
#define RBUF_POP(b) (b)[--RBUF__HDR(b)->len]
#define RBUF_RESIZE(b, sz) (RBUF_FIT((b), (sz)), ((b) ? RBUF__HDR(b)->len = (sz) : 0))
#define RBUF_CLEAR(b) ((b) ? RBUF__HDR(b)->len = 0 : 0)
#define RBUF_TRYFIT(b, n) (RBUF_FIT((b), (n)), (((b) && RBUF_CAP(b) >= (size_t)(n)) || !(n)))
#define RBUF_REMOVE(b, idx) memmove((b) + (idx), (b) + (idx) + 1, (--RBUF__HDR(b)->len - (idx)) * sizeof(*(b)))

struct rbuf__hdr
{
   size_t len;
   size_t cap;
};

#ifdef __GNUC__
__attribute__((__unused__))
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505) /* Unreferenced local function has been removed */
#endif
static void *rbuf__grow(void *buf,
      size_t new_len, size_t elem_size)
{
   struct rbuf__hdr *new_hdr;
   size_t new_cap  = MAX(2 * RBUF_CAP(buf), MAX(new_len, 16));
   size_t new_size = sizeof(struct rbuf__hdr) + new_cap*elem_size;
   if (buf)
   {
      new_hdr      = (struct rbuf__hdr *)realloc(RBUF__HDR(buf), new_size);
      if (!new_hdr)
         return buf; /* out of memory, return unchanged */
   }
   else
   {
      new_hdr      = (struct rbuf__hdr *)malloc(new_size);
      if (!new_hdr)
         return NULL; /* out of memory */
      new_hdr->len = 0;
   }
   new_hdr->cap    = new_cap;
   return new_hdr + 1;
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

#endif

./include/libretro-common/include/array/rhmap.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rhmap.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ARRAY_RHMAP_H__
#define __LIBRETRO_SDK_ARRAY_RHMAP_H__

/*
 * This file implements a hash map with 32-bit keys.
 * Based on the implementation from the public domain Bitwise project
 * by Per Vognsen - https://github.com/pervognsen/bitwise
 *
 * It's a super simple type safe hash map for C with no need
 * to predeclare any type or anything.
 * Will always allocate memory for twice the amount of max elements
 * so larger structs should be stored as pointers or indices to an array.
 * Can be used in C++ with POD types (without any constructor/destructor).
 *
 * Be careful not to supply modifying statements to the macro arguments.
 * Something like RHMAP_FIT(map, i++); would have unintended results.
 *
 * Sample usage:
 *
 * -- Set 2 elements with string keys and mytype_t values:
 * mytype_t* map = NULL;
 * RHMAP_SET_STR(map, "foo", foo_element);
 * RHMAP_SET_STR(map, "bar", bar_element);
 * -- now RHMAP_LEN(map) == 2, RHMAP_GET_STR(map, "foo") == foo_element
 *
 * -- Check if keys exist:
 * bool has_foo = RHMAP_HAS_STR(map, "foo");
 * bool has_baz = RHMAP_HAS_STR(map, "baz");
 * -- now has_foo == true, has_baz == false
 *
 * -- Removing a key:
 * bool removed = RHMAP_DEL_STR(map, "bar");
 * bool removed_again = RHMAP_DEL_STR(map, "bar");
 * -- now RHMAP_LEN(map) == 1, removed == true, removed_again == false
 *
 * -- Add/modify via pointer:
 * mytype_t* p_elem = RHMAP_PTR_STR(map, "qux");
 * p_elem->a = 123;
 * -- New keys initially have memory uninitialized
 * -- Pointers can get invalidated when a key is added/removed
 *
 * -- Looking up the index for a given key:
 * ptrdiff_t idx_foo = RHMAP_IDX_STR(map, "foo");
 * ptrdiff_t idx_invalid = RHMAP_IDX_STR(map, "invalid");
 * -- now idx_foo >= 0, idx_invalid == -1, map[idx_foo] == foo_element
 * -- Indices can change when a key is added/removed
 *
 * -- Clear all elements (keep memory allocated):
 * RHMAP_CLEAR(map);
 * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 16
 *
 * -- Reserve memory for at least N elements:
 * RHMAP_FIT(map, 30);
 * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 64
 *
 * -- Add elements with custom hash keys:
 * RHMAP_SET(map, my_uint32_hash(key1), some_element);
 * RHMAP_SET(map, my_uint32_hash(key2), other_element);
 * -- now RHMAP_LEN(map) == 2, _GET/_HAS/_DEL/_PTR/_IDX also exist
 *
 * -- Iterate elements (random order, order can change on insert):
 * for (size_t i = 0, cap = RHMAP_CAP(map); i != cap, i++)
 *   if (RHMAP_KEY(map, i))
 * ------ here map[i] is the value of key RHMAP_KEY(map, i)
 *
 * -- Set a custom null value (is zeroed by default):
 * RHMAP_SETNULLVAL(map, map_null);
 * -- now RHMAP_GET_STR(map, "invalid") == map_null
 *
 * -- Free allocated memory:
 * RHMAP_FREE(map);
 * -- now map == NULL, RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 0
 *
 * -- To handle running out of memory:
 * bool ran_out_of_memory = !RHMAP_TRYFIT(map, 1000);
 * -- before setting an element (with SET, PTR or NULLVAL).
 * -- When out of memory, map will stay unmodified.
 *
 */

#include <stdlib.h> /* for malloc, realloc */
#include <string.h> /* for memcpy, memset */
#include <stddef.h> /* for ptrdiff_t, size_t */
#include <stdint.h> /* for uint32_t */

#define RHMAP_LEN(b) ((b) ? RHMAP__HDR(b)->len : 0)
#define RHMAP_MAX(b) ((b) ? RHMAP__HDR(b)->maxlen : 0)
#define RHMAP_CAP(b) ((b) ? RHMAP__HDR(b)->maxlen + 1 : 0)
#define RHMAP_KEY(b, idx) (RHMAP__HDR(b)->keys[idx])
#define RHMAP_KEY_STR(b, idx) (RHMAP__HDR(b)->key_strs[idx])
#define RHMAP_SETNULLVAL(b, val) (RHMAP__FIT1(b), b[-1] = (val))
#define RHMAP_CLEAR(b) ((b) ? (memset(RHMAP__HDR(b)->keys, 0, RHMAP_CAP(b) * sizeof(uint32_t)), RHMAP__HDR(b)->len = 0) : 0)
#define RHMAP_FREE(b) ((b) ? (rhmap__free(RHMAP__HDR(b)), (b) = NULL) : 0)
#define RHMAP_FIT(b, n) ((!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))) ? 0 : RHMAP__GROW(b, n))
#define RHMAP_TRYFIT(b, n) (RHMAP_FIT((b), (n)), (!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))))

#define RHMAP_SET(b, key, val) RHMAP_SET_FULL(b, key, NULL, val)
#define RHMAP_GET(b, key)      RHMAP_GET_FULL(b, key, NULL)
#define RHMAP_HAS(b, key)      RHMAP_HAS_FULL(b, key, NULL)
#define RHMAP_DEL(b, key)      RHMAP_DEL_FULL(b, key, NULL)
#define RHMAP_PTR(b, key)      RHMAP_PTR_FULL(b, key, NULL)
#define RHMAP_IDX(b, key)      RHMAP_IDX_FULL(b, key, NULL)

#ifdef __GNUC__
#define RHMAP__UNUSED __attribute__((__unused__))
#else
#define RHMAP__UNUSED
#endif

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505) /* Unreferenced local function has been removed */
#endif

#define RHMAP_SET_FULL(b, key, str, val) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)] = (val))
#define RHMAP_GET_FULL(b, key, str) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0)])
#define RHMAP_HAS_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) != -1 : 0)
#define RHMAP_DEL_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, sizeof(*(b))) != -1 : 0)
#define RHMAP_PTR_FULL(b, key, str) (RHMAP__FIT1(b), &b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)])
#define RHMAP_IDX_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) : -1)

#define RHMAP_SET_STR(b, string_key, val) RHMAP_SET_FULL(b, rhmap_hash_string(string_key), string_key, val)
#define RHMAP_GET_STR(b, string_key)      RHMAP_GET_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_HAS_STR(b, string_key)      RHMAP_HAS_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_DEL_STR(b, string_key)      RHMAP_DEL_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_PTR_STR(b, string_key)      RHMAP_PTR_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_IDX_STR(b, string_key)      RHMAP_IDX_FULL(b, rhmap_hash_string(string_key), string_key)

RHMAP__UNUSED static uint32_t rhmap_hash_string(const char* str)
{
   unsigned char c;
   uint32_t hash = (uint32_t)0x811c9dc5;
   while ((c = (unsigned char)*(str++)) != '\0')
      hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);
   return (hash ? hash : 1);
}

struct rhmap__hdr { size_t len, maxlen; uint32_t *keys; char** key_strs; };
#define RHMAP__HDR(b) (((struct rhmap__hdr *)&(b)[-1])-1)
#define RHMAP__GROW(b, n) (*(void**)(&(b)) = rhmap__grow((void*)(b), sizeof(*(b)), (size_t)(n)))
#define RHMAP__FIT1(b) ((b) && RHMAP_LEN(b) * 2 <= RHMAP_MAX(b) ? 0 : RHMAP__GROW(b, 0))

RHMAP__UNUSED static void* rhmap__grow(void* old_ptr, size_t elem_size, size_t reserve)
{
   struct rhmap__hdr *old_hdr = (old_ptr ? ((struct rhmap__hdr *)((char*)old_ptr-elem_size))-1 : NULL);
   struct rhmap__hdr *new_hdr;
   char *new_vals;
   size_t new_max = (old_ptr ? old_hdr->maxlen * 2 + 1 : 15);
   for (; new_max / 2 <= reserve; new_max = new_max * 2 + 1)
      if (new_max == (size_t)-1)
         return old_ptr; /* overflow */

   new_hdr = (struct rhmap__hdr *)malloc(sizeof(struct rhmap__hdr) + (new_max + 2) * elem_size);
   if (!new_hdr)
      return old_ptr; /* out of memory */

   new_hdr->maxlen = new_max;
   new_hdr->keys = (uint32_t *)calloc(new_max + 1, sizeof(uint32_t));
   if (!new_hdr->keys)
   {
      /* out of memory */
      free(new_hdr);
      return old_ptr;
   }
   new_hdr->key_strs = (char**)calloc(new_max + 1, sizeof(char*));
   if (!new_hdr->key_strs)
   {
      /* out of memory */
      free(new_hdr->keys);
      free(new_hdr);
      return old_ptr;
   }

   new_vals = ((char*)(new_hdr + 1)) + elem_size;
   if (old_ptr)
   {
      size_t i;
      char* old_vals = ((char*)(old_hdr + 1)) + elem_size;
      for (i = 0; i <= old_hdr->maxlen; i++)
      {
         uint32_t key, j;
         if (!old_hdr->keys[i])
            continue;
         for (key = old_hdr->keys[i], j = key;; j++)
         {
            if (!new_hdr->keys[j &= new_hdr->maxlen])
            {
               new_hdr->keys[j] = key;
               new_hdr->key_strs[j] = old_hdr->key_strs[i];
               memcpy(new_vals + j * elem_size, old_vals + i * elem_size, elem_size);
               break;
            }
         }
      }
      memcpy(new_vals - elem_size, old_vals - elem_size, elem_size);
      new_hdr->len = old_hdr->len;
      free(old_hdr->keys);
      free(old_hdr->key_strs);
      free(old_hdr);
   }
   else
   {
      memset(new_vals - elem_size, 0, elem_size);
      new_hdr->len = 0;
   }
   return new_vals;
}

/* This is just a custom version of strdup so we don't have an inherent
 * dependency on strdup for this file. It is functionally equivalent to
 * a system-provided strdup */
static char *rhmap_strdup(const char *s)
{
    char *out;
    int count = 0;
    while (s[count])
        ++count;
    ++count;
    out = (char*)malloc(sizeof(char) * count);
    out[--count] = 0;
    while (--count >= 0)
        out[count] = s[count];
    return out;
}

RHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key, const char * str, int add, size_t del)
{
   uint32_t i;

   if (!key)
      return (ptrdiff_t)-1;

   for (i = key;; i++)
   {
      if (hdr->keys[i &= hdr->maxlen] == key && (!hdr->key_strs[i] || !str || !strcmp(hdr->key_strs[i], str)))
      {
         if (del)
         {
            hdr->len--;
            hdr->keys[i] = 0;
            free(hdr->key_strs[i]);
            hdr->key_strs[i] = NULL;
            while ((key = hdr->keys[i = (i + 1) & hdr->maxlen]) != 0)
            {
               if ((key = (uint32_t)rhmap__idx(hdr, key, hdr->key_strs[i], 1, 0)) == i) continue;
               hdr->len--;
               hdr->keys[i] = 0;
               free(hdr->key_strs[i]);
               hdr->key_strs[i] = NULL;
               memcpy(((char*)(hdr + 1)) + (key + 1) * del,
                     ((char*)(hdr + 1)) + (i + 1) * del, del);
            }
         }
         return (ptrdiff_t)i;
      }
      if (!hdr->keys[i])
      {
         if (add)
         {
            hdr->len++;
            hdr->keys[i] = key;
            if (str)
               hdr->key_strs[i] = rhmap_strdup(str);
            return (ptrdiff_t)i;
         }
         return (ptrdiff_t)-1;
      }
   }
}

RHMAP__UNUSED static void rhmap__free(struct rhmap__hdr* hdr)
{
   size_t i;
   for (i=0;i<hdr->maxlen+1;i++)
   {
      free(hdr->key_strs[i]);
   }
   free(hdr->key_strs);
   free(hdr->keys);
   free(hdr);
}

#if defined(_MSC_VER)
#pragma warning(pop)
#endif

#endif

./include/libretro-common/include/audio/audio_mixer.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mixer.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_MIXER__H
#define __LIBRETRO_SDK_AUDIO_MIXER__H

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <boolean.h>
#include <retro_common_api.h>

#include <audio/audio_resampler.h>

RETRO_BEGIN_DECLS

enum audio_mixer_type
{
   AUDIO_MIXER_TYPE_NONE = 0,
   AUDIO_MIXER_TYPE_WAV,
   AUDIO_MIXER_TYPE_OGG,
   AUDIO_MIXER_TYPE_MOD,
   AUDIO_MIXER_TYPE_FLAC,
   AUDIO_MIXER_TYPE_MP3
};

typedef struct audio_mixer_sound audio_mixer_sound_t;
typedef struct audio_mixer_voice audio_mixer_voice_t;

typedef void (*audio_mixer_stop_cb_t)(audio_mixer_sound_t* sound, unsigned reason);

/* Reasons passed to the stop callback. */
#define AUDIO_MIXER_SOUND_FINISHED 0
#define AUDIO_MIXER_SOUND_STOPPED  1
#define AUDIO_MIXER_SOUND_REPEATED 2

void audio_mixer_init(unsigned rate);

void audio_mixer_done(void);

audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,
      const char *resampler_ident, enum resampler_quality quality);
audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size);
audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size);
audio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size);
audio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size);

void audio_mixer_destroy(audio_mixer_sound_t* sound);

audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb);

void audio_mixer_stop(audio_mixer_voice_t* voice);

float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice);

void audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val);

void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bool override);

RETRO_END_DECLS

#endif

./include/libretro-common/include/audio/audio_mix.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mix.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_MIX_H__
#define __LIBRETRO_SDK_AUDIO_MIX_H__

#include <retro_common_api.h>

#include <stdint.h>
#include <stddef.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif

#include <formats/rwav.h>
#include <audio/audio_resampler.h>

RETRO_BEGIN_DECLS

typedef struct
{
   double ratio;
   void *buf;
   int16_t *upsample_buf;
   float *float_buf;
   float *float_resample_buf;
   int16_t *resample_buf;
   const retro_resampler_t *resampler;
   void *resampler_data;
   rwav_t *rwav;
   ssize_t len;
   size_t resample_len;
   int sample_rate;
   bool resample;
} audio_chunk_t;

#if defined(__SSE2__)
#define audio_mix_volume           audio_mix_volume_SSE2

void audio_mix_volume_SSE2(float *out,
      const float *in, float vol, size_t samples);
#else
#define audio_mix_volume           audio_mix_volume_C
#endif

void audio_mix_volume_C(float *dst, const float *src, float vol, size_t samples);

void audio_mix_free_chunk(audio_chunk_t *chunk);

audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,
      const char *resampler_ident, enum resampler_quality quality);

size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk);

/**
 * audio_mix_get_chunk_sample:
 * @chunk              : audio chunk instance
 * @channel            : channel of the sample (0=left, 1=right)
 * @index              : index of the sample
 *
 * Get a sample from an audio chunk.
 *
 * Returns: A signed 16-bit audio sample, (if necessary) resampled into the desired output rate.
 **/
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t sample);

int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk);

int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk);

RETRO_END_DECLS

#endif

./include/libretro-common/include/audio/audio_resampler.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_resampler.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H
#define __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H

#include <stdint.h>
#include <stddef.h>

#include <boolean.h>
#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#define RESAMPLER_SIMD_SSE      (1 << 0)
#define RESAMPLER_SIMD_SSE2     (1 << 1)
#define RESAMPLER_SIMD_VMX      (1 << 2)
#define RESAMPLER_SIMD_VMX128   (1 << 3)
#define RESAMPLER_SIMD_AVX      (1 << 4)
#define RESAMPLER_SIMD_NEON     (1 << 5)
#define RESAMPLER_SIMD_SSE3     (1 << 6)
#define RESAMPLER_SIMD_SSSE3    (1 << 7)
#define RESAMPLER_SIMD_MMX      (1 << 8)
#define RESAMPLER_SIMD_MMXEXT   (1 << 9)
#define RESAMPLER_SIMD_SSE4     (1 << 10)
#define RESAMPLER_SIMD_SSE42    (1 << 11)
#define RESAMPLER_SIMD_AVX2     (1 << 12)
#define RESAMPLER_SIMD_VFPU     (1 << 13)
#define RESAMPLER_SIMD_PS       (1 << 14)

enum resampler_quality
{
   RESAMPLER_QUALITY_DONTCARE = 0,
   RESAMPLER_QUALITY_LOWEST,
   RESAMPLER_QUALITY_LOWER,
   RESAMPLER_QUALITY_NORMAL,
   RESAMPLER_QUALITY_HIGHER,
   RESAMPLER_QUALITY_HIGHEST
};

/* A bit-mask of all supported SIMD instruction sets.
 * Allows an implementation to pick different
 * resampler_implementation structs.
 */
typedef unsigned resampler_simd_mask_t;

#define RESAMPLER_API_VERSION 1

/**
 * A struct that groups the input and output of a resampler.
 */
struct resampler_data
{
   /**
    * The buffer containing the data to be resampled.
    */
   const float *data_in;

   /**
    * The buffer that will be used to store resampled output.
    * Must be allocated in advance, and must not be the same as data_in.
    */
   float *data_out;

   /**
    * The size of ::data_in, in frames (\em not bytes or samples).
    * For example, 32-bit stereo frames would consist of 8 bytes
    * (two 4-byte floats per frame).
    */
   size_t input_frames;

   /**
    * The number of frames (\em not bytes or samples) that the resampler produced.
    * This value is set by the resampler.
    * The resampler may not provide the same number of frames with each use,
    * so be sure to check this value.
    */
   size_t output_frames;

   /**
    * The desired ratio of output_frames to input_frames.
    * This value is used to determine the number of frames written to \c data_out.
    * If this value is (almost) equal to 1,
    * then resampling may be skipped.
    */
   double ratio;
};

/* Returns true if config key was found. Otherwise,
 * returns false, and sets value to default value.
 */
typedef int (*resampler_config_get_float_t)(void *userdata,
      const char *key, float *value, float default_value);

typedef int (*resampler_config_get_int_t)(void *userdata,
      const char *key, int *value, int default_value);

/* Allocates an array with values. free() with resampler_config_free_t. */
typedef int (*resampler_config_get_float_array_t)(void *userdata,
      const char *key, float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values);

typedef int (*resampler_config_get_int_array_t)(void *userdata,
      const char *key, int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values);

typedef int (*resampler_config_get_string_t)(void *userdata,
      const char *key, char **output, const char *default_output);

/* Calls free() in host runtime. Sometimes needed on Windows.
 * free() on NULL is fine. */
typedef void (*resampler_config_free_t)(void *ptr);

struct resampler_config
{
   resampler_config_get_float_t get_float;
   resampler_config_get_int_t get_int;

   resampler_config_get_float_array_t get_float_array;
   resampler_config_get_int_array_t get_int_array;

   resampler_config_get_string_t get_string;
   /* Avoid problems where resampler plug and host are
    * linked against different C runtimes. */
   resampler_config_free_t free;
};

/* Bandwidth factor. Will be < 1.0 for downsampling, > 1.0 for upsampling.
 * Corresponds to expected resampling ratio. */
typedef void *(*resampler_init_t)(const struct resampler_config *config,
      double bandwidth_mod, enum resampler_quality quality,
      resampler_simd_mask_t mask);

/* Frees the handle. */
typedef void (*resampler_free_t)(void *data);

/* Processes input data. */
typedef void (*resampler_process_t)(void *_data, struct resampler_data *data);

typedef struct retro_resampler
{
   resampler_init_t     init;
   resampler_process_t  process;
   resampler_free_t     free;

   /* Must be RESAMPLER_API_VERSION */
   unsigned api_version;

   /* Human readable identifier of implementation. */
   const char *ident;

   /* Computer-friendly short version of ident.
    * Lower case, no spaces and special characters, etc. */
   const char *short_ident;
} retro_resampler_t;

typedef struct audio_frame_float
{
   float l;
   float r;
} audio_frame_float_t;

extern retro_resampler_t sinc_resampler;
#ifdef HAVE_CC_RESAMPLER
extern retro_resampler_t CC_resampler;
#endif
extern retro_resampler_t nearest_resampler;

/**
 * audio_resampler_driver_find_handle:
 * @index              : index of driver to get handle to.
 *
 * Returns: handle to audio resampler driver at index. Can be NULL
 * if nothing found.
 **/
const void *audio_resampler_driver_find_handle(int index);

/**
 * audio_resampler_driver_find_ident:
 * @index              : index of driver to get handle to.
 *
 * Returns: Human-readable identifier of audio resampler driver at index.
 * Can be NULL if nothing found.
 **/
const char *audio_resampler_driver_find_ident(int index);

/**
 * retro_resampler_realloc:
 * @re                         : Resampler handle
 * @backend                    : Resampler backend that is about to be set.
 * @ident                      : Identifier name for resampler we want.
 * @bw_ratio                   : Bandwidth ratio.
 *
 * Reallocates resampler. Will free previous handle before
 * allocating a new one. If ident is NULL, first resampler will be used.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
      const char *ident, enum resampler_quality quality, double bw_ratio);

RETRO_END_DECLS

#endif

./include/libretro-common/include/audio/conversion/dual_mono.h

/* Copyright  (C) 2010-2023 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_CONVERSION_DUAL_MONO__
#define __LIBRETRO_SDK_CONVERSION_DUAL_MONO__

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/**
 * Duplicates 1-channel (mono) frames into 2-channel (stereo) frames.
 * The resulting array is suitable for use in the resampler,
 * or for any use case that demands stereo input.
 * This version operates on 32-bit floating-point samples.
 *
 * May use SIMD intrinsics on supported platforms,
 * but will work without them.
 *
 * Will do nothing if \c out or \c in are \c NULL.
 *
 * @param[out] out The location in which the converted frames will be stored.
 * Must have enough room for twice the value of \c frames.
 * @param[in] in The location of the frames to convert.
 * @param[in] frames The number of frames to convert.
 */
void convert_to_dual_mono_float(float *out, const float *in, size_t frames);

/**
 * Downmixes 2-channel (stereo) frames into 1-channel (mono) frames.
 * This is intended for dual-mono audio (i.e. where both channels are identical),
 * but it will work if both channels are different.
 *
 * This version operates on 32-bit floating-point samples.
 * It preserves the left channel and ignores the right channel.
 *
 * Will do nothing if \c out or \c in are \c NULL.
 *
 * @param[out] out The location in which the converted frames will be stored.
 * Must have enough room for half the value of <code>frames * sizeof(float)</code>.
 * @param[in] in The location of the frames to convert.
 * @param[in] frames The number of frames to convert.
 */
void convert_to_mono_float_left(float *out, const float *in, size_t frames);

RETRO_END_DECLS

#endif

./include/libretro-common/include/audio/conversion/float_to_s16.h

/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__
#define __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#include <stdint.h>
#include <stddef.h>

/**
 * Converts an array of floating-point audio samples
 * to signed integer 16-bit audio samples,
 * possibly using SIMD intrinsics.
 *
 * @param out The buffer that will be used to store the converted samples.
 * @param in The buffer containing the samples to convert.
 * Any number of channels is supported.
 * @param samples The length of \c in in samples, \em not bytes or frames.
 * \c out must be as large as <tt>sizeof(int16_t) * samples</tt>.
 * @see convert_s16_to_float
 **/
void convert_float_to_s16(int16_t *out,
      const float *in, size_t samples);

/**
 * Initializes any prerequisites for
 * using SIMD implementations of \c convert_float_to_s16.
 *
 * If SIMD intrinsics are not available or no initialization is required,
 * this function does nothing.
 *
 * @see convert_float_to_s16
 **/
void convert_float_to_s16_init_simd(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/audio/conversion/s16_to_float.h

/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__
#define __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/**
 * Converts an array of signed integer 16-bit audio samples
 * to floating-point format,
 * possibly using SIMD intrinsics.
 *
 * @param out The buffer that will be used to store the converted samples.
 * @param in The buffer containing the samples to convert.
 * Any number of channels is supported.
 * @param samples The length of \c in in samples, \em not bytes or frames.
 * \c out must be as large as <tt>sizeof(float) * samples</tt>.
 * @param gain The gain (audio volume) to apply to the samples.
 * Pass a value of 1.0 to not apply any gain.
 * @see convert_float_to_s16
 **/
void convert_s16_to_float(float *out,
      const int16_t *in, size_t samples, float gain);

/**
 * Initializes any prerequisites for
 * using SIMD implementations of \c convert_s16_to_float.
 *
 * If SIMD intrinsics are not available or no initialization is required,
 * this function does nothing.
 *
 * @see convert_s16_to_float
 **/
void convert_s16_to_float_init_simd(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/audio/dsp_filter.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dsp_filter.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_DSP_FILTER_H
#define __LIBRETRO_SDK_AUDIO_DSP_FILTER_H

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

typedef struct retro_dsp_filter retro_dsp_filter_t;

retro_dsp_filter_t *retro_dsp_filter_new(const char *filter_config,
      void *string_data, float sample_rate);

void retro_dsp_filter_free(retro_dsp_filter_t *dsp);

/**
 * A struct that groups the input and output of a DSP filter.
 */
struct retro_dsp_data
{
   float *input;
   unsigned input_frames;

   /* Set by retro_dsp_filter_process(). */
   float *output;
   unsigned output_frames;
};

void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
      struct retro_dsp_data *data);

RETRO_END_DECLS

#endif

./include/libretro-common/include/boolean.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (boolean.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_BOOLEAN_H
#define __LIBRETRO_SDK_BOOLEAN_H

#ifndef __cplusplus

#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include <stdbool.h>
#endif

#endif

#endif

./include/libretro-common/include/cdrom/cdrom.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (cdrom.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_CDROM_H
#define __LIBRETRO_SDK_CDROM_H

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>

#include <vfs/vfs.h>
#include <libretro.h>
#include <retro_common_api.h>
#include <retro_inline.h>

#include <boolean.h>

struct string_list;

RETRO_BEGIN_DECLS

typedef struct
{
   unsigned short g1_timeout;
   unsigned short g2_timeout;
   unsigned short g3_timeout;
} cdrom_group_timeouts_t;

typedef struct
{
   unsigned lba_start; /* start of pregap */
   unsigned lba; /* start of data */
   unsigned track_size; /* in LBAs */
   unsigned track_bytes;
   unsigned char track_num;
   unsigned char min; /* start of data */
   unsigned char sec;
   unsigned char frame;
   unsigned char mode;
   bool audio;
} cdrom_track_t;

typedef struct
{
   cdrom_track_t track[99];         /* unsigned alignment */
   cdrom_group_timeouts_t timeouts; /* unsigned short alignment */
   unsigned char num_tracks;
   char drive;
} cdrom_toc_t;

void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);

unsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame);

void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame);

int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *s, size_t len);

int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc);

/* needs 32 bytes for full vendor, product and version */
int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *s, size_t len, bool *is_cdrom);

int cdrom_read(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip);

int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed);

int cdrom_stop(libretro_vfs_implementation_file *stream);

int cdrom_unlock(libretro_vfs_implementation_file *stream);

int cdrom_open_tray(libretro_vfs_implementation_file *stream);

int cdrom_close_tray(libretro_vfs_implementation_file *stream);

/* must be freed by the caller */
struct string_list* cdrom_get_available_drives(void);

bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream);

bool cdrom_drive_has_media(const char drive);

void cdrom_get_current_config_core(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream);

int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len);

bool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled);

bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts);

bool cdrom_has_atip(libretro_vfs_implementation_file *stream);

size_t cdrom_device_fillpath(char *s, size_t len, char drive, unsigned char track, bool is_cue);

RETRO_END_DECLS

#endif

./include/libretro-common/include/clamping.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (clamping.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_CLAMPING_H
#define _LIBRETRO_SDK_CLAMPING_H

#include <stdint.h>
#include <retro_inline.h>

/**
 * Clamps a floating-point value to the specified range.
 *
 * @param val The value to clamp.
 * @param lower The minimum possible value.
 * @param upper The maximum possible value.
 *
 * @returns \c val clamped to between \c lower and \c upper (inclusive).
 */
static INLINE float clamp_float(float val, float lower, float upper)
{
   if (val < lower)
      return lower;
   if (val > upper)
      return upper;
   return val;
}

/**
 * Clamps an integer to fit in 8 bits.
 *
 * @param val The value to clamp.
 * @return \c val clamped to between 0 and 255 (inclusive).
 */
static INLINE uint8_t clamp_8bit(int val)
{
   if (val > 255)
      return 255;
   if (val < 0)
      return 0;
   return (uint8_t)val;
}

#endif

./include/libretro-common/include/compat/apple_compat.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (apple_compat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __APPLE_COMPAT_H
#define __APPLE_COMPAT_H

#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif

#ifdef __OBJC__

#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4)
typedef int NSInteger;
typedef unsigned NSUInteger;
typedef float CGFloat;
#endif

#ifndef __has_feature
/* Compatibility with non-Clang compilers. */
#define __has_feature(x) 0
#endif

#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif

#ifndef NS_INLINE
#define NS_INLINE inline
#endif

NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X)
{
#if __has_feature(objc_arc)
   return (__bridge_retained CFTypeRef)X;
#else
   return X;
#endif
}

#endif

#ifdef IOS
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <Foundation/Foundation.h>
#endif

#else

#ifdef __OBJC__
#include <objc/objc-runtime.h>
#endif
#endif

#endif

./include/libretro-common/include/compat/fnmatch.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fnmatch.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_FNMATCH_H__
#define __LIBRETRO_SDK_COMPAT_FNMATCH_H__

#define	FNM_NOMATCH	1

/**
 * Portable implementation of \c fnmatch(3),
 * except \c flags is not implemented.
 * @see https://man7.org/linux/man-pages/man3/fnmatch.3.html
 */
int rl_fnmatch(const char *pattern, const char *string, int flags);

#endif

./include/libretro-common/include/compat/fopen_utf8.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fopen_utf8.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H

#ifdef _WIN32
/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */
/* TODO: enable */
/* #define fopen (use fopen_utf8 instead) */
void *fopen_utf8(const char * filename, const char * mode);
#else
#define fopen_utf8 fopen
#endif
#endif

./include/libretro-common/include/compat/getopt.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (getopt.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_GETOPT_H
#define __LIBRETRO_SDK_COMPAT_GETOPT_H

#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif

/**
 * @file getopt.h
 *
 * Portable reimplementation of a subset of libc's \c getopt_long.
 * Not designed to be fully compatible,
 * but it's enough for RetroArch's purposes.
 *
 * If \c getopt_long is available (as determined by \c HAVE_GETOPT_LONG), it will be used instead.
 *
 * @see https://man7.org/linux/man-pages/man3/getopt.3.html
 */

#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
/* Avoid possible naming collisions during link since we
 * prefer to use the actual name. */
#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex)

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

struct option
{
   const char *name;
   int has_arg;
   int *flag;
   int val;
};

/* argv[] is declared with char * const argv[] in GNU,
 * but this makes no sense, as non-POSIX getopt_long
 * mutates argv (non-opts are moved to the end). */
int getopt_long(int argc, char *argv[],
      const char *optstring, const struct option *longopts, int *longindex);
extern char *optarg;
extern int optind, opterr, optopt;

RETRO_END_DECLS

/* If these are variously #defined, then we have bigger problems */
#ifndef no_argument
   #define no_argument 0
   #define required_argument 1
   #define optional_argument 2
#endif

/* HAVE_GETOPT_LONG */
#endif

/* pragma once */
#endif

./include/libretro-common/include/compat/ifaddrs.h

/*
 * Copyright (c) 1995, 1999
 *	Berkeley Software Design, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
 */

#ifndef	_IFADDRS_H_
#define	_IFADDRS_H_

struct ifaddrs
{
   struct ifaddrs  *ifa_next;
   char		*ifa_name;
   unsigned int	 ifa_flags;
   struct sockaddr	*ifa_addr;
   struct sockaddr	*ifa_netmask;
   struct sockaddr	*ifa_dstaddr;
   void		*ifa_data;
};

/*
 * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
 * to be included it must be included before this header file.
 */
#ifndef	ifa_broadaddr
#define	ifa_broadaddr	ifa_dstaddr	/* broadcast address interface */
#endif

#include <sys/cdefs.h>

/**
 * Portable reimplementation of \c getifaddrs().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/getifaddrs.3.html
 */
extern int getifaddrs(struct ifaddrs **ifap);

/**
 * Portable reimplementation of \c freeifaddrs().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/getifaddrs.3.html
 */
extern void freeifaddrs(struct ifaddrs *ifa);

#endif

./include/libretro-common/include/compat/intrinsics.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (intrinsics.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_INTRINSICS_H
#define __LIBRETRO_SDK_COMPAT_INTRINSICS_H

#include <stdint.h>
#include <stddef.h>
#include <string.h>

#include <retro_common_api.h>
#include <retro_inline.h>

#if defined(_MSC_VER) && !defined(_XBOX)
#if (_MSC_VER > 1310)
#include <intrin.h>
#endif
#endif

RETRO_BEGIN_DECLS

/**
 * Counts the leading zero bits in a \c uint16_t.
 * Uses compiler intrinsics if available, or a standard C implementation if not.
 *
 * @param val Value to count leading zeroes in.
 * @return Number of leading zeroes in \c val.
 */
static INLINE unsigned compat_clz_u16(uint16_t val)
{
#if defined(__GNUC__)
   return __builtin_clz(val << 16 | 0x8000);
#else
   unsigned ret = 0;

   while(!(val & 0x8000) && ret < 16)
   {
      val <<= 1;
      ret++;
   }

   return ret;
#endif
}

/**
 * Counts the trailing zero bits in a \c uint16_t.
 * Uses compiler intrinsics if available, or a standard C implementation if not.
 *
 * @param val Value to count trailing zeroes in.
 * @return Number of trailing zeroes in \c val.
 */
static INLINE int compat_ctz(unsigned x)
{
#if defined(__GNUC__) && !defined(RARCH_CONSOLE)
   return __builtin_ctz(x);
#elif _MSC_VER >= 1400 && !defined(_XBOX) && !defined(__WINRT__)
   unsigned long r = 0;
   _BitScanForward((unsigned long*)&r, x);
   return (int)r;
#else
   int count = 0;
   if (!(x & 0xffff))
   {
      x >>= 16;
      count |= 16;
   }
   if (!(x & 0xff))
   {
      x >>= 8;
      count |= 8;
   }
   if (!(x & 0xf))
   {
      x >>= 4;
      count |= 4;
   }
   if (!(x & 0x3))
   {
      x >>= 2;
      count |= 2;
   }
   if (!(x & 0x1))
      count |= 1;

   return count;
#endif
}

RETRO_END_DECLS

#endif

./include/libretro-common/include/compat/msvc.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (msvc.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_MSVC_H
#define __LIBRETRO_SDK_COMPAT_MSVC_H

#ifdef _MSC_VER

#ifdef __cplusplus
extern "C"  {
#endif

/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
#if _MSC_VER < 1900
   #include <stdio.h>
   #include <stdarg.h>
   #include <stdlib.h>

   #ifndef snprintf
      #define snprintf c99_snprintf_retro__
   #endif
   int c99_snprintf_retro__(char *s, size_t len, const char *format, ...);

   #ifndef vsnprintf
      #define vsnprintf c99_vsnprintf_retro__
   #endif
   int c99_vsnprintf_retro__(char *s, size_t len, const char *format, va_list ap);
#endif

#ifdef __cplusplus
}
#endif

#undef UNICODE /* Do not bother with UNICODE at this time. */
#include <direct.h>
#include <stddef.h>

#define _USE_MATH_DEFINES
#include <math.h>

/* Python headers defines ssize_t and sets HAVE_SSIZE_T.
 * Cannot duplicate these efforts.
 */
#ifndef HAVE_SSIZE_T
#if defined(_WIN64)
typedef __int64 ssize_t;
#elif defined(_WIN32)
typedef int ssize_t;
#endif
#endif

#define mkdir(dirname, unused) _mkdir(dirname)
#define strtoull _strtoui64
#undef strcasecmp
#define strcasecmp _stricmp
#undef strncasecmp
#define strncasecmp _strnicmp

/* Disable some of the annoying warnings. */
#pragma warning(disable : 4800)
#pragma warning(disable : 4805)
#pragma warning(disable : 4244)
#pragma warning(disable : 4305)
#pragma warning(disable : 4146)
#pragma warning(disable : 4267)
#pragma warning(disable : 4723)
#pragma warning(disable : 4996)

/* roundf and va_copy is available since MSVC 2013 */
#if _MSC_VER < 1800
#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
#define va_copy(x, y) ((x) = (y))
#endif

#if _MSC_VER <= 1310
   #ifndef __cplusplus
      /* VC6 math.h doesn't define some functions when in C mode.
       * Trying to define a prototype gives "undefined reference".
       * But providing an implementation then gives "function already has body".
       * So the equivalent of the implementations from math.h are used as
       * defines here instead, and it seems to work.
       */
      #define cosf(x) ((float)cos((double)x))
      #define powf(x, y) ((float)pow((double)x, (double)y))
      #define sinf(x) ((float)sin((double)x))
      #define ceilf(x) ((float)ceil((double)x))
      #define floorf(x) ((float)floor((double)x))
      #define sqrtf(x) ((float)sqrt((double)x))
      #define fabsf(x)    ((float)fabs((double)(x)))
   #endif

   #ifndef _strtoui64
      #define _strtoui64(x, y, z) (_atoi64(x))
   #endif

#endif

#ifndef PATH_MAX
#define PATH_MAX _MAX_PATH
#endif

#ifndef SIZE_MAX
#define SIZE_MAX _UI32_MAX
#endif

#endif
#endif

./include/libretro-common/include/compat/msvc/stdint.h

/* ISO C9x  compliant stdint.h for Microsoft Visual Studio
 * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
 *
 * Copyright (c) 2006-2008 Alexander Chemeris
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __RARCH_STDINT_H
#define __RARCH_STDINT_H

#if _MSC_VER && (_MSC_VER < 1600)
/* Pre-MSVC 2010 needs an implementation of stdint.h. */

#if _MSC_VER > 1000
#pragma once
#endif

#include <limits.h>

/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when
 * compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
 * or compiler give many errors like this:
 *
 * error C2733: second C linkage of overloaded function 'wmemchr' not allowed
 */
#ifdef __cplusplus
#if _MSC_VER <= 1200
extern "C++" {
#else
extern "C" {
#endif
#endif
#  include <wchar.h>
#ifdef __cplusplus
}
#endif

/* Define _W64 macros to mark types changing their size, like intptr_t. */
#ifndef _W64
#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
#     define _W64 __w64
#  else
#     define _W64
#  endif
#endif

/* 7.18.1 Integer types. */

/* 7.18.1.1 Exact-width integer types. */

/* Visual Studio 6 and Embedded Visual C++ 4 doesn't
 * realize that, e.g. char has the same size as __int8
 * so we give up on __intX for them.
 */
#if (_MSC_VER < 1300)
   typedef signed char       int8_t;
   typedef signed short      int16_t;
   typedef signed int        int32_t;
   typedef unsigned char     uint8_t;
   typedef unsigned short    uint16_t;
   typedef unsigned int      uint32_t;
#else
   typedef signed __int8     int8_t;
   typedef signed __int16    int16_t;
   typedef signed __int32    int32_t;
   typedef unsigned __int8   uint8_t;
   typedef unsigned __int16  uint16_t;
   typedef unsigned __int32  uint32_t;
#endif
typedef signed __int64       int64_t;
typedef unsigned __int64     uint64_t;

/* 7.18.1.2 Minimum-width integer types. */
typedef int8_t    int_least8_t;
typedef int16_t   int_least16_t;
typedef int32_t   int_least32_t;
typedef int64_t   int_least64_t;
typedef uint8_t   uint_least8_t;
typedef uint16_t  uint_least16_t;
typedef uint32_t  uint_least32_t;
typedef uint64_t  uint_least64_t;

/* 7.18.1.3 Fastest minimum-width integer types. */
typedef int8_t    int_fast8_t;
typedef int16_t   int_fast16_t;
typedef int32_t   int_fast32_t;
typedef int64_t   int_fast64_t;
typedef uint8_t   uint_fast8_t;
typedef uint16_t  uint_fast16_t;
typedef uint32_t  uint_fast32_t;
typedef uint64_t  uint_fast64_t;

/* 7.18.1.4 Integer types capable of holding object pointers. */
#ifdef _WIN64 /* [ */
   typedef signed __int64    intptr_t;
   typedef unsigned __int64  uintptr_t;
#else /* _WIN64 ][ */
   typedef _W64 signed int   intptr_t;
   typedef _W64 unsigned int uintptr_t;
#endif /* _WIN64 ] */

/* 7.18.1.5 Greatest-width integer types. */
typedef int64_t   intmax_t;
typedef uint64_t  uintmax_t;

/* 7.18.2 Limits of specified-width integer types. */

#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
/* [   See footnote 220 at page 257 and footnote 221 at page 259. */

/* 7.18.2.1 Limits of exact-width integer types. */
#define INT8_MIN     ((int8_t)_I8_MIN)
#define INT8_MAX     _I8_MAX
#define INT16_MIN    ((int16_t)_I16_MIN)
#define INT16_MAX    _I16_MAX
#define INT32_MIN    ((int32_t)_I32_MIN)
#define INT32_MAX    _I32_MAX
#define INT64_MIN    ((int64_t)_I64_MIN)
#define INT64_MAX    _I64_MAX
#define UINT8_MAX    _UI8_MAX
#define UINT16_MAX   _UI16_MAX
#define UINT32_MAX   _UI32_MAX
#define UINT64_MAX   _UI64_MAX

/* 7.18.2.2 Limits of minimum-width integer types. */
#define INT_LEAST8_MIN    INT8_MIN
#define INT_LEAST8_MAX    INT8_MAX
#define INT_LEAST16_MIN   INT16_MIN
#define INT_LEAST16_MAX   INT16_MAX
#define INT_LEAST32_MIN   INT32_MIN
#define INT_LEAST32_MAX   INT32_MAX
#define INT_LEAST64_MIN   INT64_MIN
#define INT_LEAST64_MAX   INT64_MAX
#define UINT_LEAST8_MAX   UINT8_MAX
#define UINT_LEAST16_MAX  UINT16_MAX
#define UINT_LEAST32_MAX  UINT32_MAX
#define UINT_LEAST64_MAX  UINT64_MAX

/* 7.18.2.3 Limits of fastest minimum-width integer types. */
#define INT_FAST8_MIN    INT8_MIN
#define INT_FAST8_MAX    INT8_MAX
#define INT_FAST16_MIN   INT16_MIN
#define INT_FAST16_MAX   INT16_MAX
#define INT_FAST32_MIN   INT32_MIN
#define INT_FAST32_MAX   INT32_MAX
#define INT_FAST64_MIN   INT64_MIN
#define INT_FAST64_MAX   INT64_MAX
#define UINT_FAST8_MAX   UINT8_MAX
#define UINT_FAST16_MAX  UINT16_MAX
#define UINT_FAST32_MAX  UINT32_MAX
#define UINT_FAST64_MAX  UINT64_MAX

/* 7.18.2.4 Limits of integer types capable of holding object pointers. */
#ifdef _WIN64 /* [ */
#  define INTPTR_MIN   INT64_MIN
#  define INTPTR_MAX   INT64_MAX
#  define UINTPTR_MAX  UINT64_MAX
#else /* _WIN64 ][ */
#  define INTPTR_MIN   INT32_MIN
#  define INTPTR_MAX   INT32_MAX
#  define UINTPTR_MAX  UINT32_MAX
#endif /* _WIN64 ] */

/* 7.18.2.5 Limits of greatest-width integer types */
#define INTMAX_MIN   INT64_MIN
#define INTMAX_MAX   INT64_MAX
#define UINTMAX_MAX  UINT64_MAX

/* 7.18.3 Limits of other integer types */

#ifdef _WIN64 /* [ */
#  define PTRDIFF_MIN  _I64_MIN
#  define PTRDIFF_MAX  _I64_MAX
#else  /* _WIN64 ][ */
#  define PTRDIFF_MIN  _I32_MIN
#  define PTRDIFF_MAX  _I32_MAX
#endif  /* _WIN64 ] */

#define SIG_ATOMIC_MIN  INT_MIN
#define SIG_ATOMIC_MAX  INT_MAX

#ifndef SIZE_MAX /* [ */
#  ifdef _WIN64 /* [ */
#     define SIZE_MAX  _UI64_MAX
#  else /* _WIN64 ][ */
#     define SIZE_MAX  _UI32_MAX
#  endif /* _WIN64 ] */
#endif /* SIZE_MAX ] */

/* WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> */
#ifndef WCHAR_MIN /* [ */
#  define WCHAR_MIN  0
#endif  /* WCHAR_MIN ] */
#ifndef WCHAR_MAX // [
#  define WCHAR_MAX  _UI16_MAX
#endif  /* WCHAR_MAX ] */

#define WINT_MIN  0
#define WINT_MAX  _UI16_MAX

#endif /* __STDC_LIMIT_MACROS ] */

/* 7.18.4 Limits of other integer types */

#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
/* [   See footnote 224 at page 260 */

/* 7.18.4.1 Macros for minimum-width integer constants */

#define INT8_C(val)  val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64

#define UINT8_C(val)  val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64

/* 7.18.4.2 Macros for greatest-width integer constants */
#define INTMAX_C   INT64_C
#define UINTMAX_C  UINT64_C

#endif
/* __STDC_CONSTANT_MACROS ] */

#else
/* Sanity for everything else. */
#include <stdint.h>
#endif

#endif

./include/libretro-common/include/compat/posix_string.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (posix_string.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H

#include <retro_common_api.h>

/**
 * @file posix_string.h
 *
 * Portable reimplementations of various string functions
 * that are normally provided by libc or POSIX.
 */

#ifdef _MSC_VER
#include <compat/msvc.h>
#endif

RETRO_BEGIN_DECLS

#if defined(_WIN32) || defined(DOXYGEN)
#undef strtok_r
#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)

/**
 * Portable reimplementation of \c strtok_r().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/strtok.3.html
 */
char *strtok_r(char *str, const char *delim, char **saveptr);
#endif

#if defined(_MSC_VER) || defined(DOXYGEN)
#undef strcasecmp
#undef strdup

#define strcasecmp(a, b) retro_strcasecmp__(a, b)
#define strdup(orig)     retro_strdup__(orig)
/**
 * Portable reimplementation of \c strcasecmp().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/strcasecmp.3.html
 */
int strcasecmp(const char *a, const char *b);

/**
 * Portable reimplementation of \c strdup().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/strdup.3.html
 */
char *strdup(const char *orig);

/* isblank is available since MSVC 2013 */
#if _MSC_VER < 1800
#undef isblank
#define isblank(c)       retro_isblank__(c)
/**
 * Portable reimplementation of \c isblank().
 * The original function will be used if it's available.
 *
 * @see https://en.cppreference.com/w/c/string/byte/isblank
 */
int isblank(int c);
#endif

#endif

RETRO_END_DECLS

#endif

./include/libretro-common/include/compat/strcasestr.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (strcasestr.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H
#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H

#include <string.h>

#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif

#ifndef HAVE_STRCASESTR

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/* Avoid possible naming collisions during link
 * since we prefer to use the actual name. */
#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)

/**
 * Portable reimplementation of \c strcasestr(3).
 * If the original function is available
 * (as determined by the presence of \c HAVE_STRCASESTR),
 * it will be used instead.
 *
 * @see https://man7.org/linux/man-pages/man3/strstr.3.html
 */
char *strcasestr(const char *haystack, const char *needle);

RETRO_END_DECLS

#endif

#endif

./include/libretro-common/include/compat/strl.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (strl.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
#define __LIBRETRO_SDK_COMPAT_STRL_H

/**
 * @file strl.h
 *
 * Portable implementation of \c strlcpy(3) and \c strlcat(3).
 * If these functions are available on the target platform,
 * then the originals should be imported instead.
 *
 * @see https://linux.die.net/man/3/strlcpy
 */
#include <string.h>
#include <stddef.h>

#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#ifdef __MACH__
#ifndef HAVE_STRL
#define HAVE_STRL
#endif
#endif

#ifndef HAVE_STRL
/* Avoid possible naming collisions during link since
 * we prefer to use the actual name. */
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)

#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)

/**
 * @brief Portable implementation of \c strlcpy(3).
 * @see https://linux.die.net/man/3/strlcpy
 */
size_t strlcpy(char *s, const char *source, size_t len);

/**
 * @brief Portable implementation of \c strlcat(3).
 * @see https://linux.die.net/man/3/strlcpy
 */
size_t strlcat(char *s, const char *source, size_t len);

#endif

/**
 * A version of \c strndup(3) that guarantees the result will be null-terminated.
 *
 * @param s The string to duplicate.
 * @param n The maximum number of characters to copy from \c s.
 * The result will allocate one more byte than this value.
 * @return Pointer to the cloned string.
 * Must be freed with \c free().
 */
char *strldup(const char *s, size_t n);

RETRO_END_DECLS

#endif

./include/libretro-common/include/compat/zconf.h

/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) && !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ >= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) && !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 << (windowBits+2)) +  (1 << (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 << windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include <windows.h>
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
#  include <limits.h>
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include <sys/types.h>      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include <stdarg.h>         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include <stddef.h>         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include <unixio.h>       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) && !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) && defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */

./include/libretro-common/include/compat/zconf.h.in

/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) && !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ >= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) && !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 << (windowBits+2)) +  (1 << (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 << windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include <windows.h>
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
#  include <limits.h>
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include <sys/types.h>      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include <stdarg.h>         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include <stddef.h>         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include <unixio.h>       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) && !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) && defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */

./include/libretro-common/include/compat/zlib.h

#ifndef _COMPAT_ZLIB_H
#define _COMPAT_ZLIB_H

#ifdef WANT_ZLIB

#ifdef RARCH_INTERNAL
#include "zconf.h.in"
#endif

/* zlib.h -- interface of the 'zlib' general purpose compression library
  version 1.2.8, April 28th, 2013

  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly        Mark Adler
  jloup@gzip.org          madler@alumni.caltech.edu

  The data format used by the zlib library is described by RFCs (Request for
  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
*/

#ifndef ZLIB_H
#define ZLIB_H

#include <stdint.h>
#include "zconf.h"

#ifdef __cplusplus
extern "C" {
#endif

#define ZLIB_VERSION "1.2.8"
#define ZLIB_VERNUM 0x1280
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
#define ZLIB_VER_REVISION 8
#define ZLIB_VER_SUBREVISION 0

/*
    The 'zlib' compression library provides in-memory compression and
  decompression functions, including integrity checks of the uncompressed data.
  This version of the library supports only one compression method (deflation)
  but other algorithms will be added later and will have the same stream
  interface.

    Compression can be done in a single step if the buffers are large enough,
  or can be done by repeated calls of the compression function.  In the latter
  case, the application must provide more input and/or consume the output
  (providing more output space) before each call.

    The compressed data format used by default by the in-memory functions is
  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
  around a deflate stream, which is itself documented in RFC 1951.

    The library also supports reading and writing files in gzip (.gz) format
  with an interface similar to that of stdio using the functions that start
  with "gz".  The gzip format is different from the zlib format.  gzip is a
  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.

    This library can optionally read and write gzip streams in memory as well.

    The zlib format was designed to be compact and fast for use in memory
  and on communications channels.  The gzip format was designed for single-
  file compression on file systems, has a larger header than zlib to maintain
  directory information, and uses a different, slower check method than zlib.

    The library does not install any signal handler.  The decoder checks
  the consistency of the compressed data, so the library should never crash
  even in case of corrupted input.
*/

typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);
typedef void   (*free_func)  (voidpf opaque, voidpf address);

struct internal_state;

typedef struct z_stream_s {
    z_const Bytef *next_in;     /* next input byte */
    uInt     avail_in;  /* number of bytes available at next_in */
    uLong    total_in;  /* total number of input bytes read so far */

    Bytef    *next_out; /* next output byte should be put there */
    uInt     avail_out; /* remaining free space at next_out */
    uLong    total_out; /* total number of bytes output so far */

    z_const char *msg;  /* last error message, NULL if no error */
    void *state; /* not visible by applications */

    alloc_func zalloc;  /* used to allocate the internal state */
    free_func  zfree;   /* used to free the internal state */
    voidpf     opaque;  /* private data object passed to zalloc and zfree */

    int     data_type;  /* best guess about the data type: binary or text */
    uLong   adler;      /* adler32 value of the uncompressed data */
    uLong   reserved;   /* reserved for future use */
} z_stream;

typedef z_stream FAR *z_streamp;

/*
     gzip header information passed to and from zlib routines.  See RFC 1952
  for more details on the meanings of these fields.
*/
typedef struct gz_header_s {
    int     text;       /* true if compressed data believed to be text */
    uLong   time;       /* modification time */
    int     xflags;     /* extra flags (not used when writing a gzip file) */
    int     os;         /* operating system */
    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
    uInt    extra_max;  /* space at extra (only when reading header) */
    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
    uInt    name_max;   /* space at name (only when reading header) */
    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
    uInt    comm_max;   /* space at comment (only when reading header) */
    int     hcrc;       /* true if there was or will be a header crc */
    int     done;       /* true when done reading gzip header (not used
                           when writing a gzip file) */
} gz_header;

typedef gz_header FAR *gz_headerp;

/*
     The application must update next_in and avail_in when avail_in has dropped
   to zero.  It must update next_out and avail_out when avail_out has dropped
   to zero.  The application must initialize zalloc, zfree and opaque before
   calling the init function.  All other fields are set by the compression
   library and must not be updated by the application.

     The opaque value provided by the application will be passed as the first
   parameter for calls of zalloc and zfree.  This can be useful for custom
   memory management.  The compression library attaches no meaning to the
   opaque value.

     zalloc must return Z_NULL if there is not enough memory for the object.
   If zlib is used in a multi-threaded application, zalloc and zfree must be
   thread safe.

     On 16-bit systems, the functions zalloc and zfree must be able to allocate
   exactly 65536 bytes, but will not be required to allocate more than this if
   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
   returned by zalloc for objects of exactly 65536 bytes *must* have their
   offset normalized to zero.  The default allocation function provided by this
   library ensures this (see zutil.c).  To reduce memory requirements and avoid
   any allocation of 64K objects, at the expense of compression ratio, compile
   the library with -DMAX_WBITS=14 (see zconf.h).

     The fields total_in and total_out can be used for statistics or progress
   reports.  After compression, total_in holds the total size of the
   uncompressed data and may be saved for use in the decompressor (particularly
   if the decompressor wants to decompress everything in a single step).
*/

                        /* constants */

#define Z_NO_FLUSH      0
#define Z_PARTIAL_FLUSH 1
#define Z_SYNC_FLUSH    2
#define Z_FULL_FLUSH    3
#define Z_FINISH        4
#define Z_BLOCK         5
#define Z_TREES         6
/* Allowed flush values; see deflate() and inflate() below for details */

#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative values
 * are errors, positive values are used for special but normal events.
 */

#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
/* compression levels */

#define Z_FILTERED            1
#define Z_HUFFMAN_ONLY        2
#define Z_RLE                 3
#define Z_FIXED               4
#define Z_DEFAULT_STRATEGY    0
/* compression strategy; see deflateInit2() below for details */

#define Z_BINARY   0
#define Z_TEXT     1
#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
#define Z_UNKNOWN  2
/* Possible values of the data_type field (though see inflate()) */

#define Z_DEFLATED   8
/* The deflate compression method (the only one supported in this version) */

#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */

#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */

                        /* basic functions */

 const char * zlibVersion (void);
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
   If the first character differs, the library code actually used is not
   compatible with the zlib.h header file used by the application.  This check
   is automatically made by deflateInit and inflateInit.
 */

/*
 int deflateInit (z_streamp strm, int level);

     Initializes the internal stream state for compression.  The fields
   zalloc, zfree and opaque must be initialized before by the caller.  If
   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
   allocation functions.

     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
   1 gives best speed, 9 gives best compression, 0 gives no compression at all
   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
   requests a default compromise between speed and compression (currently
   equivalent to level 6).

     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if level is not a valid compression level, or
   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
   if there is no error message.  deflateInit does not perform any compression:
   this will be done by deflate().
*/

 int deflate (z_streamp strm, int flush);
/*
    deflate compresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

    The detailed semantics are as follows.  deflate performs one or both of the
  following actions:

  - Compress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in and avail_in are updated and
    processing will resume at this point for the next call of deflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  This action is forced if the parameter flush is non zero.
    Forcing flush frequently degrades the compression ratio, so this parameter
    should be set only when necessary (in interactive applications).  Some
    output may be provided even if flush is not set.

    Before the call of deflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating avail_in or avail_out accordingly; avail_out should
  never be zero before the call.  The application can consume the compressed
  output when it wants, for example when the output buffer is full (avail_out
  == 0), or after each call of deflate().  If deflate returns Z_OK and with
  zero avail_out, it must be called again after making room in the output
  buffer because there might be more output pending.

    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
  decide how much data to accumulate before producing output, in order to
  maximize compression.

    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
  flushed to the output buffer and the output is aligned on a byte boundary, so
  that the decompressor can get all input data available so far.  (In
  particular avail_in is zero after the call if enough output space has been
  provided before the call.) Flushing may degrade compression for some
  compression algorithms and so it should be used only when necessary.  This
  completes the current deflate block and follows it with an empty stored block
  that is three bits plus filler bits to the next byte, followed by four bytes
  (00 00 ff ff).

    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
  output buffer, but the output is not aligned to a byte boundary.  All of the
  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
  This completes the current deflate block and follows it with an empty fixed
  codes block that is 10 bits long.  This assures that enough bytes are output
  in order for the decompressor to finish the block before the empty fixed code
  block.

    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
  seven bits of the current block are held to be written as the next byte after
  the next deflate block is completed.  In this case, the decompressor may not
  be provided enough bits at this point in order to complete decompression of
  the data provided so far to the compressor.  It may need to wait for the next
  block to be emitted.  This is for advanced applications that need to control
  the emission of deflate blocks.

    If flush is set to Z_FULL_FLUSH, all output is flushed as with
  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
  restart from this point if previous compressed data has been damaged or if
  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
  compression.

    If deflate returns with avail_out == 0, this function must be called again
  with the same value of the flush parameter and more output space (updated
  avail_out), until the flush is complete (deflate returns with non-zero
  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
  avail_out is greater than six to avoid repeated flush markers due to
  avail_out == 0 on return.

    If the parameter flush is set to Z_FINISH, pending input is processed,
  pending output is flushed and deflate returns with Z_STREAM_END if there was
  enough output space; if deflate returns with Z_OK, this function must be
  called again with Z_FINISH and more output space (updated avail_out) but no
  more input data, until it returns with Z_STREAM_END or an error.  After
  deflate has returned Z_STREAM_END, the only possible operations on the stream
  are deflateReset or deflateEnd.

    Z_FINISH can be used immediately after deflateInit if all the compression
  is to be done in a single step.  In this case, avail_out must be at least the
  value returned by deflateBound (see below).  Then deflate is guaranteed to
  return Z_STREAM_END.  If not enough output space is provided, deflate will
  not return Z_STREAM_END, and it must be called again as described above.

    deflate() sets strm->adler to the adler32 checksum of all input read
  so far (that is, total_in bytes).

    deflate() may update strm->data_type if it can make a good guess about
  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
  binary.  This field is only for information purposes and does not affect the
  compression algorithm in any manner.

    deflate() returns Z_OK if some progress has been made (more input
  processed or more output produced), Z_STREAM_END if all input has been
  consumed and all output has been produced (only when flush is set to
  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
  fatal, and deflate() can be called again with more input and more output
  space to continue compressing.
*/

 int deflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
   prematurely (some input or output was discarded).  In the error case, msg
   may be set but then points to a static string (which must not be
   deallocated).
*/

/*
 int inflateInit (z_streamp strm);

     Initializes the internal stream state for decompression.  The fields
   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
   exact value depends on the compression method), inflateInit determines the
   compression method from the zlib header and allocates all data structures
   accordingly; otherwise the allocation will be deferred to the first call of
   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
   use default allocation functions.

     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit() does not process any header information -- that is deferred
   until inflate() is called.
*/

 int inflate (z_streamp strm, int flush);
/*
    inflate decompresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

  The detailed semantics are as follows.  inflate performs one or both of the
  following actions:

  - Decompress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in is updated and processing will
    resume at this point for the next call of inflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  inflate() provides as much output as possible, until there is
    no more input data or no more space in the output buffer (see below about
    the flush parameter).

    Before the call of inflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating the next_* and avail_* values accordingly.  The
  application can consume the uncompressed output when it wants, for example
  when the output buffer is full (avail_out == 0), or after each call of
  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
  called again after making room in the output buffer because there might be
  more output pending.

    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
  output as possible to the output buffer.  Z_BLOCK requests that inflate()
  stop if and when it gets to the next deflate block boundary.  When decoding
  the zlib or gzip format, this will cause inflate() to return immediately
  after the header and before the first block.  When doing a raw inflate,
  inflate() will go ahead and process the first block, and will return when it
  gets to the end of that block, or when it runs out of data.

    The Z_BLOCK option assists in appending to or combining deflate streams.
  Also to assist in this, on return inflate() will set strm->data_type to the
  number of unused bits in the last byte taken from strm->next_in, plus 64 if
  inflate() is currently decoding the last block in the deflate stream, plus
  128 if inflate() returned immediately after decoding an end-of-block code or
  decoding the complete header up to just before the first byte of the deflate
  stream.  The end-of-block will not be indicated until all of the uncompressed
  data from that block has been written to strm->next_out.  The number of
  unused bits may in general be greater than seven, except when bit 7 of
  data_type is set, in which case the number of unused bits will be less than
  eight.  data_type is set as noted here every time inflate() returns for all
  flush options, and so can be used to determine the amount of currently
  consumed input in bits.

    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
  end of each deflate block header is reached, before any actual data in that
  block is decoded.  This allows the caller to determine the length of the
  deflate block header for later use in random access within a deflate block.
  256 is added to the value of strm->data_type when inflate() returns
  immediately after reaching the end of the deflate block header.

    inflate() should normally be called until it returns Z_STREAM_END or an
  error.  However if all decompression is to be performed in a single step (a
  single call of inflate), the parameter flush should be set to Z_FINISH.  In
  this case all pending input is processed and all pending output is flushed;
  avail_out must be large enough to hold all of the uncompressed data for the
  operation to complete.  (The size of the uncompressed data may have been
  saved by the compressor for this purpose.) The use of Z_FINISH is not
  required to perform an inflation in one step.  However it may be used to
  inform inflate that a faster approach can be used for the single inflate()
  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
  stream completes, which reduces inflate's memory footprint.  If the stream
  does not complete, either because not all of the stream is provided or not
  enough output space is provided, then a sliding window will be allocated and
  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
  been used.

     In this implementation, inflate() always flushes as much output as
  possible to the output buffer, and always uses the faster approach on the
  first call.  So the effects of the flush parameter in this implementation are
  on the return value of inflate() as noted below, when inflate() returns early
  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
  memory for a sliding window when Z_FINISH is used.

     If a preset dictionary is needed after this call (see inflateSetDictionary
  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
  strm->adler to the Adler-32 checksum of all output produced so far (that is,
  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
  below.  At the end of the stream, inflate() checks that its computed adler32
  checksum is equal to that saved by the compressor and returns Z_STREAM_END
  only if the checksum is correct.

    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
  deflate data.  The header type is detected automatically, if requested when
  initializing with inflateInit2().  Any information contained in the gzip
  header is not retained, so applications that need that information should
  instead use raw inflate, see inflateInit2() below, or inflateBack() and
  perform their own processing of the gzip header and trailer.  When processing
  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
  producted so far.  The CRC-32 is checked against the gzip trailer.

    inflate() returns Z_OK if some progress has been made (more input processed
  or more output produced), Z_STREAM_END if the end of the compressed data has
  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
  corrupted (input stream not conforming to the zlib format or incorrect check
  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
  inflate() can be called again with more input and more output space to
  continue decompressing.  If Z_DATA_ERROR is returned, the application may
  then call inflateSync() to look for a good compression block if a partial
  recovery of the data is desired.
*/

 int inflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
   was inconsistent.  In the error case, msg may be set but then points to a
   static string (which must not be deallocated).
*/

                        /* Advanced functions */

/*
    The following functions are needed only in some special applications.
*/

/*
 int deflateInit2 (z_streamp strm,
                                     int  level,
                                     int  method,
                                     int  windowBits,
                                     int  memLevel,
                                     int  strategy);

     This is another version of deflateInit with more compression options.  The
   fields next_in, zalloc, zfree and opaque must be initialized before by the
   caller.

     The method parameter is the compression method.  It must be Z_DEFLATED in
   this version of the library.

     The windowBits parameter is the base two logarithm of the window size
   (the size of the history buffer).  It should be in the range 8..15 for this
   version of the library.  Larger values of this parameter result in better
   compression at the expense of memory usage.  The default value is 15 if
   deflateInit is used instead.

     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
   determines the window size.  deflate() will then generate raw deflate data
   with no zlib header or trailer, and will not compute an adler32 check value.

     windowBits can also be greater than 15 for optional gzip encoding.  Add
   16 to windowBits to write a simple gzip header and trailer around the
   compressed data instead of a zlib wrapper.  The gzip header will have no
   file name, no extra data, no comment, no modification time (set to zero), no
   header crc, and the operating system will be set to 255 (unknown).  If a
   gzip stream is being written, strm->adler is a crc32 instead of an adler32.

     The memLevel parameter specifies how much memory should be allocated
   for the internal compression state.  memLevel=1 uses minimum memory but is
   slow and reduces compression ratio; memLevel=9 uses maximum memory for
   optimal speed.  The default value is 8.  See zconf.h for total memory usage
   as a function of windowBits and memLevel.

     The strategy parameter is used to tune the compression algorithm.  Use the
   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
   string match), or Z_RLE to limit match distances to one (run-length
   encoding).  Filtered data consists mostly of small values with a somewhat
   random distribution.  In this case, the compression algorithm is tuned to
   compress them better.  The effect of Z_FILTERED is to force more Huffman
   coding and less string matching; it is somewhat intermediate between
   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
   strategy parameter only affects the compression ratio but not the
   correctness of the compressed output even if it is not set appropriately.
   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
   decoder for special applications.

     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
   set to null if there is no error message.  deflateInit2 does not perform any
   compression: this will be done by deflate().
*/

 int deflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the compression dictionary from the given byte sequence
   without producing any compressed output.  When using the zlib format, this
   function must be called immediately after deflateInit, deflateInit2 or
   deflateReset, and before any call of deflate.  When doing raw deflate, this
   function must be called either before any call of deflate, or immediately
   after the completion of a deflate block, i.e. after all input has been
   consumed and all output has been delivered when using any of the flush
   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
   compressor and decompressor must use exactly the same dictionary (see
   inflateSetDictionary).

     The dictionary should consist of strings (byte sequences) that are likely
   to be encountered later in the data to be compressed, with the most commonly
   used strings preferably put towards the end of the dictionary.  Using a
   dictionary is most useful when the data to be compressed is short and can be
   predicted with good accuracy; the data can then be compressed better than
   with the default empty dictionary.

     Depending on the size of the compression data structures selected by
   deflateInit or deflateInit2, a part of the dictionary may in effect be
   discarded, for example if the dictionary is larger than the window size
   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
   useful should be put at the end of the dictionary, not at the front.  In
   addition, the current implementation of deflate will use at most the window
   size minus 262 bytes of the provided dictionary.

     Upon return of this function, strm->adler is set to the adler32 value
   of the dictionary; the decompressor may later use this value to determine
   which dictionary has been used by the compressor.  (The adler32 value
   applies to the whole dictionary even if only a subset of the dictionary is
   actually used by the compressor.) If a raw deflate was requested, then the
   adler32 value is not computed and strm->adler is not set.

     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent (for example if deflate has already been called for this stream
   or if not at a block boundary for raw deflate).  deflateSetDictionary does
   not perform any compression: this will be done by deflate().
*/

 int deflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when several compression strategies will be
   tried, for example when there are several ways of pre-processing the input
   data with a filter.  The streams that will be discarded should then be freed
   by calling deflateEnd.  Note that deflateCopy duplicates the internal
   compression state which can be quite large, so this strategy is slow and can
   consume lots of memory.

     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int deflateReset (z_streamp strm);
/*
     This function is equivalent to deflateEnd followed by deflateInit,
   but does not free and reallocate all the internal compression state.  The
   stream will keep the same compression level and any other attributes that
   may have been set by deflateInit2.

     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int deflateParams (z_streamp strm,
                                      int level,
                                      int strategy);
/*
     Dynamically update the compression level and compression strategy.  The
   interpretation of level and strategy is as in deflateInit2.  This can be
   used to switch between compression and straight copy of the input data, or
   to switch to a different kind of input data requiring a different strategy.
   If the compression level is changed, the input available so far is
   compressed with the old level (and may be flushed); the new level will take
   effect only at the next call of deflate().

     Before the call of deflateParams, the stream state must be set as for
   a call of deflate(), since the currently available input may have to be
   compressed and flushed.  In particular, strm->avail_out must be non-zero.

     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
   strm->avail_out was zero.
*/

 int deflateTune (z_streamp strm,
                                    int good_length,
                                    int max_lazy,
                                    int nice_length,
                                    int max_chain);
/*
     Fine tune deflate's internal compression parameters.  This should only be
   used by someone who understands the algorithm used by zlib's deflate for
   searching for the best matching string, and even then only by the most
   fanatic optimizer trying to squeeze out the last compressed bit for their
   specific input data.  Read the deflate.c source code for the meaning of the
   max_lazy, good_length, nice_length, and max_chain parameters.

     deflateTune() can be called after deflateInit() or deflateInit2(), and
   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
 */

 uLong deflateBound (z_streamp strm,
                                       uLong sourceLen);
/*
     deflateBound() returns an upper bound on the compressed size after
   deflation of sourceLen bytes.  It must be called after deflateInit() or
   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
   to allocate an output buffer for deflation in a single pass, and so would be
   called before deflate().  If that first deflate() call is provided the
   sourceLen input bytes, an output buffer allocated to the size returned by
   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
   to return Z_STREAM_END.  Note that it is possible for the compressed size to
   be larger than the value returned by deflateBound() if flush options other
   than Z_FINISH or Z_NO_FLUSH are used.
*/

 int deflatePending (z_streamp strm,
                                       unsigned *pending,
                                       int *bits);
/*
     deflatePending() returns the number of bytes and bits of output that have
   been generated, but not yet provided in the available output.  The bytes not
   provided would be due to the available output space having being consumed.
   The number of bits of output not provided are between 0 and 7, where they
   await more bits to join them in order to fill out a full byte.  If pending
   or bits are Z_NULL, then those values are not set.

     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
 */

 int deflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     deflatePrime() inserts bits in the deflate output stream.  The intent
   is that this function is used to start off the deflate output with the bits
   leftover from a previous deflate stream when appending to it.  As such, this
   function can only be used for raw deflate, and must be used before the first
   deflate() call after a deflateInit2() or deflateReset().  bits must be less
   than or equal to 16, and that many of the least significant bits of value
   will be inserted in the output.

     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
   source stream state was inconsistent.
*/

 int deflateSetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     deflateSetHeader() provides gzip header information for when a gzip
   stream is requested by deflateInit2().  deflateSetHeader() may be called
   after deflateInit2() or deflateReset() and before the first call of
   deflate().  The text, time, os, extra field, name, and comment information
   in the provided gz_header structure are written to the gzip header (xflag is
   ignored -- the extra flags are set according to the compression level).  The
   caller must assure that, if not Z_NULL, name and comment are terminated with
   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
   available there.  If hcrc is true, a gzip header crc is included.  Note that
   the current versions of the command-line version of gzip (up through version
   1.3.x) do not support header crc's, and will report that it is a "multi-part
   gzip file" and give up.

     If deflateSetHeader is not used, the default gzip header has text false,
   the time set to zero, and os set to 255, with no extra, name, or comment
   fields.  The gzip header is returned to the default state by deflateReset().

     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int inflateInit2 (z_streamp strm,
                                     int  windowBits);

     This is another version of inflateInit with an extra parameter.  The
   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
   before by the caller.

     The windowBits parameter is the base two logarithm of the maximum window
   size (the size of the history buffer).  It should be in the range 8..15 for
   this version of the library.  The default value is 15 if inflateInit is used
   instead.  windowBits must be greater than or equal to the windowBits value
   provided to deflateInit2() while compressing, or it must be equal to 15 if
   deflateInit2() was not used.  If a compressed stream with a larger window
   size is given as input, inflate() will return with the error code
   Z_DATA_ERROR instead of trying to allocate a larger window.

     windowBits can also be zero to request that inflate use the window size in
   the zlib header of the compressed stream.

     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
   determines the window size.  inflate() will then process raw deflate data,
   not looking for a zlib or gzip header, not generating a check value, and not
   looking for any check values for comparison at the end of the stream.  This
   is for use with other formats that use the deflate compressed data format
   such as zip.  Those formats provide their own check values.  If a custom
   format is developed using the raw deflate format for compressed data, it is
   recommended that a check value such as an adler32 or a crc32 be applied to
   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
   most applications, the zlib format should be used as is.  Note that comments
   above on the use in deflateInit2() applies to the magnitude of windowBits.

     windowBits can also be greater than 15 for optional gzip decoding.  Add
   32 to windowBits to enable zlib and gzip decoding with automatic header
   detection, or add 16 to decode only the gzip format (the zlib format will
   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
   crc32 instead of an adler32.

     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit2 does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit2() does not process any header information -- that is
   deferred until inflate() is called.
*/

 int inflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the decompression dictionary from the given uncompressed byte
   sequence.  This function must be called immediately after a call of inflate,
   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
   can be determined from the adler32 value returned by that call of inflate.
   The compressor and decompressor must use exactly the same dictionary (see
   deflateSetDictionary).  For raw inflate, this function can be called at any
   time to set the dictionary.  If the provided dictionary is smaller than the
   window and there is already data in the window, then the provided dictionary
   will amend what's there.  The application must insure that the dictionary
   that was used for compression is provided.

     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
   expected one (incorrect adler32 value).  inflateSetDictionary does not
   perform any decompression: this will be done by subsequent calls of
   inflate().
*/

 int inflateGetDictionary (z_streamp strm,
                                             Bytef *dictionary,
                                             uInt  *dictLength);
/*
     Returns the sliding dictionary being maintained by inflate.  dictLength is
   set to the number of bytes in the dictionary, and that many bytes are copied
   to dictionary.  dictionary must have enough space, where 32768 bytes is
   always enough.  If inflateGetDictionary() is called with dictionary equal to
   Z_NULL, then only the dictionary length is returned, and nothing is copied.
   Similary, if dictLength is Z_NULL, then it is not set.

     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
   stream state is inconsistent.
*/

 int inflateSync (z_streamp strm);
/*
     Skips invalid compressed data until a possible full flush point (see above
   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
   available input is skipped.  No output is provided.

     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
   All full flush points have this pattern, but not all occurrences of this
   pattern are full flush points.

     inflateSync returns Z_OK if a possible full flush point has been found,
   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
   In the success case, the application may save the current current value of
   total_in which indicates where valid compressed data was found.  In the
   error case, the application may repeatedly call inflateSync, providing more
   input each time, until success or end of the input data.
*/

 int inflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when randomly accessing a large stream.  The
   first pass through the stream can periodically record the inflate state,
   allowing restarting inflate at those points when randomly accessing the
   stream.

     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int inflateReset (z_streamp strm);
/*
     This function is equivalent to inflateEnd followed by inflateInit,
   but does not free and reallocate all the internal decompression state.  The
   stream will keep attributes that may have been set by inflateInit2.

     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int inflateReset2 (z_streamp strm,
                                      int windowBits);
/*
     This function is the same as inflateReset, but it also permits changing
   the wrap and window size requests.  The windowBits parameter is interpreted
   the same as it is for inflateInit2.

     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
   the windowBits parameter is invalid.
*/

 int inflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     This function inserts bits in the inflate input stream.  The intent is
   that this function is used to start inflating at a bit position in the
   middle of a byte.  The provided bits will be used before any bytes are used
   from next_in.  This function should only be used with raw inflate, and
   should be used before the first inflate() call after inflateInit2() or
   inflateReset().  bits must be less than or equal to 16, and that many of the
   least significant bits of value will be inserted in the input.

     If bits is negative, then the input stream bit buffer is emptied.  Then
   inflatePrime() can be called again to put bits in the buffer.  This is used
   to clear out bits leftover after feeding inflate a block description prior
   to feeding inflate codes.

     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

 long  inflateMark (z_streamp strm);
/*
     This function returns two values, one in the lower 16 bits of the return
   value, and the other in the remaining upper bits, obtained by shifting the
   return value down 16 bits.  If the upper value is -1 and the lower value is
   zero, then inflate() is currently decoding information outside of a block.
   If the upper value is -1 and the lower value is non-zero, then inflate is in
   the middle of a stored block, with the lower value equaling the number of
   bytes from the input remaining to copy.  If the upper value is not -1, then
   it is the number of bits back from the current bit position in the input of
   the code (literal or length/distance pair) currently being processed.  In
   that case the lower value is the number of bytes already emitted for that
   code.

     A code is being processed if inflate is waiting for more input to complete
   decoding of the code, or if it has completed decoding but is waiting for
   more output space to write the literal or match data.

     inflateMark() is used to mark locations in the input data for random
   access, which may be at bit positions, and to note those cases where the
   output of a code may span boundaries of random access blocks.  The current
   location in the input stream can be determined from avail_in and data_type
   as noted in the description for the Z_BLOCK flush parameter for inflate.

     inflateMark returns the value noted above or -1 << 16 if the provided
   source stream state was inconsistent.
*/

 int  inflateGetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     inflateGetHeader() requests that gzip header information be stored in the
   provided gz_header structure.  inflateGetHeader() may be called after
   inflateInit2() or inflateReset(), and before the first call of inflate().
   As inflate() processes the gzip stream, head->done is zero until the header
   is completed, at which time head->done is set to one.  If a zlib stream is
   being decoded, then head->done is set to -1 to indicate that there will be
   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
   used to force inflate() to return immediately after header processing is
   complete and before any actual data is decompressed.

     The text, time, xflags, and os fields are filled in with the gzip header
   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
   contains the maximum number of bytes to write to extra.  Once done is true,
   extra_len contains the actual extra field length, and extra contains the
   extra field, or that field truncated if extra_max is less than extra_len.
   If name is not Z_NULL, then up to name_max characters are written there,
   terminated with a zero unless the length is greater than name_max.  If
   comment is not Z_NULL, then up to comm_max characters are written there,
   terminated with a zero unless the length is greater than comm_max.  When any
   of extra, name, or comment are not Z_NULL and the respective field is not
   present in the header, then that field is set to Z_NULL to signal its
   absence.  This allows the use of deflateSetHeader() with the returned
   structure to duplicate the header.  However if those fields are set to
   allocated memory, then the application will need to save those pointers
   elsewhere so that they can be eventually freed.

     If inflateGetHeader is not used, then the header information is simply
   discarded.  The header is always checked for validity, including the header
   CRC if present.  inflateReset() will reset the process to discard the header
   information.  The application would need to call inflateGetHeader() again to
   retrieve the header from the next gzip stream.

     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int  inflateBackInit (z_streamp strm, int windowBits,
                                        unsigned char FAR *window);

     Initialize the internal stream state for decompression using inflateBack()
   calls.  The fields zalloc, zfree and opaque in strm must be initialized
   before the call.  If zalloc and zfree are Z_NULL, then the default library-
   derived memory allocation routines are used.  windowBits is the base two
   logarithm of the window size, in the range 8..15.  window is a caller
   supplied buffer of that size.  Except for special applications where it is
   assured that deflate was used with small window sizes, windowBits must be 15
   and a 32K byte window must be supplied to be able to decompress general
   deflate streams.

     See inflateBack() for the usage of these routines.

     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
   allocated, or Z_VERSION_ERROR if the version of the library does not match
   the version of the header file.
*/

typedef unsigned (*in_func) (void FAR *,
                                z_const unsigned char FAR * FAR *);
typedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);

 int  inflateBack (z_streamp strm,
                                    in_func in, void FAR *in_desc,
                                    out_func out, void FAR *out_desc);
/*
     inflateBack() does a raw inflate with a single call using a call-back
   interface for input and output.  This is potentially more efficient than
   inflate() for file i/o applications, in that it avoids copying between the
   output and the sliding window by simply making the window itself the output
   buffer.  inflate() can be faster on modern CPUs when used with large
   buffers.  inflateBack() trusts the application to not change the output
   buffer passed by the output function, at least until inflateBack() returns.

     inflateBackInit() must be called first to allocate the internal state
   and to initialize the state with the user-provided window buffer.
   inflateBack() may then be used multiple times to inflate a complete, raw
   deflate stream with each call.  inflateBackEnd() is then called to free the
   allocated state.

     A raw deflate stream is one with no zlib or gzip header or trailer.
   This routine would normally be used in a utility that reads zip or gzip
   files and writes out uncompressed files.  The utility would decode the
   header and process the trailer on its own, hence this routine expects only
   the raw deflate stream to decompress.  This is different from the normal
   behavior of inflate(), which expects either a zlib or gzip header and
   trailer around the deflate stream.

     inflateBack() uses two subroutines supplied by the caller that are then
   called by inflateBack() for input and output.  inflateBack() calls those
   routines until it reads a complete deflate stream and writes out all of the
   uncompressed data, or until it encounters an error.  The function's
   parameters and return types are defined above in the in_func and out_func
   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
   number of bytes of provided input, and a pointer to that input in buf.  If
   there is no input available, in() must return zero--buf is ignored in that
   case--and inflateBack() will return a buffer error.  inflateBack() will call
   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
   should return zero on success, or non-zero on failure.  If out() returns
   non-zero, inflateBack() will return with an error.  Neither in() nor out()
   are permitted to change the contents of the window provided to
   inflateBackInit(), which is also the buffer that out() uses to write from.
   The length written by out() will be at most the window size.  Any non-zero
   amount of input may be provided by in().

     For convenience, inflateBack() can be provided input on the first call by
   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
   in() will be called.  Therefore strm->next_in must be initialized before
   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
   must also be initialized, and then if strm->avail_in is not zero, input will
   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].

     The in_desc and out_desc parameters of inflateBack() is passed as the
   first parameter of in() and out() respectively when they are called.  These
   descriptors can be optionally used to pass any information that the caller-
   supplied in() and out() functions need to do their job.

     On return, inflateBack() will set strm->next_in and strm->avail_in to
   pass back any unused input that was provided by the last in() call.  The
   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
   in the deflate stream (in which case strm->msg is set to indicate the nature
   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
   In the case of Z_BUF_ERROR, an input or output error can be distinguished
   using strm->next_in which will be Z_NULL only if in() returned an error.  If
   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
   non-zero.  (in() will always be called before out(), so strm->next_in is
   assured to be defined if out() returns non-zero.) Note that inflateBack()
   cannot return Z_OK.
*/

 int  inflateBackEnd (z_streamp strm);
/*
     All memory allocated by inflateBackInit() is freed.

     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
   state was inconsistent.
*/

 uLong  zlibCompileFlags (void);
/* Return flags indicating compile-time options.

    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
     1.0: size of uInt
     3.2: size of uLong
     5.4: size of voidpf (pointer)
     7.6: size of z_off_t

    Compiler, assembler, and debug options:
     8: DEBUG
     9: ASMV or ASMINF -- use ASM code
     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
     11: 0 (reserved)

    One-time table building (smaller code, but not thread-safe if true):
     12: BUILDFIXED -- build static block decoding tables when needed
     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
     14,15: 0 (reserved)

    Library content (indicates missing functionality):
     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
                          deflate code when not needed)
     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
                    and decode gzip streams (to avoid linking crc code)
     18-19: 0 (reserved)

    Operation variations (changes in library functionality):
     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
     21: FASTEST -- deflate algorithm with only one, lowest compression level
     22,23: 0 (reserved)

    The sprintf variant used by gzprintf (zero is best):
     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
     26: 0 = returns value, 1 = void -- 1 means inferred string length returned

    Remainder:
     27-31: 0 (reserved)
 */

#ifndef Z_SOLO

                        /* utility functions */

/*
     The following utility functions are implemented on top of the basic
   stream-oriented functions.  To simplify the interface, some default options
   are assumed (compression level and memory usage, standard memory allocation
   functions).  The source code of these utility functions can be modified if
   you need special options.
*/

 int  compress (Bytef *dest,   uLongf *destLen,
                                 const Bytef *source, uLong sourceLen);
/*
     Compresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer.
*/

 int  compress2 (Bytef *dest,   uLongf *destLen,
                                  const Bytef *source, uLong sourceLen,
                                  int level);
/*
     Compresses the source buffer into the destination buffer.  The level
   parameter has the same meaning as in deflateInit.  sourceLen is the byte
   length of the source buffer.  Upon entry, destLen is the total size of the
   destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
   Z_STREAM_ERROR if the level parameter is invalid.
*/

 uLong  compressBound (uLong sourceLen);
/*
     compressBound() returns an upper bound on the compressed size after
   compress() or compress2() on sourceLen bytes.  It would be used before a
   compress() or compress2() call to allocate the destination buffer.
*/

 int  uncompress (Bytef *dest,   uLongf *destLen,
       const Bytef *source, uLongf sourceLen);
/*
     Decompresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be large enough to hold the entire
   uncompressed data.  (The size of the uncompressed data must have been saved
   previously by the compressor and transmitted to the decompressor by some
   mechanism outside the scope of this compression library.) Upon exit, destLen
   is the actual size of the uncompressed buffer.

     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
   the case where there is not enough room, uncompress() will fill the output
   buffer with the uncompressed data up to that point.
*/

                        /* gzip file access functions */

/*
     This library supports reading and writing files in gzip (.gz) format with
   an interface similar to that of stdio, using the functions that start with
   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
   wrapper, documented in RFC 1952, wrapped around a deflate stream.
*/

typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */

/*
 gzFile  gzopen (const char *path, const char *mode);

     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
   for fixed code compression as in "wb9F".  (See the description of
   deflateInit2 for more information about the strategy parameter.)  'T' will
   request transparent writing or appending with no compression and not using
   the gzip format.

     "a" can be used instead of "w" to request that the gzip stream that will
   be written be appended to the file.  "+" will result in an error, since
   reading and writing to the same gzip file is not supported.  The addition of
   "x" when writing will create the file exclusively, which fails if the file
   already exists.  On systems that support it, the addition of "e" when
   reading or writing will set the flag to close the file on an execve() call.

     These functions, as well as gzip, will read and decode a sequence of gzip
   streams in a file.  The append function of gzopen() can be used to create
   such a file.  (Also see gzflush() for another way to do this.)  When
   appending, gzopen does not test whether the file begins with a gzip stream,
   nor does it look for the end of the gzip streams to begin appending.  gzopen
   will simply append a gzip stream to the existing file.

     gzopen can be used to read a file which is not in gzip format; in this
   case gzread will directly read from the file without decompression.  When
   reading, this will be detected automatically by looking for the magic two-
   byte gzip header.

     gzopen returns NULL if the file could not be opened, if there was
   insufficient memory to allocate the gzFile state, or if an invalid mode was
   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
   errno can be checked to determine if the reason gzopen failed was that the
   file could not be opened.
*/

 gzFile  gzdopen (int fd, const char *mode);
/*
     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
   are obtained from calls like open, dup, creat, pipe or fileno (if the file
   has been previously opened with fopen).  The mode parameter is as in gzopen.

     The next call of gzclose on the returned gzFile will also close the file
   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
   mode);.  The duplicated descriptor should be saved to avoid a leak, since
   gzdopen does not close fd if it fails.  If you are using fileno() to get the
   file descriptor from a FILE *, then you will have to use dup() to avoid
   double-close()ing the file descriptor.  Both gzclose() and fclose() will
   close the associated file descriptor, so they need to have different file
   descriptors.

     gzdopen returns NULL if there was insufficient memory to allocate the
   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
   used until the next gz* read, write, seek, or close operation, so gzdopen
   will not detect if fd is invalid (unless fd is -1).
*/

 int  gzbuffer (gzFile file, unsigned size);
/*
     Set the internal buffer size used by this library's functions.  The
   default buffer size is 8192 bytes.  This function must be called after
   gzopen() or gzdopen(), and before any other calls that read or write the
   file.  The buffer memory allocation is always deferred to the first read or
   write.  Two buffers are allocated, either both of the specified size when
   writing, or one of the specified size and the other twice that size when
   reading.  A larger buffer size of, for example, 64K or 128K bytes will
   noticeably increase the speed of decompression (reading).

     The new buffer size also affects the maximum length for gzprintf().

     gzbuffer() returns 0 on success, or -1 on failure, such as being called
   too late.
*/

 int  gzsetparams (gzFile file, int level, int strategy);
/*
     Dynamically update the compression level or strategy.  See the description
   of deflateInit2 for the meaning of these parameters.

     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
   opened for writing.
*/

 int  gzread (gzFile file, voidp buf, unsigned len);
/*
     Reads the given number of uncompressed bytes from the compressed file.  If
   the input file is not in gzip format, gzread copies the given number of
   bytes into the buffer directly from the file.

     After reaching the end of a gzip stream in the input, gzread will continue
   to read, looking for another gzip stream.  Any number of gzip streams may be
   concatenated in the input file, and will all be decompressed by gzread().
   If something other than a gzip stream is encountered after a gzip stream,
   that remaining trailing garbage is ignored (and no error is returned).

     gzread can be used to read a gzip file that is being concurrently written.
   Upon reaching the end of the input, gzread will return with the available
   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
   gzclearerr can be used to clear the end of file indicator in order to permit
   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
   middle of a gzip stream.  Note that gzread does not return -1 in the event
   of an incomplete gzip stream.  This error is deferred until gzclose(), which
   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
   stream.  Alternatively, gzerror can be used before gzclose to detect this
   case.

     gzread returns the number of uncompressed bytes actually read, less than
   len for end of file, or -1 for error.
*/

 int  gzwrite (gzFile file,
                                voidpc buf, unsigned len);
/*
     Writes the given number of uncompressed bytes into the compressed file.
   gzwrite returns the number of uncompressed bytes written or 0 in case of
   error.
*/

 int gzprintf Z_ARG((gzFile file, const char *format, ...));
/*
     Converts, formats, and writes the arguments to the compressed file under
   control of the format string, as in fprintf.  gzprintf returns the number of
   uncompressed bytes actually written, or 0 in case of error.  The number of
   uncompressed bytes written is limited to 8191, or one less than the buffer
   size given to gzbuffer().  The caller should assure that this limit is not
   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
   nothing written.  In this case, there may also be a buffer overflow with
   unpredictable consequences, which is possible only if zlib was compiled with
   the insecure functions sprintf() or vsprintf() because the secure snprintf()
   or vsnprintf() functions were not available.  This can be determined using
   zlibCompileFlags().
*/

 int  gzputs (gzFile file, const char *s);
/*
     Writes the given null-terminated string to the compressed file, excluding
   the terminating null character.

     gzputs returns the number of characters written, or -1 in case of error.
*/

 char *  gzgets (gzFile file, char *buf, int len);
/*
     Reads bytes from the compressed file until len-1 characters are read, or a
   newline character is read and transferred to buf, or an end-of-file
   condition is encountered.  If any characters are read or if len == 1, the
   string is terminated with a null character.  If no characters are read due
   to an end-of-file or len < 1, then the buffer is left untouched.

     gzgets returns buf which is a null-terminated string, or it returns NULL
   for end-of-file or in case of error.  If there was an error, the contents at
   buf are indeterminate.
*/

 int  gzputc (gzFile file, int c);
/*
     Writes c, converted to an unsigned char, into the compressed file.  gzputc
   returns the value that was written, or -1 in case of error.
*/

 int  gzgetc (gzFile file);
/*
     Reads one byte from the compressed file.  gzgetc returns this byte or -1
   in case of end of file or error.  This is implemented as a macro for speed.
   As such, it does not do all of the checking the other functions do.  I.e.
   it does not check to see if file is NULL, nor whether the structure file
   points to has been clobbered or not.
*/

 int  gzungetc (int c, gzFile file);
/*
     Push one character back onto the stream to be read as the first character
   on the next read.  At least one character of push-back is allowed.
   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
   fail if c is -1, and may fail if a character has been pushed but not read
   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
   The pushed character will be discarded if the stream is repositioned with
   gzseek() or gzrewind().
*/

 int  gzflush (gzFile file, int flush);
/*
     Flushes all pending output into the compressed file.  The parameter flush
   is as in the deflate() function.  The return value is the zlib error number
   (see function gzerror below).  gzflush is only permitted when writing.

     If the flush parameter is Z_FINISH, the remaining data is written and the
   gzip stream is completed in the output.  If gzwrite() is called again, a new
   gzip stream will be started in the output.  gzread() is able to read such
   concatented gzip streams.

     gzflush should be called only when strictly necessary because it will
   degrade compression if called too often.
*/

/*
 z_off_t  gzseek (gzFile file,
                                   z_off_t offset, int whence);

     Sets the starting position for the next gzread or gzwrite on the given
   compressed file.  The offset represents a number of bytes in the
   uncompressed data stream.  The whence parameter is defined as in lseek(2);
   the value SEEK_END is not supported.

     If the file is opened for reading, this function is emulated but can be
   extremely slow.  If the file is opened for writing, only forward seeks are
   supported; gzseek then compresses a sequence of zeroes up to the new
   starting position.

     gzseek returns the resulting offset location as measured in bytes from
   the beginning of the uncompressed stream, or -1 in case of error, in
   particular if the file is opened for writing and the new starting position
   would be before the current position.
*/

 int     gzrewind (gzFile file);
/*
     Rewinds the given file. This function is supported only for reading.

     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
*/

/*
 z_off_t     gztell (gzFile file);

     Returns the starting position for the next gzread or gzwrite on the given
   compressed file.  This position represents a number of bytes in the
   uncompressed data stream, and is zero when starting, even if appending or
   reading a gzip stream from the middle of a file using gzdopen().

     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
*/

/*
 z_off_t  gzoffset (gzFile file);

     Returns the current offset in the file being read or written.  This offset
   includes the count of bytes that precede the gzip stream, for example when
   appending or when using gzdopen() for reading.  When reading, the offset
   does not include as yet unused buffered input.  This information can be used
   for a progress indicator.  On error, gzoffset() returns -1.
*/

 int  gzeof (gzFile file);
/*
     Returns true (1) if the end-of-file indicator has been set while reading,
   false (0) otherwise.  Note that the end-of-file indicator is set only if the
   read tried to go past the end of the input, but came up short.  Therefore,
   just like feof(), gzeof() may return false even if there is no more data to
   read, in the event that the last read request was for the exact number of
   bytes remaining in the input file.  This will happen if the input file size
   is an exact multiple of the buffer size.

     If gzeof() returns true, then the read functions will return no more data,
   unless the end-of-file indicator is reset by gzclearerr() and the input file
   has grown since the previous end of file was detected.
*/

 int  gzdirect (gzFile file);
/*
     Returns true (1) if file is being copied directly while reading, or false
   (0) if file is a gzip stream being decompressed.

     If the input file is empty, gzdirect() will return true, since the input
   does not contain a gzip stream.

     If gzdirect() is used immediately after gzopen() or gzdopen() it will
   cause buffers to be allocated to allow reading the file to determine if it
   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
   gzdirect().

     When writing, gzdirect() returns true (1) if transparent writing was
   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
   gzdirect() is not needed when writing.  Transparent writing must be
   explicitly requested, so the application already knows the answer.  When
   linking statically, using gzdirect() will include all of the zlib code for
   gzip file reading and decompression, which may not be desired.)
*/

 int     gzclose (gzFile file);
/*
     Flushes all pending output if necessary, closes the compressed file and
   deallocates the (de)compression state.  Note that once file is closed, you
   cannot call gzerror with file, since its structures have been deallocated.
   gzclose must not be called more than once on the same file, just as free
   must not be called more than once on the same allocation.

     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
   last read ended in the middle of a gzip stream, or Z_OK on success.
*/

 int  gzclose_r (gzFile file);
 int  gzclose_w (gzFile file);
/*
     Same as gzclose(), but gzclose_r() is only for use when reading, and
   gzclose_w() is only for use when writing or appending.  The advantage to
   using these instead of gzclose() is that they avoid linking in zlib
   compression or decompression code that is not used when only reading or only
   writing respectively.  If gzclose() is used, then both compression and
   decompression code will be included the application when linking to a static
   zlib library.
*/

 const char *  gzerror (gzFile file, int *errnum);
/*
     Returns the error message for the last error which occurred on the given
   compressed file.  errnum is set to zlib error number.  If an error occurred
   in the file system and not in the compression library, errnum is set to
   Z_ERRNO and the application may consult errno to get the exact error code.

     The application must not modify the returned string.  Future calls to
   this function may invalidate the previously returned string.  If file is
   closed, then the string previously returned by gzerror will no longer be
   available.

     gzerror() should be used to distinguish errors from end-of-file for those
   functions above that do not distinguish those cases in their return values.
*/

 void  gzclearerr (gzFile file);
/*
     Clears the error and end-of-file flags for file.  This is analogous to the
   clearerr() function in stdio.  This is useful for continuing to read a gzip
   file that is being written concurrently.
*/

#endif /* !Z_SOLO */

                        /* checksum functions */

/*
     These functions are not related to compression but are exported
   anyway because they might be useful in applications using the compression
   library.
*/

uint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);
/*
     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
   return the updated checksum.  If buf is Z_NULL, this function returns the
   required initial value for the checksum.

     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
   much faster.

   Usage example:

     uLong adler = adler32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       adler = adler32(adler, buffer, length);
     }
     if (adler != original_adler) error();
*/

/*
 uLong  adler32_combine (uLong adler1, uLong adler2,
                                          z_off_t len2);

     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
   that the z_off_t type (like off_t) is a signed integer.  If len2 is
   negative, the result has no meaning or utility.
*/

 uLong  crc32   (uLong crc, const Bytef *buf, uInt len);
/*
     Update a running CRC-32 with the bytes buf[0..len-1] and return the
   updated CRC-32.  If buf is Z_NULL, this function returns the required
   initial value for the crc.  Pre- and post-conditioning (one's complement) is
   performed within this function so it shouldn't be done by the application.

   Usage example:

     uLong crc = crc32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       crc = crc32(crc, buffer, length);
     }
     if (crc != original_crc) error();
*/

/*
 uLong  crc32_combine (uLong crc1, uLong crc2, z_off_t len2);

     Combine two CRC-32 check values into one.  For two sequences of bytes,
   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
   len2.
*/

                        /* various hacks, don't look :) */

/* deflateInit and inflateInit are macros to allow checking the zlib version
 * and the compiler's view of z_stream:
 */
 int  deflateInit_ (z_streamp strm, int level,
                                     const char *version, int stream_size);
 int  inflateInit_ (z_streamp strm,
                                     const char *version, int stream_size);
 int  deflateInit2_ (z_streamp strm, int  level, int  method,
                                      int windowBits, int memLevel,
                                      int strategy, const char *version,
                                      int stream_size);
 int  inflateInit2_ (z_streamp strm, int  windowBits,
                                      const char *version, int stream_size);
 int  inflateBackInit_ (z_streamp strm, int windowBits,
                                         unsigned char FAR *window,
                                         const char *version,
                                         int stream_size);
#define deflateInit(strm, level) \
        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit(strm) \
        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit2(strm, windowBits) \
        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
                      (int)sizeof(z_stream))
#define inflateBackInit(strm, windowBits, window) \
        inflateBackInit_((strm), (windowBits), (window), \
                      ZLIB_VERSION, (int)sizeof(z_stream))

#ifndef Z_SOLO

/* gzgetc() macro and its supporting function and exposed data structure.  Note
 * that the real internal state is much larger than the exposed structure.
 * This abbreviated structure exposes just enough for the gzgetc() macro.  The
 * user should not mess with these exposed elements, since their names or
 * behavior could change in the future, perhaps even capriciously.  They can
 * only be used by the gzgetc() macro.  You have been warned.
 */
 int  gzgetc_ (gzFile file);  /* backward compatibility */
#ifdef Z_PREFIX_SET
#  undef z_gzgetc
#  define z_gzgetc(g) \
          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
#else
#  define gzgetc(g) \
          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
#endif

/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
 * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
 * both are true, the application gets the *64 functions, and the regular
 * functions are changed to 64 bits) -- in case these are set on systems
 * without large file support, _LFS64_LARGEFILE must also be true
 */
#ifdef Z_LARGE64
    gzFile  gzopen64 (const char *, const char *);
    z_off64_t  gzseek64 (gzFile, z_off64_t, int);
    z_off64_t  gztell64 (gzFile);
    z_off64_t  gzoffset64 (gzFile);
    uLong  adler32_combine64 (uLong, uLong, z_off64_t);
    uLong  crc32_combine64 (uLong, uLong, z_off64_t);
#endif

#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
#  ifdef Z_PREFIX_SET
#    define z_gzopen z_gzopen64
#    define z_gzseek z_gzseek64
#    define z_gztell z_gztell64
#    define z_gzoffset z_gzoffset64
#    define z_adler32_combine z_adler32_combine64
#    define z_crc32_combine z_crc32_combine64
#  else
#    define gzopen gzopen64
#    define gzseek gzseek64
#    define gztell gztell64
#    define gzoffset gzoffset64
#    define adler32_combine adler32_combine64
#    define crc32_combine crc32_combine64
#  endif
#  ifndef Z_LARGE64
      gzFile  gzopen64 (const char *, const char *);
      z_off_t  gzseek64 (gzFile, z_off_t, int);
      z_off_t  gztell64 (gzFile);
      z_off_t  gzoffset64 (gzFile);
      uLong  adler32_combine64 (uLong, uLong, z_off_t);
      uLong  crc32_combine64 (uLong, uLong, z_off_t);
#  endif
#else
    gzFile  gzopen (const char *, const char *);
    z_off_t  gzseek (gzFile, z_off_t, int);
    z_off_t  gztell (gzFile);
    z_off_t  gzoffset (gzFile);
    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);
#endif

#else /* Z_SOLO */

    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);

#endif /* !Z_SOLO */

/* hack for buggy compilers */
#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
    struct internal_state {int dummy;};
#endif

/* undocumented functions */
 const char   *  zError           (int);
 int             inflateSyncPoint (z_streamp);

 const uint32_t * get_crc_table(void);
 int             inflateUndermine (z_streamp, int);
 int             inflateValidate  (z_streamp, int);
 int             inflateResetKeep (z_streamp);
 int             deflateResetKeep (z_streamp);
#if defined(_WIN32) && !defined(Z_SOLO)
 gzFile          gzopen_w (const wchar_t *path,
                                            const char *mode);
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
 int            gzvprintf Z_ARG((gzFile file,
                                                  const char *format,
                                                  va_list va));
#  endif
#endif

#ifdef __cplusplus
}
#endif

#endif /* ZLIB_H */

#else
#include <zlib.h>
#endif

#endif

./include/libretro-common/include/compat/zlib/zconf.h

/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) && !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ >= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) && !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 << (windowBits+2)) +  (1 << (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 << windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include <windows.h>
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
#  include <limits.h>
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include <sys/types.h>      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include <stdarg.h>         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include <stddef.h>         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include <unixio.h>       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) && !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) && defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */

./include/libretro-common/include/compat/zlib/zconf.h.in

/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) && !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ >= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) && !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 << (windowBits+2)) +  (1 << (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 << windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include <windows.h>
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
#  include <limits.h>
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include <sys/types.h>      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include <stdarg.h>         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include <stddef.h>         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include <unixio.h>       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) && !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) && defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */

./include/libretro-common/include/compat/zlib/zlib.h

#ifndef _COMPAT_ZLIB_H
#define _COMPAT_ZLIB_H

/* zlib.h -- interface of the 'zlib' general purpose compression library
  version 1.2.8, April 28th, 2013

  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly        Mark Adler
  jloup@gzip.org          madler@alumni.caltech.edu

  The data format used by the zlib library is described by RFCs (Request for
  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
*/

#ifndef ZLIB_H
#define ZLIB_H

#include <stdint.h>
#include "zconf.h"

#ifdef __cplusplus
extern "C" {
#endif

#define ZLIB_VERSION "1.2.8"
#define ZLIB_VERNUM 0x1280
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
#define ZLIB_VER_REVISION 8
#define ZLIB_VER_SUBREVISION 0

/*
    The 'zlib' compression library provides in-memory compression and
  decompression functions, including integrity checks of the uncompressed data.
  This version of the library supports only one compression method (deflation)
  but other algorithms will be added later and will have the same stream
  interface.

    Compression can be done in a single step if the buffers are large enough,
  or can be done by repeated calls of the compression function.  In the latter
  case, the application must provide more input and/or consume the output
  (providing more output space) before each call.

    The compressed data format used by default by the in-memory functions is
  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
  around a deflate stream, which is itself documented in RFC 1951.

    The library also supports reading and writing files in gzip (.gz) format
  with an interface similar to that of stdio using the functions that start
  with "gz".  The gzip format is different from the zlib format.  gzip is a
  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.

    This library can optionally read and write gzip streams in memory as well.

    The zlib format was designed to be compact and fast for use in memory
  and on communications channels.  The gzip format was designed for single-
  file compression on file systems, has a larger header than zlib to maintain
  directory information, and uses a different, slower check method than zlib.

    The library does not install any signal handler.  The decoder checks
  the consistency of the compressed data, so the library should never crash
  even in case of corrupted input.
*/

typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);
typedef void   (*free_func)  (voidpf opaque, voidpf address);

struct internal_state;

typedef struct z_stream_s {
    z_const Bytef *next_in;     /* next input byte */
    uInt     avail_in;  /* number of bytes available at next_in */
    uLong    total_in;  /* total number of input bytes read so far */

    Bytef    *next_out; /* next output byte should be put there */
    uInt     avail_out; /* remaining free space at next_out */
    uLong    total_out; /* total number of bytes output so far */

    z_const char *msg;  /* last error message, NULL if no error */
    void *state; /* not visible by applications */

    alloc_func zalloc;  /* used to allocate the internal state */
    free_func  zfree;   /* used to free the internal state */
    voidpf     opaque;  /* private data object passed to zalloc and zfree */

    int     data_type;  /* best guess about the data type: binary or text */
    uLong   adler;      /* adler32 value of the uncompressed data */
    uLong   reserved;   /* reserved for future use */
} z_stream;

typedef z_stream FAR *z_streamp;

/*
     gzip header information passed to and from zlib routines.  See RFC 1952
  for more details on the meanings of these fields.
*/
typedef struct gz_header_s {
    int     text;       /* true if compressed data believed to be text */
    uLong   time;       /* modification time */
    int     xflags;     /* extra flags (not used when writing a gzip file) */
    int     os;         /* operating system */
    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
    uInt    extra_max;  /* space at extra (only when reading header) */
    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
    uInt    name_max;   /* space at name (only when reading header) */
    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
    uInt    comm_max;   /* space at comment (only when reading header) */
    int     hcrc;       /* true if there was or will be a header crc */
    int     done;       /* true when done reading gzip header (not used
                           when writing a gzip file) */
} gz_header;

typedef gz_header FAR *gz_headerp;

/*
     The application must update next_in and avail_in when avail_in has dropped
   to zero.  It must update next_out and avail_out when avail_out has dropped
   to zero.  The application must initialize zalloc, zfree and opaque before
   calling the init function.  All other fields are set by the compression
   library and must not be updated by the application.

     The opaque value provided by the application will be passed as the first
   parameter for calls of zalloc and zfree.  This can be useful for custom
   memory management.  The compression library attaches no meaning to the
   opaque value.

     zalloc must return Z_NULL if there is not enough memory for the object.
   If zlib is used in a multi-threaded application, zalloc and zfree must be
   thread safe.

     On 16-bit systems, the functions zalloc and zfree must be able to allocate
   exactly 65536 bytes, but will not be required to allocate more than this if
   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
   returned by zalloc for objects of exactly 65536 bytes *must* have their
   offset normalized to zero.  The default allocation function provided by this
   library ensures this (see zutil.c).  To reduce memory requirements and avoid
   any allocation of 64K objects, at the expense of compression ratio, compile
   the library with -DMAX_WBITS=14 (see zconf.h).

     The fields total_in and total_out can be used for statistics or progress
   reports.  After compression, total_in holds the total size of the
   uncompressed data and may be saved for use in the decompressor (particularly
   if the decompressor wants to decompress everything in a single step).
*/

                        /* constants */

#define Z_NO_FLUSH      0
#define Z_PARTIAL_FLUSH 1
#define Z_SYNC_FLUSH    2
#define Z_FULL_FLUSH    3
#define Z_FINISH        4
#define Z_BLOCK         5
#define Z_TREES         6
/* Allowed flush values; see deflate() and inflate() below for details */

#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative values
 * are errors, positive values are used for special but normal events.
 */

#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
/* compression levels */

#define Z_FILTERED            1
#define Z_HUFFMAN_ONLY        2
#define Z_RLE                 3
#define Z_FIXED               4
#define Z_DEFAULT_STRATEGY    0
/* compression strategy; see deflateInit2() below for details */

#define Z_BINARY   0
#define Z_TEXT     1
#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
#define Z_UNKNOWN  2
/* Possible values of the data_type field (though see inflate()) */

#define Z_DEFLATED   8
/* The deflate compression method (the only one supported in this version) */

#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */

#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */

                        /* basic functions */

 const char * zlibVersion (void);
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
   If the first character differs, the library code actually used is not
   compatible with the zlib.h header file used by the application.  This check
   is automatically made by deflateInit and inflateInit.
 */

/*
 int deflateInit (z_streamp strm, int level);

     Initializes the internal stream state for compression.  The fields
   zalloc, zfree and opaque must be initialized before by the caller.  If
   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
   allocation functions.

     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
   1 gives best speed, 9 gives best compression, 0 gives no compression at all
   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
   requests a default compromise between speed and compression (currently
   equivalent to level 6).

     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if level is not a valid compression level, or
   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
   if there is no error message.  deflateInit does not perform any compression:
   this will be done by deflate().
*/

 int deflate (z_streamp strm, int flush);
/*
    deflate compresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

    The detailed semantics are as follows.  deflate performs one or both of the
  following actions:

  - Compress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in and avail_in are updated and
    processing will resume at this point for the next call of deflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  This action is forced if the parameter flush is non zero.
    Forcing flush frequently degrades the compression ratio, so this parameter
    should be set only when necessary (in interactive applications).  Some
    output may be provided even if flush is not set.

    Before the call of deflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating avail_in or avail_out accordingly; avail_out should
  never be zero before the call.  The application can consume the compressed
  output when it wants, for example when the output buffer is full (avail_out
  == 0), or after each call of deflate().  If deflate returns Z_OK and with
  zero avail_out, it must be called again after making room in the output
  buffer because there might be more output pending.

    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
  decide how much data to accumulate before producing output, in order to
  maximize compression.

    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
  flushed to the output buffer and the output is aligned on a byte boundary, so
  that the decompressor can get all input data available so far.  (In
  particular avail_in is zero after the call if enough output space has been
  provided before the call.) Flushing may degrade compression for some
  compression algorithms and so it should be used only when necessary.  This
  completes the current deflate block and follows it with an empty stored block
  that is three bits plus filler bits to the next byte, followed by four bytes
  (00 00 ff ff).

    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
  output buffer, but the output is not aligned to a byte boundary.  All of the
  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
  This completes the current deflate block and follows it with an empty fixed
  codes block that is 10 bits long.  This assures that enough bytes are output
  in order for the decompressor to finish the block before the empty fixed code
  block.

    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
  seven bits of the current block are held to be written as the next byte after
  the next deflate block is completed.  In this case, the decompressor may not
  be provided enough bits at this point in order to complete decompression of
  the data provided so far to the compressor.  It may need to wait for the next
  block to be emitted.  This is for advanced applications that need to control
  the emission of deflate blocks.

    If flush is set to Z_FULL_FLUSH, all output is flushed as with
  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
  restart from this point if previous compressed data has been damaged or if
  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
  compression.

    If deflate returns with avail_out == 0, this function must be called again
  with the same value of the flush parameter and more output space (updated
  avail_out), until the flush is complete (deflate returns with non-zero
  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
  avail_out is greater than six to avoid repeated flush markers due to
  avail_out == 0 on return.

    If the parameter flush is set to Z_FINISH, pending input is processed,
  pending output is flushed and deflate returns with Z_STREAM_END if there was
  enough output space; if deflate returns with Z_OK, this function must be
  called again with Z_FINISH and more output space (updated avail_out) but no
  more input data, until it returns with Z_STREAM_END or an error.  After
  deflate has returned Z_STREAM_END, the only possible operations on the stream
  are deflateReset or deflateEnd.

    Z_FINISH can be used immediately after deflateInit if all the compression
  is to be done in a single step.  In this case, avail_out must be at least the
  value returned by deflateBound (see below).  Then deflate is guaranteed to
  return Z_STREAM_END.  If not enough output space is provided, deflate will
  not return Z_STREAM_END, and it must be called again as described above.

    deflate() sets strm->adler to the adler32 checksum of all input read
  so far (that is, total_in bytes).

    deflate() may update strm->data_type if it can make a good guess about
  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
  binary.  This field is only for information purposes and does not affect the
  compression algorithm in any manner.

    deflate() returns Z_OK if some progress has been made (more input
  processed or more output produced), Z_STREAM_END if all input has been
  consumed and all output has been produced (only when flush is set to
  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
  fatal, and deflate() can be called again with more input and more output
  space to continue compressing.
*/

 int deflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
   prematurely (some input or output was discarded).  In the error case, msg
   may be set but then points to a static string (which must not be
   deallocated).
*/

/*
 int inflateInit (z_streamp strm);

     Initializes the internal stream state for decompression.  The fields
   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
   exact value depends on the compression method), inflateInit determines the
   compression method from the zlib header and allocates all data structures
   accordingly; otherwise the allocation will be deferred to the first call of
   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
   use default allocation functions.

     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit() does not process any header information -- that is deferred
   until inflate() is called.
*/

 int inflate (z_streamp strm, int flush);
/*
    inflate decompresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

  The detailed semantics are as follows.  inflate performs one or both of the
  following actions:

  - Decompress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in is updated and processing will
    resume at this point for the next call of inflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  inflate() provides as much output as possible, until there is
    no more input data or no more space in the output buffer (see below about
    the flush parameter).

    Before the call of inflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating the next_* and avail_* values accordingly.  The
  application can consume the uncompressed output when it wants, for example
  when the output buffer is full (avail_out == 0), or after each call of
  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
  called again after making room in the output buffer because there might be
  more output pending.

    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
  output as possible to the output buffer.  Z_BLOCK requests that inflate()
  stop if and when it gets to the next deflate block boundary.  When decoding
  the zlib or gzip format, this will cause inflate() to return immediately
  after the header and before the first block.  When doing a raw inflate,
  inflate() will go ahead and process the first block, and will return when it
  gets to the end of that block, or when it runs out of data.

    The Z_BLOCK option assists in appending to or combining deflate streams.
  Also to assist in this, on return inflate() will set strm->data_type to the
  number of unused bits in the last byte taken from strm->next_in, plus 64 if
  inflate() is currently decoding the last block in the deflate stream, plus
  128 if inflate() returned immediately after decoding an end-of-block code or
  decoding the complete header up to just before the first byte of the deflate
  stream.  The end-of-block will not be indicated until all of the uncompressed
  data from that block has been written to strm->next_out.  The number of
  unused bits may in general be greater than seven, except when bit 7 of
  data_type is set, in which case the number of unused bits will be less than
  eight.  data_type is set as noted here every time inflate() returns for all
  flush options, and so can be used to determine the amount of currently
  consumed input in bits.

    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
  end of each deflate block header is reached, before any actual data in that
  block is decoded.  This allows the caller to determine the length of the
  deflate block header for later use in random access within a deflate block.
  256 is added to the value of strm->data_type when inflate() returns
  immediately after reaching the end of the deflate block header.

    inflate() should normally be called until it returns Z_STREAM_END or an
  error.  However if all decompression is to be performed in a single step (a
  single call of inflate), the parameter flush should be set to Z_FINISH.  In
  this case all pending input is processed and all pending output is flushed;
  avail_out must be large enough to hold all of the uncompressed data for the
  operation to complete.  (The size of the uncompressed data may have been
  saved by the compressor for this purpose.) The use of Z_FINISH is not
  required to perform an inflation in one step.  However it may be used to
  inform inflate that a faster approach can be used for the single inflate()
  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
  stream completes, which reduces inflate's memory footprint.  If the stream
  does not complete, either because not all of the stream is provided or not
  enough output space is provided, then a sliding window will be allocated and
  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
  been used.

     In this implementation, inflate() always flushes as much output as
  possible to the output buffer, and always uses the faster approach on the
  first call.  So the effects of the flush parameter in this implementation are
  on the return value of inflate() as noted below, when inflate() returns early
  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
  memory for a sliding window when Z_FINISH is used.

     If a preset dictionary is needed after this call (see inflateSetDictionary
  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
  strm->adler to the Adler-32 checksum of all output produced so far (that is,
  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
  below.  At the end of the stream, inflate() checks that its computed adler32
  checksum is equal to that saved by the compressor and returns Z_STREAM_END
  only if the checksum is correct.

    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
  deflate data.  The header type is detected automatically, if requested when
  initializing with inflateInit2().  Any information contained in the gzip
  header is not retained, so applications that need that information should
  instead use raw inflate, see inflateInit2() below, or inflateBack() and
  perform their own processing of the gzip header and trailer.  When processing
  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
  produced so far.  The CRC-32 is checked against the gzip trailer.

    inflate() returns Z_OK if some progress has been made (more input processed
  or more output produced), Z_STREAM_END if the end of the compressed data has
  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
  corrupted (input stream not conforming to the zlib format or incorrect check
  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
  inflate() can be called again with more input and more output space to
  continue decompressing.  If Z_DATA_ERROR is returned, the application may
  then call inflateSync() to look for a good compression block if a partial
  recovery of the data is desired.
*/

 int inflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
   was inconsistent.  In the error case, msg may be set but then points to a
   static string (which must not be deallocated).
*/

                        /* Advanced functions */

/*
    The following functions are needed only in some special applications.
*/

/*
 int deflateInit2 (z_streamp strm,
                                     int  level,
                                     int  method,
                                     int  windowBits,
                                     int  memLevel,
                                     int  strategy);

     This is another version of deflateInit with more compression options.  The
   fields next_in, zalloc, zfree and opaque must be initialized before by the
   caller.

     The method parameter is the compression method.  It must be Z_DEFLATED in
   this version of the library.

     The windowBits parameter is the base two logarithm of the window size
   (the size of the history buffer).  It should be in the range 8..15 for this
   version of the library.  Larger values of this parameter result in better
   compression at the expense of memory usage.  The default value is 15 if
   deflateInit is used instead.

     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
   determines the window size.  deflate() will then generate raw deflate data
   with no zlib header or trailer, and will not compute an adler32 check value.

     windowBits can also be greater than 15 for optional gzip encoding.  Add
   16 to windowBits to write a simple gzip header and trailer around the
   compressed data instead of a zlib wrapper.  The gzip header will have no
   file name, no extra data, no comment, no modification time (set to zero), no
   header crc, and the operating system will be set to 255 (unknown).  If a
   gzip stream is being written, strm->adler is a crc32 instead of an adler32.

     The memLevel parameter specifies how much memory should be allocated
   for the internal compression state.  memLevel=1 uses minimum memory but is
   slow and reduces compression ratio; memLevel=9 uses maximum memory for
   optimal speed.  The default value is 8.  See zconf.h for total memory usage
   as a function of windowBits and memLevel.

     The strategy parameter is used to tune the compression algorithm.  Use the
   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
   string match), or Z_RLE to limit match distances to one (run-length
   encoding).  Filtered data consists mostly of small values with a somewhat
   random distribution.  In this case, the compression algorithm is tuned to
   compress them better.  The effect of Z_FILTERED is to force more Huffman
   coding and less string matching; it is somewhat intermediate between
   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
   strategy parameter only affects the compression ratio but not the
   correctness of the compressed output even if it is not set appropriately.
   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
   decoder for special applications.

     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
   set to null if there is no error message.  deflateInit2 does not perform any
   compression: this will be done by deflate().
*/

 int deflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the compression dictionary from the given byte sequence
   without producing any compressed output.  When using the zlib format, this
   function must be called immediately after deflateInit, deflateInit2 or
   deflateReset, and before any call of deflate.  When doing raw deflate, this
   function must be called either before any call of deflate, or immediately
   after the completion of a deflate block, i.e. after all input has been
   consumed and all output has been delivered when using any of the flush
   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
   compressor and decompressor must use exactly the same dictionary (see
   inflateSetDictionary).

     The dictionary should consist of strings (byte sequences) that are likely
   to be encountered later in the data to be compressed, with the most commonly
   used strings preferably put towards the end of the dictionary.  Using a
   dictionary is most useful when the data to be compressed is short and can be
   predicted with good accuracy; the data can then be compressed better than
   with the default empty dictionary.

     Depending on the size of the compression data structures selected by
   deflateInit or deflateInit2, a part of the dictionary may in effect be
   discarded, for example if the dictionary is larger than the window size
   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
   useful should be put at the end of the dictionary, not at the front.  In
   addition, the current implementation of deflate will use at most the window
   size minus 262 bytes of the provided dictionary.

     Upon return of this function, strm->adler is set to the adler32 value
   of the dictionary; the decompressor may later use this value to determine
   which dictionary has been used by the compressor.  (The adler32 value
   applies to the whole dictionary even if only a subset of the dictionary is
   actually used by the compressor.) If a raw deflate was requested, then the
   adler32 value is not computed and strm->adler is not set.

     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent (for example if deflate has already been called for this stream
   or if not at a block boundary for raw deflate).  deflateSetDictionary does
   not perform any compression: this will be done by deflate().
*/

 int deflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when several compression strategies will be
   tried, for example when there are several ways of pre-processing the input
   data with a filter.  The streams that will be discarded should then be freed
   by calling deflateEnd.  Note that deflateCopy duplicates the internal
   compression state which can be quite large, so this strategy is slow and can
   consume lots of memory.

     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int deflateReset (z_streamp strm);
/*
     This function is equivalent to deflateEnd followed by deflateInit,
   but does not free and reallocate all the internal compression state.  The
   stream will keep the same compression level and any other attributes that
   may have been set by deflateInit2.

     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int deflateParams (z_streamp strm,
                                      int level,
                                      int strategy);
/*
     Dynamically update the compression level and compression strategy.  The
   interpretation of level and strategy is as in deflateInit2.  This can be
   used to switch between compression and straight copy of the input data, or
   to switch to a different kind of input data requiring a different strategy.
   If the compression level is changed, the input available so far is
   compressed with the old level (and may be flushed); the new level will take
   effect only at the next call of deflate().

     Before the call of deflateParams, the stream state must be set as for
   a call of deflate(), since the currently available input may have to be
   compressed and flushed.  In particular, strm->avail_out must be non-zero.

     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
   strm->avail_out was zero.
*/

 int deflateTune (z_streamp strm,
                                    int good_length,
                                    int max_lazy,
                                    int nice_length,
                                    int max_chain);
/*
     Fine tune deflate's internal compression parameters.  This should only be
   used by someone who understands the algorithm used by zlib's deflate for
   searching for the best matching string, and even then only by the most
   fanatic optimizer trying to squeeze out the last compressed bit for their
   specific input data.  Read the deflate.c source code for the meaning of the
   max_lazy, good_length, nice_length, and max_chain parameters.

     deflateTune() can be called after deflateInit() or deflateInit2(), and
   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
 */

 uLong deflateBound (z_streamp strm,
                                       uLong sourceLen);
/*
     deflateBound() returns an upper bound on the compressed size after
   deflation of sourceLen bytes.  It must be called after deflateInit() or
   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
   to allocate an output buffer for deflation in a single pass, and so would be
   called before deflate().  If that first deflate() call is provided the
   sourceLen input bytes, an output buffer allocated to the size returned by
   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
   to return Z_STREAM_END.  Note that it is possible for the compressed size to
   be larger than the value returned by deflateBound() if flush options other
   than Z_FINISH or Z_NO_FLUSH are used.
*/

 int deflatePending (z_streamp strm,
                                       unsigned *pending,
                                       int *bits);
/*
     deflatePending() returns the number of bytes and bits of output that have
   been generated, but not yet provided in the available output.  The bytes not
   provided would be due to the available output space having being consumed.
   The number of bits of output not provided are between 0 and 7, where they
   await more bits to join them in order to fill out a full byte.  If pending
   or bits are Z_NULL, then those values are not set.

     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
 */

 int deflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     deflatePrime() inserts bits in the deflate output stream.  The intent
   is that this function is used to start off the deflate output with the bits
   leftover from a previous deflate stream when appending to it.  As such, this
   function can only be used for raw deflate, and must be used before the first
   deflate() call after a deflateInit2() or deflateReset().  bits must be less
   than or equal to 16, and that many of the least significant bits of value
   will be inserted in the output.

     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
   source stream state was inconsistent.
*/

 int deflateSetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     deflateSetHeader() provides gzip header information for when a gzip
   stream is requested by deflateInit2().  deflateSetHeader() may be called
   after deflateInit2() or deflateReset() and before the first call of
   deflate().  The text, time, os, extra field, name, and comment information
   in the provided gz_header structure are written to the gzip header (xflag is
   ignored -- the extra flags are set according to the compression level).  The
   caller must assure that, if not Z_NULL, name and comment are terminated with
   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
   available there.  If hcrc is true, a gzip header crc is included.  Note that
   the current versions of the command-line version of gzip (up through version
   1.3.x) do not support header crc's, and will report that it is a "multi-part
   gzip file" and give up.

     If deflateSetHeader is not used, the default gzip header has text false,
   the time set to zero, and os set to 255, with no extra, name, or comment
   fields.  The gzip header is returned to the default state by deflateReset().

     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int inflateInit2 (z_streamp strm,
                                     int  windowBits);

     This is another version of inflateInit with an extra parameter.  The
   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
   before by the caller.

     The windowBits parameter is the base two logarithm of the maximum window
   size (the size of the history buffer).  It should be in the range 8..15 for
   this version of the library.  The default value is 15 if inflateInit is used
   instead.  windowBits must be greater than or equal to the windowBits value
   provided to deflateInit2() while compressing, or it must be equal to 15 if
   deflateInit2() was not used.  If a compressed stream with a larger window
   size is given as input, inflate() will return with the error code
   Z_DATA_ERROR instead of trying to allocate a larger window.

     windowBits can also be zero to request that inflate use the window size in
   the zlib header of the compressed stream.

     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
   determines the window size.  inflate() will then process raw deflate data,
   not looking for a zlib or gzip header, not generating a check value, and not
   looking for any check values for comparison at the end of the stream.  This
   is for use with other formats that use the deflate compressed data format
   such as zip.  Those formats provide their own check values.  If a custom
   format is developed using the raw deflate format for compressed data, it is
   recommended that a check value such as an adler32 or a crc32 be applied to
   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
   most applications, the zlib format should be used as is.  Note that comments
   above on the use in deflateInit2() applies to the magnitude of windowBits.

     windowBits can also be greater than 15 for optional gzip decoding.  Add
   32 to windowBits to enable zlib and gzip decoding with automatic header
   detection, or add 16 to decode only the gzip format (the zlib format will
   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
   crc32 instead of an adler32.

     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit2 does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit2() does not process any header information -- that is
   deferred until inflate() is called.
*/

 int inflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the decompression dictionary from the given uncompressed byte
   sequence.  This function must be called immediately after a call of inflate,
   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
   can be determined from the adler32 value returned by that call of inflate.
   The compressor and decompressor must use exactly the same dictionary (see
   deflateSetDictionary).  For raw inflate, this function can be called at any
   time to set the dictionary.  If the provided dictionary is smaller than the
   window and there is already data in the window, then the provided dictionary
   will amend what's there.  The application must insure that the dictionary
   that was used for compression is provided.

     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
   expected one (incorrect adler32 value).  inflateSetDictionary does not
   perform any decompression: this will be done by subsequent calls of
   inflate().
*/

 int inflateGetDictionary (z_streamp strm,
                                             Bytef *dictionary,
                                             uInt  *dictLength);
/*
     Returns the sliding dictionary being maintained by inflate.  dictLength is
   set to the number of bytes in the dictionary, and that many bytes are copied
   to dictionary.  dictionary must have enough space, where 32768 bytes is
   always enough.  If inflateGetDictionary() is called with dictionary equal to
   Z_NULL, then only the dictionary length is returned, and nothing is copied.
   Similarly, if dictLength is Z_NULL, then it is not set.

     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
   stream state is inconsistent.
*/

 int inflateSync (z_streamp strm);
/*
     Skips invalid compressed data until a possible full flush point (see above
   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
   available input is skipped.  No output is provided.

     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
   All full flush points have this pattern, but not all occurrences of this
   pattern are full flush points.

     inflateSync returns Z_OK if a possible full flush point has been found,
   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
   In the success case, the application may save the current current value of
   total_in which indicates where valid compressed data was found.  In the
   error case, the application may repeatedly call inflateSync, providing more
   input each time, until success or end of the input data.
*/

 int inflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when randomly accessing a large stream.  The
   first pass through the stream can periodically record the inflate state,
   allowing restarting inflate at those points when randomly accessing the
   stream.

     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int inflateReset (z_streamp strm);
/*
     This function is equivalent to inflateEnd followed by inflateInit,
   but does not free and reallocate all the internal decompression state.  The
   stream will keep attributes that may have been set by inflateInit2.

     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int inflateReset2 (z_streamp strm,
                                      int windowBits);
/*
     This function is the same as inflateReset, but it also permits changing
   the wrap and window size requests.  The windowBits parameter is interpreted
   the same as it is for inflateInit2.

     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
   the windowBits parameter is invalid.
*/

 int inflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     This function inserts bits in the inflate input stream.  The intent is
   that this function is used to start inflating at a bit position in the
   middle of a byte.  The provided bits will be used before any bytes are used
   from next_in.  This function should only be used with raw inflate, and
   should be used before the first inflate() call after inflateInit2() or
   inflateReset().  bits must be less than or equal to 16, and that many of the
   least significant bits of value will be inserted in the input.

     If bits is negative, then the input stream bit buffer is emptied.  Then
   inflatePrime() can be called again to put bits in the buffer.  This is used
   to clear out bits leftover after feeding inflate a block description prior
   to feeding inflate codes.

     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

 long  inflateMark (z_streamp strm);
/*
     This function returns two values, one in the lower 16 bits of the return
   value, and the other in the remaining upper bits, obtained by shifting the
   return value down 16 bits.  If the upper value is -1 and the lower value is
   zero, then inflate() is currently decoding information outside of a block.
   If the upper value is -1 and the lower value is non-zero, then inflate is in
   the middle of a stored block, with the lower value equaling the number of
   bytes from the input remaining to copy.  If the upper value is not -1, then
   it is the number of bits back from the current bit position in the input of
   the code (literal or length/distance pair) currently being processed.  In
   that case the lower value is the number of bytes already emitted for that
   code.

     A code is being processed if inflate is waiting for more input to complete
   decoding of the code, or if it has completed decoding but is waiting for
   more output space to write the literal or match data.

     inflateMark() is used to mark locations in the input data for random
   access, which may be at bit positions, and to note those cases where the
   output of a code may span boundaries of random access blocks.  The current
   location in the input stream can be determined from avail_in and data_type
   as noted in the description for the Z_BLOCK flush parameter for inflate.

     inflateMark returns the value noted above or -1 << 16 if the provided
   source stream state was inconsistent.
*/

 int  inflateGetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     inflateGetHeader() requests that gzip header information be stored in the
   provided gz_header structure.  inflateGetHeader() may be called after
   inflateInit2() or inflateReset(), and before the first call of inflate().
   As inflate() processes the gzip stream, head->done is zero until the header
   is completed, at which time head->done is set to one.  If a zlib stream is
   being decoded, then head->done is set to -1 to indicate that there will be
   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
   used to force inflate() to return immediately after header processing is
   complete and before any actual data is decompressed.

     The text, time, xflags, and os fields are filled in with the gzip header
   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
   contains the maximum number of bytes to write to extra.  Once done is true,
   extra_len contains the actual extra field length, and extra contains the
   extra field, or that field truncated if extra_max is less than extra_len.
   If name is not Z_NULL, then up to name_max characters are written there,
   terminated with a zero unless the length is greater than name_max.  If
   comment is not Z_NULL, then up to comm_max characters are written there,
   terminated with a zero unless the length is greater than comm_max.  When any
   of extra, name, or comment are not Z_NULL and the respective field is not
   present in the header, then that field is set to Z_NULL to signal its
   absence.  This allows the use of deflateSetHeader() with the returned
   structure to duplicate the header.  However if those fields are set to
   allocated memory, then the application will need to save those pointers
   elsewhere so that they can be eventually freed.

     If inflateGetHeader is not used, then the header information is simply
   discarded.  The header is always checked for validity, including the header
   CRC if present.  inflateReset() will reset the process to discard the header
   information.  The application would need to call inflateGetHeader() again to
   retrieve the header from the next gzip stream.

     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int  inflateBackInit (z_streamp strm, int windowBits,
                                        unsigned char FAR *window);

     Initialize the internal stream state for decompression using inflateBack()
   calls.  The fields zalloc, zfree and opaque in strm must be initialized
   before the call.  If zalloc and zfree are Z_NULL, then the default library-
   derived memory allocation routines are used.  windowBits is the base two
   logarithm of the window size, in the range 8..15.  window is a caller
   supplied buffer of that size.  Except for special applications where it is
   assured that deflate was used with small window sizes, windowBits must be 15
   and a 32K byte window must be supplied to be able to decompress general
   deflate streams.

     See inflateBack() for the usage of these routines.

     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
   allocated, or Z_VERSION_ERROR if the version of the library does not match
   the version of the header file.
*/

typedef unsigned (*in_func) (void FAR *,
                                z_const unsigned char FAR * FAR *);
typedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);

 int  inflateBack (z_streamp strm,
                                    in_func in, void FAR *in_desc,
                                    out_func out, void FAR *out_desc);
/*
     inflateBack() does a raw inflate with a single call using a call-back
   interface for input and output.  This is potentially more efficient than
   inflate() for file i/o applications, in that it avoids copying between the
   output and the sliding window by simply making the window itself the output
   buffer.  inflate() can be faster on modern CPUs when used with large
   buffers.  inflateBack() trusts the application to not change the output
   buffer passed by the output function, at least until inflateBack() returns.

     inflateBackInit() must be called first to allocate the internal state
   and to initialize the state with the user-provided window buffer.
   inflateBack() may then be used multiple times to inflate a complete, raw
   deflate stream with each call.  inflateBackEnd() is then called to free the
   allocated state.

     A raw deflate stream is one with no zlib or gzip header or trailer.
   This routine would normally be used in a utility that reads zip or gzip
   files and writes out uncompressed files.  The utility would decode the
   header and process the trailer on its own, hence this routine expects only
   the raw deflate stream to decompress.  This is different from the normal
   behavior of inflate(), which expects either a zlib or gzip header and
   trailer around the deflate stream.

     inflateBack() uses two subroutines supplied by the caller that are then
   called by inflateBack() for input and output.  inflateBack() calls those
   routines until it reads a complete deflate stream and writes out all of the
   uncompressed data, or until it encounters an error.  The function's
   parameters and return types are defined above in the in_func and out_func
   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
   number of bytes of provided input, and a pointer to that input in buf.  If
   there is no input available, in() must return zero--buf is ignored in that
   case--and inflateBack() will return a buffer error.  inflateBack() will call
   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
   should return zero on success, or non-zero on failure.  If out() returns
   non-zero, inflateBack() will return with an error.  Neither in() nor out()
   are permitted to change the contents of the window provided to
   inflateBackInit(), which is also the buffer that out() uses to write from.
   The length written by out() will be at most the window size.  Any non-zero
   amount of input may be provided by in().

     For convenience, inflateBack() can be provided input on the first call by
   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
   in() will be called.  Therefore strm->next_in must be initialized before
   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
   must also be initialized, and then if strm->avail_in is not zero, input will
   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].

     The in_desc and out_desc parameters of inflateBack() is passed as the
   first parameter of in() and out() respectively when they are called.  These
   descriptors can be optionally used to pass any information that the caller-
   supplied in() and out() functions need to do their job.

     On return, inflateBack() will set strm->next_in and strm->avail_in to
   pass back any unused input that was provided by the last in() call.  The
   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
   in the deflate stream (in which case strm->msg is set to indicate the nature
   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
   In the case of Z_BUF_ERROR, an input or output error can be distinguished
   using strm->next_in which will be Z_NULL only if in() returned an error.  If
   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
   non-zero.  (in() will always be called before out(), so strm->next_in is
   assured to be defined if out() returns non-zero.) Note that inflateBack()
   cannot return Z_OK.
*/

 int  inflateBackEnd (z_streamp strm);
/*
     All memory allocated by inflateBackInit() is freed.

     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
   state was inconsistent.
*/

 uLong  zlibCompileFlags (void);
/* Return flags indicating compile-time options.

    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
     1.0: size of uInt
     3.2: size of uLong
     5.4: size of voidpf (pointer)
     7.6: size of z_off_t

    Compiler, assembler, and debug options:
     8: DEBUG
     9: ASMV or ASMINF -- use ASM code
     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
     11: 0 (reserved)

    One-time table building (smaller code, but not thread-safe if true):
     12: BUILDFIXED -- build static block decoding tables when needed
     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
     14,15: 0 (reserved)

    Library content (indicates missing functionality):
     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
                          deflate code when not needed)
     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
                    and decode gzip streams (to avoid linking crc code)
     18-19: 0 (reserved)

    Operation variations (changes in library functionality):
     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
     21: FASTEST -- deflate algorithm with only one, lowest compression level
     22,23: 0 (reserved)

    The sprintf variant used by gzprintf (zero is best):
     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
     26: 0 = returns value, 1 = void -- 1 means inferred string length returned

    Remainder:
     27-31: 0 (reserved)
 */

#ifndef Z_SOLO

                        /* utility functions */

/*
     The following utility functions are implemented on top of the basic
   stream-oriented functions.  To simplify the interface, some default options
   are assumed (compression level and memory usage, standard memory allocation
   functions).  The source code of these utility functions can be modified if
   you need special options.
*/

 int  compress (Bytef *dest,   uLongf *destLen,
                                 const Bytef *source, uLong sourceLen);
/*
     Compresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer.
*/

 int  compress2 (Bytef *dest,   uLongf *destLen,
                                  const Bytef *source, uLong sourceLen,
                                  int level);
/*
     Compresses the source buffer into the destination buffer.  The level
   parameter has the same meaning as in deflateInit.  sourceLen is the byte
   length of the source buffer.  Upon entry, destLen is the total size of the
   destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
   Z_STREAM_ERROR if the level parameter is invalid.
*/

 uLong  compressBound (uLong sourceLen);
/*
     compressBound() returns an upper bound on the compressed size after
   compress() or compress2() on sourceLen bytes.  It would be used before a
   compress() or compress2() call to allocate the destination buffer.
*/

 int  uncompress (unsigned char *dest,   uint32_t *destLen,
       const unsigned char *source, uint32_t sourceLen);
/*
     Decompresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be large enough to hold the entire
   uncompressed data.  (The size of the uncompressed data must have been saved
   previously by the compressor and transmitted to the decompressor by some
   mechanism outside the scope of this compression library.) Upon exit, destLen
   is the actual size of the uncompressed buffer.

     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
   the case where there is not enough room, uncompress() will fill the output
   buffer with the uncompressed data up to that point.
*/

                        /* gzip file access functions */

/*
     This library supports reading and writing files in gzip (.gz) format with
   an interface similar to that of stdio, using the functions that start with
   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
   wrapper, documented in RFC 1952, wrapped around a deflate stream.
*/

typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */

/*
 gzFile  gzopen (const char *path, const char *mode);

     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
   for fixed code compression as in "wb9F".  (See the description of
   deflateInit2 for more information about the strategy parameter.)  'T' will
   request transparent writing or appending with no compression and not using
   the gzip format.

     "a" can be used instead of "w" to request that the gzip stream that will
   be written be appended to the file.  "+" will result in an error, since
   reading and writing to the same gzip file is not supported.  The addition of
   "x" when writing will create the file exclusively, which fails if the file
   already exists.  On systems that support it, the addition of "e" when
   reading or writing will set the flag to close the file on an execve() call.

     These functions, as well as gzip, will read and decode a sequence of gzip
   streams in a file.  The append function of gzopen() can be used to create
   such a file.  (Also see gzflush() for another way to do this.)  When
   appending, gzopen does not test whether the file begins with a gzip stream,
   nor does it look for the end of the gzip streams to begin appending.  gzopen
   will simply append a gzip stream to the existing file.

     gzopen can be used to read a file which is not in gzip format; in this
   case gzread will directly read from the file without decompression.  When
   reading, this will be detected automatically by looking for the magic two-
   byte gzip header.

     gzopen returns NULL if the file could not be opened, if there was
   insufficient memory to allocate the gzFile state, or if an invalid mode was
   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
   errno can be checked to determine if the reason gzopen failed was that the
   file could not be opened.
*/

 gzFile  gzdopen (int fd, const char *mode);
/*
     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
   are obtained from calls like open, dup, creat, pipe or fileno (if the file
   has been previously opened with fopen).  The mode parameter is as in gzopen.

     The next call of gzclose on the returned gzFile will also close the file
   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
   mode);.  The duplicated descriptor should be saved to avoid a leak, since
   gzdopen does not close fd if it fails.  If you are using fileno() to get the
   file descriptor from a FILE *, then you will have to use dup() to avoid
   double-close()ing the file descriptor.  Both gzclose() and fclose() will
   close the associated file descriptor, so they need to have different file
   descriptors.

     gzdopen returns NULL if there was insufficient memory to allocate the
   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
   used until the next gz* read, write, seek, or close operation, so gzdopen
   will not detect if fd is invalid (unless fd is -1).
*/

 int  gzbuffer (gzFile file, unsigned size);
/*
     Set the internal buffer size used by this library's functions.  The
   default buffer size is 8192 bytes.  This function must be called after
   gzopen() or gzdopen(), and before any other calls that read or write the
   file.  The buffer memory allocation is always deferred to the first read or
   write.  Two buffers are allocated, either both of the specified size when
   writing, or one of the specified size and the other twice that size when
   reading.  A larger buffer size of, for example, 64K or 128K bytes will
   noticeably increase the speed of decompression (reading).

     The new buffer size also affects the maximum length for gzprintf().

     gzbuffer() returns 0 on success, or -1 on failure, such as being called
   too late.
*/

 int  gzsetparams (gzFile file, int level, int strategy);
/*
     Dynamically update the compression level or strategy.  See the description
   of deflateInit2 for the meaning of these parameters.

     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
   opened for writing.
*/

 int  gzread (gzFile file, voidp buf, unsigned len);
/*
     Reads the given number of uncompressed bytes from the compressed file.  If
   the input file is not in gzip format, gzread copies the given number of
   bytes into the buffer directly from the file.

     After reaching the end of a gzip stream in the input, gzread will continue
   to read, looking for another gzip stream.  Any number of gzip streams may be
   concatenated in the input file, and will all be decompressed by gzread().
   If something other than a gzip stream is encountered after a gzip stream,
   that remaining trailing garbage is ignored (and no error is returned).

     gzread can be used to read a gzip file that is being concurrently written.
   Upon reaching the end of the input, gzread will return with the available
   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
   gzclearerr can be used to clear the end of file indicator in order to permit
   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
   middle of a gzip stream.  Note that gzread does not return -1 in the event
   of an incomplete gzip stream.  This error is deferred until gzclose(), which
   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
   stream.  Alternatively, gzerror can be used before gzclose to detect this
   case.

     gzread returns the number of uncompressed bytes actually read, less than
   len for end of file, or -1 for error.
*/

 int  gzwrite (gzFile file,
                                voidpc buf, unsigned len);
/*
     Writes the given number of uncompressed bytes into the compressed file.
   gzwrite returns the number of uncompressed bytes written or 0 in case of
   error.
*/

 int gzprintf Z_ARG((gzFile file, const char *format, ...));
/*
     Converts, formats, and writes the arguments to the compressed file under
   control of the format string, as in fprintf.  gzprintf returns the number of
   uncompressed bytes actually written, or 0 in case of error.  The number of
   uncompressed bytes written is limited to 8191, or one less than the buffer
   size given to gzbuffer().  The caller should assure that this limit is not
   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
   nothing written.  In this case, there may also be a buffer overflow with
   unpredictable consequences, which is possible only if zlib was compiled with
   the insecure functions sprintf() or vsprintf() because the secure snprintf()
   or vsnprintf() functions were not available.  This can be determined using
   zlibCompileFlags().
*/

 int  gzputs (gzFile file, const char *s);
/*
     Writes the given null-terminated string to the compressed file, excluding
   the terminating null character.

     gzputs returns the number of characters written, or -1 in case of error.
*/

 char *  gzgets (gzFile file, char *buf, int len);
/*
     Reads bytes from the compressed file until len-1 characters are read, or a
   newline character is read and transferred to buf, or an end-of-file
   condition is encountered.  If any characters are read or if len == 1, the
   string is terminated with a null character.  If no characters are read due
   to an end-of-file or len < 1, then the buffer is left untouched.

     gzgets returns buf which is a null-terminated string, or it returns NULL
   for end-of-file or in case of error.  If there was an error, the contents at
   buf are indeterminate.
*/

 int  gzputc (gzFile file, int c);
/*
     Writes c, converted to an unsigned char, into the compressed file.  gzputc
   returns the value that was written, or -1 in case of error.
*/

 int  gzgetc (gzFile file);
/*
     Reads one byte from the compressed file.  gzgetc returns this byte or -1
   in case of end of file or error.  This is implemented as a macro for speed.
   As such, it does not do all of the checking the other functions do.  I.e.
   it does not check to see if file is NULL, nor whether the structure file
   points to has been clobbered or not.
*/

 int  gzungetc (int c, gzFile file);
/*
     Push one character back onto the stream to be read as the first character
   on the next read.  At least one character of push-back is allowed.
   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
   fail if c is -1, and may fail if a character has been pushed but not read
   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
   The pushed character will be discarded if the stream is repositioned with
   gzseek() or gzrewind().
*/

 int  gzflush (gzFile file, int flush);
/*
     Flushes all pending output into the compressed file.  The parameter flush
   is as in the deflate() function.  The return value is the zlib error number
   (see function gzerror below).  gzflush is only permitted when writing.

     If the flush parameter is Z_FINISH, the remaining data is written and the
   gzip stream is completed in the output.  If gzwrite() is called again, a new
   gzip stream will be started in the output.  gzread() is able to read such
   concatenated gzip streams.

     gzflush should be called only when strictly necessary because it will
   degrade compression if called too often.
*/

/*
 z_off_t  gzseek (gzFile file,
                                   z_off_t offset, int whence);

     Sets the starting position for the next gzread or gzwrite on the given
   compressed file.  The offset represents a number of bytes in the
   uncompressed data stream.  The whence parameter is defined as in lseek(2);
   the value SEEK_END is not supported.

     If the file is opened for reading, this function is emulated but can be
   extremely slow.  If the file is opened for writing, only forward seeks are
   supported; gzseek then compresses a sequence of zeroes up to the new
   starting position.

     gzseek returns the resulting offset location as measured in bytes from
   the beginning of the uncompressed stream, or -1 in case of error, in
   particular if the file is opened for writing and the new starting position
   would be before the current position.
*/

 int     gzrewind (gzFile file);
/*
     Rewinds the given file. This function is supported only for reading.

     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
*/

/*
 z_off_t     gztell (gzFile file);

     Returns the starting position for the next gzread or gzwrite on the given
   compressed file.  This position represents a number of bytes in the
   uncompressed data stream, and is zero when starting, even if appending or
   reading a gzip stream from the middle of a file using gzdopen().

     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
*/

/*
 z_off_t  gzoffset (gzFile file);

     Returns the current offset in the file being read or written.  This offset
   includes the count of bytes that precede the gzip stream, for example when
   appending or when using gzdopen() for reading.  When reading, the offset
   does not include as yet unused buffered input.  This information can be used
   for a progress indicator.  On error, gzoffset() returns -1.
*/

 int  gzeof (gzFile file);
/*
     Returns true (1) if the end-of-file indicator has been set while reading,
   false (0) otherwise.  Note that the end-of-file indicator is set only if the
   read tried to go past the end of the input, but came up short.  Therefore,
   just like feof(), gzeof() may return false even if there is no more data to
   read, in the event that the last read request was for the exact number of
   bytes remaining in the input file.  This will happen if the input file size
   is an exact multiple of the buffer size.

     If gzeof() returns true, then the read functions will return no more data,
   unless the end-of-file indicator is reset by gzclearerr() and the input file
   has grown since the previous end of file was detected.
*/

 int  gzdirect (gzFile file);
/*
     Returns true (1) if file is being copied directly while reading, or false
   (0) if file is a gzip stream being decompressed.

     If the input file is empty, gzdirect() will return true, since the input
   does not contain a gzip stream.

     If gzdirect() is used immediately after gzopen() or gzdopen() it will
   cause buffers to be allocated to allow reading the file to determine if it
   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
   gzdirect().

     When writing, gzdirect() returns true (1) if transparent writing was
   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
   gzdirect() is not needed when writing.  Transparent writing must be
   explicitly requested, so the application already knows the answer.  When
   linking statically, using gzdirect() will include all of the zlib code for
   gzip file reading and decompression, which may not be desired.)
*/

 int     gzclose (gzFile file);
/*
     Flushes all pending output if necessary, closes the compressed file and
   deallocates the (de)compression state.  Note that once file is closed, you
   cannot call gzerror with file, since its structures have been deallocated.
   gzclose must not be called more than once on the same file, just as free
   must not be called more than once on the same allocation.

     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
   last read ended in the middle of a gzip stream, or Z_OK on success.
*/

 int  gzclose_r (gzFile file);
 int  gzclose_w (gzFile file);
/*
     Same as gzclose(), but gzclose_r() is only for use when reading, and
   gzclose_w() is only for use when writing or appending.  The advantage to
   using these instead of gzclose() is that they avoid linking in zlib
   compression or decompression code that is not used when only reading or only
   writing respectively.  If gzclose() is used, then both compression and
   decompression code will be included the application when linking to a static
   zlib library.
*/

 const char *  gzerror (gzFile file, int *errnum);
/*
     Returns the error message for the last error which occurred on the given
   compressed file.  errnum is set to zlib error number.  If an error occurred
   in the file system and not in the compression library, errnum is set to
   Z_ERRNO and the application may consult errno to get the exact error code.

     The application must not modify the returned string.  Future calls to
   this function may invalidate the previously returned string.  If file is
   closed, then the string previously returned by gzerror will no longer be
   available.

     gzerror() should be used to distinguish errors from end-of-file for those
   functions above that do not distinguish those cases in their return values.
*/

 void  gzclearerr (gzFile file);
/*
     Clears the error and end-of-file flags for file.  This is analogous to the
   clearerr() function in stdio.  This is useful for continuing to read a gzip
   file that is being written concurrently.
*/

#endif /* !Z_SOLO */

                        /* checksum functions */

/*
     These functions are not related to compression but are exported
   anyway because they might be useful in applications using the compression
   library.
*/

uint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);
/*
     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
   return the updated checksum.  If buf is Z_NULL, this function returns the
   required initial value for the checksum.

     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
   much faster.

   Usage example:

     uLong adler = adler32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       adler = adler32(adler, buffer, length);
     }
     if (adler != original_adler) error();
*/

/*
 uLong  adler32_combine (uLong adler1, uLong adler2,
                                          z_off_t len2);

     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
   that the z_off_t type (like off_t) is a signed integer.  If len2 is
   negative, the result has no meaning or utility.
*/

 uLong  crc32   (uLong crc, const Bytef *buf, uInt len);
/*
     Update a running CRC-32 with the bytes buf[0..len-1] and return the
   updated CRC-32.  If buf is Z_NULL, this function returns the required
   initial value for the crc.  Pre- and post-conditioning (one's complement) is
   performed within this function so it shouldn't be done by the application.

   Usage example:

     uLong crc = crc32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       crc = crc32(crc, buffer, length);
     }
     if (crc != original_crc) error();
*/

/*
 uLong  crc32_combine (uLong crc1, uLong crc2, z_off_t len2);

     Combine two CRC-32 check values into one.  For two sequences of bytes,
   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
   len2.
*/

                        /* various hacks, don't look :) */

/* deflateInit and inflateInit are macros to allow checking the zlib version
 * and the compiler's view of z_stream:
 */
 int  deflateInit_ (z_streamp strm, int level,
                                     const char *version, int stream_size);
 int  inflateInit_ (z_streamp strm,
                                     const char *version, int stream_size);
 int  deflateInit2_ (z_streamp strm, int  level, int  method,
                                      int windowBits, int memLevel,
                                      int strategy, const char *version,
                                      int stream_size);
 int  inflateInit2_ (z_streamp strm, int  windowBits,
                                      const char *version, int stream_size);
 int  inflateBackInit_ (z_streamp strm, int windowBits,
                                         unsigned char FAR *window,
                                         const char *version,
                                         int stream_size);
#define deflateInit(strm, level) \
        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit(strm) \
        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit2(strm, windowBits) \
        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
                      (int)sizeof(z_stream))
#define inflateBackInit(strm, windowBits, window) \
        inflateBackInit_((strm), (windowBits), (window), \
                      ZLIB_VERSION, (int)sizeof(z_stream))

#ifndef Z_SOLO

/* gzgetc() macro and its supporting function and exposed data structure.  Note
 * that the real internal state is much larger than the exposed structure.
 * This abbreviated structure exposes just enough for the gzgetc() macro.  The
 * user should not mess with these exposed elements, since their names or
 * behavior could change in the future, perhaps even capriciously.  They can
 * only be used by the gzgetc() macro.  You have been warned.
 */
 int  gzgetc_ (gzFile file);  /* backward compatibility */
#ifdef Z_PREFIX_SET
#  undef z_gzgetc
#  define z_gzgetc(g) \
          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
#else
#  define gzgetc(g) \
          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
#endif

/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
 * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
 * both are true, the application gets the *64 functions, and the regular
 * functions are changed to 64 bits) -- in case these are set on systems
 * without large file support, _LFS64_LARGEFILE must also be true
 */
#ifdef Z_LARGE64
    gzFile  gzopen64 (const char *, const char *);
    z_off64_t  gzseek64 (gzFile, z_off64_t, int);
    z_off64_t  gztell64 (gzFile);
    z_off64_t  gzoffset64 (gzFile);
    uLong  adler32_combine64 (uLong, uLong, z_off64_t);
    uLong  crc32_combine64 (uLong, uLong, z_off64_t);
#endif

#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
#  ifdef Z_PREFIX_SET
#    define z_gzopen z_gzopen64
#    define z_gzseek z_gzseek64
#    define z_gztell z_gztell64
#    define z_gzoffset z_gzoffset64
#    define z_adler32_combine z_adler32_combine64
#    define z_crc32_combine z_crc32_combine64
#  else
#    define gzopen gzopen64
#    define gzseek gzseek64
#    define gztell gztell64
#    define gzoffset gzoffset64
#    define adler32_combine adler32_combine64
#    define crc32_combine crc32_combine64
#  endif
#  ifndef Z_LARGE64
      gzFile  gzopen64 (const char *, const char *);
      z_off_t  gzseek64 (gzFile, z_off_t, int);
      z_off_t  gztell64 (gzFile);
      z_off_t  gzoffset64 (gzFile);
      uLong  adler32_combine64 (uLong, uLong, z_off_t);
      uLong  crc32_combine64 (uLong, uLong, z_off_t);
#  endif
#else
    gzFile  gzopen (const char *, const char *);
    z_off_t  gzseek (gzFile, z_off_t, int);
    z_off_t  gztell (gzFile);
    z_off_t  gzoffset (gzFile);
    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);
#endif

#else /* Z_SOLO */

    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);

#endif /* !Z_SOLO */

/* hack for buggy compilers */
#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
    struct internal_state {int dummy;};
#endif

/* undocumented functions */
 const char   *  zError           (int);
 int             inflateSyncPoint (z_streamp);

const uint32_t * get_crc_table(void);
 int             inflateUndermine (z_streamp, int);
 int             inflateResetKeep (z_streamp);
 int             deflateResetKeep (z_streamp);
#if defined(_WIN32) && !defined(Z_SOLO)
 gzFile          gzopen_w (const wchar_t *path,
                                            const char *mode);
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
 int            gzvprintf Z_ARG((gzFile file,
                                                  const char *format,
                                                  va_list va));
#  endif
#endif

#ifdef __cplusplus
}
#endif

#endif /* ZLIB_H */

#endif

./include/libretro-common/include/compat/zlib/zutil.h

#ifndef _COMPAT_ZUTIL_H
#define _COMPAT_ZUTIL_H

#ifdef WANT_ZLIB

/* zutil.h -- internal interface and configuration of the compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* @(#) $Id$ */

#ifndef ZUTIL_H
#define ZUTIL_H

#ifdef HAVE_HIDDEN
#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
#  define ZLIB_INTERNAL
#endif

#include <zlib.h>

#if defined(STDC) && !defined(Z_SOLO)
#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))
#    include <stddef.h>
#  endif
#  include <string.h>
#  include <stdlib.h>
#endif

#ifdef Z_SOLO
   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
#endif

#ifndef local
#  define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */

typedef unsigned char  uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long  ulg;

extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
/* (array size given to avoid silly warnings with Visual C++) */
/* (array entry size given to avoid silly string cast warnings) */

#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]

#define ERR_RETURN(strm,err) \
  return (strm->msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */

        /* common constants */

#ifndef DEF_WBITS
#  define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */

#if MAX_MEM_LEVEL >= 8
#  define DEF_MEM_LEVEL 8
#else
#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
#endif
/* default memLevel */

#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES    2
/* The three kinds of block type */

#define MIN_MATCH  3
#define MAX_MATCH  258
/* The minimum and maximum match lengths */

#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */

        /* target dependencies */

#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
#  define OS_CODE  0x00
#  ifndef Z_SOLO
#    if defined(__TURBOC__) || defined(__BORLANDC__)
#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
         /* Allow compilation with ANSI keywords only enabled */
         void _Cdecl farfree( void *block );
         void *_Cdecl farmalloc( unsigned long nbytes );
#      else
#        include <alloc.h>
#      endif
#    else /* MSC or DJGPP */
#      include <malloc.h>
#    endif
#  endif
#endif

#ifdef AMIGA
#  define OS_CODE  0x01
#endif

#if defined(VAXC) || defined(VMS)
#  define OS_CODE  0x02
#  define F_OPEN(name, mode) \
     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif

#if defined(ATARI) || defined(atarist)
#  define OS_CODE  0x05
#endif

#ifdef OS2
#  define OS_CODE  0x06
#  if defined(M_I86) && !defined(Z_SOLO)
#    include <malloc.h>
#  endif
#endif

#if defined(MACOS) || defined(TARGET_OS_MAC)
#  define OS_CODE  0x07
#  ifndef Z_SOLO
#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
#      include <unix.h> /* for fdopen */
#    else
#      ifndef fdopen
#        define fdopen(fd,mode) NULL /* No fdopen() */
#      endif
#    endif
#  endif
#endif

#ifdef TOPS20
#  define OS_CODE  0x0a
#endif

#ifdef WIN32
#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
#    define OS_CODE  0x0b
#  endif
#endif

#ifdef __50SERIES /* Prime/PRIMOS */
#  define OS_CODE  0x0f
#endif

#if defined(_BEOS_) || defined(RISCOS)
#  define fdopen(fd,mode) NULL /* No fdopen() */
#endif

#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
#  if defined(_WIN32_WCE)
#    define fdopen(fd,mode) NULL /* No fdopen() */
#    ifndef _PTRDIFF_T_DEFINED
       typedef int ptrdiff_t;
#      define _PTRDIFF_T_DEFINED
#    endif
#  else
#    define fdopen(fd,type)  _fdopen(fd,type)
#  endif
#endif

#if defined(__BORLANDC__) && !defined(MSDOS)
  #pragma warn -8004
  #pragma warn -8008
  #pragma warn -8066
#endif

/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
    uLong adler32_combine64 (uLong, uLong, z_off_t);
    uLong crc32_combine64 (uLong, uLong, z_off_t);
#endif

        /* common defaults */

#ifndef OS_CODE
#  define OS_CODE  0x03  /* assume Unix */
#endif

#ifndef F_OPEN
#  define F_OPEN(name, mode) fopen((name), (mode))
#endif

         /* functions */

#if defined(pyr) || defined(Z_SOLO)
#  define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
 /* Use our own functions for small and medium model with MSC <= 5.0.
  * You may have to use the same strategy for Borland C (untested).
  * The __SC__ check is for Symantec.
  */
#  define NO_MEMCPY
#endif
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
#  define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
#    define zmemcpy _fmemcpy
#    define zmemcmp _fmemcmp
#    define zmemzero(dest, len) _fmemset(dest, 0, len)
#  else
#    define zmemcpy memcpy
#    define zmemcmp memcmp
#    define zmemzero(dest, len) memset(dest, 0, len)
#  endif
#else
   void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
   int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
   void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
#endif

/* Diagnostic functions */
#  define Assert(cond,msg)
#  define Trace(x)
#  define Tracev(x)
#  define Tracevv(x)
#  define Tracec(c,x)
#  define Tracecv(c,x)

#ifndef Z_SOLO
   voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
                                    unsigned size);
   void ZLIB_INTERNAL zcfree  (voidpf opaque, voidpf ptr);
#endif

#define ZALLOC(strm, items, size) \
           (*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}

/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))

#endif /* ZUTIL_H */

#else
#include <zutil.h>
#endif

#endif

./include/libretro-common/include/compat/zutil.h

#ifndef _COMPAT_ZUTIL_H
#define _COMPAT_ZUTIL_H

#ifdef WANT_ZLIB

/* zutil.h -- internal interface and configuration of the compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* @(#) $Id$ */

#ifndef ZUTIL_H
#define ZUTIL_H

#ifdef HAVE_HIDDEN
#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
#  define ZLIB_INTERNAL
#endif

#include <compat/zlib.h>

#if defined(STDC) && !defined(Z_SOLO)
#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))
#    include <stddef.h>
#  endif
#  include <string.h>
#  include <stdlib.h>
#endif

#ifdef Z_SOLO
   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
#endif

#ifndef local
#  define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */

typedef unsigned char  uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long  ulg;

extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
/* (array size given to avoid silly warnings with Visual C++) */
/* (array entry size given to avoid silly string cast warnings) */

#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]

#define ERR_RETURN(strm,err) \
  return (strm->msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */

        /* common constants */

#ifndef DEF_WBITS
#  define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */

#if MAX_MEM_LEVEL >= 8
#  define DEF_MEM_LEVEL 8
#else
#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
#endif
/* default memLevel */

#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES    2
/* The three kinds of block type */

#define MIN_MATCH  3
#define MAX_MATCH  258
/* The minimum and maximum match lengths */

#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */

        /* target dependencies */

#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
#  define OS_CODE  0x00
#  ifndef Z_SOLO
#    if defined(__TURBOC__) || defined(__BORLANDC__)
#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
         /* Allow compilation with ANSI keywords only enabled */
         void _Cdecl farfree( void *block );
         void *_Cdecl farmalloc( unsigned long nbytes );
#      else
#        include <alloc.h>
#      endif
#    else /* MSC or DJGPP */
#      include <malloc.h>
#    endif
#  endif
#endif

#ifdef AMIGA
#  define OS_CODE  0x01
#endif

#if defined(VAXC) || defined(VMS)
#  define OS_CODE  0x02
#  define F_OPEN(name, mode) \
     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif

#if defined(ATARI) || defined(atarist)
#  define OS_CODE  0x05
#endif

#ifdef OS2
#  define OS_CODE  0x06
#  if defined(M_I86) && !defined(Z_SOLO)
#    include <malloc.h>
#  endif
#endif

#if defined(MACOS) || defined(TARGET_OS_MAC)
#  define OS_CODE  0x07
#  ifndef Z_SOLO
#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
#      include <unix.h> /* for fdopen */
#    else
#      ifndef fdopen
#        define fdopen(fd,mode) NULL /* No fdopen() */
#      endif
#    endif
#  endif
#endif

#ifdef TOPS20
#  define OS_CODE  0x0a
#endif

#ifdef WIN32
#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
#    define OS_CODE  0x0b
#  endif
#endif

#ifdef __50SERIES /* Prime/PRIMOS */
#  define OS_CODE  0x0f
#endif

#if defined(_BEOS_) || defined(RISCOS)
#  define fdopen(fd,mode) NULL /* No fdopen() */
#endif

#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
#  if defined(_WIN32_WCE)
#    define fdopen(fd,mode) NULL /* No fdopen() */
#    ifndef _PTRDIFF_T_DEFINED
       typedef int ptrdiff_t;
#      define _PTRDIFF_T_DEFINED
#    endif
#  else
#    define fdopen(fd,type)  _fdopen(fd,type)
#  endif
#endif

#if defined(__BORLANDC__) && !defined(MSDOS)
  #pragma warn -8004
  #pragma warn -8008
  #pragma warn -8066
#endif

/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
    uLong adler32_combine64 (uLong, uLong, z_off_t);
    uLong crc32_combine64 (uLong, uLong, z_off_t);
#endif

        /* common defaults */

#ifndef OS_CODE
#  define OS_CODE  0x03  /* assume Unix */
#endif

#ifndef F_OPEN
#  define F_OPEN(name, mode) fopen((name), (mode))
#endif

         /* functions */

#if defined(pyr) || defined(Z_SOLO)
#  define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
 /* Use our own functions for small and medium model with MSC <= 5.0.
  * You may have to use the same strategy for Borland C (untested).
  * The __SC__ check is for Symantec.
  */
#  define NO_MEMCPY
#endif
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
#  define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
#    define zmemcpy _fmemcpy
#    define zmemcmp _fmemcmp
#    define zmemzero(dest, len) _fmemset(dest, 0, len)
#  else
#    define zmemcpy memcpy
#    define zmemcmp memcmp
#    define zmemzero(dest, len) memset(dest, 0, len)
#  endif
#else
   void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
   int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
   void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
#endif

/* Diagnostic functions */
#  define Assert(cond,msg)
#  define Trace(x)
#  define Tracev(x)
#  define Tracevv(x)
#  define Tracec(c,x)
#  define Tracecv(c,x)

#ifndef Z_SOLO
   voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
                                    unsigned size);
   void ZLIB_INTERNAL zcfree  (voidpf opaque, voidpf ptr);
#endif

#define ZALLOC(strm, items, size) \
           (*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}

/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))

#endif /* ZUTIL_H */

#else
#include <zutil.h>
#endif

#endif

./include/libretro-common/include/defines/cocoa_defines.h

/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (cocoa_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __COCOA_COMMON_DEFINES_H
#define __COCOA_COMMON_DEFINES_H

#include <AvailabilityMacros.h>

#ifndef MAC_OS_X_VERSION_10_12
#define MAC_OS_X_VERSION_10_12 101200
#endif

#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
#define HAS_MACOSX_10_12 0
#define NSEventModifierFlagCommand NSCommandKeyMask
#define NSEventModifierFlagControl NSControlKeyMask
#define NSEventModifierFlagHelp NSHelpKeyMask
#define NSEventModifierFlagNumericPad NSNumericPadKeyMask
#define NSEventModifierFlagOption NSAlternateKeyMask
#define NSEventModifierFlagShift NSShiftKeyMask
#define NSCompositingOperationSourceOver NSCompositeSourceOver
#define NSEventMaskApplicationDefined NSApplicationDefinedMask
#define NSEventTypeApplicationDefined NSApplicationDefined
#define NSEventTypeCursorUpdate NSCursorUpdate
#define NSEventTypeMouseMoved NSMouseMoved
#define NSEventTypeMouseEntered NSMouseEntered
#define NSEventTypeMouseExited NSMouseExited
#define NSEventTypeLeftMouseDown NSLeftMouseDown
#define NSEventTypeRightMouseDown NSRightMouseDown
#define NSEventTypeOtherMouseDown NSOtherMouseDown
#define NSEventTypeLeftMouseUp NSLeftMouseUp
#define NSEventTypeRightMouseUp NSRightMouseUp
#define NSEventTypeOtherMouseUp NSOtherMouseUp
#define NSEventTypeLeftMouseDragged NSLeftMouseDragged
#define NSEventTypeRightMouseDragged NSRightMouseDragged
#define NSEventTypeOtherMouseDragged NSOtherMouseDragged
#define NSEventTypeScrollWheel NSScrollWheel
#define NSEventTypeKeyDown NSKeyDown
#define NSEventTypeKeyUp NSKeyUp
#define NSEventTypeFlagsChanged NSFlagsChanged
#define NSEventMaskAny NSAnyEventMask
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
#define NSWindowStyleMaskClosable NSClosableWindowMask
#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
#define NSWindowStyleMaskResizable NSResizableWindowMask
#define NSWindowStyleMaskTitled NSTitledWindowMask
#define NSAlertStyleCritical NSCriticalAlertStyle
#define NSAlertStyleInformational NSInformationalAlertStyle
#define NSAlertStyleWarning  NSWarningAlertStyle
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
#define NSControlSizeRegular NSRegularControlSize
#else
#define HAS_MACOSX_10_12 1
#endif

#endif

./include/libretro-common/include/defines/d3d_defines.h

/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (d3d_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef D3DVIDEO_DEFINES_H
#define D3DVIDEO_DEFINES_H

#if defined(DEBUG) || defined(_DEBUG)
#define D3D_DEBUG_INFO
#endif

#if defined(HAVE_D3D9)
/* Direct3D 9 */

#ifndef D3DCREATE_SOFTWARE_VERTEXPROCESSING
#define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0
#endif

#elif defined(HAVE_D3D8)

/* Direct3D 8 */

#if !defined(D3DLOCK_NOSYSLOCK) && defined(_XBOX)
#define D3DLOCK_NOSYSLOCK (0)
#endif

#endif

#endif

./include/libretro-common/include/defines/gx_defines.h

/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gx_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _GX_DEFINES_H
#define _GX_DEFINES_H

#ifdef GEKKO

#define SYSMEM1_SIZE 0x01800000

#ifndef _SHIFTL
#define _SHIFTL(v, s, w)	((uint32_t) (((uint32_t)(v) & ((0x01 << (w)) - 1)) << (s)))
#define _SHIFTR(v, s, w)	((uint32_t)(((uint32_t)(v) >> (s)) & ((0x01 << (w)) - 1)))
#endif

#define OSThread lwp_t
#define OSCond lwpq_t
#define OSThreadQueue lwpq_t

#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
#define OSLockMutex(mutex) LWP_MutexLock(mutex)
#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)

#define OSInitCond(cond) LWP_CondInit(cond)
#define OSSignalCond(cond) LWP_ThreadSignal(cond)
#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)

#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
#define OSCloseThreadQueue(queue) LWP_CloseQueue(queue)
#define OSSleepThread(queue) LWP_ThreadSleep(queue)
#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)

#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)

#define BLIT_LINE_16(off) \
{ \
   const uint32_t *tmp_src = src; \
   uint32_t       *tmp_dst = dst; \
   for (unsigned x = 0; x < width2 >> 1; x++, tmp_src += 2, tmp_dst += 8) \
   { \
      tmp_dst[ 0 + off] = BLIT_LINE_16_CONV(tmp_src[0]); \
      tmp_dst[ 1 + off] = BLIT_LINE_16_CONV(tmp_src[1]); \
   } \
   src += tmp_pitch; \
}

#define BLIT_LINE_32(off) \
{ \
   const uint16_t *tmp_src = src; \
   uint16_t       *tmp_dst = dst; \
   for (unsigned x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \
   { \
      tmp_dst[  0 + off] = tmp_src[0] | 0xFF00; \
      tmp_dst[ 16 + off] = tmp_src[1]; \
      tmp_dst[  1 + off] = tmp_src[2] | 0xFF00; \
      tmp_dst[ 17 + off] = tmp_src[3]; \
      tmp_dst[  2 + off] = tmp_src[4] | 0xFF00; \
      tmp_dst[ 18 + off] = tmp_src[5]; \
      tmp_dst[  3 + off] = tmp_src[6] | 0xFF00; \
      tmp_dst[ 19 + off] = tmp_src[7]; \
   } \
   src += tmp_pitch; \
}

#define AIInit AUDIO_Init
#define AIInitDMA AUDIO_InitDMA
#define AIStartDMA AUDIO_StartDMA
#define AIStopDMA AUDIO_StopDMA
#define AIRegisterDMACallback AUDIO_RegisterDMACallback
#define AISetDSPSampleRate AUDIO_SetDSPSampleRate

#endif

#endif

./include/libretro-common/include/defines/ps3_defines.h

/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (ps3_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _PS3_DEFINES_H
#define _PS3_DEFINES_H

/*============================================================
	AUDIO PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <audio/audio.h>
#include <sys/thread.h>

#include <sys/event_queue.h>
#include <lv2/mutex.h>
#include <lv2/cond.h>

/*forward decl. for audioAddData */
extern int audioAddData(uint32_t portNum, float *data,
      uint32_t frames, float volume);

#define PS3_SYS_NO_TIMEOUT 0
#define param_attrib attrib

#else
#include <sdk_version.h>
#include <cell/audio.h>
#include <sys/event.h>
#include <sys/synchronization.h>

#define numChannels nChannel
#define numBlocks nBlock
#define param_attrib attr

#define audioQuit cellAudioQuit 
#define audioInit cellAudioInit
#define audioPortStart cellAudioPortStart
#define audioPortOpen cellAudioPortOpen
#define audioPortClose cellAudioPortClose
#define audioPortStop cellAudioPortStop
#define audioPortParam CellAudioPortParam
#define audioPortOpen cellAudioPortOpen
#define audioAddData cellAudioAddData

/* event queue functions */
#define sysEventQueueReceive sys_event_queue_receive
#define audioSetNotifyEventQueue cellAudioSetNotifyEventQueue
#define audioRemoveNotifyEventQueue cellAudioRemoveNotifyEventQueue
#define audioCreateNotifyEventQueue cellAudioCreateNotifyEventQueue

#define sysLwCondCreate sys_lwcond_create
#define sysLwCondDestroy sys_lwcond_destroy
#define sysLwCondWait sys_lwcond_wait
#define sysLwCondSignal sys_lwcond_signal

#define sysLwMutexDestroy sys_lwmutex_destroy
#define sysLwMutexLock sys_lwmutex_lock
#define sysLwMutexUnlock sys_lwmutex_unlock
#define sysLwMutexCreate sys_lwmutex_create

#define AUDIO_BLOCK_SAMPLES CELL_AUDIO_BLOCK_SAMPLES
#define SYSMODULE_NET CELL_SYSMODULE_NET
#define PS3_SYS_NO_TIMEOUT SYS_NO_TIMEOUT

#define sys_lwmutex_attr_t sys_lwmutex_attribute_t 
#define sys_lwcond_attr_t sys_lwcond_attribute_t 
#define sys_sem_t sys_semaphore_t

#define sysGetSystemTime sys_time_get_system_time
#define sysModuleLoad cellSysmoduleLoadModule
#define sysModuleUnload cellSysmoduleUnloadModule

#define netInitialize sys_net_initialize_network

#endif

/*============================================================
	INPUT PAD PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <io/pad.h>
#define CELL_PAD_CAPABILITY_SENSOR_MODE      4
#define CELL_PAD_SETTING_SENSOR_ON           4
#define CELL_PAD_STATUS_ASSIGN_CHANGES       2
#define CELL_PAD_BTN_OFFSET_DIGITAL1         2
#define CELL_PAD_BTN_OFFSET_DIGITAL2         3
#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X   4
#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y   5
#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X    6
#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y    7
#define CELL_PAD_BTN_OFFSET_PRESS_RIGHT      8
#define CELL_PAD_BTN_OFFSET_PRESS_LEFT       9
#define CELL_PAD_BTN_OFFSET_PRESS_UP         10
#define CELL_PAD_BTN_OFFSET_PRESS_DOWN       11
#define CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE   12
#define CELL_PAD_BTN_OFFSET_PRESS_CIRCLE     13
#define CELL_PAD_BTN_OFFSET_PRESS_CROSS      14
#define CELL_PAD_BTN_OFFSET_PRESS_SQUARE     15
#define CELL_PAD_BTN_OFFSET_PRESS_L1         16
#define CELL_PAD_BTN_OFFSET_PRESS_R1         17
#define CELL_PAD_BTN_OFFSET_PRESS_L2         18
#define CELL_PAD_BTN_OFFSET_PRESS_R2         19
#define CELL_PAD_BTN_OFFSET_SENSOR_X         20
#define CELL_PAD_BTN_OFFSET_SENSOR_Y         21
#define CELL_PAD_BTN_OFFSET_SENSOR_Z         22
#define CELL_PAD_BTN_OFFSET_SENSOR_G         23
#define CELL_PAD_CTRL_LEFT          (128)
#define CELL_PAD_CTRL_DOWN          (64)
#define CELL_PAD_CTRL_RIGHT         (32)
#define CELL_PAD_CTRL_UP            (16)
#define CELL_PAD_CTRL_START         (8)
#define CELL_PAD_CTRL_R3            (4)
#define CELL_PAD_CTRL_L3            (2)
#define CELL_PAD_CTRL_SELECT        (1)
#define CELL_PAD_CTRL_SQUARE        (128)
#define CELL_PAD_CTRL_CROSS         (64)
#define CELL_PAD_CTRL_CIRCLE        (32)
#define CELL_PAD_CTRL_TRIANGLE      (16)
#define CELL_PAD_CTRL_R1            (8)
#define CELL_PAD_CTRL_L1            (4)
#define CELL_PAD_CTRL_R2            (2)
#define CELL_PAD_CTRL_L2            (1)
#define CELL_PAD_CTRL_LDD_PS        (1)
#define CELL_PAD_STATUS_CONNECTED   (1)
#define CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN
#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CROSS  (1)
#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CIRCLE (0)
#define now_connect connected
#define CellPadActParam padActParam
#define cellPadSetPortSetting ioPadSetPortSetting
#define cellSysutilGetSystemParamInt sysUtilGetSystemParamInt
#define cellPadSetActDirect ioPadSetActDirect
#define CellPadInfo2 padInfo2
#define cellPadGetInfo2 ioPadGetInfo2
#define CellPadData padData
#define cellPadGetData ioPadGetData
#define cellPadInit ioPadInit 
#define cellPadEnd ioPadEnd
#else
#include <cell/pad.h>
#define padInfo2 CellPadInfo2
#define padData CellPadData
#define ioPadGetInfo2 cellPadGetInfo2 
#define ioPadGetData cellPadGetData
#define ioPadInit cellPadInit
#define ioPadEnd cellPadEnd
#define ioPadSetPortSetting cellPadSetPortSetting 
#endif

/*============================================================
	INPUT MOUSE PROTOTYPES
============================================================ */

#ifdef HAVE_MOUSE

#ifdef __PSL1GHT__
#include <io/mouse.h>

/* define ps3 mouse structs */
#define CellMouseInfo mouseInfo
#define CellMouseData mouseData

/* define all the ps3 mouse functions */
#define cellMouseInit ioMouseInit
#define cellMouseGetData ioMouseGetData
#define cellMouseEnd ioMouseEnd
#define cellMouseGetInfo ioMouseGetInfo

/* PSL1GHT does not define these in its header */
#define CELL_MOUSE_BUTTON_1 (UINT64_C(1) << 0) /* Button 1 */
#define CELL_MOUSE_BUTTON_2 (UINT64_C(1) << 1) /* Button 2 */
#define CELL_MOUSE_BUTTON_3 (UINT64_C(1) << 2) /* Button 3 */
#define CELL_MOUSE_BUTTON_4 (UINT64_C(1) << 3) /* Button 4 */
#define CELL_MOUSE_BUTTON_5 (UINT64_C(1) << 4) /* Button 5 */
#define CELL_MOUSE_BUTTON_6 (UINT64_C(1) << 5) /* Button 6 */
#define CELL_MOUSE_BUTTON_7 (UINT64_C(1) << 6) /* Button 7 */
#define CELL_MOUSE_BUTTON_8 (UINT64_C(1) << 7) /* Button 8 */

#else
#include <cell/mouse.h>
#define mouseInfo CellMouseInfo
#define mouseData CellMouseData

#define ioMouseInit cellMouseInit
#define ioMouseGetData cellMouseGetData
#define ioMouseEnd cellMouseEnd
#define ioMouseGetInfo cellMouseGetInfo
#endif

#endif

/*============================================================
	INPUT KEYBOARD PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <io/kb.h>

#define CELL_KB_RMODE_INPUTCHAR KB_RMODE_INPUTCHAR
#define CELL_KB_CODETYPE_RAW    KB_CODETYPE_RAW

#define cellKbData KbData
#define cellKbInfo KbInfo

#define cellKbSetCodeType ioKbSetCodeType
#define cellKbSetReadMode ioKbSetReadMode
#define cellKbInit ioKbInit
#define cellKbGetInfo ioKbGetInfo
#define cellKbRead ioKbRead
#else
#include <cell/keyboard.h>

#define KB_RMODE_INPUTCHAR CELL_KB_RMODE_INPUTCHAR
#define KB_CODETYPE_RAW    CELL_KB_CODETYPE_RAW

#define KbInfo cellKbInfo

#define ioKbSetCodeType cellKbSetCodeType
#define ioKbSetReadMode cellKbSetReadMode
#define ioKbInit cellKbInit
#define ioKbGetInfo cellKbGetInfo
#define ioKbRead cellKbRead

/* Keyboard RAWDAT Key code (can't be converted to ASCII codes) */
#define KB_RAWKEY_NO_EVENT			0x00
#define KB_RAWKEY_E_ROLLOVER			0x01
#define KB_RAWKEY_E_POSTFAIL			0x02
#define KB_RAWKEY_E_UNDEF			0x03
#define KB_RAWKEY_ESCAPE			0x29
#define KB_RAWKEY_106_KANJI			0x35	/* The half-width/full width Kanji key code */
#define KB_RAWKEY_CAPS_LOCK			0x39
#define KB_RAWKEY_F1				0x3a
#define KB_RAWKEY_F2				0x3b
#define KB_RAWKEY_F3				0x3c
#define KB_RAWKEY_F4				0x3d
#define KB_RAWKEY_F5				0x3e
#define KB_RAWKEY_F6				0x3f
#define KB_RAWKEY_F7				0x40
#define KB_RAWKEY_F8				0x41
#define KB_RAWKEY_F9				0x42
#define KB_RAWKEY_F10				0x43
#define KB_RAWKEY_F11				0x44
#define KB_RAWKEY_F12				0x45
#define KB_RAWKEY_PRINTSCREEN			0x46
#define KB_RAWKEY_SCROLL_LOCK			0x47
#define KB_RAWKEY_PAUSE				0x48
#define KB_RAWKEY_INSERT			0x49
#define KB_RAWKEY_HOME				0x4a
#define KB_RAWKEY_PAGE_UP			0x4b
#define KB_RAWKEY_DELETE			0x4c
#define KB_RAWKEY_END				0x4d
#define KB_RAWKEY_PAGE_DOWN			0x4e
#define KB_RAWKEY_RIGHT_ARROW			0x4f
#define KB_RAWKEY_LEFT_ARROW			0x50
#define KB_RAWKEY_DOWN_ARROW			0x51
#define KB_RAWKEY_UP_ARROW			0x52
#define KB_RAWKEY_NUM_LOCK			0x53
#define KB_RAWKEY_APPLICATION			0x65	/* Application key code */
#define KB_RAWKEY_KANA				0x88	/* Katakana/Hiragana/Romaji key code */
#define KB_RAWKEY_HENKAN			0x8a	/* Conversion key code */
#define KB_RAWKEY_MUHENKAN			0x8b	/* No Conversion key code */

/* Keyboard RAW Key Code definition */
#define KB_RAWKEY_A				0x04
#define KB_RAWKEY_B				0x05
#define KB_RAWKEY_C				0x06
#define KB_RAWKEY_D				0x07
#define KB_RAWKEY_E				0x08
#define KB_RAWKEY_F				0x09
#define KB_RAWKEY_G				0x0A
#define KB_RAWKEY_H				0x0B
#define KB_RAWKEY_I				0x0C
#define KB_RAWKEY_J				0x0D
#define KB_RAWKEY_K				0x0E
#define KB_RAWKEY_L				0x0F
#define KB_RAWKEY_M				0x10
#define KB_RAWKEY_N				0x11
#define KB_RAWKEY_O				0x12
#define KB_RAWKEY_P				0x13
#define KB_RAWKEY_Q				0x14
#define KB_RAWKEY_R				0x15
#define KB_RAWKEY_S				0x16
#define KB_RAWKEY_T				0x17
#define KB_RAWKEY_U				0x18
#define KB_RAWKEY_V				0x19
#define KB_RAWKEY_W				0x1A
#define KB_RAWKEY_X				0x1B
#define KB_RAWKEY_Y				0x1C
#define KB_RAWKEY_Z				0x1D
#define KB_RAWKEY_1				0x1E
#define KB_RAWKEY_2				0x1F
#define KB_RAWKEY_3				0x20
#define KB_RAWKEY_4				0x21
#define KB_RAWKEY_5				0x22
#define KB_RAWKEY_6				0x23
#define KB_RAWKEY_7				0x24
#define KB_RAWKEY_8				0x25
#define KB_RAWKEY_9				0x26
#define KB_RAWKEY_0				0x27
#define KB_RAWKEY_ENTER				0x28
#define KB_RAWKEY_ESC				0x29
#define KB_RAWKEY_BS				0x2A
#define KB_RAWKEY_TAB				0x2B
#define KB_RAWKEY_SPACE				0x2C
#define KB_RAWKEY_MINUS				0x2D
#define KB_RAWKEY_EQUAL_101			0x2E	/* = and + */
#define KB_RAWKEY_ACCENT_CIRCONFLEX_106 	0x2E	/* ^ and ~ */
#define KB_RAWKEY_LEFT_BRACKET_101		0x2F	/* [ */
#define KB_RAWKEY_ATMARK_106			0x2F	/* @ */
#define KB_RAWKEY_RIGHT_BRACKET_101		0x30	/* ] */
#define KB_RAWKEY_LEFT_BRACKET_106		0x30	/* [ */
#define KB_RAWKEY_BACKSLASH_101			0x31	/* \ and | */
#define KB_RAWKEY_RIGHT_BRACKET_106		0x32	/* ] */
#define KB_RAWKEY_SEMICOLON			0x33	/* ; */
#define KB_RAWKEY_QUOTATION_101			0x34	/* ' and " */
#define KB_RAWKEY_COLON_106			0x34	/* : and * */
#define KB_RAWKEY_COMMA		    		0x36
#define KB_RAWKEY_PERIOD			0x37
#define KB_RAWKEY_SLASH		    		0x38
#define KB_RAWKEY_CAPS_LOCK			0x39
#define KB_RAWKEY_KPAD_NUMLOCK			0x53
#define KB_RAWKEY_KPAD_SLASH			0x54
#define KB_RAWKEY_KPAD_ASTERISK			0x55
#define KB_RAWKEY_KPAD_MINUS			0x56
#define KB_RAWKEY_KPAD_PLUS			0x57
#define KB_RAWKEY_KPAD_ENTER			0x58
#define KB_RAWKEY_KPAD_1			0x59
#define KB_RAWKEY_KPAD_2			0x5A
#define KB_RAWKEY_KPAD_3			0x5B
#define KB_RAWKEY_KPAD_4			0x5C
#define KB_RAWKEY_KPAD_5			0x5D
#define KB_RAWKEY_KPAD_6			0x5E
#define KB_RAWKEY_KPAD_7			0x5F
#define KB_RAWKEY_KPAD_8			0x60
#define KB_RAWKEY_KPAD_9			0x61
#define KB_RAWKEY_KPAD_0			0x62
#define KB_RAWKEY_KPAD_PERIOD			0x63
#define KB_RAWKEY_BACKSLASH_106			0x87
#define KB_RAWKEY_YEN_106			0x89

#define KB_CODETYPE_RAW CELL_KB_CODETYPE_RAW

/*! \brief Keyboard Led State. */
typedef struct KbLed
{
	union
   {
      uint32_t leds;
      struct
      {
         uint32_t reserved	   : 27;	/*!< \brief Reserved MSB */
         uint32_t kana		   : 1;	/*!< \brief LED Kana 0:OFF 1:ON Bit4 */
         uint32_t compose		: 1;	/*!< \brief LED Compose 0:OFF 1:ON Bit3 */
         uint32_t scroll_lock	: 1;	/*!< \brief LED Scroll Lock 0:OFF 1:ON Bit2 */
         uint32_t caps_lock	: 1;	/*!< \brief LED Caps Lock 0:OFF 1:ON Bit1 */
         uint32_t num_lock	   : 1;	/*!< \brief LED Num Lock 0:OFF 1:ON Bit0 LSB */
      }_KbLedS;
   }_KbLedU;
} KbLed;


/*! \brief Keyboard Modifier Key State. */
typedef struct KbMkey
{
   union
   {
      uint32_t mkeys;
      struct
      {
         uint32_t reserved	   : 24;	/*!< \brief Reserved MSB */
         uint32_t r_win		   : 1;	/*!< \brief Modifier Key Right WIN 0:OFF 1:ON Bit7 */
         uint32_t r_alt		   : 1;	/*!< \brief Modifier Key Right ALT 0:OFF 1:ON Bit6 */
         uint32_t r_shift		: 1;	/*!< \brief Modifier Key Right SHIFT 0:OFF 1:ON Bit5 */		
         uint32_t r_ctrl		: 1;	/*!< \brief Modifier Key Right CTRL 0:OFF 1:ON Bit4 */
         uint32_t l_win		   : 1;	/*!< \brief Modifier Key Left WIN 0:OFF 1:ON Bit3 */
         uint32_t l_alt		   : 1;	/*!< \brief Modifier Key Left ALT 0:OFF 1:ON Bit2 */
         uint32_t l_shift		: 1;	/*!< \brief Modifier Key Left SHIFT 0:OFF 1:ON Bit1 */
         uint32_t l_ctrl		: 1;	/*!< \brief Modifier Key Left CTRL 0:OFF 1:ON Bit0 LSB */
         /* For Macintosh Keyboard ALT & WIN correspond respectively to OPTION & APPLE keys */
      }_KbMkeyS;
   }_KbMkeyU;
} KbMkey;

/*! \brief Keyboard input data data structure. */
typedef struct KbData
{
	KbLed led;					/*!< \brief Keyboard Led State */
	KbMkey mkey;				/*!< \brief Keyboard Modifier Key State */
	int32_t  nb_keycode;				/*!< \brief Number of key codes (0 equal no data) */
	uint16_t keycode[MAX_KEYCODES];	/*!< \brief Keycode values */
} KbData;
#endif

/*============================================================
	OSK PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <sysutil/osk.h>
/* define all the OSK functions */
#define pOskLoadAsync oskLoadAsync
#define pOskSetLayoutMode oskSetLayoutMode
#define pOskSetKeyLayoutOption oskSetKeyLayoutOption
#define pOskGetSize oskGetSize
#define pOskDisableDimmer oskDisableDimmer
#define pOskAbort oskAbort
#define pOskUnloadAsync oskUnloadAsync

/* define OSK structs / types */
#define sys_memory_container_t sys_mem_container_t
#define CellOskDialogPoint oskPoint
#define CellOskDialogInputFieldInfo oskInputFieldInfo
#define CellOskDialogCallbackReturnParam oskCallbackReturnParam
#define CellOskDialogParam oskParam

#define osk_allowed_panels allowedPanels
#define osk_prohibit_flags prohibitFlags

#define osk_inputfield_message message
#define osk_inputfield_starttext startText
#define osk_inputfield_max_length maxLength
#define osk_callback_return_param res
#define osk_callback_num_chars len
#define osk_callback_return_string str

/* define the OSK defines */
#define CELL_OSKDIALOG_10KEY_PANEL OSK_10KEY_PANEL
#define CELL_OSKDIALOG_FULLKEY_PANEL OSK_FULLKEY_PANEL
#define CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_CENTER OSK_LAYOUTMODE_HORIZONTAL_ALIGN_CENTER
#define CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_TOP OSK_LAYOUTMODE_VERTICAL_ALIGN_TOP
#define CELL_OSKDIALOG_PANELMODE_NUMERAL OSK_PANEL_TYPE_NUMERAL
#define CELL_OSKDIALOG_PANELMODE_NUMERAL_FULL_WIDTH OSK_PANEL_TYPE_NUMERAL_FULL_WIDTH
#define CELL_OSKDIALOG_PANELMODE_ALPHABET OSK_PANEL_TYPE_ALPHABET
#define CELL_OSKDIALOG_PANELMODE_ENGLISH OSK_PANEL_TYPE_ENGLISH
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK (0)
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED (1)
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT (2)
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT (3)
#define CELL_OSKDIALOG_STRING_SIZE (512)
#else
#include <sysutil/sysutil_oskdialog.h>
/* define all the OSK functions */
#define pOskLoadAsync cellOskDialogLoadAsync
#define pOskSetLayoutMode cellOskDialogSetLayoutMode
#define pOskSetKeyLayoutOption cellOskDialogSetKeyLayoutOption
#define pOskGetSize cellOskDialogGetSize
#define pOskDisableDimmer cellOskDialogDisableDimmer
#define pOskAbort cellOskDialogAbort
#define pOskUnloadAsync cellOskDialogUnloadAsync

/* define OSK structs / types */
#define osk_allowed_panels allowOskPanelFlg
#define osk_prohibit_flags prohibitFlgs
#define osk_inputfield_message message
#define osk_inputfield_starttext init_text
#define osk_inputfield_max_length limit_length
#define osk_callback_return_param result
#define osk_callback_num_chars numCharsResultString
#define osk_callback_return_string pResultString
#endif

/*============================================================
	JPEG/PNG DECODING/ENCODING PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__

#define spu_enable enable
#define stream_select stream
#define color_alpha alpha
#define color_space space
#define output_mode mode
#define output_bytes_per_line bytes_per_line
#define output_width width
#define output_height height

#define CELL_OK 0
#define PTR_NULL 0

#else
/* define the JPEG/PNG struct member names */
#define spu_enable spuThreadEnable
#define ppu_prio ppuThreadPriority
#define spu_prio spuThreadPriority
#define malloc_func cbCtrlMallocFunc
#define malloc_arg cbCtrlMallocArg
#define free_func cbCtrlFreeFunc
#define free_arg cbCtrlFreeArg
#define stream_select srcSelect
#define file_name fileName
#define file_offset fileOffset
#define file_size fileSize
#define stream_ptr streamPtr
#define stream_size streamSize
#define down_scale downScale
#define color_alpha outputColorAlpha
#define color_space outputColorSpace
#define cmd_ptr commandPtr
#define quality method
#define output_mode outputMode
#define output_bytes_per_line outputBytesPerLine
#define output_width outputWidth
#define output_height outputHeight
#define bit_depth outputBitDepth
#define pack_flag outputPackFlag
#define alpha_select outputAlphaSelect

#define PTR_NULL NULL

#endif

/*============================================================
	TIMER PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#define sys_timer_usleep usleep
#endif

/*============================================================
	THREADING PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <sys/thread.h>

/* FIXME - not sure if this is correct -> FIXED! 1 and not 0 */
#define SYS_THREAD_CREATE_JOINABLE THREAD_JOINABLE

#else
#include <sys/ppu_thread.h>

#define SYS_PROCESS_SPAWN_STACK_SIZE_1M SYS_PROCESS_PRIMARY_STACK_SIZE_1M 
#define SYS_THREAD_CREATE_JOINABLE SYS_PPU_THREAD_CREATE_JOINABLE

#define sysThreadCreate sys_ppu_thread_create 
#define sysThreadJoin sys_ppu_thread_join 
#define sysThreadExit sys_ppu_thread_exit 

#define sysProcessExit sys_process_exit 
#define sysProcessExitSpawn2 sys_game_process_exitspawn 

#endif

/*============================================================
	MEMORY PROTOTYPES
============================================================ */

#ifndef __PSL1GHT__
#define sysMemContainerCreate sys_memory_container_create 
#define sysMemContainerDestroy sys_memory_container_destroy 
#endif

/*============================================================
	RSX PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <sysutil/video.h>
#define CELL_GCM_FALSE GCM_FALSE
#define CELL_GCM_TRUE GCM_TRUE

#define CELL_GCM_ONE GCM_ONE
#define CELL_GCM_ZERO GCM_ZERO
#define CELL_GCM_ALWAYS GCM_ALWAYS

#define CELL_GCM_LOCATION_LOCAL GCM_LOCATION_RSX
#define CELL_GCM_LOCATION_MAIN GCM_LOCATION_CELL

#define CELL_GCM_MAX_RT_DIMENSION (4096)

#define CELL_GCM_TEXTURE_LINEAR_NEAREST GCM_TEXTURE_LINEAR_MIPMAP_NEAREST
#define CELL_GCM_TEXTURE_LINEAR_LINEAR GCM_TEXTURE_LINEAR_MIPMAP_LINEAR
#define CELL_GCM_TEXTURE_NEAREST_LINEAR GCM_TEXTURE_NEAREST_MIPMAP_LINEAR
#define CELL_GCM_TEXTURE_NEAREST_NEAREST GCM_TEXTURE_NEAREST_MIPMAP_NEAREST
#define CELL_GCM_TEXTURE_NEAREST GCM_TEXTURE_NEAREST
#define CELL_GCM_TEXTURE_LINEAR GCM_TEXTURE_LINEAR

#define CELL_GCM_TEXTURE_A8R8G8B8 GCM_TEXTURE_FORMAT_A8R8G8B8
#define CELL_GCM_TEXTURE_R5G6B5 GCM_TEXTURE_FORMAT_R5G6B5
#define CELL_GCM_TEXTURE_A1R5G5B5 GCM_TEXTURE_FORMAT_A1R5G5B5

#define CELL_GCM_TEXTURE_CLAMP_TO_EDGE GCM_TEXTURE_CLAMP_TO_EDGE

#define CELL_GCM_TEXTURE_MAX_ANISO_1 GCM_TEXTURE_MAX_ANISO_1
#define CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX GCM_TEXTURE_CONVOLUTION_QUINCUNX
#define CELL_GCM_TEXTURE_ZFUNC_NEVER GCM_TEXTURE_ZFUNC_NEVER

#define CELL_GCM_DISPLAY_HSYNC GCM_FLIP_HSYNC
#define CELL_GCM_DISPLAY_VSYNC GCM_FLIP_VSYNC

#define CELL_GCM_CLEAR_R GCM_CLEAR_R
#define CELL_GCM_CLEAR_G GCM_CLEAR_G
#define CELL_GCM_CLEAR_B GCM_CLEAR_B
#define CELL_GCM_CLEAR_A GCM_CLEAR_A

#define CELL_GCM_FUNC_ADD GCM_FUNC_ADD

#define CELL_GCM_SMOOTH	(0x1D01)
#define CELL_GCM_DEBUG_LEVEL2 2

#define CELL_GCM_COMPMODE_DISABLED 0

#define CELL_GCM_TRANSFER_LOCAL_TO_LOCAL 0

#define CELL_GCM_TEXTURE_REMAP_ORDER_XYXY (0)
#define CELL_GCM_TEXTURE_REMAP_ORDER_XXXY (1)

#define CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL (0)

#define CELL_GCM_TEXTURE_REMAP_FROM_A (0)
#define CELL_GCM_TEXTURE_REMAP_FROM_R (1)
#define CELL_GCM_TEXTURE_REMAP_FROM_G (2)
#define CELL_GCM_TEXTURE_REMAP_FROM_B (3)

#define CELL_GCM_TEXTURE_REMAP_ZERO (0)
#define CELL_GCM_TEXTURE_REMAP_ONE (1)
#define CELL_GCM_TEXTURE_REMAP_REMAP (2)

#define CELL_GCM_MAX_TEXIMAGE_COUNT (16)

#define CELL_GCM_TEXTURE_WRAP (1)

#define CELL_GCM_TEXTURE_NR (0x00)
#define CELL_GCM_TEXTURE_LN (0x20)

#define CELL_GCM_TEXTURE_B8 (0x81)

#define CELL_RESC_720x480 RESC_720x480
#define CELL_RESC_720x576 RESC_720x576
#define CELL_RESC_1280x720 RESC_1280x720
#define CELL_RESC_1920x1080 RESC_1920x1080

#define CELL_RESC_FULLSCREEN RESC_FULLSCREEN
#define CELL_RESC_PANSCAN RESC_PANSCAN
#define CELL_RESC_LETTERBOX RESC_LETTERBOX
#define CELL_RESC_CONSTANT_VRAM RESC_CONSTANT_VRAM
#define CELL_RESC_MINIMUM_GPU_LOAD RESC_MINIMUM_GPU_LOAD

#define CELL_RESC_PAL_50 RESC_PAL_50
#define CELL_RESC_PAL_60_DROP RESC_PAL_60_DROP
#define CELL_RESC_PAL_60_INTERPOLATE RESC_PAL_60_INTERPOLATE
#define CELL_RESC_PAL_60_INTERPOLATE_30_DROP RESC_PAL_60_INTERPOLATE_30_DROP
#define CELL_RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE

#define CELL_RESC_INTERLACE_FILTER RESC_INTERLACE_FILTER
#define CELL_RESC_NORMAL_BILINEAR RESC_NORMAL_BILINEAR

#define CELL_RESC_ELEMENT_HALF RESC_ELEMENT_HALF

#define CELL_VIDEO_OUT_ASPECT_AUTO VIDEO_ASPECT_AUTO
#define CELL_VIDEO_OUT_ASPECT_4_3 VIDEO_ASPECT_4_3
#define CELL_VIDEO_OUT_ASPECT_16_9 VIDEO_ASPECT_16_9

#define CELL_VIDEO_OUT_RESOLUTION_480 VIDEO_RESOLUTION_480
#define CELL_VIDEO_OUT_RESOLUTION_576 VIDEO_RESOLUTION_576
#define CELL_VIDEO_OUT_RESOLUTION_720 VIDEO_RESOLUTION_720
#define CELL_VIDEO_OUT_RESOLUTION_1080 VIDEO_RESOLUTION_1080
#define CELL_VIDEO_OUT_RESOLUTION_960x1080 VIDEO_RESOLUTION_960x1080
#define CELL_VIDEO_OUT_RESOLUTION_1280x1080 VIDEO_RESOLUTION_1280x1080
#define CELL_VIDEO_OUT_RESOLUTION_1440x1080 VIDEO_RESOLUTION_1440x1080
#define CELL_VIDEO_OUT_RESOLUTION_1600x1080 VIDEO_RESOLUTION_1600x1080

#define CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE VIDEO_SCANMODE_PROGRESSIVE

#define CELL_VIDEO_OUT_PRIMARY VIDEO_PRIMARY

#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8 VIDEO_BUFFER_FORMAT_XRGB
#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT VIDEO_BUFFER_FORMAT_FLOAT

#define CellGcmSurface gcmSurface
#define CellGcmTexture gcmTexture
#define CellGcmContextData _gcmCtxData
#define CellGcmConfig gcmConfiguration
#define CellVideoOutConfiguration videoConfiguration
#define CellVideoOutResolution videoResolution
#define CellVideoOutState videoState

#define CellRescInitConfig rescInitConfig
#define CellRescSrc rescSrc
#define CellRescBufferMode rescBufferMode

#define resolutionId resolution
#define memoryFrequency memoryFreq
#define coreFrequency coreFreq

#define cellGcmFinish rsxFinish

#define cellGcmGetFlipStatus gcmGetFlipStatus
#define cellGcmResetFlipStatus gcmResetFlipStatus
#define cellGcmSetWaitFlip gcmSetWaitFlip
#define cellGcmSetDebugOutputLevel gcmSetDebugOutputLevel
#define cellGcmSetDisplayBuffer gcmSetDisplayBuffer
#define cellGcmSetGraphicsHandler gcmSetGraphicsHandler
#define cellGcmSetFlipHandler gcmSetFlipHandler
#define cellGcmSetVBlankHandler gcmSetVBlankHandler
#define cellGcmGetConfiguration gcmGetConfiguration
#define cellGcmSetJumpCommand rsxSetJumpCommand
#define cellGcmFlush rsxFlushBuffer
#define cellGcmSetFlipMode gcmSetFlipMode
#define cellGcmSetFlip gcmSetFlip
#define cellGcmGetLabelAddress gcmGetLabelAddress
#define cellGcmUnbindTile gcmUnbindTile
#define cellGcmBindTile gcmBindTile
#define cellGcmSetTileInfo gcmSetTileInfo
#define cellGcmAddressToOffset gcmAddressToOffset

#define cellRescCreateInterlaceTable rescCreateInterlaceTable
#define cellRescSetDisplayMode rescSetDisplayMode
#define cellRescGetNumColorBuffers rescGetNumColorBuffers
#define cellRescGetBufferSize rescGetBufferSize
#define cellRescSetBufferAddress rescSetBufferAddress
#define cellRescGetFlipStatus rescGetFlipStatus
#define cellRescResetFlipStatus rescResetFlipStatus
#define cellRescSetConvertAndFlip rescSetConvertAndFlip
#define cellRescSetVBlankHandler rescSetVBlankHandler
#define cellRescSetFlipHandler rescSetFlipHandler
#define cellRescAdjustAspectRatio rescAdjustAspectRatio
#define cellRescSetWaitFlip rescSetWaitFlip
#define cellRescSetSrc rescSetSrc
#define cellRescInit rescInit
#define cellRescExit rescExit

#define cellVideoOutConfigure videoConfigure
#define cellVideoOutGetState videoGetState
#define cellVideoOutGetResolution videoGetResolution
#define cellVideoOutGetResolutionAvailability videoGetResolutionAvailability

#define cellGcmSetViewportInline rsxSetViewport
#define cellGcmSetReferenceCommandInline rsxSetReferenceCommand
#define cellGcmSetBlendEquationInline rsxSetBlendEquation
#define cellGcmSetWriteBackEndLabelInline rsxSetWriteBackendLabel
#define cellGcmSetWaitLabelInline rsxSetWaitLabel
#define cellGcmSetDepthTestEnableInline rsxSetDepthTestEnable
#define cellGcmSetScissorInline rsxSetScissor
#define cellGcmSetBlendEnableInline rsxSetBlendEnable
#define cellGcmSetClearColorInline rsxSetClearColor
#define cellGcmSetBlendFuncInline rsxSetBlendFunc
#define cellGcmSetBlendColorInline rsxSetBlendColor
#define cellGcmSetTextureFilterInline rsxTextureFilter
#define cellGcmSetTextureControlInline rsxTextureControl
#define cellGcmSetCullFaceEnableInline rsxSetCullFaceEnable
#define cellGcmSetShadeModeInline rsxSetShadeModel
#define cellGcmSetTransferImage rsxSetTransferImage
#define cellGcmSetBlendColor rsxSetBlendColor
#define cellGcmSetBlendEquation rsxSetBlendEquation
#define cellGcmSetBlendFunc rsxSetBlendFunc
#define cellGcmSetClearColor rsxSetClearColor
#define cellGcmSetScissor rsxSetScissor
#define celGcmSetInvalidateVertexCache(fifo) rsxInvalidateTextureCache(fifo, GCM_INVALIDATE_VERTEX_TEXTURE)
#else
#define cellGcmSetTransferImage cellGcmSetTransferImageInline
#define celGcmSetInvalidateVertexCache cellGcmSetInvalidateVertexCacheInline
#define rsxInit cellGcmInit
#define rsxInvalidateTextureCache(a, b) cellGcmSetInvalidateVertexCache(a)
#define rsxTextureControl cellGcmSetTextureControlInline
#define rsxSetBlendEnable cellGcmSetBlendEnableInline 
#endif

/*============================================================
	NETWORK PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <net/netctl.h>

#define cellNetCtlInit netCtlInit
#define cellNetCtlGetState netCtlGetState
#define cellNetCtlTerm netCtlTerm

#define CELL_NET_CTL_STATE_IPObtained NET_CTL_STATE_IPObtained
#else
#define netCtlInit cellNetCtlInit
#define netCtlGetState cellNetCtlGetState
#define netCtlTerm cellNetCtlTerm
#define NET_CTL_STATE_IPObtained CELL_NET_CTL_STATE_IPObtained
#endif

/*============================================================
	NET PROTOTYPES
============================================================ */

#if defined(HAVE_NETWORKING)
#ifdef __PSL1GHT__
#include <net/net.h>

#define socketselect select
#define socketclose close

#define sys_net_initialize_network netInitialize
#define sys_net_finalize_network netFinalizeNetwork
#else
#include <netex/net.h>
#include <np.h>
#include <np/drm.h>

#define netInitialize sys_net_initialize_network
#define netFinalizeNetwork sys_net_finalize_network
#endif
#endif

/*============================================================
	SYSUTIL PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include <sysutil/game.h>
#define CellGameContentSize sysGameContentSize
#define cellGameContentPermit sysGameContentPermit
#define cellGameBootCheck sysGameBootCheck

#define CELL_GAME_ATTRIBUTE_APP_HOME   (UINT64_C(1) <<1) /* boot from / app_home/PS3_GAME */
#define CELL_GAME_DIRNAME_SIZE			32

#define CELL_GAME_GAMETYPE_SYS		0
#define CELL_GAME_GAMETYPE_DISC		1
#define CELL_GAME_GAMETYPE_HDD		2
#define CELL_GAME_GAMETYPE_GAMEDATA	3
#define CELL_GAME_GAMETYPE_HOME		4

#endif

#if defined(HAVE_SYSUTILS)
#ifdef __PSL1GHT__
#include <sysutil/sysutil.h>

#define CELL_SYSUTIL_REQUEST_EXITGAME SYSUTIL_EXIT_GAME

#define cellSysutilRegisterCallback sysUtilRegisterCallback
#define cellSysutilCheckCallback sysUtilCheckCallback
#else
#include <sysutil/sysutil_screenshot.h>
#include <sysutil/sysutil_common.h>
#include <sysutil/sysutil_gamecontent.h>
#endif
#endif

#if(CELL_SDK_VERSION > 0x340000)
#include <sysutil/sysutil_bgmplayback.h>
#endif

/*============================================================
	SYSMODULE PROTOTYPES
============================================================ */

#if defined(HAVE_SYSMODULES)
#ifdef __PSL1GHT__
#include <sysmodule/sysmodule.h>

#define CELL_SYSMODULE_IO SYSMODULE_IO
#define CELL_SYSMODULE_FS SYSMODULE_FS
#define CELL_SYSMODULE_NET SYSMODULE_NET
#define CELL_SYSMODULE_SYSUTIL_NP SYSMODULE_SYSUTIL_NP
#define CELL_SYSMODULE_JPGDEC SYSMODULE_JPGDEC
#define CELL_SYSMODULE_PNGDEC SYSMODULE_PNGDEC
#define CELL_SYSMODULE_FONT SYSMODULE_FONT
#define CELL_SYSMODULE_FREETYPE SYSMODULE_FREETYPE
#define CELL_SYSMODULE_FONTFT SYSMODULE_FONTFT

#define cellSysmoduleLoadModule sysModuleLoad
#define cellSysmoduleUnloadModule sysModuleUnload

#else
#include <cell/sysmodule.h>

#define sysModuleLoad cellSysmoduleLoadModule
#define sysModuleUnload cellSysmoduleUnloadModule
#define SYSMODULE_NET CELL_SYSMODULE_NET
#endif
#endif

/*============================================================
	FS PROTOTYPES
============================================================ */
#define FS_SUCCEEDED 0
#define FS_TYPE_DIR 1
#ifdef __PSL1GHT__
#include <lv2/sysfs.h>
#ifndef O_RDONLY
#define O_RDONLY SYS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY SYS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT SYS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC SYS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR SYS_O_RDWR
#endif
#else
#include <cell/cell_fs.h>
#ifndef O_RDONLY
#define O_RDONLY CELL_FS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY CELL_FS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT CELL_FS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC CELL_FS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR CELL_FS_O_RDWR
#endif
#ifndef sysFsStat
#define sysFsStat cellFsStat
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsOpendir
#define sysFsOpendir cellFsOpendir
#endif
#ifndef sysFsReaddir
#define sysFsReaddir cellFsReaddir
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsClosedir
#define sysFsClosedir cellFsClosedir
#endif
#endif

#endif

./include/libretro-common/include/defines/ps4_defines.h

#ifndef _PS4_DEFINES_H
#define _PS4_DEFINES_H

#define PS4_MAX_ORBISPADS 16
#define PS4_MAX_PAD_PORT_TYPES 3

#define	ORBISPAD_L3		        0x00000002
#define	ORBISPAD_R3		        0x00000004
#define	ORBISPAD_OPTIONS	    0x00000008
#define	ORBISPAD_UP		        0x00000010
#define	ORBISPAD_RIGHT		    0x00000020
#define	ORBISPAD_DOWN		      0x00000040
#define	ORBISPAD_LEFT		      0x00000080
#define	ORBISPAD_L2		        0x00000100
#define	ORBISPAD_R2		        0x00000200
#define	ORBISPAD_L1		        0x00000400
#define	ORBISPAD_R1		        0x00000800
#define	ORBISPAD_TRIANGLE	    0x00001000
#define	ORBISPAD_CIRCLE		    0x00002000
#define	ORBISPAD_CROSS		    0x00004000
#define	ORBISPAD_SQUARE		    0x00008000
#define	ORBISPAD_TOUCH_PAD	  0x00100000
#define	ORBISPAD_INTERCEPTED	0x80000000

#define SceUID uint32_t
#define SceKernelStat OrbisKernelStat
#define SCE_KERNEL_PRIO_FIFO_DEFAULT 700
#define SCE_AUDIO_OUT_PORT_TYPE_MAIN   0
#define SCE_AUDIO_OUT_MODE_STEREO      1
#define SCE_MOUSE_BUTTON_PRIMARY 0x00000001
#define SCE_MOUSE_BUTTON_SECONDARY 0x00000002
#define SCE_MOUSE_BUTTON_OPTIONAL 0x00000004
#define SCE_MOUSE_BUTTON_INTERCEPTED 0x80000000
#define SCE_MOUSE_OPEN_PARAM_MERGED	0x01
#define SCE_MOUSE_PORT_TYPE_STANDARD 0
#define SCE_DBG_KEYBOARD_PORT_TYPE_STANDARD	0
#define SCE_USER_SERVICE_MAX_LOGIN_USERS 16
#define SCE_USER_SERVICE_USER_ID_INVALID 0xFFFFFFFF
#define SCE_ORBISPAD_ERROR_ALREADY_OPENED 0x80920004
#define SCE_PAD_PORT_TYPE_STANDARD 0
#define SCE_PAD_PORT_TYPE_SPECIAL	2
#define SCE_PAD_PORT_TYPE_REMOTE_CONTROL 16
#define SCE_KERNEL_PROT_CPU_RW 0x02
#define SCE_KERNEL_MAP_FIXED 0x10

#endif

./include/libretro-common/include/defines/psp_defines.h

/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (psp_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _PSP_DEFINES_H
#define _PSP_DEFINES_H

/*============================================================
	ERROR PROTOTYPES
============================================================ */

#ifndef SCE_OK
#define SCE_OK 0
#endif

/*============================================================
	DISPLAY PROTOTYPES
============================================================ */

#if defined(SN_TARGET_PSP2) || defined(VITA)

#ifdef VITA
int sceClibPrintf ( const char * format, ... );
#define printf sceClibPrintf
#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
#else
#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
#endif

#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, sync)

#define PSP_FB_WIDTH        960
#define PSP_FB_HEIGHT       544
#define PSP_PITCH_PIXELS 1024

/* Memory left to the system for threads and other internal stuffs */
#ifdef SCE_LIBC_SIZE
#define RAM_THRESHOLD 0x2000000 + SCE_LIBC_SIZE
#else
#define RAM_THRESHOLD 0x2000000
#endif

#elif defined(PSP)
#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync)

#define SCE_DISPLAY_UPDATETIMING_NEXTVSYNC 1

#define PSP_FB_WIDTH        512
#define PSP_FB_HEIGHT       512
#define PSP_PITCH_PIXELS 512

#endif

/*============================================================
	INPUT PROTOTYPES
============================================================ */

#if defined(SN_TARGET_PSP2) || defined(VITA)

#define STATE_BUTTON(state) ((state).buttons)
#define STATE_ANALOGLX(state) ((state).lx)
#define STATE_ANALOGLY(state) ((state).ly)
#define STATE_ANALOGRX(state) ((state).rx)
#define STATE_ANALOGRY(state) ((state).ry)

#if defined(VITA)
#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_ANALOG)

#define PSP_CTRL_LEFT SCE_CTRL_LEFT
#define PSP_CTRL_DOWN SCE_CTRL_DOWN
#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT
#define PSP_CTRL_UP SCE_CTRL_UP
#define PSP_CTRL_START SCE_CTRL_START
#define PSP_CTRL_SELECT SCE_CTRL_SELECT
#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE
#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE
#define PSP_CTRL_CROSS SCE_CTRL_CROSS
#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE
#define PSP_CTRL_L SCE_CTRL_L1
#define PSP_CTRL_R SCE_CTRL_R1
#define PSP_CTRL_L2 SCE_CTRL_LTRIGGER
#define PSP_CTRL_R2 SCE_CTRL_RTRIGGER
#define PSP_CTRL_L3 SCE_CTRL_L3
#define PSP_CTRL_R3 SCE_CTRL_R3
#define STATE_ANALOGL2(state) ((state).lt)
#define STATE_ANALOGR2(state) ((state).rt)
#else
#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_DIGITALANALOG)

#define PSP_CTRL_LEFT SCE_CTRL_LEFT
#define PSP_CTRL_DOWN SCE_CTRL_DOWN
#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT
#define PSP_CTRL_UP SCE_CTRL_UP
#define PSP_CTRL_START SCE_CTRL_START
#define PSP_CTRL_SELECT SCE_CTRL_SELECT
#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE
#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE
#define PSP_CTRL_CROSS SCE_CTRL_CROSS
#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE
#define PSP_CTRL_L SCE_CTRL_L
#define PSP_CTRL_R SCE_CTRL_R
#endif

#if defined(VITA)
#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingModeExt(mode)
#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositiveExt2(port, pad_data, bufs)
#else
#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)
#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(port, pad_data, bufs)
#endif

#elif defined(PSP)

#define PSP_CTRL_L PSP_CTRL_LTRIGGER
#define PSP_CTRL_R PSP_CTRL_RTRIGGER

#define STATE_BUTTON(state) ((state).Buttons)
#define STATE_ANALOGLX(state) ((state).Lx)
#define STATE_ANALOGLY(state) ((state).Ly)
#define STATE_ANALOGRX(state) ((state).Rx)
#define STATE_ANALOGRY(state) ((state).Ry)

#define DEFAULT_SAMPLING_MODE (PSP_CTRL_MODE_ANALOG)

#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)
#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(pad_data, bufs)
#endif

#endif

./include/libretro-common/include/dynamic/dylib.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dylib.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __DYLIB_H
#define __DYLIB_H

#include <boolean.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <retro_common_api.h>

#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
#define NEED_DYNAMIC
#else
#undef NEED_DYNAMIC
#endif

RETRO_BEGIN_DECLS

/**
 * Opaque handle to a dynamic library.
 * @see dylib_load
 */
typedef void *dylib_t;

/**
 * Opaque handle to a function exposed by a dynamic library.
 *
 * Should be cast to a known function pointer type before being used.
 * @see dylib_proc
 */
typedef void (*function_t)(void);

#ifdef NEED_DYNAMIC
/**
 * Loads a dynamic library in a platform-independent manner.
 *
 * @param path Path to the library to load.
 * May be either a complete path or a filename without an extension.
 * If not a complete path, the operating system will search for a library by this name;
 * details will depend on the platform.
 * @note The returned library must be freed with \c dylib_close
 * before the core or frontend exits.
 *
 * @return Handle to the loaded library, or \c NULL on failure.
 * Upon failure, \c dylib_error may be used
 * to retrieve a string describing the error.
 * @see dylib_close
 * @see dylib_error
 * @see dylib_proc
 **/
dylib_t dylib_load(const char *path);

/**
 * Frees the resources associated with a dynamic library.
 *
 * Any function pointers obtained from the library may become invalid,
 * depending on whether the operating system manages reference counts to dynamic libraries.
 *
 * If there was an error closing the library,
 * it will be reported by \c dylib_error.
 *
 * @param lib Handle to the library to close.
 * Behavior is undefined if \c NULL.
 **/
void dylib_close(dylib_t lib);

/**
 * Returns a string describing the most recent error that occurred
 * within the other \c dylib functions.
 *
 * @return Pointer to the most recent error string,
 * \c or NULL if there was no error.
 * @warning The returned string is only valid
 * until the next call to a \c dylib function.
 * Additionally, the string is managed by the library
 * and should not be modified or freed by the caller.
 */
char *dylib_error(void);

/**
 * Returns a pointer to a function exposed by a dynamic library.
 *
 * @param lib The library to get a function pointer from.
 * @param proc The name of the function to get a pointer to.
 * @return Pointer to the requested function,
 * or \c NULL if there was an error.
 * This must be cast to the correct function pointer type before being used.
 * @warning The returned pointer is only valid for the lifetime of \c lib.
 * Once \c lib is closed, all function pointers returned from it will be invalidated;
 * using them is undefined behavior.
 */
function_t dylib_proc(dylib_t lib, const char *proc);
#endif

RETRO_END_DECLS

#endif

./include/libretro-common/include/encodings/base64.h

#ifndef _LIBRETRO_ENCODINGS_BASE64_H
#define _LIBRETRO_ENCODINGS_BASE64_H

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/**
 * Encodes binary data into a \c NULL-terminated base64 string.
 *
 * @param binaryData The data to encode.
 * Behavior is undefined if \c NULL.
 * @param len The length of the data to encode.
 * @param flen Pointer to the length of the returned string.
 * @return Pointer to the base64-encoded string, or \c NULL on failure.
 * The returned string is owned by the caller and must be released with \c free().
 * @see unbase64
 */
char* base64(const void* binaryData, int len, int *flen);

/**
 * Decodes a base64-encoded string into binary data.
 *
 * @param ascii The base64 string to decode, in ASCII format.
 * @param len Length of the string to decode.
 * @param flen Pointer to the length of the returned data.
 * @return The decoded binary data, or \c NULL on failure.
 * The returned buffer is owned by the caller and must be released with \c free().
 * @see base64
 */
unsigned char* unbase64(const char* ascii, int len, int *flen);

RETRO_END_DECLS

#endif

./include/libretro-common/include/encodings/crc32.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (crc32.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_ENCODINGS_CRC32_H
#define _LIBRETRO_ENCODINGS_CRC32_H

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/**
 * Computes a buffer's CRC32 checksum.
 *
 * @param crc The initial CRC32 value.
 * @param buf The buffer to calculate the CRC32 checksum of.
 * @param len The length of the data in \c buf.
 * @return The CRC32 checksum of the given buffer.
 */
uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len);

RETRO_END_DECLS

#endif

./include/libretro-common/include/encodings/utf.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (utf.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_ENCODINGS_UTF_H
#define _LIBRETRO_ENCODINGS_UTF_H

#include <stdint.h>
#include <stddef.h>

#include <boolean.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

enum CodePage
{
   CODEPAGE_LOCAL = 0, /* CP_ACP */
   CODEPAGE_UTF8  = 65001 /* CP_UTF8 */
};

/**
 * utf8_conv_utf32:
 *
 * Simple implementation. Assumes the sequence is
 * properly synchronized and terminated.
 **/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
      const char *in, size_t in_size);

/**
 * utf16_conv_utf8:
 *
 * Leaf function.
 **/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
      const uint16_t *in, size_t in_size);

/**
 * utf8len:
 *
 * Leaf function.
 **/
size_t utf8len(const char *string);

/**
 * utf8cpy:
 *
 * Acts mostly like strlcpy.
 *
 * Copies the given number of UTF-8 characters,
 * but at most @d_len bytes.
 *
 * Always NULL terminates. Does not copy half a character.
 * @s is assumed valid UTF-8.
 * Use only if @chars is considerably less than @d_len. 
 *
 * Hidden non-leaf function cost:
 * - Calls memcpy
 *
 * @return Number of bytes. 
 **/
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);

/**
 * utf8skip:
 *
 * Leaf function
 **/
const char *utf8skip(const char *str, size_t chars);

/** 
 * utf8_walk:
 *
 * Does not validate the input.
 *
 * Leaf function.
 *
 * @return Returns garbage if it's not UTF-8.
 **/
uint32_t utf8_walk(const char **string);

/**
 * utf16_to_char_string:
 **/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);

/**
 * utf8_to_local_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *utf8_to_local_string_alloc(const char *str);

/**
 * local_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *local_to_utf8_string_alloc(const char *str);

/**
 * utf8_to_utf16_string_alloc:
 * 
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
wchar_t *utf8_to_utf16_string_alloc(const char *str);

/**
 * utf16_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *utf16_to_utf8_string_alloc(const wchar_t *str);

RETRO_END_DECLS

#endif

./include/libretro-common/include/encodings/win32.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (utf.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_ENCODINGS_WIN32_H
#define _LIBRETRO_ENCODINGS_WIN32_H

#ifndef _XBOX
#ifdef _WIN32
/*#define UNICODE
#include <tchar.h>
#include <wchar.h>*/

#ifdef __cplusplus
extern "C" {
#endif

#include <encodings/utf.h>

#ifdef __cplusplus
}
#endif

#endif
#endif

#ifdef UNICODE
#define CHAR_TO_WCHAR_ALLOC(s, ws) \
   size_t ws##_size = (NULL != s && s[0] ? strlen(s) : 0) + 1; \
   wchar_t *ws = (wchar_t*)calloc(ws##_size, 2); \
   if (NULL != s && s[0]) \
      MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws##_size / sizeof(wchar_t));

#define WCHAR_TO_CHAR_ALLOC(ws, s) \
   size_t s##_size = ((NULL != ws && ws[0] ? wcslen((const wchar_t*)ws) : 0) / 2) + 1; \
   char *s = (char*)calloc(s##_size, 1); \
   if (NULL != ws && ws[0]) \
      utf16_to_char_string((const uint16_t*)ws, s, s##_size);

#else
#define CHAR_TO_WCHAR_ALLOC(s, ws) char *ws = (NULL != s && s[0] ? strdup(s) : NULL);
#define WCHAR_TO_CHAR_ALLOC(ws, s) char *s = (NULL != ws && ws[0] ? strdup(ws) : NULL);
#endif

#endif

./include/libretro-common/include/fastcpy.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fastcpy.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* in the future ASM and new c++ features can be added to speed up copying */
#include <stdint.h>
#include <string.h>
#include <retro_inline.h>

static INLINE void* memcpy16(void* dst, void* src, size_t len)
{
   return memcpy(dst, src, len * 2);
}

static INLINE void* memcpy32(void* dst, void* src, size_t len)
{
   return memcpy(dst, src, len * 4);
}

static INLINE void* memcpy64(void* dst, void* src, size_t len)
{
   return memcpy(dst, src, len * 8);
}

#ifdef USECPPSTDFILL
#include <algorithm>

static INLINE void* memset16(void* dst,uint16_t val, size_t len)
{
   uint16_t *typedptr = (uint16_t*)dst;
   std::fill(typedptr, typedptr + len, val);
   return dst;
}

static INLINE void* memset32(void* dst, uint32_t val, size_t len)
{
   uint32_t *typedptr = (uint32_t*)dst;
   std::fill(typedptr, typedptr + len, val);
   return dst;
}

static INLINE void* memset64(void* dst, uint64_t val, size_t len)
{
   uint64_t *typedptr = (uint64_t*)dst;
   std::fill(typedptr, typedptr + len, val);
   return dst;
}
#else
static INLINE void *memset16(void* dst, uint16_t val, size_t len)
{
   size_t i;
   uint16_t *typedptr = (uint16_t*)dst;
   for (i = 0; i < len; i++)
      typedptr[i] = val;
   return dst;
}

static INLINE void *memset32(void* dst, uint32_t val, size_t len)
{
   size_t i;
   uint32_t *typedptr = (uint32_t*)dst;
   for (i = 0; i < len; i++)
      typedptr[i] = val;
   return dst;
}

static INLINE void *memset64(void* dst, uint64_t val, size_t len)
{
   size_t i;
   uint64_t *typedptr = (uint64_t*)dst;
   for (i = 0; i < len;i++)
      typedptr[i] = val;
   return dst;
}
#endif

./include/libretro-common/include/features/features_cpu.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (features_cpu.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_CPU_INFO_H
#define _LIBRETRO_SDK_CPU_INFO_H

#include <retro_common_api.h>

#include <stdint.h>

#include <libretro.h>

RETRO_BEGIN_DECLS

/**
 * Gets the time in ticks since some unspecified epoch.
 * The notion of a "tick" varies per platform.
 *
 * The epoch may change between devices or across reboots.
 *
 * Suitable for use as a default implementation of \c retro_perf_callback::get_perf_counter,
 * (or as a fallback by the core),
 * although a frontend may provide its own implementation.
 *
 * @return The current time, in ticks.
 * @see retro_perf_callback::get_perf_counter
 */
retro_perf_tick_t cpu_features_get_perf_counter(void);

/**
 * Gets the time in microseconds since some unspecified epoch.
 *
 * The epoch may change between devices or across reboots.
 *
 * Suitable for use as a default implementation of \c retro_perf_callback::get_time_usec,
 * (or as a fallback by the core),
 * although a frontend may provide its own implementation.
 *
 * @return The current time, in microseconds.
 * @see retro_perf_callback::get_time_usec
 */
retro_time_t cpu_features_get_time_usec(void);

/**
 * Returns the available features (mostly SIMD extensions)
 * supported by this CPU.
 *
 * Suitable for use as a default implementation of \c retro_perf_callback::get_time_usec,
 * (or as a fallback by the core),
 * although a frontend may provide its own implementation.
 *
 * @return Bitmask of all CPU features available.
 * @see RETRO_SIMD
 * @see retro_perf_callback::get_cpu_features
 */
uint64_t cpu_features_get(void);

/**
 * @return The number of CPU cores available,
 * or 1 if the number of cores could not be determined.
 */
unsigned cpu_features_get_core_amount(void);

/**
 * Returns the name of the CPU model.
 *
 * @param[out] name Pointer to a buffer to store the name.
 * Will be \c NULL-terminated.
 * If \c NULL, this value will not be modified.
 * @param len The amount of space available in \c name.
 */
void cpu_features_get_model_name(char *name, int len);

RETRO_END_DECLS

#endif

./include/libretro-common/include/file/archive_file.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_ARCHIVE_FILE_H__
#define LIBRETRO_SDK_ARCHIVE_FILE_H__

#include <stdint.h>
#include <stddef.h>
#include <boolean.h>

#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif

#include <retro_miscellaneous.h>

#include <retro_common_api.h>

#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h" /* for HAVE_MMAP */
#endif

RETRO_BEGIN_DECLS

enum file_archive_transfer_type
{
   ARCHIVE_TRANSFER_NONE = 0,
   ARCHIVE_TRANSFER_INIT,
   ARCHIVE_TRANSFER_ITERATE,
   ARCHIVE_TRANSFER_DEINIT,
   ARCHIVE_TRANSFER_DEINIT_ERROR
};

typedef struct file_archive_handle
{
   uint8_t  *data;
   uint32_t real_checksum;
} file_archive_file_handle_t;

typedef struct file_archive_transfer
{
   int64_t archive_size;
   void *context;
   struct RFILE *archive_file;
   const struct file_archive_file_backend *backend;
#ifdef HAVE_MMAP
   uint8_t *archive_mmap_data;
   int archive_mmap_fd;
#endif
   unsigned step_total;
   unsigned step_current;
   enum file_archive_transfer_type type;
} file_archive_transfer_t;

typedef struct
{
   file_archive_transfer_t archive;             /* int64_t alignment */
   char *source_file;
   char *subdir;
   char *target_dir;
   char *target_file;
   char *valid_ext;
   char *callback_error;
   struct archive_extract_userdata *userdata;
} decompress_state_t;

struct archive_extract_userdata
{
   /* These are set or read by the archive processing */
   char *first_extracted_file_path;
   const char *extraction_directory;
   struct string_list *ext;
   struct string_list *list;
   file_archive_transfer_t *transfer;
   /* Not used by the processing, free to use outside or in iterate callback */
   decompress_state_t *dec;
   void* cb_data;
   uint32_t crc;
   char archive_path[PATH_MAX_LENGTH];
   char current_file_path[PATH_MAX_LENGTH];
   bool found_file;
   bool list_only;
};

/* Returns true when parsing should continue. False to stop. */
typedef int (*file_archive_file_cb)(const char *name, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata);

struct file_archive_file_backend
{
   int (*archive_parse_file_init)(
      file_archive_transfer_t *state,
      const char *file);
   int (*archive_parse_file_iterate_step)(
      void *context,
      const char *valid_exts,
      struct archive_extract_userdata *userdata,
      file_archive_file_cb file_cb);
   void (*archive_parse_file_free)(
      void *context);

   bool     (*stream_decompress_data_to_file_init)(
      void *context, file_archive_file_handle_t *handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size);
   int      (*stream_decompress_data_to_file_iterate)(
      void *context,
      file_archive_file_handle_t *handle);

   uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t);
   int64_t (*compressed_file_read)(const char *path, const char *needle, void **buf,
         const char *optional_outfile);
   const char *ident;
};

int file_archive_parse_file_iterate(
      file_archive_transfer_t *state,
      bool *returnerr,
      const char *file,
      const char *valid_exts,
      file_archive_file_cb file_cb,
      struct archive_extract_userdata *userdata);

void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state);

int file_archive_parse_file_progress(file_archive_transfer_t *state);

/**
 * file_archive_extract_file:
 * @archive_path                : filename path to ZIP archive.
 * @valid_exts                  : valid extensions for a file.
 * @extraction_directory        : the directory to extract the temporary
 *                                file to.
 *
 * Extract file from archive. If no file inside the archive is
 * specified, the first file found will be used.
 *
 * Returns : true (1) on success, otherwise false (0).
 **/
bool file_archive_extract_file(const char *archive_path,
      const char *valid_exts, const char *extraction_dir,
      char *out_path, size_t len);

/* Warning: 'list' must zero initialised before
 * calling this function, otherwise memory leaks/
 * undefined behaviour will occur */
bool file_archive_get_file_list_noalloc(struct string_list *list,
      const char *path,
      const char *valid_exts);

/**
 * file_archive_get_file_list:
 * @path                        : filename path of archive
 * @valid_exts                  : Valid extensions of archive to be parsed.
 *                                If NULL, allow all.
 *
 * Returns: string listing of files from archive on success, otherwise NULL.
 **/
struct string_list* file_archive_get_file_list(const char *path, const char *valid_exts);

bool file_archive_perform_mode(const char *name, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata);

int file_archive_compressed_read(
      const char* path, void **buf,
      const char* optional_filename, int64_t *length);

const struct file_archive_file_backend* file_archive_get_zlib_file_backend(void);
const struct file_archive_file_backend* file_archive_get_7z_file_backend(void);

const struct file_archive_file_backend* file_archive_get_file_backend(const char *path);

/**
 * file_archive_get_file_crc32:
 * @path                         : filename path of archive
 *
 * Returns: CRC32 of the specified file in the archive, otherwise 0.
 * If no path within the archive is specified, the first
 * file found inside is used.
 **/
uint32_t file_archive_get_file_crc32(const char *path);

extern const struct file_archive_file_backend zlib_backend;
extern const struct file_archive_file_backend sevenzip_backend;

RETRO_END_DECLS

#endif

./include/libretro-common/include/file/config_file.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_CONFIG_FILE_H
#define __LIBRETRO_SDK_CONFIG_FILE_H

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

#include <boolean.h>

#define CONFIG_GET_BOOL_BASE(conf, base, var, key) do { \
   bool tmp = false; \
   if (config_get_bool(conf, key, &tmp)) \
      base->var = tmp; \
} while(0)

#define CONFIG_GET_INT_BASE(conf, base, var, key) do { \
   int tmp = 0; \
   if (config_get_int(conf, key, &tmp)) \
      base->var = tmp; \
} while(0)

#define CONFIG_GET_FLOAT_BASE(conf, base, var, key) do { \
   float tmp = 0.0f; \
   if (config_get_float(conf, key, &tmp)) \
      base->var = tmp; \
} while(0)

enum config_file_flags
{
   CONF_FILE_FLG_MODIFIED                 = (1 << 0),
   CONF_FILE_FLG_GUARANTEED_NO_DUPLICATES = (1 << 1)
};

struct config_file
{
   char *path;
   struct config_entry_list **entries_map;
   struct config_entry_list *entries;
   struct config_entry_list *tail;
   struct config_entry_list *last;
   struct config_include_list *includes;
   struct path_linked_list *references;
   unsigned include_depth;
   uint8_t flags;
};

typedef struct config_file config_file_t;

struct config_file_cb
{
   void (*config_file_new_entry_cb)(char*, char*);
};

typedef struct config_file_cb config_file_cb_t ;

/* Config file format
 * - # are treated as comments. Rest of the line is ignored.
 * - Format is: key = value. There can be as many spaces as you like in-between.
 * - Value can be wrapped inside "" for multiword strings. (foo = "hai u")
 * - #include includes a config file in-place.
 *
 * Path is relative to where config file was loaded unless an absolute path is chosen.
 * Key/value pairs from an #include are read-only, and cannot be modified.
 */

/**
 * config_file_new:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new(const char *path);

config_file_t *config_file_new_alloc(void);

/**
 * config_file_initialize:
 *
 * Leaf function.
 **/
void config_file_initialize(struct config_file *conf);

/**
 * config_file_new_with_callback:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 * Includes cb callbacks  to run custom code during config file processing.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new_with_callback(
      const char *path, config_file_cb_t *cb);

/**
 * config_file_new_from_string:
 *
 * Load a config file from a string.
 *
 * NOTE: This will modify @from_string.
 * Pass a copy of source string if original
 * contents must be preserved
 **/
config_file_t *config_file_new_from_string(char *from_string,
      const char *path);

config_file_t *config_file_new_from_path_to_string(const char *path);

/**
 * config_file_free:
 *
 * Frees config file.
 **/
void config_file_free(config_file_t *conf);

size_t config_file_add_reference(config_file_t *conf, char *path);

bool config_file_deinitialize(config_file_t *conf);

/**
 * config_append_file:
 *
 * Loads a new config, and appends its data to @conf.
 * The key-value pairs of the new config file takes priority over the old.
 **/
bool config_append_file(config_file_t *conf, const char *path);

/* All extract functions return true when value is valid and exists.
 * Returns false otherwise. */

struct config_entry_list
{
   char *key;
   char *value;
   struct config_entry_list *next;
   /* If we got this from an #include,
    * do not allow overwrite. */
   bool readonly;
};

struct config_file_entry
{
   const char *key;
   const char *value;
   /* Used intentionally. Opaque here. */
   const struct config_entry_list *next;
};

struct config_entry_list *config_get_entry(
      const config_file_t *conf, const char *key);

/**
 * config_get_entry_list_head:
 *
 * Leaf function.
 **/
bool config_get_entry_list_head(config_file_t *conf,
      struct config_file_entry *entry);

/**
 * config_get_entry_list_next:
 *
 * Leaf function.
 **/
bool config_get_entry_list_next(struct config_file_entry *entry);

/**
 * config_get_double:
 *
 * Extracts a double from config file.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 * - Calls strtod
 *
 * @return True if double found, otherwise false.
 **/
bool config_get_double(config_file_t *conf, const char *entry, double *in);

/**
 * config_get_float:
 *
 * Extracts a float from config file.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 * - Calls strtod
 *
 * @return true if found, otherwise false.
 **/
bool config_get_float(config_file_t *conf, const char *entry, float *in);

/* Extracts an int from config file. */
bool config_get_int(config_file_t *conf, const char *entry, int *in);

/* Extracts an uint from config file. */
bool config_get_uint(config_file_t *conf, const char *entry, unsigned *in);

/* Extracts an size_t from config file. */
bool config_get_size_t(config_file_t *conf, const char *key, size_t *in);

#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
/* Extracts an uint64 from config file. */
bool config_get_uint64(config_file_t *conf, const char *entry, uint64_t *in);
#endif

/* Extracts an unsigned int from config file treating input as hex. */
bool config_get_hex(config_file_t *conf, const char *entry, unsigned *in);

/**
 * config_get_char:
 *
 * Extracts a single char from config file.
 * If value consists of several chars, this is an error.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 *
 * @return true if found, otherwise false.
 **/
bool config_get_char(config_file_t *conf, const char *entry, char *in);

/**
 * config_get_string:
 *
 * Extracts an allocated string in *in. This must be free()-d if
 * this function succeeds.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 * - Calls strdup
 *
 * @return true if found, otherwise false.
 **/
bool config_get_string(config_file_t *conf, const char *entry, char **in);

/* Extracts a string to a preallocated buffer. Avoid memory allocation. */
bool config_get_array(config_file_t *conf, const char *entry, char *s, size_t len);

/**
  * config_get_config_path:
  *
  * Extracts a string to a preallocated buffer.
  * Avoid memory allocation.
  *
  * Hidden non-leaf function cost:
  * - Calls strlcpy
  **/
size_t config_get_config_path(config_file_t *conf, char *s, size_t len);

/* Extracts a string to a preallocated buffer. Avoid memory allocation.
 * Recognized magic like ~/. Similar to config_get_array() otherwise. */
bool config_get_path(config_file_t *conf, const char *entry, char *s, size_t len);

/**
 * config_get_bool:
 *
 * Extracts a boolean from config.
 * Valid boolean true are "true" and "1". Valid false are "false" and "0".
 * Other values will be treated as an error.
 *
 * Hidden non-leaf function cost:
 * - Calls string_is_equal() x times
 *
 * @return true if preconditions are true, otherwise false.
 **/
bool config_get_bool(config_file_t *conf, const char *entry, bool *in);

/* Setters. Similar to the getters.
 * Will not write to entry if the entry was obtained from an #include. */
size_t config_set_double(config_file_t *conf, const char *entry, double value);
size_t config_set_float(config_file_t *conf, const char *entry, float value);
size_t config_set_int(config_file_t *conf, const char *entry, int val);
size_t config_set_hex(config_file_t *conf, const char *entry, unsigned val);
size_t config_set_uint64(config_file_t *conf, const char *entry, uint64_t val);
size_t config_set_char(config_file_t *conf, const char *entry, char val);
size_t config_set_uint(config_file_t *conf, const char *key, unsigned int val);

void config_set_path(config_file_t *conf, const char *entry, const char *val);
void config_set_string(config_file_t *conf, const char *entry, const char *val);
void config_unset(config_file_t *conf, const char *key);

/**
 * config_file_write:
 *
 * Write the current config to a file.
 **/
bool config_file_write(config_file_t *conf, const char *path, bool val);

/**
 * config_file_dump:
 *
 * Dump the current config to an already opened file.
 * Does not close the file.
 **/
void config_file_dump(config_file_t *conf, FILE *file, bool val);

RETRO_END_DECLS

#endif

./include/libretro-common/include/file/config_file_userdata.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_userdata.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H
#define _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H

#include <string.h>

#include <file/config_file.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

struct config_file_userdata
{
   config_file_t *conf;
   const char *prefix[2];
};

int config_userdata_get_float(void *userdata, const char *key_str,
      float *value, float default_value);

int config_userdata_get_int(void *userdata, const char *key_str,
      int *value, int default_value);

int config_userdata_get_hex(void *userdata, const char *key_str,
      unsigned *value, unsigned default_value);

int config_userdata_get_float_array(void *userdata, const char *key_str,
      float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values);

int config_userdata_get_int_array(void *userdata, const char *key_str,
      int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values);

int config_userdata_get_string(void *userdata, const char *key_str,
      char **output, const char *default_output);

void config_userdata_free(void *ptr);

RETRO_END_DECLS

#endif

./include/libretro-common/include/file/file_path.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_path.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FILE_PATH_H
#define __LIBRETRO_SDK_FILE_PATH_H

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>

#include <libretro.h>
#include <retro_common_api.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

#define PATH_REQUIRED_VFS_VERSION 3

void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);

/* Order in this enum is equivalent to negative sort order in filelist
 *  (i.e. DIRECTORY is on top of PLAIN_FILE) */
enum
{
   RARCH_FILETYPE_UNSET,
   RARCH_PLAIN_FILE,
   RARCH_COMPRESSED_FILE_IN_ARCHIVE,
   RARCH_COMPRESSED_ARCHIVE,
   RARCH_DIRECTORY,
   RARCH_FILE_UNSUPPORTED
};

struct path_linked_list
{
   char *path;
   struct path_linked_list *next;
};

/**
 * Create a new linked list with one item in it
 * The path on this item will be set to NULL
**/
struct path_linked_list* path_linked_list_new(void);

/* Free the entire linked list */
void path_linked_list_free(struct path_linked_list *in_path_linked_list);

/**
 * Add a node to the linked list with this path
 * If the first node's path if it's not yet set,
 * set this instead
**/
void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);

/**
 * path_is_compressed_file:
 * @path               : path
 *
 * Checks if path is a compressed file.
 *
 * Returns: true (1) if path is a compressed file, otherwise false (0).
 **/
bool path_is_compressed_file(const char *path);

/**
 * path_contains_compressed_file:
 * @path               : path
 *
 * Checks if path contains a compressed file.
 *
 * Currently we only check for hash symbol (#) inside the pathname.
 * If path is ever expanded to a general URI, we should check for that here.
 *
 * Example:  Somewhere in the path there might be a compressed file
 * E.g.: /path/to/file.7z#mygame.img
 *
 * Returns: true (1) if path contains compressed file, otherwise false (0).
 **/
#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)

/**
 * path_get_archive_delim:
 * @path               : path
 *
 * Find delimiter of an archive file. Only the first '#'
 * after a compression extension is considered.
 *
 * @return pointer to the delimiter in the path if it contains
 * a path inside a compressed file, otherwise NULL.
 **/
const char *path_get_archive_delim(const char *path);

/**
 * path_get_extension:
 * @path               : path
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * Hidden non-leaf function cost:
 * - calls string_is_empty()
 * - calls strrchr
 *
 * @return extension part from the path.
 **/
const char *path_get_extension(const char *path);

/**
 * path_get_extension_mutable:
 * @path               : path
 *
 * Specialized version of path_get_extension(). Return
 * value is mutable.
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * @return extension part from the path.
 **/
char *path_get_extension_mutable(const char *path);

/**
 * path_remove_extension:
 * @path               : path
 *
 * Mutates path by removing its extension. Removes all
 * text after and including the last '.'.
 * Only '.'s after the last slash are considered.
 *
 * Hidden non-leaf function cost:
 * - calls strrchr
 *
 * @return
 * 1) If path has an extension, returns path with the
 *    extension removed.
 * 2) If there is no extension, returns NULL.
 * 3) If path is empty or NULL, returns NULL
 */
char *path_remove_extension(char *path);

/**
 * path_basename:
 * @path               : path
 *
 * Get basename from @path.
 *
 * Hidden non-leaf function cost:
 * - Calls path_get_archive_delim()
 *
 * @return basename from path.
 **/
const char *path_basename(const char *path);

/**
 * path_basename_nocompression:
 * @path               : path
 *
 * Specialized version of path_basename().
 * Get basename from @path.
 *
 * @return basename from path.
 **/
const char *path_basename_nocompression(const char *path);

/**
 * path_basedir:
 * @path               : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 **/
size_t path_basedir(char *path);

/**
 * path_parent_dir:
 * @s                  : path
 * @len                : size of buffer
 *
 * Extracts parent directory by mutating path.
 * Assumes that path is a directory. Keeps trailing '/'.
 * If the path was already at the root directory, returns empty string
 **/
size_t path_parent_dir(char *s, size_t len);

/**
 * path_resolve_realpath:
 * @s                  : input and output buffer for path
 * @size               : size of buffer
 * @resolve_symlinks   : whether to resolve symlinks or not
 *
 * Resolves use of ".", "..", multiple slashes etc in absolute paths.
 *
 * Relative paths are rebased on the current working dir.
 *
 * @return @s if successful, NULL otherwise.
 * Note: Not implemented on consoles
 * Note: Symlinks are only resolved on Unix-likes
 * Note: The current working dir might not be what you expect,
 *       e.g. on Android it is "/"
 *       Use of fill_pathname_resolve_relative() should be preferred
 **/
char *path_resolve_realpath(char *s, size_t len, bool resolve_symlinks);

/**
 * path_relative_to:
 * @s                  : buffer to write the relative path to
 * @path               : path to be expressed relatively
 * @base               : relative to this
 * @len                : size of output buffer
 *
 * Turns @path into a path relative to @base and writes it to @s.
 *
 * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
 * Both @path and @base are assumed to be absolute paths without "." or "..".
 *
 * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
 *
 * @return Length of the string copied into @s
 **/
size_t path_relative_to(char *s, const char *path, const char *base,
      size_t len);

/**
 * path_is_absolute:
 * @path               : path
 *
 * Checks if @path is an absolute path or a relative path.
 *
 * @return true if path is absolute, false if path is relative.
 **/
bool path_is_absolute(const char *path);

/**
 * fill_pathname:
 * @s                  : output path
 * @in_path            : input  path
 * @replace            : what to replace
 * @len                : buffer size of output path
 *
 * FIXME: Verify
 *
 * Replaces filename extension with 'replace' and outputs result to s.
 * The extension here is considered to be the string from the last '.'
 * to the end.
 *
 * Only '.'s after the last slash are considered as extensions.
 * If no '.' is present, in_path and replace will simply be concatenated.
 * 'len' is buffer size of 's'.
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
 * s = "/foo/bar/baz/boo.asm"
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =>
 * s = "/foo/bar/baz/boo"
 *
 * Hidden non-leaf function cost:
 * - calls strlcpy 2x
 * - calls strrchr
 * - calls strlcat
 *
 * @return Length of the string copied into @s
 */
size_t fill_pathname(char *s, const char *in_path,
      const char *replace, size_t len);

/**
 * fill_dated_filename:
 * @s                  : output filename
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by 'RetroArch', and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
 *
 * Hidden non-leaf function cost:
 * - Calls rtime_localtime()
 * - Calls strftime
 * - Calls strlcat
 *
 **/
size_t fill_dated_filename(char *s, const char *ext, size_t len);

/**
 * fill_str_dated_filename:
 * @s                  : output filename
 * @in_str             : input string
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by the string @in_str, and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
 *
 * Hidden non-leaf function cost:
 * - Calls time
 * - Calls rtime_localtime()
 * - Calls strlcpy 2x
 * - Calls string_is_empty()
 * - Calls strftime
 * - Calls strlcat
 *
 * @return Length of the string copied into @s
 **/
size_t fill_str_dated_filename(char *s, const char *in_str, const char *ext, size_t len);

/**
 * find_last_slash:
 * @str                : path
 *
 * Find last slash in path. Tries to find
 * a backslash on Windows too which takes precedence
 * over regular slash.

 * Hidden non-leaf function cost:
 * - calls strrchr
 *
 * @return pointer to last slash/backslash found in @str.
 **/
char *find_last_slash(const char *str);

/**
 * fill_pathname_dir:
 * @s                  : input directory path
 * @in_basename        : input basename to be appended to @s
 * @replace            : replacement to be appended to @in_basename
 * @len                : size of buffer
 *
 * Appends basename of 'in_basename', to 's', along with 'replace'.
 * Basename of in_basename is the string after the last '/' or '\\',
 * i.e the filename without directories.
 *
 * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
 * 'len' is buffer size of 's'.
 *
 * E.g..: s = "/tmp/some_dir", in_basename = "/some_content/foo.c",
 * replace = ".asm" => s = "/tmp/some_dir/foo.c.asm"
 *
 * Hidden non-leaf function cost:
 * - Calls fill_pathname_slash()
 * - Calls path_basename()
 * - Calls strlcpy 2x
 **/
size_t fill_pathname_dir(char *s, const char *in_basename,
      const char *replace, size_t len);

/**
 * fill_pathname_base:
 * @s                  : output path
 * @in_path            : input path
 * @len                : size of output path
 *
 * Copies basename of @in_path into @s.
 *
 * Hidden non-leaf function cost:
 * - Calls path_basename()
 * - Calls strlcpy
 *
 * @return length of the string copied into @s
 **/
size_t fill_pathname_base(char *s, const char *in_path, size_t len);

/**
 * fill_pathname_basedir:
 * @s                  : output directory
 * @in_path            : input path
 * @len                : size of output directory
 *
 * Copies base directory of @in_path into @s.
 * If in_path is a path without any slashes (relative current directory),
 * @s will get path "./".
 *
 * Hidden non-leaf function cost:
 * - Calls strlcpy
 * - Calls path_basedir()
 **/
size_t fill_pathname_basedir(char *s, const char *in_path, size_t len);

/**
 * fill_pathname_parent_dir_name:
 * @s                  : output string
 * @in_dir             : input directory
 * @len                : size of @s
 *
 * Copies only the parent directory name of @in_dir into @s.
 * The two buffers must not overlap. Removes trailing '/'.
 *
 * Hidden non-leaf function cost:
 * - Calls strdup
 * - Can call strlcpy
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_parent_dir_name(char *s,
      const char *in_dir, size_t len);

/**
 * fill_pathname_parent_dir:
 * @s                  : output directory
 * @in_dir             : input directory
 * @len                : size of output directory
 *
 * Copies parent directory of @in_dir into @s.
 * Assumes @in_dir is a directory. Keeps trailing '/'.
 * If the path was already at the root directory, @s will be an empty string.
 *
 * Hidden non-leaf function cost:
 * - Can call strlcpy if (@s!= @in_dir)
 * - Calls strlen if (@s == @in_dir)
 * - Calls path_parent_dir()
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_parent_dir(char *s,
      const char *in_dir, size_t len);

/**
 * fill_pathname_resolve_relative:
 * @s                  : output path
 * @in_refpath         : input reference path
 * @in_path            : input path
 * @len                : size of @s
 *
 * Joins basedir of @in_refpath together with @in_path.
 * If @in_path is an absolute path, s = in_path.
 * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
 * s = "/foo/bar/foobar.cg".
 **/
void fill_pathname_resolve_relative(char *s, const char *in_refpath,
      const char *in_path, size_t len);

/**
 * fill_pathname_join:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get two consecutive slashes
 * between directory and path.
 *
 * Hidden non-leaf function cost:
 * - calls strlcpy at least once
 * - calls fill_pathname_slash()
 *
 * Deprecated. Use fill_pathname_join_special() instead
 * if you can ensure @dir != @s
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join(char *s, const char *dir,
      const char *path, size_t len);

/**
 * fill_pathname_join_special:
 * @s                  : output path
 * @dir                : directory. Cannot be identical to @s
 * @path               : path
 * @len                : size of output path
 *
 *
 * Specialized version of fill_pathname_join.
 * Unlike fill_pathname_join(),
 * @dir and @s CANNOT be identical.
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get two consecutive slashes
 * between directory and path.
 *
 * Hidden non-leaf function cost:
 * - calls strlcpy 2x
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join_special(char *s,
      const char *dir, const char *path, size_t len);

size_t fill_pathname_join_special_ext(char *s,
      const char *dir,  const char *path,
      const char *last, const char *ext,
      size_t len);

/**
 * fill_pathname_join_delim:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @delim              : delimiter
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together
 * using the given delimiter (@delim).
 *
 * Hidden non-leaf function cost:
 * - can call strlen
 * - can call strlcpy
 * - can call strlcat
 **/
size_t fill_pathname_join_delim(char *s, const char *dir,
      const char *path, const char delim, size_t len);

size_t fill_pathname_expand_special(char *s,
      const char *in_path, size_t len);

size_t fill_pathname_abbreviate_special(char *s,
      const char *in_path, size_t len);

/**
 * fill_pathname_abbreviated_or_relative:
 *
 * Fills the supplied path with either the abbreviated path or
 * the relative path, which ever one has less depth / number of slashes
 *
 * If lengths of abbreviated and relative paths are the same,
 * the relative path will be used
 * @in_path can be an absolute, relative or abbreviated path
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_abbreviated_or_relative(char *s,
		const char *in_refpath, const char *in_path, size_t len);

/**
 * sanitize_path_part:
 *
 * @path_part          : directory or filename
 * @len                : length of path_part
 *
 * Takes single part of a path eg. single filename
 * or directory, and removes any special chars that are
 * unavailable.
 *
 * @returns new string that has been sanitized
 **/
const char *sanitize_path_part(const char *path_part, size_t len);

/**
 * pathname_conform_slashes_to_os:
 *
 * @path               : path
 *
 * Leaf function.
 *
 * Changes the slashes to the correct kind for the os
 * So forward slash on linux and backslash on Windows
 **/
void pathname_conform_slashes_to_os(char *s);

/**
 * pathname_make_slashes_portable:
 * @path               : path
 *
 * Leaf function.
 *
 * Change all slashes to forward so they are more
 * portable between Windows and Linux
 **/
void pathname_make_slashes_portable(char *s);

/**
 * path_basedir:
 * @path               : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 **/
void path_basedir_wrapper(char *s);

/**
 * path_char_is_slash:
 * @c                  : character
 *
 * Checks if character (@c) is a slash.
 *
 * @return true if character is a slash, otherwise false.
 **/
#ifdef _WIN32
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else
#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
#endif

/**
 * path_default_slash and path_default_slash_c:
 *
 * Gets the default slash separator.
 *
 * @return default slash separator.
 **/
#ifdef _WIN32
#define PATH_DEFAULT_SLASH() "\\"
#define PATH_DEFAULT_SLASH_C() '\\'
#else
#define PATH_DEFAULT_SLASH() "/"
#define PATH_DEFAULT_SLASH_C() '/'
#endif

/**
 * fill_pathname_slash:
 * @s                  : path
 * @len                : size of path
 *
 * Assumes path is a directory. Appends a slash
 * if not already there.

 * Hidden non-leaf function cost:
 * - can call strlcat once if it returns false
 * - calls strlen
 **/
size_t fill_pathname_slash(char *s, size_t len);

#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
size_t fill_pathname_application_path(char *s, size_t len);
size_t fill_pathname_application_dir(char *s, size_t len);
size_t fill_pathname_home_dir(char *s, size_t len);
#endif

/**
 * path_mkdir:
 * @dir                : directory
 *
 * Create directory on filesystem.
 *
 * Recursive function.
 *
 * Hidden non-leaf function cost:
 * - Calls strdup
 * - Calls path_parent_dir()
 * - Calls strcmp
 * - Calls path_is_directory()
 * - Calls path_mkdir()
 *
 * @return true if directory could be created, otherwise false.
 **/
bool path_mkdir(const char *dir);

/**
 * path_is_directory:
 * @path               : path
 *
 * Checks if path is a directory.
 *
 * @return true if path is a directory, otherwise false.
 */
bool path_is_directory(const char *path);

/* Time format strings with AM-PM designation require special
 * handling due to platform dependence
 * @return Length of the string written to @s
 */
size_t strftime_am_pm(char *s, size_t len, const char* format,
      const void* timeptr);

bool path_is_character_special(const char *path);

int path_stat(const char *path);

bool path_is_valid(const char *path);

int32_t path_get_size(const char *path);

bool is_path_accessible_using_standard_io(const char *path);

RETRO_END_DECLS

#endif

./include/libretro-common/include/file/nbio.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_NBIO_H
#define __LIBRETRO_SDK_NBIO_H

#include <stddef.h>
#include <boolean.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#ifndef NBIO_READ
#define NBIO_READ   0
#endif

#ifndef NBIO_WRITE
#define NBIO_WRITE  1
#endif

#ifndef NBIO_UPDATE
#define NBIO_UPDATE 2
#endif

/* these two are blocking; nbio_iterate always returns true, but that operation (or something earlier) may take arbitrarily long */
#ifndef BIO_READ
#define BIO_READ    3
#endif

#ifndef BIO_WRITE
#define BIO_WRITE   4
#endif

typedef struct nbio_intf
{
   void *(*open)(const char * filename, unsigned mode);

   void (*begin_read)(void *data);

   void (*begin_write)(void *data);

   bool (*iterate)(void *data);

   void (*resize)(void *data, size_t len);

   void *(*get_ptr)(void *data, size_t* len);

   void (*cancel)(void *data);

   void (*free)(void *data);

   /* Human readable string. */
   const char *ident;
} nbio_intf_t;

/*
 * Creates an nbio structure for performing the
 * given operation on the given file.
 */
void *nbio_open(const char * filename, unsigned mode);

/*
 * Starts reading the given file. When done, it will be available in nbio_get_ptr.
 * Can not be done if the structure was created with {N,}BIO_WRITE.
 */
void nbio_begin_read(void *data);

/*
 * Starts writing to the given file. Before this, you should've copied the data to nbio_get_ptr.
 * Can not be done if the structure was created with {N,}BIO_READ.
 */
void nbio_begin_write(void *data);

/*
 * Performs part of the requested operation, or checks how it's going.
 * When it returns true, it's done.
 */
bool nbio_iterate(void *data);

/*
 * Resizes the file up to the given size; cannot shrink.
 * Can not be done if the structure was created with {N,}BIO_READ.
 */
void nbio_resize(void *data, size_t len);

/*
 * Returns a pointer to the file data. Writable only if structure was not created with {N,}BIO_READ.
 * If any operation is in progress, the pointer will be NULL, but len will still be correct.
 */
void* nbio_get_ptr(void *data, size_t* len);

/*
 * Stops any pending operation, allowing the object to be freed.
 */
void nbio_cancel(void *data);

/*
 * Deletes the nbio structure and its associated pointer.
 */
void nbio_free(void *data);

RETRO_END_DECLS

#endif

./include/libretro-common/include/filters.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (filters.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILTERS_H
#define _LIBRETRO_SDK_FILTERS_H

/* for MSVC; should be benign under any circumstances */
#define _USE_MATH_DEFINES

#include <stdlib.h>
#include <math.h>
#include <retro_inline.h>
#include <retro_math.h>

/**
 * sinc:
 *
 * Pure function.
 **/
static INLINE double sinc(double val)
{
   if (fabs(val) < 0.00001)
      return 1.0;
   return sin(val) / val;
}

/**
 * paeth:
 *
 * Pure function.
 * Paeth prediction filter.
 **/
static INLINE int paeth(int a, int b, int c)
{
   int p  = a + b - c;
   int pa = abs(p - a);
   int pb = abs(p - b);
   int pc = abs(p - c);

   if (pa <= pb && pa <= pc)
      return a;
   else if (pb <= pc)
      return b;
   return c;
}

/**
 * besseli0:
 *
 * Pure function.
 *
 * Modified Bessel function of first order.
 * Check Wiki for mathematical definition ...
 **/
static INLINE double besseli0(double x)
{
   int i;
   double sum            = 0.0;
   double factorial      = 1.0;
   double factorial_mult = 0.0;
   double x_pow          = 1.0;
   double two_div_pow    = 1.0;
   double x_sqr          = x * x;

   /* Approximate. This is an infinite sum.
    * Luckily, it converges rather fast. */
   for (i = 0; i < 18; i++)
   {
      sum            += x_pow * two_div_pow / (factorial * factorial);
      factorial_mult += 1.0;
      x_pow          *= x_sqr;
      two_div_pow    *= 0.25;
      factorial      *= factorial_mult;
   }

   return sum;
}

static INLINE double kaiser_window_function(double index, double beta)
{
   return besseli0(beta * sqrtf(1 - index * index));
}

#endif

./include/libretro-common/include/formats/cdfs.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (cdfs.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RARCH_CDFS_H
#define __RARCH_CDFS_H

#include <streams/interface_stream.h>

RETRO_BEGIN_DECLS

/* these functions provide an interface for locating and reading files within a data track
 * of a CD (following the ISO-9660 directory structure definition)
 */

typedef struct cdfs_track_t
{
   intfstream_t* stream;
   unsigned int stream_sector_size;
   unsigned int stream_sector_header_size;
   unsigned int first_sector_offset;
   unsigned int first_sector_index;
} cdfs_track_t;

typedef struct cdfs_file_t
{
   struct cdfs_track_t* track;
   int first_sector;
   int current_sector;
   int sector_buffer_valid;
   unsigned int current_sector_offset;
   unsigned int size;
   unsigned int pos;
   uint8_t sector_buffer[2048];
} cdfs_file_t;

/* opens the specified file within the CD or virtual CD.
 * if path is NULL, will open the raw CD (useful for 
 * reading CD without having to worry about sector sizes,
 * headers, or checksum data)
 */
int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* stream, const char* path);

void cdfs_close_file(cdfs_file_t* file);

int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len);

int64_t cdfs_get_size(cdfs_file_t* file);

int64_t cdfs_tell(cdfs_file_t* file);

int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence);

void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector);

uint32_t cdfs_get_num_sectors(cdfs_file_t* file);

uint32_t cdfs_get_first_sector(cdfs_file_t* file);

/* opens the specified track in a CD or virtual CD file - the resulting stream should be passed to
 * cdfs_open_file to get access to a file within the CD.
 *
 * supported files:
 *   real CD - path will be in the form "cdrom://drive1.cue" or "cdrom://d:/drive.cue"
 *   bin/cue - path will point to the cue file
 *   chd     - path will point to the chd file
 *
 * for bin/cue files, the following storage modes are supported:
 *   MODE2/2352
 *   MODE1/2352
 *   MODE1/2048 - untested
 *   MODE2/2336 - untested
 */
cdfs_track_t* cdfs_open_track(const char* path, unsigned int track_index);

/* opens the first data track in a CD or virtual CD file. see cdfs_open_track for supported file formats
 */
cdfs_track_t* cdfs_open_data_track(const char* path);

/* opens a raw track file for a CD or virtual CD.
 *
 * supported files:
 *   real CD - path will be in the form "cdrom://drive1-track01.bin" or "cdrom://d:/drive-track01.bin"
 *             NOTE: cue file for CD must be opened first to populate vfs_cdrom_toc.
 *   bin     - path will point to the bin file
 *   iso     - path will point to the iso file
 */
cdfs_track_t* cdfs_open_raw_track(const char* path);

/* closes the CD or virtual CD track and frees the associated memory */
void cdfs_close_track(cdfs_track_t* track);

RETRO_END_DECLS

#endif /* __RARCH_CDFS_H */

./include/libretro-common/include/formats/image.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (image.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RARCH_IMAGE_CONTEXT_H
#define __RARCH_IMAGE_CONTEXT_H

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

enum image_process_code
{
   IMAGE_PROCESS_ERROR     = -2,
   IMAGE_PROCESS_ERROR_END = -1,
   IMAGE_PROCESS_NEXT      =  0,
   IMAGE_PROCESS_END       =  1
};

struct texture_image
{
   uint32_t *pixels;
   unsigned width;
   unsigned height;
   bool supports_rgba;
};

enum image_type_enum
{
   IMAGE_TYPE_NONE = 0,
   IMAGE_TYPE_PNG,
   IMAGE_TYPE_JPEG,
   IMAGE_TYPE_BMP,
   IMAGE_TYPE_TGA
};

enum image_type_enum image_texture_get_type(const char *path);

bool image_texture_set_color_shifts(unsigned *r_shift, unsigned *g_shift,
      unsigned *b_shift, unsigned *a_shift,
      struct texture_image *out_img);

bool image_texture_color_convert(unsigned r_shift,
      unsigned g_shift, unsigned b_shift, unsigned a_shift,
      struct texture_image *out_img);

bool image_texture_load_buffer(struct texture_image *img,
   enum image_type_enum type, void *s, size_t len);

bool image_texture_load(struct texture_image *img, const char *path);
void image_texture_free(struct texture_image *img);

/* Image transfer */

void image_transfer_free(void *data, enum image_type_enum type);

void *image_transfer_new(enum image_type_enum type);

bool image_transfer_start(void *data, enum image_type_enum type);

void image_transfer_set_buffer_ptr(
      void *data,
      enum image_type_enum type,
      void *ptr,
      size_t len);

int image_transfer_process(
      void *data,
      enum image_type_enum type,
      uint32_t **buf,
      size_t len,
      unsigned *width,
      unsigned *height);

bool image_transfer_iterate(void *data, enum image_type_enum type);

bool image_transfer_is_valid(void *data, enum image_type_enum type);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/logiqx_dat.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (logiqx_dat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__
#define __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__

#include <retro_common_api.h>
#include <retro_miscellaneous.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

/* Trivial handler for DAT files in Logiqx XML format
 * (http://www.logiqx.com/). Provides bare minimum
 * functionality - predominantly concerned with obtaining
 * description text for specific arcade ROM images.
 *
 * Note: Also supports the following alternative DAT
 * formats, since they are functionally identical to
 * Logiqx XML (but with different element names):
 * > MAME List XML
 * > MAME 'Software List' */

/* Prevent direct access to logiqx_dat_t members */
typedef struct logiqx_dat logiqx_dat_t;

/* Holds all metadata for a single game entry
 * in the DAT file (minimal at present - may be
 * expanded with individual internal ROM data
 * if required) */
typedef struct
{
   char name[NAME_MAX_LENGTH];
   char description[NAME_MAX_LENGTH];
   char year[8];
   char manufacturer[128];
   bool is_bios;
   bool is_runnable;
} logiqx_dat_game_info_t;

/* Validation */

/* Performs rudimentary validation of the specified
 * Logiqx XML DAT file path (not rigorous - just
 * enough to prevent obvious errors).
 * Also provides access to file size (DAT files can
 * be very large, so it is useful to have this information
 * on hand - i.e. so we can check that the system has
 * enough free memory to load the file). */
bool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size);

/* File initialisation/de-initialisation */

/* Loads specified Logiqx XML DAT file from disk.
 * Returned logiqx_dat_t object must be free'd using
 * logiqx_dat_free().
 * Returns NULL if file is invalid or a read error
 * occurs. */
logiqx_dat_t *logiqx_dat_init(const char *path);

/* Frees specified DAT file */
void logiqx_dat_free(logiqx_dat_t *dat_file);

/* Game information access */

/* Sets/resets internal node pointer to the first
 * entry in the DAT file */
void logiqx_dat_set_first(logiqx_dat_t *dat_file);

/* Fetches game information for the current entry
 * in the DAT file and increments the internal node
 * pointer.
 * Returns false if the end of the DAT file has been
 * reached (in which case 'game_info' will be invalid) */
bool logiqx_dat_get_next(
      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info);

/* Fetches information for the specified game.
 * Returns false if game does not exist, or arguments
 * are invalid. */
bool logiqx_dat_search(
      logiqx_dat_t *dat_file, const char *game_name,
      logiqx_dat_game_info_t *game_info);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/m3u_file.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (m3u_file.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_M3U_FILE_H__
#define __LIBRETRO_SDK_FORMAT_M3U_FILE_H__

#include <retro_common_api.h>

#include <stdint.h>
#include <stddef.h>
#include <boolean.h>

RETRO_BEGIN_DECLS

/* Trivial handler for M3U playlist files */

/* M3U file extension */
#define M3U_FILE_EXT "m3u"

/* Prevent direct access to m3u_file_t members */
typedef struct content_m3u_file m3u_file_t;

/* Holds all metadata for a single M3U file entry */
typedef struct
{
   char *path;
   char *full_path;
   char *label;
} m3u_file_entry_t;

/* Defines entry label formatting when
 * writing M3U files to disk */
enum m3u_file_label_type
{
   M3U_FILE_LABEL_NONE = 0,
   M3U_FILE_LABEL_NONSTD,
   M3U_FILE_LABEL_EXTSTD,
   M3U_FILE_LABEL_RETRO
};

/* File Initialisation / De-Initialisation */

/* Creates and initialises an M3U file
 * - If 'path' refers to an existing file,
 *   contents is parsed
 * - If path does not exist, an empty M3U file
 *   is created
 * - Returned m3u_file_t object must be free'd using
 *   m3u_file_free()
 * - Returns NULL in the event of an error */
m3u_file_t *m3u_file_init(const char *path);

/* Frees specified M3U file */
void m3u_file_free(m3u_file_t *m3u_file);

/* Getters */

/* Returns M3U file path */
char *m3u_file_get_path(m3u_file_t *m3u_file);

/* Returns number of entries in M3U file */
size_t m3u_file_get_size(m3u_file_t *m3u_file);

/* Fetches specified M3U file entry
 * - Returns false if 'idx' is invalid, or internal
 *   entry is NULL */
bool m3u_file_get_entry(
      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry);

/* Setters */

/* Adds specified entry to the M3U file
 * - Returns false if path is invalid, or
 *   memory could not be allocated for the
 *   entry */
bool m3u_file_add_entry(
      m3u_file_t *m3u_file, const char *path, const char *label);

/* Removes all entries in M3U file */
void m3u_file_clear(m3u_file_t *m3u_file);

/* Saving */

/* Saves M3U file to disk
 * - Setting 'label_type' to M3U_FILE_LABEL_NONE
 *   just outputs entry paths - this the most
 *   common format supported by most cores
 * - Returns false in the event of an error */
bool m3u_file_save(
      m3u_file_t *m3u_file, enum m3u_file_label_type label_type);

/* Utilities */

/* Sorts M3U file entries in alphabetical order */
void m3u_file_qsort(m3u_file_t *m3u_file);

/* Returns true if specified path corresponds
 * to an M3U file (simple convenience function) */
bool m3u_file_is_m3u(const char *path);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rbmp.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbmp.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RBMP_H__
#define __LIBRETRO_SDK_FORMAT_RBMP_H__

#include <retro_common_api.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

enum rbmp_source_type
{
   RBMP_SOURCE_TYPE_DONT_CARE,
   RBMP_SOURCE_TYPE_BGR24,
   RBMP_SOURCE_TYPE_XRGB888,
   RBMP_SOURCE_TYPE_RGB565,
   RBMP_SOURCE_TYPE_ARGB8888
};

typedef struct rbmp rbmp_t;

bool rbmp_save_image(
      const char *filename,
      const void *frame,
      unsigned width,
      unsigned height,
      unsigned pitch,
      enum rbmp_source_type type);

int rbmp_process_image(rbmp_t *rbmp, void **buf,
      size_t size, unsigned *width, unsigned *height);

void form_bmp_header(uint8_t *header,
      unsigned width, unsigned height,
      bool is32bpp);

bool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data);

void rbmp_free(rbmp_t *rbmp);

rbmp_t *rbmp_alloc(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rjpeg.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjpeg.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RJPEG_H__
#define __LIBRETRO_SDK_FORMAT_RJPEG_H__

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

typedef struct rjpeg rjpeg_t;

int rjpeg_process_image(rjpeg_t *rjpeg, void **buf,
      size_t size, unsigned *width, unsigned *height);

bool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data);

void rjpeg_free(rjpeg_t *rjpeg);

rjpeg_t *rjpeg_alloc(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rjson.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjson.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RJSON_H__
#define __LIBRETRO_SDK_FORMAT_RJSON_H__

#include <retro_common_api.h>
#include <boolean.h> /* bool */
#include <stddef.h> /* size_t */

RETRO_BEGIN_DECLS

/* List of possible element types returned by rjson_next */
enum rjson_type
{
   RJSON_DONE,
   RJSON_OBJECT, RJSON_ARRAY, RJSON_OBJECT_END, RJSON_ARRAY_END,
   RJSON_STRING, RJSON_NUMBER, RJSON_TRUE, RJSON_FALSE, RJSON_NULL,
   RJSON_ERROR
};

/* Options that can be passed to rjson_set_options */
enum rjson_option
{
   /* Allow UTF-8 byte order marks */
   RJSON_OPTION_ALLOW_UTF8BOM                      = (1<<0),
   /* Allow JavaScript style comments in the stream */
   RJSON_OPTION_ALLOW_COMMENTS                     = (1<<1),
   /* Allow unescaped control characters in strings (bytes 0x00 - 0x1F) */
   RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS = (1<<2),
   /* Ignore invalid Unicode escapes and don't validate UTF-8 codes */
   RJSON_OPTION_IGNORE_INVALID_ENCODING            = (1<<3),
   /* Replace invalid Unicode escapes and UTF-8 codes with a '?' character */
   RJSON_OPTION_REPLACE_INVALID_ENCODING           = (1<<4),
   /* Ignore carriage return (\r escape sequence) in strings */
   RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN      = (1<<5),
   /* Allow data after the end of the top JSON object/array/value */
   RJSON_OPTION_ALLOW_TRAILING_DATA                = (1<<6)
};

/* Custom data input callback
 * Should return > 0 and <= len on success, 0 on file end and < 0 on error. */
typedef int (*rjson_io_t)(void* buf, int len, void *user_data);
typedef struct rjson rjson_t;
struct intfstream_internal;
struct RFILE;

/* Create a new parser instance from various sources */
rjson_t *rjson_open_stream(struct intfstream_internal *stream);
rjson_t *rjson_open_rfile(struct RFILE *rfile);
rjson_t *rjson_open_buffer(const void *buffer, size_t len);
rjson_t *rjson_open_string(const char *string, size_t len);
rjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size);

/* Free the parser instance created with rjson_open_* */
void rjson_free(rjson_t *json);

/* Set one or more enum rjson_option, will override previously set options.
 * Use bitwise OR to concatenate multiple options.
 * By default none of the options are set. */
void rjson_set_options(rjson_t *json, char rjson_option_flags);

/* Sets the maximum context depth, recursion inside arrays and objects.
 * By default this is set to 50. */
void rjson_set_max_depth(rjson_t *json, unsigned int max_depth);

/* Parse to the next JSON element and return the type of it.
 * Will return RJSON_DONE when successfully reaching the end or
 * RJSON_ERROR when an error was encountered. */
enum rjson_type rjson_next(rjson_t *json);

/* Get the current string, null-terminated unescaped UTF-8 encoded.
 * Can only be used when the current element is RJSON_STRING or RJSON_NUMBER.
 * The returned pointer is only valid until the parsing continues. */
const char *rjson_get_string(rjson_t *json, size_t *length);

/* Returns the current number (or string) converted to double or int */
double rjson_get_double(rjson_t *json);
int    rjson_get_int(rjson_t *json);

/* Returns a string describing the error once rjson_next/rjson_parse
 * has returned an unrecoverable RJSON_ERROR (otherwise returns ""). */
const char *rjson_get_error(rjson_t *json);

/* Can be used to set a custom error description on an invalid JSON structure.
 * Maximum length of 79 characters and once set the parsing can't continue. */
void rjson_set_error(rjson_t *json, const char* error);

/* Functions to get the current position in the source stream as well as */
/* a bit of source json around the current position for additional detail
 * when parsing has failed with RJSON_ERROR.
 * Intended to be used with printf style formatting like:
 * printf("Invalid JSON at line %d, column %d - %s - Source: ...%.*s...\n",
 *       (int)rjson_get_source_line(json), (int)rjson_get_source_column(json),
 *       rjson_get_error(json), rjson_get_source_context_len(json),
 *       rjson_get_source_context_buf(json)); */
size_t      rjson_get_source_line(rjson_t *json);
size_t      rjson_get_source_column(rjson_t *json);
int         rjson_get_source_context_len(rjson_t *json);
const char* rjson_get_source_context_buf(rjson_t *json);

/* Confirm the parsing context stack, for example calling
   rjson_check_context(json, 2, RJSON_OBJECT, RJSON_ARRAY)
   returns true when inside "{ [ ..." but not for "[ .." or "{ [ { ..." */
bool rjson_check_context(rjson_t *json, unsigned int depth, ...);

/* Returns the current level of nested objects/arrays */
unsigned int rjson_get_context_depth(rjson_t *json);

/* Return the current parsing context, that is, RJSON_OBJECT if we are inside
 * an object, RJSON_ARRAY if we are inside an array, and RJSON_DONE or
 * RJSON_ERROR if we are not yet/anymore in either. */
enum rjson_type rjson_get_context_type(rjson_t *json);

/* While inside an object or an array, this return the number of parsing
 * events that have already been observed at this level with rjson_next.
 * In particular, inside an object, an odd number would indicate that the just
 * observed RJSON_STRING event is a member name. */
size_t rjson_get_context_count(rjson_t *json);

/* Parse an entire JSON stream with a list of element specific handlers.
 * Each of the handlers can be passed a function or NULL to ignore it.
 * If a handler returns false, the parsing will abort and the returned
 * rjson_type will indicate on which element type parsing was aborted.
 * Otherwise the return value will be RJSON_DONE or RJSON_ERROR. */
enum rjson_type rjson_parse(rjson_t *json, void* context,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context));

/* A simpler interface to parse a JSON in memory. This will avoid any memory
 * allocations unless the document contains strings longer than 512 characters.
 * In the error handler, error will be "" if any of the other handlers aborted. */
bool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context),
      void (*error_handler        )(void *context, int line, int col, const char* error));

/* ------------------------------------------------------------------------- */

/* Options that can be passed to rjsonwriter_set_options */
enum rjsonwriter_option
{
   /* Don't write spaces, tabs or newlines to the output (except in strings) */
   RJSONWRITER_OPTION_SKIP_WHITESPACE = (1<<0)
};

/* Custom data output callback
 * Should return len on success and < len on a write error. */
typedef int (*rjsonwriter_io_t)(const void* buf, int len, void *user_data);
typedef struct rjsonwriter rjsonwriter_t;

/* Create a new writer instance to various targets */
rjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream);
rjsonwriter_t *rjsonwriter_open_rfile(struct RFILE *rfile);
rjsonwriter_t *rjsonwriter_open_memory(void);
rjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data);

/* When opened with rjsonwriter_open_memory, will return the generated JSON.
 * Result is always null-terminated. Passed len can be NULL if not needed,
 * otherwise returned len will be string length without null-terminator.
 * Returns NULL if writing ran out of memory or not opened from memory.
 * Returned buffer is only valid until writer is modified or freed. */
char* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len);

/* When opened with rjsonwriter_open_memory, will return current length */
int rjsonwriter_count_memory_buffer(rjsonwriter_t *writer);

/* When opened with rjsonwriter_open_memory, will clear the buffer.
   The buffer will be partially erased if keep_len is > 0.
   No memory is freed or re-allocated with this function. */
void rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len);

/* Free rjsonwriter handle and return result of final rjsonwriter_flush call */
bool rjsonwriter_free(rjsonwriter_t *writer);

/* Set one or more enum rjsonwriter_option, will override previously set options.
 * Use bitwise OR to concatenate multiple options.
 * By default none of the options are set. */
void rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags);

/* Flush any buffered output data to the output stream.
 * Returns true if the data was successfully written. Once writing fails once,
 * no more data will be written and flush will always returns false */
bool rjsonwriter_flush(rjsonwriter_t *writer);

/* Returns a string describing an error or "" if there was none.
 * The only error possible is "output error" after the io function failed.
 * If rjsonwriter_rawf were used manually, "out of memory" is also possible. */
const char *rjsonwriter_get_error(rjsonwriter_t *writer);

/* Used by the inline functions below to append raw data */
void rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len);
void rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...);

/* Add a UTF-8 encoded string
 * Special and control characters are automatically escaped.
 * If NULL is passed an empty string will be written (not JSON null). */
void rjsonwriter_add_string(rjsonwriter_t *writer, const char *value);
void rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len);

void rjsonwriter_add_double(rjsonwriter_t *writer, double value);

void rjsonwriter_add_spaces(rjsonwriter_t *writer, int count);

void rjsonwriter_add_tabs(rjsonwriter_t *writer, int count);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rjson_helpers.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjson.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__
#define __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__

#include <retro_common_api.h>
#include <retro_inline.h> /* INLINE */
#include <boolean.h> /* bool */
#include <stddef.h> /* size_t */

RETRO_BEGIN_DECLS

/* Functions to add JSON token characters */
static INLINE void rjsonwriter_add_start_object(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "{", 1); }

static INLINE void rjsonwriter_add_end_object(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "}", 1); }

static INLINE void rjsonwriter_add_start_array(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "[", 1); }

static INLINE void rjsonwriter_add_end_array(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "]", 1); }

static INLINE void rjsonwriter_add_colon(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, ":", 1); }

static INLINE void rjsonwriter_add_comma(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, ",", 1); }

/* Functions to add whitespace characters */
/* These do nothing with the option RJSONWRITER_OPTION_SKIP_WHITESPACE */
static INLINE void rjsonwriter_add_newline(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "\n", 1); }

static INLINE void rjsonwriter_add_space(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, " ", 1); }

static INLINE void rjsonwriter_add_tab(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "\t", 1); }

static INLINE void rjsonwriter_add_unsigned(rjsonwriter_t *writer, unsigned value)
      { rjsonwriter_rawf(writer, "%u", value); }

/* Add a signed or unsigned integer or a double number */
static INLINE void rjsonwriter_add_int(rjsonwriter_t *writer, int value)
      { rjsonwriter_rawf(writer, "%d", value); }

static INLINE void rjsonwriter_add_bool(rjsonwriter_t *writer, bool value)
      { rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5)); }

static INLINE void rjsonwriter_add_null(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "null", 4); }

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rpng.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RPNG_H__
#define __LIBRETRO_SDK_FORMAT_RPNG_H__

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

typedef struct rpng rpng_t;

rpng_t *rpng_init(const char *path);

bool rpng_is_valid(rpng_t *rpng);

bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len);

rpng_t *rpng_alloc(void);

void rpng_free(rpng_t *rpng);

bool rpng_iterate_image(rpng_t *rpng);

int rpng_process_image(rpng_t *rpng,
      void **data, size_t size, unsigned *width, unsigned *height);

bool rpng_start(rpng_t *rpng);

bool rpng_save_image_argb(const char *path, const uint32_t *data,
      unsigned width, unsigned height, unsigned pitch);
bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
      unsigned width, unsigned height, unsigned pitch);

uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
      unsigned width, unsigned height, signed pitch, uint64_t *bytes);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rtga.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtga.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RTGA_H__
#define __LIBRETRO_SDK_FORMAT_RTGA_H__

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

typedef struct rtga rtga_t;

int rtga_process_image(rtga_t *rtga, void **buf,
      size_t size, unsigned *width, unsigned *height);

bool rtga_set_buf_ptr(rtga_t *rtga, void *data);

void rtga_free(rtga_t *rtga);

rtga_t *rtga_alloc(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rwav.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rwav.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RWAV_H__
#define __LIBRETRO_SDK_FORMAT_RWAV_H__

#include <retro_common_api.h>
#include <stdint.h>

RETRO_BEGIN_DECLS

typedef struct
{
   /* bits per sample */
   unsigned int bitspersample;

   /* number of channels */
   unsigned int numchannels;

   /* sample rate */
   unsigned int samplerate;

   /* number of *samples* */
   size_t numsamples;

   /* number of *bytes* in the pointer below, i.e. numsamples * numchannels * bitspersample/8 */
   size_t subchunk2size;

   /* PCM data */
   const void* samples;
} rwav_t;

enum rwav_state
{
   RWAV_ITERATE_ERROR    = -1,
   RWAV_ITERATE_MORE     = 0,
   RWAV_ITERATE_DONE     = 1,
   RWAV_ITERATE_BUF_SIZE = 4096
};

typedef struct rwav_iterator rwav_iterator_t;

/**
 * Initializes the iterator to fill the out structure with data parsed from buf.
 */
void rwav_init(rwav_iterator_t *iter, rwav_t *out, const void* buf, size_t len);

/**
 * Parses a piece of the data. Continue calling as long as it returns RWAV_ITERATE_MORE.
 * Stop calling otherwise, and check for errors. If RWAV_ITERATE_DONE is returned,
 * the rwav_t structure passed to rwav_init is ready to be used. The iterator does not
 * have to be freed.
 */
enum rwav_state rwav_iterate(rwav_iterator_t *iter);

/**
 * Loads the entire data in one go.
 */
enum rwav_state rwav_load(rwav_t *out, const void *buf, size_t len);

/**
 * Frees parsed wave data.
 */
void rwav_free(rwav_t *rwav);

RETRO_END_DECLS

#endif

./include/libretro-common/include/formats/rxml.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_FORMAT_RXML_H__
#define __LIBRETRO_SDK_FORMAT_RXML_H__

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/* Total NIH. Very trivial "XML" implementation for use in RetroArch.
 * Error checking is minimal. Invalid documents may lead to very
 * buggy behavior, but memory corruption should never happen.
 *
 * Only parts of standard that RetroArch cares about is supported.
 * Nothing more, nothing less. "Clever" XML documents will
 * probably break the implementation.
 *
 * Do *NOT* try to use this for anything else. You have been warned.
 */

typedef struct rxml_document rxml_document_t;

struct rxml_attrib_node
{
   char *attrib;
   char *value;
   struct rxml_attrib_node *next;
};

typedef struct rxml_node
{
   char *name;
   char *data;
   struct rxml_attrib_node *attrib;

   struct rxml_node *children;
   struct rxml_node *next;
} rxml_node_t;

rxml_document_t *rxml_load_document(const char *path);
rxml_document_t *rxml_load_document_string(const char *str);
void rxml_free_document(rxml_document_t *doc);

struct rxml_node *rxml_root_node(rxml_document_t *doc);

const char *rxml_node_attrib(struct rxml_node *node, const char *attrib);

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/gl_capabilities.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gl_capabilities.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _GL_CAPABILITIES_H
#define _GL_CAPABILITIES_H

#include <boolean.h>
#include <retro_common_api.h>

RETRO_BEGIN_DECLS

enum gl_capability_enum
{
   GL_CAPS_NONE = 0,
   GL_CAPS_EGLIMAGE,
   GL_CAPS_SYNC,
   GL_CAPS_MIPMAP,
   GL_CAPS_VAO,
   GL_CAPS_FBO,
   GL_CAPS_ARGB8,
   GL_CAPS_DEBUG,
   GL_CAPS_PACKED_DEPTH_STENCIL,
   GL_CAPS_ES2_COMPAT,
   GL_CAPS_UNPACK_ROW_LENGTH,
   GL_CAPS_FULL_NPOT_SUPPORT,
   GL_CAPS_SRGB_FBO,
   GL_CAPS_SRGB_FBO_ES3,
   GL_CAPS_FP_FBO,
   GL_CAPS_BGRA8888,
   GL_CAPS_GLES3_SUPPORTED,
   GL_CAPS_TEX_STORAGE,
   GL_CAPS_TEX_STORAGE_EXT
};

bool gl_query_core_context_in_use(void);

void gl_query_core_context_set(bool set);

void gl_query_core_context_unset(void);

bool gl_query_extension(const char *ext);

bool gl_check_error(char **error_string);

bool gl_check_capability(enum gl_capability_enum enum_idx);

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/math/matrix_3x3.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (matrix_3x3.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__
#define __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__

#include <boolean.h>
#include <math.h>
#include <string.h>

#include <retro_common_api.h>
#include <retro_inline.h>

RETRO_BEGIN_DECLS

typedef struct math_matrix_3x3
{
   float data[9];
} math_matrix_3x3;

#define MAT_ELEM_3X3(mat, r, c) ((mat).data[3 * (r) + (c)])

#define matrix_3x3_init(mat, n11, n12, n13, n21, n22, n23, n31, n32, n33) \
   MAT_ELEM_3X3(mat, 0, 0) = n11; \
   MAT_ELEM_3X3(mat, 0, 1) = n12; \
   MAT_ELEM_3X3(mat, 0, 2) = n13; \
   MAT_ELEM_3X3(mat, 1, 0) = n21; \
   MAT_ELEM_3X3(mat, 1, 1) = n22; \
   MAT_ELEM_3X3(mat, 1, 2) = n23; \
   MAT_ELEM_3X3(mat, 2, 0) = n31; \
   MAT_ELEM_3X3(mat, 2, 1) = n32; \
   MAT_ELEM_3X3(mat, 2, 2) = n33

#define matrix_3x3_identity(mat) \
   MAT_ELEM_3X3(mat, 0, 0) = 1.0f; \
   MAT_ELEM_3X3(mat, 0, 1) = 0; \
   MAT_ELEM_3X3(mat, 0, 2) = 0; \
   MAT_ELEM_3X3(mat, 1, 0) = 0; \
   MAT_ELEM_3X3(mat, 1, 1) = 1.0f; \
   MAT_ELEM_3X3(mat, 1, 2) = 0; \
   MAT_ELEM_3X3(mat, 2, 0) = 0; \
   MAT_ELEM_3X3(mat, 2, 1) = 0; \
   MAT_ELEM_3X3(mat, 2, 2) = 1.0f

#define matrix_3x3_divide_scalar(mat, s) \
   MAT_ELEM_3X3(mat, 0, 0) /= s; \
   MAT_ELEM_3X3(mat, 0, 1) /= s; \
   MAT_ELEM_3X3(mat, 0, 2) /= s; \
   MAT_ELEM_3X3(mat, 1, 0) /= s; \
   MAT_ELEM_3X3(mat, 1, 1) /= s; \
   MAT_ELEM_3X3(mat, 1, 2) /= s; \
   MAT_ELEM_3X3(mat, 2, 0) /= s; \
   MAT_ELEM_3X3(mat, 2, 1) /= s; \
   MAT_ELEM_3X3(mat, 2, 2) /= s

#define matrix_3x3_transpose(mat, in) \
   MAT_ELEM_3X3(mat, 0, 0) = MAT_ELEM_3X3(in, 0, 0); \
   MAT_ELEM_3X3(mat, 1, 0) = MAT_ELEM_3X3(in, 0, 1); \
   MAT_ELEM_3X3(mat, 2, 0) = MAT_ELEM_3X3(in, 0, 2); \
   MAT_ELEM_3X3(mat, 0, 1) = MAT_ELEM_3X3(in, 1, 0); \
   MAT_ELEM_3X3(mat, 1, 1) = MAT_ELEM_3X3(in, 1, 1); \
   MAT_ELEM_3X3(mat, 2, 1) = MAT_ELEM_3X3(in, 1, 2); \
   MAT_ELEM_3X3(mat, 0, 2) = MAT_ELEM_3X3(in, 2, 0); \
   MAT_ELEM_3X3(mat, 1, 2) = MAT_ELEM_3X3(in, 2, 1); \
   MAT_ELEM_3X3(mat, 2, 2) = MAT_ELEM_3X3(in, 2, 2)

#define matrix_3x3_multiply(out, a, b) \
   MAT_ELEM_3X3(out, 0, 0) =  \
      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 0) + \
      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 0) + \
      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 0); \
   MAT_ELEM_3X3(out, 0, 1) = \
      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 1) + \
      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 1) + \
      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 1); \
   MAT_ELEM_3X3(out, 0, 2) = \
      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 2) + \
      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 2) + \
      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 2); \
   MAT_ELEM_3X3(out, 1, 0) = \
      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 0) + \
      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 0) + \
      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 0); \
   MAT_ELEM_3X3(out, 1, 1) =  \
      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 1) + \
      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 1) + \
      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 1); \
   MAT_ELEM_3X3(out, 1, 2) = \
      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 2) + \
      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 2) + \
      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 2); \
   MAT_ELEM_3X3(out, 2, 0) =  \
      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 0) + \
      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 0) + \
      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 0); \
   MAT_ELEM_3X3(out, 2, 1) = \
      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 1) + \
      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 1) + \
      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 1); \
   MAT_ELEM_3X3(out, 2, 2) =  \
      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 2) + \
      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 2) + \
      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 2)

#define matrix_3x3_determinant(mat) (MAT_ELEM_3X3(mat, 0, 0) * (MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 1)) - MAT_ELEM_3X3(mat, 0, 1) * (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 0)) + MAT_ELEM_3X3(mat, 0, 2) * (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 0)))

#define matrix_3x3_adjoint(mat) \
   MAT_ELEM_3X3(mat, 0, 0) =  (MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 1)); \
   MAT_ELEM_3X3(mat, 0, 1) = -(MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 2, 1)); \
   MAT_ELEM_3X3(mat, 0, 2) =  (MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 1, 1) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 1, 1)); \
   MAT_ELEM_3X3(mat, 1, 0) = -(MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 1, 1) =  (MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 1, 2) = -(MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 1, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 1, 0)); \
   MAT_ELEM_3X3(mat, 2, 0) =  (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 2, 1) = -(MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 2, 2) =  (MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 1, 1) - MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 1, 0))

#define FLOATS_ARE_EQUAL(x, y)  (fabs(x - y) <= 0.00001f * ((x) > (y) ? (y) : (x)))
#define FLOAT_IS_ZERO(x)        (FLOATS_ARE_EQUAL((x) + 1, 1))

static INLINE bool matrix_3x3_invert(math_matrix_3x3 *mat)
{
   float det = matrix_3x3_determinant(*mat);

   if (FLOAT_IS_ZERO(det))
      return false;

   matrix_3x3_adjoint(*mat);
   matrix_3x3_divide_scalar(*mat, det);

   return true;
}

static INLINE bool matrix_3x3_square_to_quad(
      const float dx0, const float dy0,
      const float dx1, const float dy1,
      const float dx3, const float dy3,
      const float dx2, const float dy2,
      math_matrix_3x3 *mat)
{
   float a, b, d, e;
   float ax  = dx0 - dx1 + dx2 - dx3;
   float ay  = dy0 - dy1 + dy2 - dy3;
   float c   = dx0;
   float f   = dy0;
   float g   = 0;
   float h   = 0;

   if (FLOAT_IS_ZERO(ax) && FLOAT_IS_ZERO(ay))
   {
      /* affine case */
      a = dx1 - dx0;
      b = dx2 - dx1;
      d = dy1 - dy0;
      e = dy2 - dy1;
   }
   else
   {
      float ax1 = dx1 - dx2;
      float ax2 = dx3 - dx2;
      float ay1 = dy1 - dy2;
      float ay2 = dy3 - dy2;

      /* determinants */
      float gtop    =  ax  * ay2 - ax2 * ay;
      float htop    =  ax1 * ay  - ax  * ay1;
      float bottom  =  ax1 * ay2 - ax2 * ay1;

      if (!bottom)
         return false;

      g = gtop / bottom;
      h = htop / bottom;

      a = dx1 - dx0 + g * dx1;
      b = dx3 - dx0 + h * dx3;
      d = dy1 - dy0 + g * dy1;
      e = dy3 - dy0 + h * dy3;
   }

   matrix_3x3_init(*mat,
         a, d, g,
         b, e, h,
         c, f, 1.f);

   return true;
}

static INLINE bool matrix_3x3_quad_to_square(
      const float sx0, const float sy0,
      const float sx1, const float sy1,
      const float sx2, const float sy2,
      const float sx3, const float sy3,
      math_matrix_3x3 *mat)
{
   return matrix_3x3_square_to_quad(sx0, sy0, sx1, sy1,
         sx2, sy2, sx3, sy3,
         mat) ? matrix_3x3_invert(mat) : false;
}

static INLINE bool matrix_3x3_quad_to_quad(
      const float dx0, const float dy0,
      const float dx1, const float dy1,
      const float dx2, const float dy2,
      const float dx3, const float dy3,
      const float sx0, const float sy0,
      const float sx1, const float sy1,
      const float sx2, const float sy2,
      const float sx3, const float sy3,
      math_matrix_3x3 *mat)
{
   math_matrix_3x3 square_to_quad;

   if (matrix_3x3_square_to_quad(dx0, dy0, dx1, dy1,
            dx2, dy2, dx3, dy3,
            &square_to_quad))
   {
      math_matrix_3x3 quad_to_square;
      if (matrix_3x3_quad_to_square(sx0, sy0, sx1, sy1,
               sx2, sy2, sx3, sy3,
               &quad_to_square))
      {
         matrix_3x3_multiply(*mat, quad_to_square, square_to_quad);

         return true;
      }
   }

   return false;
}

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/math/matrix_4x4.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (matrix_4x4.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__
#define __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__

#include <retro_common_api.h>

#include <math.h>
#include <gfx/math/vector_3.h>

/* Column-major matrix (OpenGL-style).
 * Reimplements functionality from FF OpenGL pipeline to be able
 * to work on GLES 2.0 and modern GL variants.
 */

#define MAT_ELEM_4X4(mat, row, column) ((mat).data[4 * (column) + (row)])

RETRO_BEGIN_DECLS

typedef struct math_matrix_4x4
{
   float data[16];
} math_matrix_4x4;

#define matrix_4x4_copy(dst, src) \
   MAT_ELEM_4X4(dst, 0, 0) = MAT_ELEM_4X4(src, 0, 0); \
   MAT_ELEM_4X4(dst, 0, 1) = MAT_ELEM_4X4(src, 0, 1); \
   MAT_ELEM_4X4(dst, 0, 2) = MAT_ELEM_4X4(src, 0, 2); \
   MAT_ELEM_4X4(dst, 0, 3) = MAT_ELEM_4X4(src, 0, 3); \
   MAT_ELEM_4X4(dst, 1, 0) = MAT_ELEM_4X4(src, 1, 0); \
   MAT_ELEM_4X4(dst, 1, 1) = MAT_ELEM_4X4(src, 1, 1); \
   MAT_ELEM_4X4(dst, 1, 2) = MAT_ELEM_4X4(src, 1, 2); \
   MAT_ELEM_4X4(dst, 1, 3) = MAT_ELEM_4X4(src, 1, 3); \
   MAT_ELEM_4X4(dst, 2, 0) = MAT_ELEM_4X4(src, 2, 0); \
   MAT_ELEM_4X4(dst, 2, 1) = MAT_ELEM_4X4(src, 2, 1); \
   MAT_ELEM_4X4(dst, 2, 2) = MAT_ELEM_4X4(src, 2, 2); \
   MAT_ELEM_4X4(dst, 2, 3) = MAT_ELEM_4X4(src, 2, 3); \
   MAT_ELEM_4X4(dst, 3, 0) = MAT_ELEM_4X4(src, 3, 0); \
   MAT_ELEM_4X4(dst, 3, 1) = MAT_ELEM_4X4(src, 3, 1); \
   MAT_ELEM_4X4(dst, 3, 2) = MAT_ELEM_4X4(src, 3, 2); \
   MAT_ELEM_4X4(dst, 3, 3) = MAT_ELEM_4X4(src, 3, 3)

/*
 * Sets mat to an identity matrix
 */
#define matrix_4x4_identity(mat) \
   MAT_ELEM_4X4(mat, 0, 0)    = 1.0f; \
   MAT_ELEM_4X4(mat, 0, 1)    = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2)    = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3)    = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0)    = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1)    = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 2)    = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3)    = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0)    = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1)    = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2)    = 1.0f; \
   MAT_ELEM_4X4(mat, 2, 3)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3)    = 1.0f

/*
 * Sets out to the transposed matrix of in
 */

#define matrix_4x4_transpose(out, in) \
   MAT_ELEM_4X4(out, 0, 0) = MAT_ELEM_4X4(in, 0, 0); \
   MAT_ELEM_4X4(out, 1, 0) = MAT_ELEM_4X4(in, 0, 1); \
   MAT_ELEM_4X4(out, 2, 0) = MAT_ELEM_4X4(in, 0, 2); \
   MAT_ELEM_4X4(out, 3, 0) = MAT_ELEM_4X4(in, 0, 3); \
   MAT_ELEM_4X4(out, 0, 1) = MAT_ELEM_4X4(in, 1, 0); \
   MAT_ELEM_4X4(out, 1, 1) = MAT_ELEM_4X4(in, 1, 1); \
   MAT_ELEM_4X4(out, 2, 1) = MAT_ELEM_4X4(in, 1, 2); \
   MAT_ELEM_4X4(out, 3, 1) = MAT_ELEM_4X4(in, 1, 3); \
   MAT_ELEM_4X4(out, 0, 2) = MAT_ELEM_4X4(in, 2, 0); \
   MAT_ELEM_4X4(out, 1, 2) = MAT_ELEM_4X4(in, 2, 1); \
   MAT_ELEM_4X4(out, 2, 2) = MAT_ELEM_4X4(in, 2, 2); \
   MAT_ELEM_4X4(out, 3, 2) = MAT_ELEM_4X4(in, 2, 3); \
   MAT_ELEM_4X4(out, 0, 3) = MAT_ELEM_4X4(in, 3, 0); \
   MAT_ELEM_4X4(out, 1, 3) = MAT_ELEM_4X4(in, 3, 1); \
   MAT_ELEM_4X4(out, 2, 3) = MAT_ELEM_4X4(in, 3, 2); \
   MAT_ELEM_4X4(out, 3, 3) = MAT_ELEM_4X4(in, 3, 3)

/*
 * Builds an X-axis rotation matrix
 */
#define matrix_4x4_rotate_x(mat, radians) \
{ \
   float cosine            = cosf(radians); \
   float sine              = sinf(radians); \
   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = cosine; \
   MAT_ELEM_4X4(mat, 1, 2) = -sine; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = sine; \
   MAT_ELEM_4X4(mat, 2, 2) = cosine; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
}

/*
 * Builds a rotation matrix using the
 * rotation around the Y-axis.
 */

#define matrix_4x4_rotate_y(mat, radians) \
{ \
   float cosine            = cosf(radians); \
   float sine              = sinf(radians); \
   MAT_ELEM_4X4(mat, 0, 0) = cosine; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = -sine; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = sine; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = cosine; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
}

/*
 * Builds a rotation matrix using the
 * rotation around the Z-axis.
 */
#define matrix_4x4_rotate_z(mat, radians) \
{ \
   float cosine            = cosf(radians); \
   float sine              = sinf(radians); \
   MAT_ELEM_4X4(mat, 0, 0) = cosine; \
   MAT_ELEM_4X4(mat, 0, 1) = -sine; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = sine; \
   MAT_ELEM_4X4(mat, 1, 1) = cosine; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
}

/*
 * Creates an orthographic projection matrix.
 */
#define matrix_4x4_ortho(mat, left, right, bottom, top, znear, zfar) \
{ \
   float rl                = (right) - (left); \
   float tb                = (top)   - (bottom); \
   float fn                = (zfar)  - (znear); \
   MAT_ELEM_4X4(mat, 0, 0) =  2.0f / rl; \
   MAT_ELEM_4X4(mat, 0, 1) =  0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) =  0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = -((left) + (right))  / rl; \
   MAT_ELEM_4X4(mat, 1, 0) =  0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) =  2.0f / tb; \
   MAT_ELEM_4X4(mat, 1, 2) =  0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = -((top)  + (bottom)) / tb; \
   MAT_ELEM_4X4(mat, 2, 0) =  0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) =  0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = -2.0f / fn; \
   MAT_ELEM_4X4(mat, 2, 3) = -((zfar) + (znear))  / fn; \
   MAT_ELEM_4X4(mat, 3, 0) =  0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) =  0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) =  0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) =  1.0f; \
}

#define matrix_4x4_lookat(out, eye, center, up) \
{ \
   vec3_t zaxis;   /* the "forward" vector */ \
   vec3_t xaxis;   /* the "right"   vector */ \
   vec3_t yaxis;   /* the "up"      vector */ \
   vec3_copy(zaxis, center); \
   vec3_subtract(zaxis, eye); \
   vec3_normalize(zaxis); \
   vec3_cross(xaxis, zaxis, up); \
   vec3_normalize(xaxis); \
   vec3_cross(yaxis, xaxis, zaxis); \
   MAT_ELEM_4X4(out, 0, 0) = xaxis[0]; \
   MAT_ELEM_4X4(out, 0, 1) = yaxis[0]; \
   MAT_ELEM_4X4(out, 0, 2) = -zaxis[0]; \
   MAT_ELEM_4X4(out, 0, 3) = 0.0; \
   MAT_ELEM_4X4(out, 1, 0) = xaxis[1]; \
   MAT_ELEM_4X4(out, 1, 1) = yaxis[1]; \
   MAT_ELEM_4X4(out, 1, 2) = -zaxis[1]; \
   MAT_ELEM_4X4(out, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(out, 2, 0) = xaxis[2]; \
   MAT_ELEM_4X4(out, 2, 1) = yaxis[2]; \
   MAT_ELEM_4X4(out, 2, 2) = -zaxis[2]; \
   MAT_ELEM_4X4(out, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(out, 3, 0) = -(xaxis[0] * eye[0] + xaxis[1] * eye[1] + xaxis[2] * eye[2]); \
   MAT_ELEM_4X4(out, 3, 1) = -(yaxis[0] * eye[0] + yaxis[1] * eye[1] + yaxis[2] * eye[2]); \
   MAT_ELEM_4X4(out, 3, 2) = (zaxis[0] * eye[0] + zaxis[1] * eye[1] + zaxis[2] * eye[2]); \
   MAT_ELEM_4X4(out, 3, 3) = 1.f; \
}

/*
 * Multiplies a with b, stores the result in out
 */

#define matrix_4x4_multiply(out, a, b) \
   MAT_ELEM_4X4(out, 0, 0) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 0, 1) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 0, 2) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 0, 3) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 3); \
   MAT_ELEM_4X4(out, 1, 0) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 1, 1) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 1, 2) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 1, 3) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 3); \
   MAT_ELEM_4X4(out, 2, 0) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 2, 1) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 2, 2) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 2, 3) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 3); \
   MAT_ELEM_4X4(out, 3, 0) =  \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 3, 1) =  \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 3, 2) = \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 3, 3) =  \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 3)

#define matrix_4x4_scale(mat, x, y, z) \
   MAT_ELEM_4X4(mat, 0, 0) = x; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = y; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = z; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f

/*
 * Builds a translation matrix. All other elements in
 * the matrix will be set to zero except for the
 * diagonal which is set to 1.0
 */

#define matrix_4x4_translate(mat, x, y, z) \
   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = x; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 2) = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = y; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \
   MAT_ELEM_4X4(mat, 2, 3) = z; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f

/*
 * Creates a perspective projection matrix.
 */

#define  matrix_4x4_projection(mat, y_fov, aspect, znear, zfar) \
{ \
   float const a           = 1.f / tan((y_fov) / 2.f); \
   float delta_z           = (zfar) - (znear); \
   MAT_ELEM_4X4(mat, 0, 0) = a / (aspect); \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = a; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = -(((zfar) + (znear)) / delta_z); \
   MAT_ELEM_4X4(mat, 2, 3) = -1.f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = -((2.f * (zfar) * (znear)) / delta_z); \
   MAT_ELEM_4X4(mat, 3, 3) = 0.0f; \
}

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/math/vector_2.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_2.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__
#define __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__

#include <stdint.h>
#include <math.h>

#include <retro_common_api.h>
#include <retro_inline.h>

RETRO_BEGIN_DECLS

typedef float vec2_t[2];

#define vec2_dot(a, b)   ((a[0] * b[0]) + (a[1] * b[1]))

#define vec2_cross(a, b) ((a[0]*b[1]) - (a[1]*b[0]))

#define vec2_add(dst, src) \
   dst[0] += src[0]; \
   dst[1] += src[1]

#define vec2_subtract(dst, src) \
   dst[0] -= src[0]; \
   dst[1] -= src[1]

#define vec2_copy(dst, src) \
   dst[0] = src[0]; \
   dst[1] = src[1]

static INLINE float overflow(void)
{
   unsigned i;
   volatile float f = 1e10;

   for (i = 0; i < 10; ++i)
      f *= f;
   return f;
}

static INLINE int16_t tofloat16(float f)
{
	union uif32
   {
      float f;
      uint32_t i;
   };

   int i, s, e, m;
   union uif32 Entry;
   Entry.f = f;
   i       = (int)Entry.i;
   s       =  (i >> 16) & 0x00008000;
   e       = ((i >> 23) & 0x000000ff) - (127 - 15);
   m       =   i        & 0x007fffff;

   if (e <= 0)
   {
      if (e < -10)
         return (int16_t)(s);

      m = (m | 0x00800000) >> (1 - e);

      if (m & 0x00001000)
         m += 0x00002000;

      return (int16_t)(s | (m >> 13));
   }

   if (e == 0xff - (127 - 15))
   {
      if (m == 0)
         return (int16_t)(s | 0x7c00);

      m >>= 13;

      return (int16_t)(s | 0x7c00 | m | (m == 0));
   }

   if (m &  0x00001000)
   {
      m += 0x00002000;

      if (m & 0x00800000)
      {
         m =  0;
         e += 1;
      }
   }

   if (e > 30)
   {
      overflow();

      return (int16_t)(s | 0x7c00);
   }

   return (int16_t)(s | (e << 10) | (m >> 13));
}

static INLINE unsigned int vec2_packHalf2x16(float vec0, float vec1)
{
   union
   {
      int16_t in[2];
      unsigned int out;
   } u;

   u.in[0] = tofloat16(vec0);
   u.in[1] = tofloat16(vec1);

   return u.out;
}

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/math/vector_3.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_3.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__
#define __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__

#include <stdint.h>
#include <math.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

typedef float vec3_t[3];

#define vec3_dot(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])

#define vec3_cross(dst, a, b)  \
   dst[0] = a[1]*b[2] - a[2]*b[1]; \
   dst[1] = a[2]*b[0] - a[0]*b[2]; \
   dst[2] = a[0]*b[1] - a[1]*b[0]

#define vec3_length(a) sqrtf(vec3_dot(a,a))

#define vec3_add(dst, src) \
   dst[0] += src[0]; \
   dst[1] += src[1]; \
   dst[2] += src[2]

#define vec3_subtract(dst, src) \
   dst[0] -= src[0]; \
   dst[1] -= src[1]; \
   dst[2] -= src[2]

#define vec3_scale(dst, scale) \
   dst[0] *= scale; \
   dst[1] *= scale; \
   dst[2] *= scale

#define vec3_copy(dst, src) \
   dst[0] = src[0]; \
   dst[1] = src[1]; \
   dst[2] = src[2]

#define vec3_normalize(dst) vec3_scale(dst,1.0f / vec3_length(dst))

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/math/vector_4.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_4.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__
#define __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__

#include <stdint.h>
#include <math.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

typedef float vec4_t[4];

#define vec4_add(dst, src) \
   dst[0] += src[0]; \
   dst[1] += src[1]; \
   dst[2] += src[2]; \
   dst[3] += src[3]

#define vec4_subtract(dst, src) \
   dst[0] -= src[0]; \
   dst[1] -= src[1]; \
   dst[2] -= src[2]; \
   dst[3] -= src[3]

#define vec4_scale(dst, scale) \
   dst[0] *= scale; \
   dst[1] *= scale; \
   dst[2] *= scale; \
   dst[3] *= scale

#define vec4_copy(dst, src) \
   dst[0] = src[0]; \
   dst[1] = src[1]; \
   dst[2] = src[2]; \
   dst[3] = src[3]

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/scaler/filter.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (filter.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_FILTER_H__
#define __LIBRETRO_SDK_SCALER_FILTER_H__

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#include <boolean.h>
#include <gfx/scaler/scaler.h>

bool scaler_gen_filter(struct scaler_ctx *ctx);

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/scaler/pixconv.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (pixconv.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_PIXCONV_H__
#define __LIBRETRO_SDK_SCALER_PIXCONV_H__

#include <clamping.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

void conv_0rgb1555_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_0rgb1555_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_0rgb1555(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_abgr8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgba4444_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgba4444_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_bgr24_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_bgr24_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_0rgb1555(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_rgba4444(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_abgr8888_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_abgr8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_0rgb1555_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_yuyv_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_copy(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/scaler/scaler.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_H__
#define __LIBRETRO_SDK_SCALER_H__

#include <stdint.h>
#include <stddef.h>
#include <boolean.h>
#include <clamping.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

enum scaler_pix_fmt
{
   SCALER_FMT_ARGB8888 = 0,
   SCALER_FMT_ABGR8888,
   SCALER_FMT_0RGB1555,
   SCALER_FMT_RGB565,
   SCALER_FMT_BGR24,
   SCALER_FMT_YUYV,
   SCALER_FMT_RGBA4444
};

enum scaler_type
{
   SCALER_TYPE_UNKNOWN = 0,
   SCALER_TYPE_POINT,
   SCALER_TYPE_BILINEAR,
   SCALER_TYPE_SINC
};

struct scaler_filter
{
   int16_t *filter;
   int     *filter_pos;
   int      filter_len;
   int      filter_stride;
};

struct scaler_ctx
{
   void (*scaler_horiz)(const struct scaler_ctx*,
         const void*, int);
   void (*scaler_vert)(const struct scaler_ctx*,
         void*, int);
   void (*scaler_special)(const struct scaler_ctx*,
         void*, const void*, int, int, int, int, int, int);

   void (*in_pixconv)(void*, const void*, int, int, int, int);
   void (*out_pixconv)(void*, const void*, int, int, int, int);
   void (*direct_pixconv)(void*, const void*, int, int, int, int);
   struct scaler_filter horiz, vert;   /* ptr alignment */

   struct
   {
      uint32_t *frame;
      int stride;
   } input;

   struct
   {
      uint64_t *frame;
      int width;
      int height;
      int stride;
   } scaled;

   struct
   {
      uint32_t *frame;
      int stride;
   } output;

   int in_width;
   int in_height;
   int in_stride;

   int out_width;
   int out_height;
   int out_stride;

   enum scaler_pix_fmt in_fmt;
   enum scaler_pix_fmt out_fmt;
   enum scaler_type scaler_type;

   bool unscaled;
};

bool scaler_ctx_gen_filter(struct scaler_ctx *ctx);

void scaler_ctx_gen_reset(struct scaler_ctx *ctx);

/**
 * scaler_ctx_scale:
 * @ctx          : pointer to scaler context object.
 * @output       : pointer to output image.
 * @input        : pointer to input image.
 *
 * Scales an input image to an output image.
 **/
void scaler_ctx_scale(struct scaler_ctx *ctx,
      void *output, const void *input);

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/scaler/scaler_int.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler_int.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_INT_H__
#define __LIBRETRO_SDK_SCALER_INT_H__

#include <gfx/scaler/scaler.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

void scaler_argb8888_vert(const struct scaler_ctx *ctx,
      void *output, int stride);

void scaler_argb8888_horiz(const struct scaler_ctx *ctx,
      const void *input, int stride);

void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
      void *output, const void *input,
      int out_width, int out_height,
      int in_width, int in_height,
      int out_stride, int in_stride);

RETRO_END_DECLS

#endif

./include/libretro-common/include/gfx/video_frame.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (video_frame.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_VIDEO_FRAME_H
#define _LIBRETRO_SDK_VIDEO_FRAME_H

#include <stdint.h>
#include <retro_common_api.h>
#include <retro_inline.h>

#include <gfx/scaler/scaler.h>

#include <libretro.h>

RETRO_BEGIN_DECLS

#define scaler_ctx_scale_direct(ctx, output, input) \
{ \
   if (ctx && ctx->unscaled && ctx->direct_pixconv) \
      /* Just perform straight pixel conversion. */ \
      ctx->direct_pixconv(output, input, \
            ctx->out_width,  ctx->out_height, \
            ctx->out_stride, ctx->in_stride); \
   else \
      scaler_ctx_scale(ctx, output, input); \
}

static INLINE void video_frame_convert_rgb16_to_rgb32(
      struct scaler_ctx *scaler,
      void *output,
      const void *input,
      int width, int height,
      int in_pitch)
{
   if (width != scaler->in_width || height != scaler->in_height)
   {
      scaler->in_width    = width;
      scaler->in_height   = height;
      scaler->out_width   = width;
      scaler->out_height  = height;
      scaler->in_fmt      = SCALER_FMT_RGB565;
      scaler->out_fmt     = SCALER_FMT_ARGB8888;
      scaler->scaler_type = SCALER_TYPE_POINT;
      scaler_ctx_gen_filter(scaler);
   }

   scaler->in_stride  = in_pitch;
   scaler->out_stride = width * sizeof(uint32_t);

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_scale(
      struct scaler_ctx *scaler,
      void *output,
      const void *input,
      enum scaler_pix_fmt format,
      unsigned scaler_width,
      unsigned scaler_height,
      unsigned scaler_pitch,
      unsigned width,
      unsigned height,
      unsigned pitch)
{
   if (
            width  != (unsigned)scaler->in_width
         || height != (unsigned)scaler->in_height
         || format != scaler->in_fmt
         || pitch  != (unsigned)scaler->in_stride
      )
   {
      scaler->in_fmt    = format;
      scaler->in_width  = width;
      scaler->in_height = height;
      scaler->in_stride = pitch;

      scaler->out_width  = scaler_width;
      scaler->out_height = scaler_height;
      scaler->out_stride = scaler_pitch;

      scaler_ctx_gen_filter(scaler);
   }

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_record_scale(
      struct scaler_ctx *scaler,
      void *output,
      const void *input,
      unsigned scaler_width,
      unsigned scaler_height,
      unsigned scaler_pitch,
      unsigned width,
      unsigned height,
      unsigned pitch,
      bool bilinear)
{
   if (
            width  != (unsigned)scaler->in_width
         || height != (unsigned)scaler->in_height
      )
   {
      scaler->in_width    = width;
      scaler->in_height   = height;
      scaler->in_stride   = pitch;

      scaler->scaler_type = bilinear ?
         SCALER_TYPE_BILINEAR : SCALER_TYPE_POINT;

      scaler->out_width  = scaler_width;
      scaler->out_height = scaler_height;
      scaler->out_stride = scaler_pitch;

      scaler_ctx_gen_filter(scaler);
   }

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_convert_argb8888_to_abgr8888(
      struct scaler_ctx *scaler,
      void *output, const void *input,
      int width, int height, int in_pitch)
{
   if (width != scaler->in_width || height != scaler->in_height)
   {
      scaler->in_width    = width;
      scaler->in_height   = height;
      scaler->out_width   = width;
      scaler->out_height  = height;
      scaler->in_fmt      = SCALER_FMT_ARGB8888;
      scaler->out_fmt     = SCALER_FMT_ABGR8888;
      scaler->scaler_type = SCALER_TYPE_POINT;
      scaler_ctx_gen_filter(scaler);
   }

   scaler->in_stride  = in_pitch;
   scaler->out_stride = width * sizeof(uint32_t);

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_convert_to_bgr24(
      struct scaler_ctx *scaler,
      void *output, const void *input,
      int width, int height, int in_pitch)
{
   scaler->in_width    = width;
   scaler->in_height   = height;
   scaler->out_width   = width;
   scaler->out_height  = height;
   scaler->out_fmt     = SCALER_FMT_BGR24;
   scaler->scaler_type = SCALER_TYPE_POINT;

   scaler_ctx_gen_filter(scaler);

   scaler->in_stride   = in_pitch;
   scaler->out_stride  = width * 3;

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_convert_rgba_to_bgr(
      const void *src_data,
      void *dst_data,
      unsigned width)
{
   unsigned x;
   uint8_t      *dst  = (uint8_t*)dst_data;
   const uint8_t *src = (const uint8_t*)src_data;

   for (x = 0; x < width; x++, dst += 3, src += 4)
   {
      dst[0] = src[2];
      dst[1] = src[1];
      dst[2] = src[0];
   }
}

static INLINE void video_pixel_frame_scale(
      struct scaler_ctx *scaler,
      void *output, const void *data,
      unsigned width, unsigned height,
      size_t pitch)
{
   scaler->in_width      = width;
   scaler->in_height     = height;
   scaler->out_width     = width;
   scaler->out_height    = height;
   scaler->in_stride     = (int)pitch;
   scaler->out_stride    = width * sizeof(uint16_t);
   scaler_ctx_scale_direct(scaler, output, data);
}

RETRO_END_DECLS

#endif

./include/libretro-common/include/glsm/glsm.h

/* Copyright (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsm.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_GLSM_H
#define LIBRETRO_SDK_GLSM_H

#include <retro_common_api.h>

#include <boolean.h>
#include <libretro.h>
#include <glsym/rglgen_headers.h>

RETRO_BEGIN_DECLS

#ifdef HAVE_OPENGLES2
typedef double GLdouble;
typedef double GLclampd;
#endif

#if defined(HAVE_OPENGLES2)
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
#elif (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER_EXT
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT
#elif defined(HAVE_PSGL)
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER_OES
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_SCE
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_OES
#else
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
#endif

#if defined(HAVE_PSGL)
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
#elif (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
#else
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0
#endif

#ifndef GL_FOG
#define GL_FOG 0x0B60
#endif

#ifndef GL_ALPHA_TEST
#define GL_ALPHA_TEST 0x0BC0
#endif

#ifndef GL_CLIP_DISTANCE0
#define GL_CLIP_DISTANCE0 0x3000
#endif

#define MAX_ATTRIB 8

enum
{
   SGL_DEPTH_TEST             = 0,
   SGL_BLEND,
   SGL_POLYGON_OFFSET_FILL,
   SGL_FOG,
   SGL_CULL_FACE,
   SGL_ALPHA_TEST,
   SGL_SCISSOR_TEST,
   SGL_STENCIL_TEST,
#if !defined(HAVE_OPENGLES)
   SGL_DEPTH_CLAMP,
   SGL_CLIP_DISTANCE0,
#endif
   SGL_DITHER,
   SGL_SAMPLE_ALPHA_TO_COVERAGE,
   SGL_SAMPLE_COVERAGE,
#ifndef HAVE_OPENGLES
   SGL_COLOR_LOGIC_OP,
#endif
   SGL_CAP_MAX
};

enum glsm_state_ctl
{
   GLSM_CTL_NONE = 0,
   GLSM_CTL_STATE_SETUP,
   GLSM_CTL_STATE_BIND,
   GLSM_CTL_STATE_UNBIND,
   GLSM_CTL_STATE_CONTEXT_RESET,
   GLSM_CTL_STATE_CONTEXT_DESTROY,
   GLSM_CTL_STATE_CONTEXT_INIT,
   GLSM_CTL_IS_IMM_VBO,
   GLSM_CTL_SET_IMM_VBO,
   GLSM_CTL_UNSET_IMM_VBO,
   GLSM_CTL_IMM_VBO_DISABLE,
   GLSM_CTL_IMM_VBO_DRAW,
   GLSM_CTL_PROC_ADDRESS_GET
};

typedef bool (*glsm_imm_vbo_draw)(void *);
typedef bool (*glsm_imm_vbo_disable)(void *);
typedef bool (*glsm_framebuffer_lock)(void *);

typedef struct glsm_ctx_proc_address
{
   retro_get_proc_address_t addr;
} glsm_ctx_proc_address_t;

typedef struct glsm_ctx_params
{
   glsm_framebuffer_lock    framebuffer_lock;
   glsm_imm_vbo_draw        imm_vbo_draw;
   glsm_imm_vbo_disable     imm_vbo_disable;
   retro_hw_context_reset_t context_reset;
   retro_hw_context_reset_t context_destroy;
   retro_environment_t environ_cb;
   bool stencil;
   unsigned major;
   unsigned minor;
   enum retro_hw_context_type context_type;
} glsm_ctx_params_t;

GLuint glsm_get_current_framebuffer(void);

bool glsm_ctl(enum glsm_state_ctl state, void *data);

RETRO_END_DECLS

#endif

./include/libretro-common/include/glsm/glsmsym.h

/* Copyright (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsmsym.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_GLSM_SYM_H
#define LIBRETRO_SDK_GLSM_SYM_H

#include <glsm/glsm.h>

#ifdef HAVE_GLSYM_PRIVATE
#include "glsym_private.h"
#endif

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/* deprecated old FF-style GL symbols */
#define glTexCoord2f                rglTexCoord2f

/* more forward-compatible GL subset symbols */
#define glDrawRangeElementsBaseVertex rglDrawRangeElementsBaseVertex
#define glProvokingVertex           rglProvokingVertex
#define glGetInteger64v             rglGetInteger64v
#define glGenSamplers               rglGenSamplers
#define glBindSampler               rglBindSampler
#define glSamplerParameteri         rglSamplerParameteri
#define glGetBufferSubData          rglGetBufferSubData
#define glUniform2iv                rglUniform2iv
#define glUniform2uiv               rglUniform2uiv
#define glTextureView               rglTextureView
#define glGetQueryObjectuiv         rglGetQueryObjectuiv
#define glGenQueries                rglGenQueries
#define glDeleteQueries             rglDeleteQueries
#define glBeginQuery                rglBeginQuery
#define glEndQuery                  rglEndQuery
#define glBlitFramebuffer           rglBlitFramebuffer
#define glVertexAttrib4f            rglVertexAttrib4f
#define glVertexAttrib4fv           rglVertexAttrib4fv
#define glDrawArrays                rglDrawArrays
#define glDrawElements              rglDrawElements
#define glCompressedTexImage2D      rglCompressedTexImage2D
#define glBindTexture               rglBindTexture
#define glActiveTexture             rglActiveTexture
#define glFramebufferTexture        rglFramebufferTexture
#define glFramebufferTexture2D      rglFramebufferTexture2D
#define glFramebufferRenderbuffer   rglFramebufferRenderbuffer
#define glDeleteFramebuffers        rglDeleteFramebuffers
#define glDeleteTextures            rglDeleteTextures
#define glDeleteBuffers             rglDeleteBuffers
#define glRenderbufferStorage       rglRenderbufferStorage
#define glBindRenderbuffer          rglBindRenderbuffer
#define glDeleteRenderbuffers       rglDeleteRenderbuffers
#define glGenRenderbuffers          rglGenRenderbuffers
#define glGenFramebuffers           rglGenFramebuffers
#define glGenTextures               rglGenTextures
#define glBindFramebuffer           rglBindFramebuffer
#define glGenerateMipmap            rglGenerateMipmap
#define glCheckFramebufferStatus    rglCheckFramebufferStatus
#define glBindFragDataLocation      rglBindFragDataLocation
#define glBindAttribLocation        rglBindAttribLocation
#define glLinkProgram               rglLinkProgram
#define glGetProgramiv              rglGetProgramiv
#define glGetShaderiv               rglGetShaderiv
#define glAttachShader              rglAttachShader
#define glDetachShader              rglDetachShader
#define glShaderSource              rglShaderSource
#define glCompileShader             rglCompileShader
#define glCreateProgram             rglCreateProgram
#define glGetShaderInfoLog          rglGetShaderInfoLog
#define glGetProgramInfoLog         rglGetProgramInfoLog
#define glIsProgram                 rglIsProgram
#define glEnableVertexAttribArray   rglEnableVertexAttribArray
#define glDisableVertexAttribArray  rglDisableVertexAttribArray
#define glVertexAttribPointer       rglVertexAttribPointer
#define glVertexAttribIPointer      rglVertexAttribIPointer
#define glVertexAttribLPointer      rglVertexAttribLPointer
#define glGetUniformLocation        rglGetUniformLocation
#define glGenBuffers                rglGenBuffers
#define glDisable(T)                rglDisable(S##T)
#define glEnable(T)                 rglEnable(S##T)
#define glIsEnabled(T)              rglIsEnabled(S##T)
#define glUseProgram                rglUseProgram
#define glDepthMask                 rglDepthMask
#define glStencilMask               rglStencilMask
#define glBufferData                rglBufferData
#define glBufferSubData             rglBufferSubData
#define glBindBuffer                rglBindBuffer
#define glCreateShader              rglCreateShader
#define glDeleteShader              rglDeleteShader
#define glDeleteProgram             rglDeleteProgram
#define glUniform1f                 rglUniform1f
#define glUniform1i                 rglUniform1i
#define glUniform2f                 rglUniform2f
#define glUniform2i                 rglUniform2i
#define glUniform2fv                rglUniform2fv
#define glUniform3f                 rglUniform3f
#define glUniform3fv                rglUniform3fv
#define glUniform4i                 rglUniform4i
#define glUniform4f                 rglUniform4f
#define glUniform4fv                rglUniform4fv
#define glUniform1ui                rglUniform1ui
#define glUniform2ui                rglUniform2ui
#define glUniform3ui                rglUniform3ui
#define glUniform4ui                rglUniform4ui
#define glGetActiveUniform          rglGetActiveUniform
#define glBlendFunc                 rglBlendFunc
#define glBlendFuncSeparate         rglBlendFuncSeparate
#define glDepthFunc                 rglDepthFunc
#define glColorMask                 rglColorMask
#define glClearColor                rglClearColor
#define glViewport                  rglViewport
#define glScissor                   rglScissor
#define glStencilFunc               rglStencilFunc
#define glCullFace                  rglCullFace
#define glStencilOp                 rglStencilOp
#define glFrontFace                 rglFrontFace
#define glDepthRange                rglDepthRange
#define glClearDepth                rglClearDepth
#define glPolygonOffset             rglPolygonOffset
#define glPixelStorei               rglPixelStorei
#define glReadBuffer                rglReadBuffer
#define glUniformMatrix4fv          rglUniformMatrix4fv
#define glGetAttribLocation         rglGetAttribLocation
#define glTexStorage2D              rglTexStorage2D
#define glDrawBuffers               rglDrawBuffers
#define glGenVertexArrays           rglGenVertexArrays
#define glBindVertexArray           rglBindVertexArray
#define glBlendEquation             rglBlendEquation
#define glBlendColor                rglBlendColor
#define glBlendEquationSeparate     rglBlendEquationSeparate
#define glCopyImageSubData          rglCopyImageSubData
#define glMapBuffer                 rglMapBuffer
#define glUnmapBuffer               rglUnmapBuffer
#define glMapBufferRange            rglMapBufferRange
#define glUniformBlockBinding       rglUniformBlockBinding
#define glGetUniformBlockIndex      rglGetUniformBlockIndex
#define glGetActiveUniformBlockiv   rglGetActiveUniformBlockiv
#define glBindBufferBase            rglBindBufferBase
#define glGetUniformIndices         rglGetUniformIndices
#define glGetActiveUniformsiv       rglGetActiveUniformsiv
#define glGetError                  rglGetError
#define glClear                     rglClear
#define glPolygonMode               rglPolygonMode
#define glLineWidth                 rglLineWidth
#define glTexImage3D                rglTexImage3D
#define glTexImage2DMultisample     rglTexImage2DMultisample
#define glTexStorage2DMultisample   rglTexStorage2DMultisample
#define glMemoryBarrier             rglMemoryBarrier
#define glBindImageTexture          rglBindImageTexture
#define glProgramBinary             rglProgramBinary
#define glGetProgramBinary          rglGetProgramBinary
#define glProgramParameteri         rglProgramParameteri
#define glTexSubImage2D             rglTexSubImage2D
#define glDeleteVertexArrays        rglDeleteVertexArrays
#define glRenderbufferStorageMultisample rglRenderbufferStorageMultisample
#define glUniform1iv                rglUniform1iv
#define glUniform1fv                rglUniform1fv
#define glValidateProgram           rglValidateProgram
#define glGetStringi                rglGetStringi
#define glTexBuffer                 rglTexBuffer
#define glClearBufferfv             rglClearBufferfv
#define glClearBufferfi             rglClearBufferfi
#define glWaitSync                  rglWaitSync
#define glFenceSync                 rglFenceSync
#define glDeleteSync                rglDeleteSync
#define glBufferStorage             rglBufferStorage
#define glFlushMappedBufferRange    rglFlushMappedBufferRange
#define glClientWaitSync            rglClientWaitSync
#define glDrawElementsBaseVertex    rglDrawElementsBaseVertex

const GLubyte* rglGetStringi(GLenum name, GLuint index);
void rglTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer);
void rglClearBufferfv( 	GLenum buffer,
  	GLint drawBuffer,
  	const GLfloat * value);
void rglClearBufferfi( 	GLenum buffer,
  	GLint drawBuffer,
  	GLfloat depth,
  	GLint stencil);
void rglValidateProgram(GLuint program);
void rglRenderbufferStorageMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height);
void rglUniform1iv(GLint location,  GLsizei count,  const GLint *value);
void rglUniform1fv(GLint location,  GLsizei count,  const GLfloat *value);
void rglProgramParameteri( 	GLuint program,
  	GLenum pname,
  	GLint value);
void rglGetProgramBinary( 	GLuint program,
  	GLsizei bufsize,
  	GLsizei *length,
  	GLenum *binaryFormat,
  	void *binary);
void rglProgramBinary(GLuint program,
  	GLenum binaryFormat,
  	const void *binary,
  	GLsizei length);
void rglBindImageTexture( 	GLuint unit,
  	GLuint texture,
  	GLint level,
  	GLboolean layered,
  	GLint layer,
  	GLenum access,
  	GLenum format);
void rglTexStorage2DMultisample(GLenum target, GLsizei samples,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLboolean fixedsamplelocations);
void rglGetActiveUniformsiv( 	GLuint program,
  	GLsizei uniformCount,
  	const GLuint *uniformIndices,
  	GLenum pname,
  	GLint *params);
void rglGetUniformIndices( 	GLuint program,
  	GLsizei uniformCount,
  	const GLchar **uniformNames,
  	GLuint *uniformIndices);
void rglBindBufferBase( 	GLenum target,
  	GLuint index,
  	GLuint buffer);
void rglGetActiveUniformBlockiv( 	GLuint program,
  	GLuint uniformBlockIndex,
  	GLenum pname,
  	GLint *params);
GLuint rglGetUniformBlockIndex( 	GLuint program,
  	const GLchar *uniformBlockName);
void * rglMapBuffer(	GLenum target, GLenum access);
void *rglMapBufferRange( 	GLenum target,
  	GLintptr offset,
  	GLsizeiptr length,
  	GLbitfield access);
GLboolean rglUnmapBuffer( 	GLenum target);
void rglBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void rglBlendEquation(GLenum mode);
void rglGenVertexArrays(GLsizei n, GLuint *arrays);
void rglReadBuffer(GLenum mode);
void rglPixelStorei(GLenum pname, GLint param);
void rglTexCoord2f(GLfloat s, GLfloat t);
void rglDrawElements(GLenum mode, GLsizei count, GLenum type,
                           const GLvoid * indices);
void rglTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
      GLsizei width, GLsizei height);
void rglCompressedTexImage2D(GLenum target, GLint level,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLint border, GLsizei imageSize, const GLvoid *data);
void glBindTexture(GLenum target, GLuint texture);
void glActiveTexture(GLenum texture);
void rglFramebufferTexture(GLenum target, GLenum attachment,
  	GLuint texture, GLint level);
void rglFramebufferTexture2D(GLenum target, GLenum attachment,
      GLenum textarget, GLuint texture, GLint level);
void rglFramebufferRenderbuffer(GLenum target, GLenum attachment,
      GLenum renderbuffertarget, GLuint renderbuffer);
void rglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
void rglRenderbufferStorage(GLenum target, GLenum internalFormat,
      GLsizei width, GLsizei height);
void rglDeleteTextures(GLsizei n, const GLuint *textures);
void rglBindRenderbuffer(GLenum target, GLuint renderbuffer);
void rglDeleteRenderbuffers(GLsizei n, GLuint *renderbuffers);
void rglGenRenderbuffers(GLsizei n, GLuint *renderbuffers);
void rglGenFramebuffers(GLsizei n, GLuint *ids);
void rglGenTextures(GLsizei n, GLuint *textures);
void rglBindFramebuffer(GLenum target, GLuint framebuffer);
void rglGenerateMipmap(GLenum target);
GLenum rglCheckFramebufferStatus(GLenum target);
void rglBindFragDataLocation(GLuint program, GLuint colorNumber,
                                   const char * name);
void rglBindAttribLocation(GLuint program, GLuint index, const GLchar *name);
void rglLinkProgram(GLuint program);
void rglGetProgramiv(GLuint shader, GLenum pname, GLint *params);
void rglGetShaderiv(GLuint shader, GLenum pname, GLint *params);
void rglAttachShader(GLuint program, GLuint shader);
void rglShaderSource(GLuint shader, GLsizei count,
      const GLchar **string, const GLint *length);
void rglCompileShader(GLuint shader);
GLuint rglCreateProgram(void);
void rglGetShaderInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog);
void rglGetProgramInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog);
GLboolean rglIsProgram(GLuint program);
void rglEnableVertexAttribArray(GLuint index);
void rglDisableVertexAttribArray(GLuint index);
void rglVertexAttribPointer(GLuint name, GLint size,
      GLenum type, GLboolean normalized, GLsizei stride,
      const GLvoid* pointer);
GLint rglGetUniformLocation(GLuint program, const GLchar *name);
void rglGenBuffers(GLsizei n, GLuint *buffers);
void rglDisable(GLenum cap);
void rglEnable(GLenum cap);
void rglUseProgram(GLuint program);
void rglDepthMask(GLboolean flag);
void rglStencilMask(GLenum mask);
void rglBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
void rglBufferSubData(GLenum target, GLintptr offset,
      GLsizeiptr size, const GLvoid *data);
void rglBindBuffer(GLenum target, GLuint buffer);
GLuint rglCreateShader(GLenum shader);
void rglDeleteShader(GLuint shader);
void rglUniform1f(GLint location, GLfloat v0);
void rglUniform1i(GLint location, GLint v0);
void rglUniform2f(GLint location, GLfloat v0, GLfloat v1);
void rglUniform2i(GLint location, GLint v0, GLint v1);
void rglUniform2fv(GLint location, GLsizei count, const GLfloat *value);
void rglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void rglUniform3fv(GLint location, GLsizei count, const GLfloat *value);
void rglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
void rglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
void rglUniform4fv(GLint location, GLsizei count, const GLfloat *value);
void rglBlendFunc(GLenum sfactor, GLenum dfactor);
void rglBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha,
      GLenum dstAlpha);
void rglDepthFunc(GLenum func);
void rglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
void rglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void rglViewport(GLint x, GLint y, GLsizei width, GLsizei height);
void rglScissor(GLint x, GLint y, GLsizei width, GLsizei height);
GLboolean rglIsEnabled(GLenum cap);
void rglStencilFunc(GLenum func, GLint ref, GLuint mask);
void rglCullFace(GLenum mode);
void rglStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
void rglFrontFace(GLenum mode);
void rglDepthRange(GLclampd zNear, GLclampd zFar);
void rglClearDepth(GLdouble depth);
void rglPolygonOffset(GLfloat factor, GLfloat units);
void rglDrawArrays(GLenum mode, GLint first, GLsizei count);
void rglVertexAttrib4f(GLuint name, GLfloat x, GLfloat y,
      GLfloat z, GLfloat w);
void rglVertexAttrib4fv(GLuint name, GLfloat* v);
void rglDeleteProgram(GLuint program);
void rglDeleteBuffers(GLsizei n, const GLuint *buffers);
void rglUniform2uiv(	GLint location,
 	GLsizei count,
 	const GLuint *value);
void rglTextureView(	GLuint texture,
 	GLenum target,
 	GLuint origtexture,
 	GLenum internalformat,
 	GLuint minlevel,
 	GLuint numlevels,
 	GLuint minlayer,
 	GLuint numlayers);
void rglGenQueries(	GLsizei n,
 	GLuint * ids);
void rglDeleteQueries(	GLsizei n,
 	const GLuint * ids);
void rglBeginQuery(	GLenum target,
 	GLuint id);
void rglEndQuery(	GLenum target);
void rglGetQueryObjectuiv(	GLuint id,
 	GLenum pname,
 	GLuint * params);
void rglBlitFramebuffer(
      GLint srcX0, GLint srcY0,
      GLint srcX1, GLint srcY1,
      GLint dstX0, GLint dstY0,
      GLint dstX1, GLint dstY1,
      GLbitfield mask, GLenum filter);
void rglDetachShader(GLuint program, GLuint shader);
void rglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
      const GLfloat *value);
GLint rglGetAttribLocation(GLuint program, const GLchar *name);
void rglDrawBuffers(GLsizei n, const GLenum *bufs);
void rglBindVertexArray(GLuint array);

void rglGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
      GLsizei *length, GLint *size, GLenum *type, GLchar *name);
void rglUniform1ui(GLint location, GLuint v);
void rglUniform2ui(GLint location, GLuint v0, GLuint v1);
void rglUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);
void rglUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
void rglBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
void rglCopyImageSubData( 	GLuint srcName,
  	GLenum srcTarget,
  	GLint srcLevel,
  	GLint srcX,
  	GLint srcY,
  	GLint srcZ,
  	GLuint dstName,
  	GLenum dstTarget,
  	GLint dstLevel,
  	GLint dstX,
  	GLint dstY,
  	GLint dstZ,
  	GLsizei srcWidth,
  	GLsizei srcHeight,
  	GLsizei srcDepth);
void rglVertexAttribIPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer);
void rglVertexAttribLPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer);
void rglUniformBlockBinding( 	GLuint program,
  	GLuint uniformBlockIndex,
  	GLuint uniformBlockBinding);
GLenum rglGetError(void);
void rglClear(GLbitfield mask);
void rglPolygonMode(GLenum face, GLenum mode);
void rglLineWidth(GLfloat width);
void rglTexImage3D(	GLenum target,
 	GLint level,
 	GLint internalFormat,
 	GLsizei width,
 	GLsizei height,
 	GLsizei depth,
 	GLint border,
 	GLenum format,
 	GLenum type,
 	const GLvoid * data);
void rglTexImage2DMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height,
  	GLboolean fixedsamplelocations);
void rglMemoryBarrier( 	GLbitfield barriers);
void rglTexSubImage2D( 	GLenum target,
  	GLint level,
  	GLint xoffset,
  	GLint yoffset,
  	GLsizei width,
  	GLsizei height,
  	GLenum format,
  	GLenum type,
  	const GLvoid * pixels);
void rglDeleteVertexArrays(GLsizei n, const GLuint *arrays);
void *rglFenceSync(GLenum condition, GLbitfield flags);
void rglDeleteSync(void *sync);
void rglWaitSync(void *sync, GLbitfield flags, uint64_t timeout);
void rglBufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GLbitfield flags);
void rglFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
GLenum rglClientWaitSync(void *sync, GLbitfield flags, uint64_t timeout);
void rglDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
			       GLvoid *indices, GLint basevertex);
void rglGetBufferSubData(	GLenum target,
 	GLintptr offset,
 	GLsizeiptr size,
 	GLvoid * data);
void rglSamplerParameteri(	GLuint sampler,
 	GLenum pname,
 	GLint param);
void rglBindSampler(	GLuint unit,
 	GLuint sampler);
void rglGenSamplers(	GLsizei n,
 	GLuint *samplers);
void rglGetInteger64v(	GLenum pname,
 	int64_t * data);
void rglUniform2iv(	GLint location,
 	GLsizei count,
 	const GLint *value);
void rglProvokingVertex(	GLenum provokeMode);
void rglDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex);

RETRO_END_DECLS

#endif

./include/libretro-common/include/glsym/glsym_es2.h

#ifndef RGLGEN_DECL_H__
#define RGLGEN_DECL_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef GL_APIENTRY
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#endif
#ifndef GL_OES_EGL_image
typedef void *GLeglImageOES;
#endif
#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)
typedef GLint GLfixed;
#endif

typedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);
typedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
typedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAOESPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
typedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
typedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);
typedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
typedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
typedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
typedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
typedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
typedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
typedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
typedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);
typedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);
typedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);
typedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);

#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR
#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR
#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR
#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR
#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR
#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR
#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR
#define glObjectLabelKHR __rglgen_glObjectLabelKHR
#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR
#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR
#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR
#define glGetPointervKHR __rglgen_glGetPointervKHR
#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR
#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR
#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR
#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR
#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR
#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES
#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES
#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES
#define glEnableiOES __rglgen_glEnableiOES
#define glDisableiOES __rglgen_glDisableiOES
#define glBlendEquationiOES __rglgen_glBlendEquationiOES
#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES
#define glBlendFunciOES __rglgen_glBlendFunciOES
#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES
#define glColorMaskiOES __rglgen_glColorMaskiOES
#define glIsEnablediOES __rglgen_glIsEnablediOES
#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES
#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES
#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES
#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES
#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES
#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES
#define glProgramBinaryOES __rglgen_glProgramBinaryOES
#define glMapBufferOES __rglgen_glMapBufferOES
#define glUnmapBufferOES __rglgen_glUnmapBufferOES
#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES
#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES
#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES
#define glPatchParameteriOES __rglgen_glPatchParameteriOES
#define glTexImage3DOES __rglgen_glTexImage3DOES
#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES
#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES
#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES
#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES
#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES
#define glTexParameterIivOES __rglgen_glTexParameterIivOES
#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES
#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES
#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES
#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES
#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES
#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES
#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES
#define glTexBufferOES __rglgen_glTexBufferOES
#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES
#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES
#define glTextureViewOES __rglgen_glTextureViewOES
#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES
#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES
#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES
#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES
#define glViewportArrayvOES __rglgen_glViewportArrayvOES
#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES
#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES
#define glScissorArrayvOES __rglgen_glScissorArrayvOES
#define glScissorIndexedOES __rglgen_glScissorIndexedOES
#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES
#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES
#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES
#define glGetFloati_vOES __rglgen_glGetFloati_vOES
#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT
#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT
#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT
#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT
#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT
#define glBufferStorageEXT __rglgen_glBufferStorageEXT
#define glClearTexImageEXT __rglgen_glClearTexImageEXT
#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT
#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT
#define glLabelObjectEXT __rglgen_glLabelObjectEXT
#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT
#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT
#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT
#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT
#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT
#define glGenQueriesEXT __rglgen_glGenQueriesEXT
#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT
#define glIsQueryEXT __rglgen_glIsQueryEXT
#define glBeginQueryEXT __rglgen_glBeginQueryEXT
#define glEndQueryEXT __rglgen_glEndQueryEXT
#define glQueryCounterEXT __rglgen_glQueryCounterEXT
#define glGetQueryivEXT __rglgen_glGetQueryivEXT
#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT
#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT
#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT
#define glEnableiEXT __rglgen_glEnableiEXT
#define glDisableiEXT __rglgen_glDisableiEXT
#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT
#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT
#define glBlendFunciEXT __rglgen_glBlendFunciEXT
#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT
#define glColorMaskiEXT __rglgen_glColorMaskiEXT
#define glIsEnablediEXT __rglgen_glIsEnablediEXT
#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT
#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT
#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT
#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT
#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT
#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT
#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT
#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT
#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT
#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT
#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT
#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT
#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT
#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT
#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT
#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT
#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT
#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT
#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT
#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT
#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT
#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT
#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT
#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT
#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT
#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT
#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT
#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT
#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT
#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT
#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT
#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT
#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT
#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT
#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT
#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT
#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT
#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT
#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT
#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT
#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT
#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT
#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT
#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT
#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT
#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT
#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT
#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT
#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT
#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT
#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT
#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT
#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT
#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT
#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT
#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT
#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT
#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT
#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT
#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT
#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT
#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT
#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT
#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT
#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT
#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT
#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT
#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT
#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT
#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT
#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT
#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT
#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT
#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT
#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT
#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT
#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT
#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT
#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT
#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT
#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT
#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT
#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT
#define glTexBufferEXT __rglgen_glTexBufferEXT
#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT
#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT
#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT
#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT
#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT
#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT
#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT
#define glTextureViewEXT __rglgen_glTextureViewEXT
#define glesEXT __rglgen_glesEXT
#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR
#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR

extern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
extern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
extern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
extern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
extern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
extern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
extern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
extern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
extern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
extern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
extern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
extern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
extern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
extern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
extern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
extern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
extern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
extern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
extern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
extern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
extern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
extern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
extern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
extern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
extern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
extern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
extern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
extern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
extern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
extern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
extern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
extern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
extern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
extern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
extern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
extern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
extern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
extern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
extern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
extern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
extern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
extern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
extern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
extern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
extern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
extern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
extern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
extern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
extern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
extern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
extern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
extern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
extern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
extern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
extern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
extern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
extern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
extern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
extern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
extern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
extern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
extern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
extern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
extern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
extern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
extern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
extern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
extern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
extern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
extern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
extern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
extern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
extern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
extern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
extern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
extern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
extern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
extern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
extern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
extern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
extern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
extern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
extern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
extern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
extern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
extern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
extern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
extern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
extern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
extern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
extern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
extern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
extern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
extern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
extern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
extern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
extern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
extern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
extern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
extern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
extern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
extern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
extern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
extern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
extern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
extern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
extern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
extern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
extern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
extern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
extern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
extern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
extern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
extern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
extern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
extern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
extern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
extern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
extern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
extern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
extern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
extern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
extern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
extern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
extern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
extern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
extern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
extern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
extern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
extern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
extern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
extern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
extern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
extern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
extern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
extern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
extern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
extern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
extern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
extern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
extern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
extern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
extern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
extern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
extern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
extern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
extern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
extern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
extern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;

struct rglgen_sym_map { const char *sym; void *ptr; };
extern const struct rglgen_sym_map rglgen_symbol_map[];
#ifdef __cplusplus
}
#endif
#endif

./include/libretro-common/include/glsym/glsym_es3.h

#ifndef RGLGEN_DECL_H__
#define RGLGEN_DECL_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef GL_APIENTRY
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#endif
#ifndef GL_OES_EGL_image
typedef void *GLeglImageOES;
#endif
#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)
typedef GLint GLfixed;
#endif
#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)
typedef long long int GLint64;
typedef unsigned long long int GLuint64;
typedef unsigned long long int GLuint64EXT;
typedef struct __GLsync *GLsync;
#endif
#ifndef GL_APIENTRYP
#define GL_APIENTRYP GL_APIENTRY*
#endif
typedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);
typedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
typedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAOESPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
typedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
typedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);
typedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
typedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
typedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
typedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
typedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
typedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
typedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
typedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);
typedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);
typedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);
typedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);

#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR
#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR
#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR
#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR
#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR
#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR
#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR
#define glObjectLabelKHR __rglgen_glObjectLabelKHR
#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR
#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR
#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR
#define glGetPointervKHR __rglgen_glGetPointervKHR
#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR
#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR
#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR
#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR
#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR
#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES
#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES
#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES
#define glEnableiOES __rglgen_glEnableiOES
#define glDisableiOES __rglgen_glDisableiOES
#define glBlendEquationiOES __rglgen_glBlendEquationiOES
#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES
#define glBlendFunciOES __rglgen_glBlendFunciOES
#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES
#define glColorMaskiOES __rglgen_glColorMaskiOES
#define glIsEnablediOES __rglgen_glIsEnablediOES
#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES
#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES
#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES
#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES
#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES
#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES
#define glProgramBinaryOES __rglgen_glProgramBinaryOES
#define glMapBufferOES __rglgen_glMapBufferOES
#define glUnmapBufferOES __rglgen_glUnmapBufferOES
#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES
#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES
#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES
#define glPatchParameteriOES __rglgen_glPatchParameteriOES
#define glTexImage3DOES __rglgen_glTexImage3DOES
#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES
#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES
#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES
#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES
#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES
#define glTexParameterIivOES __rglgen_glTexParameterIivOES
#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES
#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES
#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES
#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES
#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES
#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES
#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES
#define glTexBufferOES __rglgen_glTexBufferOES
#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES
#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES
#define glTextureViewOES __rglgen_glTextureViewOES
#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES
#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES
#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES
#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES
#define glViewportArrayvOES __rglgen_glViewportArrayvOES
#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES
#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES
#define glScissorArrayvOES __rglgen_glScissorArrayvOES
#define glScissorIndexedOES __rglgen_glScissorIndexedOES
#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES
#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES
#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES
#define glGetFloati_vOES __rglgen_glGetFloati_vOES
#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT
#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT
#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT
#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT
#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT
#define glBufferStorageEXT __rglgen_glBufferStorageEXT
#define glClearTexImageEXT __rglgen_glClearTexImageEXT
#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT
#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT
#define glLabelObjectEXT __rglgen_glLabelObjectEXT
#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT
#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT
#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT
#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT
#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT
#define glGenQueriesEXT __rglgen_glGenQueriesEXT
#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT
#define glIsQueryEXT __rglgen_glIsQueryEXT
#define glBeginQueryEXT __rglgen_glBeginQueryEXT
#define glEndQueryEXT __rglgen_glEndQueryEXT
#define glQueryCounterEXT __rglgen_glQueryCounterEXT
#define glGetQueryivEXT __rglgen_glGetQueryivEXT
#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT
#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT
#define glGetQueryObjecti64vEXT __rglgen_glGetQueryObjecti64vEXT
#define glGetQueryObjectui64vEXT __rglgen_glGetQueryObjectui64vEXT
#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT
#define glEnableiEXT __rglgen_glEnableiEXT
#define glDisableiEXT __rglgen_glDisableiEXT
#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT
#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT
#define glBlendFunciEXT __rglgen_glBlendFunciEXT
#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT
#define glColorMaskiEXT __rglgen_glColorMaskiEXT
#define glIsEnablediEXT __rglgen_glIsEnablediEXT
#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT
#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT
#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT
#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT
#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT
#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT
#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT
#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT
#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT
#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT
#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT
#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT
#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT
#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT
#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT
#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT
#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT
#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT
#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT
#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT
#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT
#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT
#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT
#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT
#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT
#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT
#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT
#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT
#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT
#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT
#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT
#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT
#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT
#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT
#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT
#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT
#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT
#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT
#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT
#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT
#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT
#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT
#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT
#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT
#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT
#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT
#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT
#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT
#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT
#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT
#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT
#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT
#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT
#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT
#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT
#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT
#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT
#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT
#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT
#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT
#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT
#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT
#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT
#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT
#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT
#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT
#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT
#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT
#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT
#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT
#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT
#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT
#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT
#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT
#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT
#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT
#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT
#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT
#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT
#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT
#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT
#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT
#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT
#define glTexBufferEXT __rglgen_glTexBufferEXT
#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT
#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT
#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT
#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT
#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT
#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT
#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT
#define glTextureViewEXT __rglgen_glTextureViewEXT
#define glesEXT __rglgen_glesEXT
#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR
#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR

extern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
extern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
extern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
extern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
extern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
extern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
extern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
extern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
extern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
extern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
extern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
extern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
extern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
extern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
extern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
extern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
extern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
extern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
extern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
extern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
extern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
extern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
extern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
extern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
extern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
extern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
extern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
extern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
extern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
extern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
extern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
extern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
extern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
extern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
extern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
extern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
extern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
extern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
extern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
extern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
extern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
extern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
extern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
extern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
extern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
extern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
extern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
extern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
extern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
extern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
extern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
extern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
extern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
extern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
extern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
extern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
extern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
extern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
extern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
extern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
extern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
extern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
extern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
extern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
extern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
extern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
extern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
extern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
extern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
extern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
extern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
extern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
extern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
extern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
extern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
extern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
extern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
extern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
extern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
extern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
extern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
extern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
extern RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;
extern RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;
extern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
extern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
extern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
extern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
extern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
extern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
extern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
extern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
extern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
extern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
extern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
extern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
extern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
extern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
extern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
extern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
extern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
extern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
extern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
extern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
extern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
extern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
extern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
extern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
extern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
extern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
extern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
extern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
extern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
extern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
extern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
extern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
extern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
extern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
extern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
extern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
extern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
extern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
extern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
extern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
extern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
extern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
extern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
extern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
extern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
extern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
extern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
extern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
extern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
extern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
extern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
extern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
extern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
extern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
extern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
extern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
extern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
extern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
extern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
extern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
extern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
extern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
extern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
extern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
extern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
extern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
extern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;

struct rglgen_sym_map { const char *sym; void *ptr; };
extern const struct rglgen_sym_map rglgen_symbol_map[];
#ifdef __cplusplus
}
#endif
#endif

./include/libretro-common/include/glsym/glsym_gl.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_DECL_H__
#define RGLGEN_DECL_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef GL_APIENTRY
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#endif
#ifndef GL_OES_EGL_image
typedef void *GLeglImageOES;
#endif
#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)
typedef GLint GLfixed;
#endif
#if defined(__MACH__) && !defined(OS_TARGET_IPHONE) && !defined(MAC_OS_X_VERSION_10_7)
typedef long long int GLint64;
typedef unsigned long long int GLuint64;
typedef unsigned long long int GLuint64EXT;
typedef struct __GLsync *GLsync;
#endif
typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLFOGCOORDFPROC) (GLfloat coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDFVPROC) (const GLfloat *coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDDPROC) (GLdouble coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDDVPROC) (const GLdouble *coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IVPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IPROC) (GLint x, GLint y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) (GLenum mode);
typedef void (APIENTRYP RGLSYMGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
typedef void (APIENTRYP RGLSYMGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (APIENTRYP RGLSYMGLISQUERYPROC) (GLuint id);
typedef void (APIENTRYP RGLSYMGLBEGINQUERYPROC) (GLenum target, GLuint id);
typedef void (APIENTRYP RGLSYMGLENDQUERYPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP RGLSYMGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef GLboolean (APIENTRYP RGLSYMGLISBUFFERPROC) (GLuint buffer);
typedef void (APIENTRYP RGLSYMGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
typedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
typedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data);
typedef void *(APIENTRYP RGLSYMGLMAPBUFFERPROC) (GLenum target, GLenum access);
typedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP RGLSYMGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
typedef void (APIENTRYP RGLSYMGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
typedef void (APIENTRYP RGLSYMGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask);
typedef void (APIENTRYP RGLSYMGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
typedef void (APIENTRYP RGLSYMGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint (APIENTRYP RGLSYMGLCREATEPROGRAMPROC) (void);
typedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP RGLSYMGLDETACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
typedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP RGLSYMGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
typedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPROC) (GLuint program);
typedef GLboolean (APIENTRYP RGLSYMGLISSHADERPROC) (GLuint shader);
typedef void (APIENTRYP RGLSYMGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
typedef void (APIENTRYP RGLSYMGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FPROC) (GLint location, GLfloat v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef void (APIENTRYP RGLSYMGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
typedef void (APIENTRYP RGLSYMGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
typedef void (APIENTRYP RGLSYMGLENABLEIPROC) (GLenum target, GLuint index);
typedef void (APIENTRYP RGLSYMGLDISABLEIPROC) (GLenum target, GLuint index);
typedef GLboolean (APIENTRYP RGLSYMGLISENABLEDIPROC) (GLenum target, GLuint index);
typedef void (APIENTRYP RGLSYMGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);
typedef void (APIENTRYP RGLSYMGLENDTRANSFORMFEEDBACKPROC) (void);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
typedef void (APIENTRYP RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
typedef void (APIENTRYP RGLSYMGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);
typedef void (APIENTRYP RGLSYMGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);
typedef void (APIENTRYP RGLSYMGLENDCONDITIONALRENDERPROC) (void);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params);
typedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name);
typedef GLint (APIENTRYP RGLSYMGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLUNIFORM1UIPROC) (GLint location, GLuint v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
typedef const GLubyte *(APIENTRYP RGLSYMGLGETSTRINGIPROC) (GLenum name, GLuint index);
typedef GLboolean (APIENTRYP RGLSYMGLISRENDERBUFFERPROC) (GLuint renderbuffer);
typedef void (APIENTRYP RGLSYMGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);
typedef void (APIENTRYP RGLSYMGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers);
typedef void (APIENTRYP RGLSYMGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);
typedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef GLboolean (APIENTRYP RGLSYMGLISFRAMEBUFFERPROC) (GLuint framebuffer);
typedef void (APIENTRYP RGLSYMGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
typedef void (APIENTRYP RGLSYMGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers);
typedef void (APIENTRYP RGLSYMGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);
typedef GLenum (APIENTRYP RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
typedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGENERATEMIPMAPPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
typedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
typedef void *(APIENTRYP RGLSYMGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
typedef void (APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
typedef void (APIENTRYP RGLSYMGLBINDVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRYP RGLSYMGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
typedef void (APIENTRYP RGLSYMGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
typedef GLboolean (APIENTRYP RGLSYMGLISVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLPRIMITIVERESTARTINDEXPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
typedef GLuint (APIENTRYP RGLSYMGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
typedef void (APIENTRYP RGLSYMGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
typedef void (APIENTRYP RGLSYMGLPROVOKINGVERTEXPROC) (GLenum mode);
typedef GLsync (APIENTRYP RGLSYMGLFENCESYNCPROC) (GLenum condition, GLbitfield flags);
typedef GLboolean (APIENTRYP RGLSYMGLISSYNCPROC) (GLsync sync);
typedef void (APIENTRYP RGLSYMGLDELETESYNCPROC) (GLsync sync);
typedef GLenum (APIENTRYP RGLSYMGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
typedef void (APIENTRYP RGLSYMGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
typedef void (APIENTRYP RGLSYMGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data);
typedef void (APIENTRYP RGLSYMGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
typedef void (APIENTRYP RGLSYMGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val);
typedef void (APIENTRYP RGLSYMGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask);
typedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
typedef GLint (APIENTRYP RGLSYMGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
typedef void (APIENTRYP RGLSYMGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers);
typedef GLboolean (APIENTRYP RGLSYMGLISSAMPLERPROC) (GLuint sampler);
typedef void (APIENTRYP RGLSYMGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLQUERYCOUNTERPROC) (GLuint id, GLenum target);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXP2UIPROC) (GLenum type, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXP3UIPROC) (GLenum type, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXP4UIPROC) (GLenum type, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLNORMALP3UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLCOLORP3UIPROC) (GLenum type, GLuint color);
typedef void (APIENTRYP RGLSYMGLCOLORP3UIVPROC) (GLenum type, const GLuint *color);
typedef void (APIENTRYP RGLSYMGLCOLORP4UIPROC) (GLenum type, GLuint color);
typedef void (APIENTRYP RGLSYMGLCOLORP4UIVPROC) (GLenum type, const GLuint *color);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color);
typedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGPROC) (GLfloat value);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);
typedef void (APIENTRYP RGLSYMGLUNIFORM1DPROC) (GLint location, GLdouble x);
typedef void (APIENTRYP RGLSYMGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params);
typedef GLint (APIENTRYP RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name);
typedef GLuint (APIENTRYP RGLSYMGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
typedef void (APIENTRYP RGLSYMGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values);
typedef void (APIENTRYP RGLSYMGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
typedef void (APIENTRYP RGLSYMGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values);
typedef void (APIENTRYP RGLSYMGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id);
typedef void (APIENTRYP RGLSYMGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids);
typedef void (APIENTRYP RGLSYMGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);
typedef GLboolean (APIENTRYP RGLSYMGLISTRANSFORMFEEDBACKPROC) (GLuint id);
typedef void (APIENTRYP RGLSYMGLPAUSETRANSFORMFEEDBACKPROC) (void);
typedef void (APIENTRYP RGLSYMGLRESUMETRANSFORMFEEDBACKPROC) (void);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream);
typedef void (APIENTRYP RGLSYMGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id);
typedef void (APIENTRYP RGLSYMGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index);
typedef void (APIENTRYP RGLSYMGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLRELEASESHADERCOMPILERPROC) (void);
typedef void (APIENTRYP RGLSYMGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
typedef void (APIENTRYP RGLSYMGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f);
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHFPROC) (GLfloat d);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
typedef void (APIENTRYP RGLSYMGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
typedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
typedef void (APIENTRYP RGLSYMGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
typedef void (APIENTRYP RGLSYMGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);
typedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings);
typedef void (APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);
typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines);
typedef void (APIENTRYP RGLSYMGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);
typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPIPELINEPROC) (GLuint pipeline);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
typedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v);
typedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f);
typedef void (APIENTRYP RGLSYMGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (APIENTRYP RGLSYMGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
typedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
typedef void (APIENTRYP RGLSYMGLMEMORYBARRIERPROC) (GLbitfield barriers);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect);
typedef void (APIENTRYP RGLSYMGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
typedef void (APIENTRYP RGLSYMGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
typedef void (APIENTRYP RGLSYMGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
typedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERDATAPROC) (GLuint buffer);
typedef void (APIENTRYP RGLSYMGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
typedef void (APIENTRYP RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params);
typedef GLuint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
typedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
typedef void (APIENTRYP RGLSYMGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
typedef void (APIENTRYP RGLSYMGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKPROC) (RGLGENGLDEBUGPROC callback, const void *userParam);
typedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (APIENTRYP RGLSYMGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
typedef void (APIENTRYP RGLSYMGLPOPDEBUGGROUPPROC) (void);
typedef void (APIENTRYP RGLSYMGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
typedef void (APIENTRYP RGLSYMGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (APIENTRYP RGLSYMGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
typedef void (APIENTRYP RGLSYMGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (APIENTRYP RGLSYMGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
typedef void (APIENTRYP RGLSYMGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
typedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP RGLSYMGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);
typedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
typedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTUREHANDLEARBPROC) (GLuint texture);
typedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler);
typedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
typedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle);
typedef GLuint64 (APIENTRYP RGLSYMGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
typedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access);
typedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle);
typedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value);
typedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
typedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
typedef GLboolean (APIENTRYP RGLSYMGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
#ifdef __APPLE__
	struct _cl_context;
	struct _cl_event;
#endif
typedef GLsync (APIENTRYP RGLSYMGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);
typedef void (APIENTRYP RGLSYMGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKARBPROC) (RGLGENGLDEBUGPROCARB callback, const void *userParam);
typedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (APIENTRYP RGLSYMGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (APIENTRYP RGLSYMGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);
typedef void (APIENTRYP RGLSYMGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
typedef void (APIENTRYP RGLSYMGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);
typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMARBPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
typedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
typedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
typedef void (APIENTRYP RGLSYMGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
typedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor);
typedef void (APIENTRYP RGLSYMGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert);
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
typedef void (APIENTRYP RGLSYMGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (APIENTRYP RGLSYMGLISQUERYARBPROC) (GLuint id);
typedef void (APIENTRYP RGLSYMGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
typedef void (APIENTRYP RGLSYMGLENDQUERYARBPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
typedef GLenum (APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC) (void);
typedef void (APIENTRYP RGLSYMGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);
typedef void (APIENTRYP RGLSYMGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (APIENTRYP RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
typedef void (APIENTRYP RGLSYMGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
typedef void (APIENTRYP RGLSYMGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values);
typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values);
typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values);
typedef void (APIENTRYP RGLSYMGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern);
typedef void (APIENTRYP RGLSYMGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
typedef void (APIENTRYP RGLSYMGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
typedef void (APIENTRYP RGLSYMGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
typedef void (APIENTRYP RGLSYMGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
typedef void (APIENTRYP RGLSYMGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
typedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGARBPROC) (GLfloat value);
typedef void (APIENTRYP RGLSYMGLDELETEOBJECTARBPROC) (GLhandleARB obj);
typedef GLhandleARB (APIENTRYP RGLSYMGLGETHANDLEARBPROC) (GLenum pname);
typedef void (APIENTRYP RGLSYMGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
typedef GLhandleARB (APIENTRYP RGLSYMGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
typedef void (APIENTRYP RGLSYMGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);
typedef void (APIENTRYP RGLSYMGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
typedef GLhandleARB (APIENTRYP RGLSYMGLCREATEPROGRAMOBJECTARBPROC) (void);
typedef void (APIENTRYP RGLSYMGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
typedef void (APIENTRYP RGLSYMGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
typedef void (APIENTRYP RGLSYMGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IARBPROC) (GLint location, GLint v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
typedef void (APIENTRYP RGLSYMGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
typedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
typedef void (APIENTRYP RGLSYMGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);
typedef void (APIENTRYP RGLSYMGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);
typedef GLboolean (APIENTRYP RGLSYMGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);
typedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);
typedef void (APIENTRYP RGLSYMGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLVERTEXBLENDARBPROC) (GLint count);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP RGLSYMGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
typedef GLboolean (APIENTRYP RGLSYMGLISBUFFERARBPROC) (GLuint buffer);
typedef void (APIENTRYP RGLSYMGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
typedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
typedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
typedef void *(APIENTRYP RGLSYMGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
typedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERARBPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer);
typedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
typedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVARBPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVARBPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVARBPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVARBPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1BOESPROC) (GLbyte s);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX2BOESPROC) (GLbyte x);
typedef void (APIENTRYP RGLSYMGLVERTEX2BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX3BOESPROC) (GLbyte x, GLbyte y);
typedef void (APIENTRYP RGLSYMGLVERTEX3BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z);
typedef void (APIENTRYP RGLSYMGLVERTEX4BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);
typedef void (APIENTRYP RGLSYMGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHXOESPROC) (GLfixed depth);
typedef void (APIENTRYP RGLSYMGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
typedef void (APIENTRYP RGLSYMGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);
typedef void (APIENTRYP RGLSYMGLFOGXOESPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);
typedef void (APIENTRYP RGLSYMGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);
typedef void (APIENTRYP RGLSYMGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);
typedef void (APIENTRYP RGLSYMGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLLINEWIDTHXOESPROC) (GLfixed width);
typedef void (APIENTRYP RGLSYMGLLOADMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);
typedef void (APIENTRYP RGLSYMGLMULTMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
typedef void (APIENTRYP RGLSYMGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
typedef void (APIENTRYP RGLSYMGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLPOINTSIZEXOESPROC) (GLfixed size);
typedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
typedef void (APIENTRYP RGLSYMGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert);
typedef void (APIENTRYP RGLSYMGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLACCUMXOESPROC) (GLenum op, GLfixed value);
typedef void (APIENTRYP RGLSYMGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);
typedef void (APIENTRYP RGLSYMGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue);
typedef void (APIENTRYP RGLSYMGLCOLOR3XVOESPROC) (const GLfixed *components);
typedef void (APIENTRYP RGLSYMGLCOLOR4XVOESPROC) (const GLfixed *components);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLEVALCOORD1XOESPROC) (GLfixed u);
typedef void (APIENTRYP RGLSYMGLEVALCOORD1XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v);
typedef void (APIENTRYP RGLSYMGLEVALCOORD2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v);
typedef void (APIENTRYP RGLSYMGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values);
typedef void (APIENTRYP RGLSYMGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLINDEXXOESPROC) (GLfixed component);
typedef void (APIENTRYP RGLSYMGLINDEXXVOESPROC) (const GLfixed *component);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);
typedef void (APIENTRYP RGLSYMGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);
typedef void (APIENTRYP RGLSYMGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2);
typedef void (APIENTRYP RGLSYMGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLNORMAL3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLPASSTHROUGHXOESPROC) (GLfixed token);
typedef void (APIENTRYP RGLSYMGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values);
typedef void (APIENTRYP RGLSYMGLPIXELSTOREXPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor);
typedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities);
typedef void (APIENTRYP RGLSYMGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y);
typedef void (APIENTRYP RGLSYMGLRASTERPOS2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLRASTERPOS3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w);
typedef void (APIENTRYP RGLSYMGLRASTERPOS4XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);
typedef void (APIENTRYP RGLSYMGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1XOESPROC) (GLfixed s);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLVERTEX2XOESPROC) (GLfixed x);
typedef void (APIENTRYP RGLSYMGLVERTEX2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX3XOESPROC) (GLfixed x, GLfixed y);
typedef void (APIENTRYP RGLSYMGLVERTEX3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLVERTEX4XVOESPROC) (const GLfixed *coords);
typedef GLbitfield (APIENTRYP RGLSYMGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHFOESPROC) (GLclampf depth);
typedef void (APIENTRYP RGLSYMGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
typedef void (APIENTRYP RGLSYMGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);
typedef void (APIENTRYP RGLSYMGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);

#define glDrawRangeElements __rglgen_glDrawRangeElements
#define glTexImage3D __rglgen_glTexImage3D
#define glTexSubImage3D __rglgen_glTexSubImage3D
#define glCopyTexSubImage3D __rglgen_glCopyTexSubImage3D
#define glActiveTexture __rglgen_glActiveTexture
#define glSampleCoverage __rglgen_glSampleCoverage
#define glCompressedTexImage3D __rglgen_glCompressedTexImage3D
#define glCompressedTexImage2D __rglgen_glCompressedTexImage2D
#define glCompressedTexImage1D __rglgen_glCompressedTexImage1D
#define glCompressedTexSubImage3D __rglgen_glCompressedTexSubImage3D
#define glCompressedTexSubImage2D __rglgen_glCompressedTexSubImage2D
#define glCompressedTexSubImage1D __rglgen_glCompressedTexSubImage1D
#define glGetCompressedTexImage __rglgen_glGetCompressedTexImage
#define glClientActiveTexture __rglgen_glClientActiveTexture
#define glMultiTexCoord1d __rglgen_glMultiTexCoord1d
#define glMultiTexCoord1dv __rglgen_glMultiTexCoord1dv
#define glMultiTexCoord1f __rglgen_glMultiTexCoord1f
#define glMultiTexCoord1fv __rglgen_glMultiTexCoord1fv
#define glMultiTexCoord1i __rglgen_glMultiTexCoord1i
#define glMultiTexCoord1iv __rglgen_glMultiTexCoord1iv
#define glMultiTexCoord1s __rglgen_glMultiTexCoord1s
#define glMultiTexCoord1sv __rglgen_glMultiTexCoord1sv
#define glMultiTexCoord2d __rglgen_glMultiTexCoord2d
#define glMultiTexCoord2dv __rglgen_glMultiTexCoord2dv
#define glMultiTexCoord2f __rglgen_glMultiTexCoord2f
#define glMultiTexCoord2fv __rglgen_glMultiTexCoord2fv
#define glMultiTexCoord2i __rglgen_glMultiTexCoord2i
#define glMultiTexCoord2iv __rglgen_glMultiTexCoord2iv
#define glMultiTexCoord2s __rglgen_glMultiTexCoord2s
#define glMultiTexCoord2sv __rglgen_glMultiTexCoord2sv
#define glMultiTexCoord3d __rglgen_glMultiTexCoord3d
#define glMultiTexCoord3dv __rglgen_glMultiTexCoord3dv
#define glMultiTexCoord3f __rglgen_glMultiTexCoord3f
#define glMultiTexCoord3fv __rglgen_glMultiTexCoord3fv
#define glMultiTexCoord3i __rglgen_glMultiTexCoord3i
#define glMultiTexCoord3iv __rglgen_glMultiTexCoord3iv
#define glMultiTexCoord3s __rglgen_glMultiTexCoord3s
#define glMultiTexCoord3sv __rglgen_glMultiTexCoord3sv
#define glMultiTexCoord4d __rglgen_glMultiTexCoord4d
#define glMultiTexCoord4dv __rglgen_glMultiTexCoord4dv
#define glMultiTexCoord4f __rglgen_glMultiTexCoord4f
#define glMultiTexCoord4fv __rglgen_glMultiTexCoord4fv
#define glMultiTexCoord4i __rglgen_glMultiTexCoord4i
#define glMultiTexCoord4iv __rglgen_glMultiTexCoord4iv
#define glMultiTexCoord4s __rglgen_glMultiTexCoord4s
#define glMultiTexCoord4sv __rglgen_glMultiTexCoord4sv
#define glLoadTransposeMatrixf __rglgen_glLoadTransposeMatrixf
#define glLoadTransposeMatrixd __rglgen_glLoadTransposeMatrixd
#define glMultTransposeMatrixf __rglgen_glMultTransposeMatrixf
#define glMultTransposeMatrixd __rglgen_glMultTransposeMatrixd
#define glBlendFuncSeparate __rglgen_glBlendFuncSeparate
#define glMultiDrawArrays __rglgen_glMultiDrawArrays
#define glMultiDrawElements __rglgen_glMultiDrawElements
#define glPointParameterf __rglgen_glPointParameterf
#define glPointParameterfv __rglgen_glPointParameterfv
#define glPointParameteri __rglgen_glPointParameteri
#define glPointParameteriv __rglgen_glPointParameteriv
#define glFogCoordf __rglgen_glFogCoordf
#define glFogCoordfv __rglgen_glFogCoordfv
#define glFogCoordd __rglgen_glFogCoordd
#define glFogCoorddv __rglgen_glFogCoorddv
#define glFogCoordPointer __rglgen_glFogCoordPointer
#define glSecondaryColor3b __rglgen_glSecondaryColor3b
#define glSecondaryColor3bv __rglgen_glSecondaryColor3bv
#define glSecondaryColor3d __rglgen_glSecondaryColor3d
#define glSecondaryColor3dv __rglgen_glSecondaryColor3dv
#define glSecondaryColor3f __rglgen_glSecondaryColor3f
#define glSecondaryColor3fv __rglgen_glSecondaryColor3fv
#define glSecondaryColor3i __rglgen_glSecondaryColor3i
#define glSecondaryColor3iv __rglgen_glSecondaryColor3iv
#define glSecondaryColor3s __rglgen_glSecondaryColor3s
#define glSecondaryColor3sv __rglgen_glSecondaryColor3sv
#define glSecondaryColor3ub __rglgen_glSecondaryColor3ub
#define glSecondaryColor3ubv __rglgen_glSecondaryColor3ubv
#define glSecondaryColor3ui __rglgen_glSecondaryColor3ui
#define glSecondaryColor3uiv __rglgen_glSecondaryColor3uiv
#define glSecondaryColor3us __rglgen_glSecondaryColor3us
#define glSecondaryColor3usv __rglgen_glSecondaryColor3usv
#define glSecondaryColorPointer __rglgen_glSecondaryColorPointer
#define glWindowPos2d __rglgen_glWindowPos2d
#define glWindowPos2dv __rglgen_glWindowPos2dv
#define glWindowPos2f __rglgen_glWindowPos2f
#define glWindowPos2fv __rglgen_glWindowPos2fv
#define glWindowPos2i __rglgen_glWindowPos2i
#define glWindowPos2iv __rglgen_glWindowPos2iv
#define glWindowPos2s __rglgen_glWindowPos2s
#define glWindowPos2sv __rglgen_glWindowPos2sv
#define glWindowPos3d __rglgen_glWindowPos3d
#define glWindowPos3dv __rglgen_glWindowPos3dv
#define glWindowPos3f __rglgen_glWindowPos3f
#define glWindowPos3fv __rglgen_glWindowPos3fv
#define glWindowPos3i __rglgen_glWindowPos3i
#define glWindowPos3iv __rglgen_glWindowPos3iv
#define glWindowPos3s __rglgen_glWindowPos3s
#define glWindowPos3sv __rglgen_glWindowPos3sv
#define glBlendColor __rglgen_glBlendColor
#define glBlendEquation __rglgen_glBlendEquation
#define glGenQueries __rglgen_glGenQueries
#define glDeleteQueries __rglgen_glDeleteQueries
#define glIsQuery __rglgen_glIsQuery
#define glBeginQuery __rglgen_glBeginQuery
#define glEndQuery __rglgen_glEndQuery
#define glGetQueryiv __rglgen_glGetQueryiv
#define glGetQueryObjectiv __rglgen_glGetQueryObjectiv
#define glGetQueryObjectuiv __rglgen_glGetQueryObjectuiv
#define glBindBuffer __rglgen_glBindBuffer
#define glDeleteBuffers __rglgen_glDeleteBuffers
#define glGenBuffers __rglgen_glGenBuffers
#define glIsBuffer __rglgen_glIsBuffer
#define glBufferData __rglgen_glBufferData
#define glBufferSubData __rglgen_glBufferSubData
#define glGetBufferSubData __rglgen_glGetBufferSubData
#define glMapBuffer __rglgen_glMapBuffer
#define glUnmapBuffer __rglgen_glUnmapBuffer
#define glGetBufferParameteriv __rglgen_glGetBufferParameteriv
#define glGetBufferPointerv __rglgen_glGetBufferPointerv
#define glBlendEquationSeparate __rglgen_glBlendEquationSeparate
#define glDrawBuffers __rglgen_glDrawBuffers
#define glStencilOpSeparate __rglgen_glStencilOpSeparate
#define glStencilFuncSeparate __rglgen_glStencilFuncSeparate
#define glStencilMaskSeparate __rglgen_glStencilMaskSeparate
#define glAttachShader __rglgen_glAttachShader
#define glBindAttribLocation __rglgen_glBindAttribLocation
#define glCompileShader __rglgen_glCompileShader
#define glCreateProgram __rglgen_glCreateProgram
#define glCreateShader __rglgen_glCreateShader
#define glDeleteProgram __rglgen_glDeleteProgram
#define glDeleteShader __rglgen_glDeleteShader
#define glDetachShader __rglgen_glDetachShader
#define glDisableVertexAttribArray __rglgen_glDisableVertexAttribArray
#define glEnableVertexAttribArray __rglgen_glEnableVertexAttribArray
#define glGetActiveAttrib __rglgen_glGetActiveAttrib
#define glGetActiveUniform __rglgen_glGetActiveUniform
#define glGetAttachedShaders __rglgen_glGetAttachedShaders
#define glGetAttribLocation __rglgen_glGetAttribLocation
#define glGetProgramiv __rglgen_glGetProgramiv
#define glGetProgramInfoLog __rglgen_glGetProgramInfoLog
#define glGetShaderiv __rglgen_glGetShaderiv
#define glGetShaderInfoLog __rglgen_glGetShaderInfoLog
#define glGetShaderSource __rglgen_glGetShaderSource
#define glGetUniformLocation __rglgen_glGetUniformLocation
#define glGetUniformfv __rglgen_glGetUniformfv
#define glGetUniformiv __rglgen_glGetUniformiv
#define glGetVertexAttribdv __rglgen_glGetVertexAttribdv
#define glGetVertexAttribfv __rglgen_glGetVertexAttribfv
#define glGetVertexAttribiv __rglgen_glGetVertexAttribiv
#define glGetVertexAttribPointerv __rglgen_glGetVertexAttribPointerv
#define glIsProgram __rglgen_glIsProgram
#define glIsShader __rglgen_glIsShader
#define glLinkProgram __rglgen_glLinkProgram
#define glShaderSource __rglgen_glShaderSource
#define glUseProgram __rglgen_glUseProgram
#define glUniform1f __rglgen_glUniform1f
#define glUniform2f __rglgen_glUniform2f
#define glUniform3f __rglgen_glUniform3f
#define glUniform4f __rglgen_glUniform4f
#define glUniform1i __rglgen_glUniform1i
#define glUniform2i __rglgen_glUniform2i
#define glUniform3i __rglgen_glUniform3i
#define glUniform4i __rglgen_glUniform4i
#define glUniform1fv __rglgen_glUniform1fv
#define glUniform2fv __rglgen_glUniform2fv
#define glUniform3fv __rglgen_glUniform3fv
#define glUniform4fv __rglgen_glUniform4fv
#define glUniform1iv __rglgen_glUniform1iv
#define glUniform2iv __rglgen_glUniform2iv
#define glUniform3iv __rglgen_glUniform3iv
#define glUniform4iv __rglgen_glUniform4iv
#define glUniformMatrix2fv __rglgen_glUniformMatrix2fv
#define glUniformMatrix3fv __rglgen_glUniformMatrix3fv
#define glUniformMatrix4fv __rglgen_glUniformMatrix4fv
#define glValidateProgram __rglgen_glValidateProgram
#define glVertexAttrib1d __rglgen_glVertexAttrib1d
#define glVertexAttrib1dv __rglgen_glVertexAttrib1dv
#define glVertexAttrib1f __rglgen_glVertexAttrib1f
#define glVertexAttrib1fv __rglgen_glVertexAttrib1fv
#define glVertexAttrib1s __rglgen_glVertexAttrib1s
#define glVertexAttrib1sv __rglgen_glVertexAttrib1sv
#define glVertexAttrib2d __rglgen_glVertexAttrib2d
#define glVertexAttrib2dv __rglgen_glVertexAttrib2dv
#define glVertexAttrib2f __rglgen_glVertexAttrib2f
#define glVertexAttrib2fv __rglgen_glVertexAttrib2fv
#define glVertexAttrib2s __rglgen_glVertexAttrib2s
#define glVertexAttrib2sv __rglgen_glVertexAttrib2sv
#define glVertexAttrib3d __rglgen_glVertexAttrib3d
#define glVertexAttrib3dv __rglgen_glVertexAttrib3dv
#define glVertexAttrib3f __rglgen_glVertexAttrib3f
#define glVertexAttrib3fv __rglgen_glVertexAttrib3fv
#define glVertexAttrib3s __rglgen_glVertexAttrib3s
#define glVertexAttrib3sv __rglgen_glVertexAttrib3sv
#define glVertexAttrib4Nbv __rglgen_glVertexAttrib4Nbv
#define glVertexAttrib4Niv __rglgen_glVertexAttrib4Niv
#define glVertexAttrib4Nsv __rglgen_glVertexAttrib4Nsv
#define glVertexAttrib4Nub __rglgen_glVertexAttrib4Nub
#define glVertexAttrib4Nubv __rglgen_glVertexAttrib4Nubv
#define glVertexAttrib4Nuiv __rglgen_glVertexAttrib4Nuiv
#define glVertexAttrib4Nusv __rglgen_glVertexAttrib4Nusv
#define glVertexAttrib4bv __rglgen_glVertexAttrib4bv
#define glVertexAttrib4d __rglgen_glVertexAttrib4d
#define glVertexAttrib4dv __rglgen_glVertexAttrib4dv
#define glVertexAttrib4f __rglgen_glVertexAttrib4f
#define glVertexAttrib4fv __rglgen_glVertexAttrib4fv
#define glVertexAttrib4iv __rglgen_glVertexAttrib4iv
#define glVertexAttrib4s __rglgen_glVertexAttrib4s
#define glVertexAttrib4sv __rglgen_glVertexAttrib4sv
#define glVertexAttrib4ubv __rglgen_glVertexAttrib4ubv
#define glVertexAttrib4uiv __rglgen_glVertexAttrib4uiv
#define glVertexAttrib4usv __rglgen_glVertexAttrib4usv
#define glVertexAttribPointer __rglgen_glVertexAttribPointer
#define glUniformMatrix2x3fv __rglgen_glUniformMatrix2x3fv
#define glUniformMatrix3x2fv __rglgen_glUniformMatrix3x2fv
#define glUniformMatrix2x4fv __rglgen_glUniformMatrix2x4fv
#define glUniformMatrix4x2fv __rglgen_glUniformMatrix4x2fv
#define glUniformMatrix3x4fv __rglgen_glUniformMatrix3x4fv
#define glUniformMatrix4x3fv __rglgen_glUniformMatrix4x3fv
#define glColorMaski __rglgen_glColorMaski
#define glGetBooleani_v __rglgen_glGetBooleani_v
#define glGetIntegeri_v __rglgen_glGetIntegeri_v
#define glEnablei __rglgen_glEnablei
#define glDisablei __rglgen_glDisablei
#define glIsEnabledi __rglgen_glIsEnabledi
#define glBeginTransformFeedback __rglgen_glBeginTransformFeedback
#define glEndTransformFeedback __rglgen_glEndTransformFeedback
#define glBindBufferRange __rglgen_glBindBufferRange
#define glBindBufferBase __rglgen_glBindBufferBase
#define glTransformFeedbackVaryings __rglgen_glTransformFeedbackVaryings
#define glGetTransformFeedbackVarying __rglgen_glGetTransformFeedbackVarying
#define glClampColor __rglgen_glClampColor
#define glBeginConditionalRender __rglgen_glBeginConditionalRender
#define glEndConditionalRender __rglgen_glEndConditionalRender
#define glVertexAttribIPointer __rglgen_glVertexAttribIPointer
#define glGetVertexAttribIiv __rglgen_glGetVertexAttribIiv
#define glGetVertexAttribIuiv __rglgen_glGetVertexAttribIuiv
#define glVertexAttribI1i __rglgen_glVertexAttribI1i
#define glVertexAttribI2i __rglgen_glVertexAttribI2i
#define glVertexAttribI3i __rglgen_glVertexAttribI3i
#define glVertexAttribI4i __rglgen_glVertexAttribI4i
#define glVertexAttribI1ui __rglgen_glVertexAttribI1ui
#define glVertexAttribI2ui __rglgen_glVertexAttribI2ui
#define glVertexAttribI3ui __rglgen_glVertexAttribI3ui
#define glVertexAttribI4ui __rglgen_glVertexAttribI4ui
#define glVertexAttribI1iv __rglgen_glVertexAttribI1iv
#define glVertexAttribI2iv __rglgen_glVertexAttribI2iv
#define glVertexAttribI3iv __rglgen_glVertexAttribI3iv
#define glVertexAttribI4iv __rglgen_glVertexAttribI4iv
#define glVertexAttribI1uiv __rglgen_glVertexAttribI1uiv
#define glVertexAttribI2uiv __rglgen_glVertexAttribI2uiv
#define glVertexAttribI3uiv __rglgen_glVertexAttribI3uiv
#define glVertexAttribI4uiv __rglgen_glVertexAttribI4uiv
#define glVertexAttribI4bv __rglgen_glVertexAttribI4bv
#define glVertexAttribI4sv __rglgen_glVertexAttribI4sv
#define glVertexAttribI4ubv __rglgen_glVertexAttribI4ubv
#define glVertexAttribI4usv __rglgen_glVertexAttribI4usv
#define glGetUniformuiv __rglgen_glGetUniformuiv
#define glBindFragDataLocation __rglgen_glBindFragDataLocation
#define glGetFragDataLocation __rglgen_glGetFragDataLocation
#define glUniform1ui __rglgen_glUniform1ui
#define glUniform2ui __rglgen_glUniform2ui
#define glUniform3ui __rglgen_glUniform3ui
#define glUniform4ui __rglgen_glUniform4ui
#define glUniform1uiv __rglgen_glUniform1uiv
#define glUniform2uiv __rglgen_glUniform2uiv
#define glUniform3uiv __rglgen_glUniform3uiv
#define glUniform4uiv __rglgen_glUniform4uiv
#define glTexParameterIiv __rglgen_glTexParameterIiv
#define glTexParameterIuiv __rglgen_glTexParameterIuiv
#define glGetTexParameterIiv __rglgen_glGetTexParameterIiv
#define glGetTexParameterIuiv __rglgen_glGetTexParameterIuiv
#define glClearBufferiv __rglgen_glClearBufferiv
#define glClearBufferuiv __rglgen_glClearBufferuiv
#define glClearBufferfv __rglgen_glClearBufferfv
#define glClearBufferfi __rglgen_glClearBufferfi
#define glGetStringi __rglgen_glGetStringi
#define glIsRenderbuffer __rglgen_glIsRenderbuffer
#define glBindRenderbuffer __rglgen_glBindRenderbuffer
#define glDeleteRenderbuffers __rglgen_glDeleteRenderbuffers
#define glGenRenderbuffers __rglgen_glGenRenderbuffers
#define glRenderbufferStorage __rglgen_glRenderbufferStorage
#define glGetRenderbufferParameteriv __rglgen_glGetRenderbufferParameteriv
#define glIsFramebuffer __rglgen_glIsFramebuffer
#define glBindFramebuffer __rglgen_glBindFramebuffer
#define glDeleteFramebuffers __rglgen_glDeleteFramebuffers
#define glGenFramebuffers __rglgen_glGenFramebuffers
#define glCheckFramebufferStatus __rglgen_glCheckFramebufferStatus
#define glFramebufferTexture1D __rglgen_glFramebufferTexture1D
#define glFramebufferTexture2D __rglgen_glFramebufferTexture2D
#define glFramebufferTexture3D __rglgen_glFramebufferTexture3D
#define glFramebufferRenderbuffer __rglgen_glFramebufferRenderbuffer
#define glGetFramebufferAttachmentParameteriv __rglgen_glGetFramebufferAttachmentParameteriv
#define glGenerateMipmap __rglgen_glGenerateMipmap
#define glBlitFramebuffer __rglgen_glBlitFramebuffer
#define glRenderbufferStorageMultisample __rglgen_glRenderbufferStorageMultisample
#define glFramebufferTextureLayer __rglgen_glFramebufferTextureLayer
#define glMapBufferRange __rglgen_glMapBufferRange
#define glFlushMappedBufferRange __rglgen_glFlushMappedBufferRange
#define glBindVertexArray __rglgen_glBindVertexArray
#define glDeleteVertexArrays __rglgen_glDeleteVertexArrays
#define glGenVertexArrays __rglgen_glGenVertexArrays
#define glIsVertexArray __rglgen_glIsVertexArray
#define glDrawArraysInstanced __rglgen_glDrawArraysInstanced
#define glDrawElementsInstanced __rglgen_glDrawElementsInstanced
#define glTexBuffer __rglgen_glTexBuffer
#define glPrimitiveRestartIndex __rglgen_glPrimitiveRestartIndex
#define glCopyBufferSubData __rglgen_glCopyBufferSubData
#define glGetUniformIndices __rglgen_glGetUniformIndices
#define glGetActiveUniformsiv __rglgen_glGetActiveUniformsiv
#define glGetActiveUniformName __rglgen_glGetActiveUniformName
#define glGetUniformBlockIndex __rglgen_glGetUniformBlockIndex
#define glGetActiveUniformBlockiv __rglgen_glGetActiveUniformBlockiv
#define glGetActiveUniformBlockName __rglgen_glGetActiveUniformBlockName
#define glUniformBlockBinding __rglgen_glUniformBlockBinding
#define glDrawElementsBaseVertex __rglgen_glDrawElementsBaseVertex
#define glDrawRangeElementsBaseVertex __rglgen_glDrawRangeElementsBaseVertex
#define glDrawElementsInstancedBaseVertex __rglgen_glDrawElementsInstancedBaseVertex
#define glMultiDrawElementsBaseVertex __rglgen_glMultiDrawElementsBaseVertex
#define glProvokingVertex __rglgen_glProvokingVertex
#define glFenceSync __rglgen_glFenceSync
#define glIsSync __rglgen_glIsSync
#define glDeleteSync __rglgen_glDeleteSync
#define glClientWaitSync __rglgen_glClientWaitSync
#define glWaitSync __rglgen_glWaitSync
#define glGetInteger64v __rglgen_glGetInteger64v
#define glGetSynciv __rglgen_glGetSynciv
#define glGetInteger64i_v __rglgen_glGetInteger64i_v
#define glGetBufferParameteri64v __rglgen_glGetBufferParameteri64v
#define glFramebufferTexture __rglgen_glFramebufferTexture
#define glTexImage2DMultisample __rglgen_glTexImage2DMultisample
#define glTexImage3DMultisample __rglgen_glTexImage3DMultisample
#define glGetMultisamplefv __rglgen_glGetMultisamplefv
#define glSampleMaski __rglgen_glSampleMaski
#define glBindFragDataLocationIndexed __rglgen_glBindFragDataLocationIndexed
#define glGetFragDataIndex __rglgen_glGetFragDataIndex
#define glGenSamplers __rglgen_glGenSamplers
#define glDeleteSamplers __rglgen_glDeleteSamplers
#define glIsSampler __rglgen_glIsSampler
#define glBindSampler __rglgen_glBindSampler
#define glSamplerParameteri __rglgen_glSamplerParameteri
#define glSamplerParameteriv __rglgen_glSamplerParameteriv
#define glSamplerParameterf __rglgen_glSamplerParameterf
#define glSamplerParameterfv __rglgen_glSamplerParameterfv
#define glSamplerParameterIiv __rglgen_glSamplerParameterIiv
#define glSamplerParameterIuiv __rglgen_glSamplerParameterIuiv
#define glGetSamplerParameteriv __rglgen_glGetSamplerParameteriv
#define glGetSamplerParameterIiv __rglgen_glGetSamplerParameterIiv
#define glGetSamplerParameterfv __rglgen_glGetSamplerParameterfv
#define glGetSamplerParameterIuiv __rglgen_glGetSamplerParameterIuiv
#define glQueryCounter __rglgen_glQueryCounter
#define glGetQueryObjecti64v __rglgen_glGetQueryObjecti64v
#define glGetQueryObjectui64v __rglgen_glGetQueryObjectui64v
#define glVertexAttribDivisor __rglgen_glVertexAttribDivisor
#define glVertexAttribP1ui __rglgen_glVertexAttribP1ui
#define glVertexAttribP1uiv __rglgen_glVertexAttribP1uiv
#define glVertexAttribP2ui __rglgen_glVertexAttribP2ui
#define glVertexAttribP2uiv __rglgen_glVertexAttribP2uiv
#define glVertexAttribP3ui __rglgen_glVertexAttribP3ui
#define glVertexAttribP3uiv __rglgen_glVertexAttribP3uiv
#define glVertexAttribP4ui __rglgen_glVertexAttribP4ui
#define glVertexAttribP4uiv __rglgen_glVertexAttribP4uiv
#define glVertexP2ui __rglgen_glVertexP2ui
#define glVertexP2uiv __rglgen_glVertexP2uiv
#define glVertexP3ui __rglgen_glVertexP3ui
#define glVertexP3uiv __rglgen_glVertexP3uiv
#define glVertexP4ui __rglgen_glVertexP4ui
#define glVertexP4uiv __rglgen_glVertexP4uiv
#define glTexCoordP1ui __rglgen_glTexCoordP1ui
#define glTexCoordP1uiv __rglgen_glTexCoordP1uiv
#define glTexCoordP2ui __rglgen_glTexCoordP2ui
#define glTexCoordP2uiv __rglgen_glTexCoordP2uiv
#define glTexCoordP3ui __rglgen_glTexCoordP3ui
#define glTexCoordP3uiv __rglgen_glTexCoordP3uiv
#define glTexCoordP4ui __rglgen_glTexCoordP4ui
#define glTexCoordP4uiv __rglgen_glTexCoordP4uiv
#define glMultiTexCoordP1ui __rglgen_glMultiTexCoordP1ui
#define glMultiTexCoordP1uiv __rglgen_glMultiTexCoordP1uiv
#define glMultiTexCoordP2ui __rglgen_glMultiTexCoordP2ui
#define glMultiTexCoordP2uiv __rglgen_glMultiTexCoordP2uiv
#define glMultiTexCoordP3ui __rglgen_glMultiTexCoordP3ui
#define glMultiTexCoordP3uiv __rglgen_glMultiTexCoordP3uiv
#define glMultiTexCoordP4ui __rglgen_glMultiTexCoordP4ui
#define glMultiTexCoordP4uiv __rglgen_glMultiTexCoordP4uiv
#define glNormalP3ui __rglgen_glNormalP3ui
#define glNormalP3uiv __rglgen_glNormalP3uiv
#define glColorP3ui __rglgen_glColorP3ui
#define glColorP3uiv __rglgen_glColorP3uiv
#define glColorP4ui __rglgen_glColorP4ui
#define glColorP4uiv __rglgen_glColorP4uiv
#define glSecondaryColorP3ui __rglgen_glSecondaryColorP3ui
#define glSecondaryColorP3uiv __rglgen_glSecondaryColorP3uiv
#define glMinSampleShading __rglgen_glMinSampleShading
#define glBlendEquationi __rglgen_glBlendEquationi
#define glBlendEquationSeparatei __rglgen_glBlendEquationSeparatei
#define glBlendFunci __rglgen_glBlendFunci
#define glBlendFuncSeparatei __rglgen_glBlendFuncSeparatei
#define glDrawArraysIndirect __rglgen_glDrawArraysIndirect
#define glDrawElementsIndirect __rglgen_glDrawElementsIndirect
#define glUniform1d __rglgen_glUniform1d
#define glUniform2d __rglgen_glUniform2d
#define glUniform3d __rglgen_glUniform3d
#define glUniform4d __rglgen_glUniform4d
#define glUniform1dv __rglgen_glUniform1dv
#define glUniform2dv __rglgen_glUniform2dv
#define glUniform3dv __rglgen_glUniform3dv
#define glUniform4dv __rglgen_glUniform4dv
#define glUniformMatrix2dv __rglgen_glUniformMatrix2dv
#define glUniformMatrix3dv __rglgen_glUniformMatrix3dv
#define glUniformMatrix4dv __rglgen_glUniformMatrix4dv
#define glUniformMatrix2x3dv __rglgen_glUniformMatrix2x3dv
#define glUniformMatrix2x4dv __rglgen_glUniformMatrix2x4dv
#define glUniformMatrix3x2dv __rglgen_glUniformMatrix3x2dv
#define glUniformMatrix3x4dv __rglgen_glUniformMatrix3x4dv
#define glUniformMatrix4x2dv __rglgen_glUniformMatrix4x2dv
#define glUniformMatrix4x3dv __rglgen_glUniformMatrix4x3dv
#define glGetUniformdv __rglgen_glGetUniformdv
#define glGetSubroutineUniformLocation __rglgen_glGetSubroutineUniformLocation
#define glGetSubroutineIndex __rglgen_glGetSubroutineIndex
#define glGetActiveSubroutineUniformiv __rglgen_glGetActiveSubroutineUniformiv
#define glGetActiveSubroutineUniformName __rglgen_glGetActiveSubroutineUniformName
#define glGetActiveSubroutineName __rglgen_glGetActiveSubroutineName
#define glUniformSubroutinesuiv __rglgen_glUniformSubroutinesuiv
#define glGetUniformSubroutineuiv __rglgen_glGetUniformSubroutineuiv
#define glGetProgramStageiv __rglgen_glGetProgramStageiv
#define glPatchParameteri __rglgen_glPatchParameteri
#define glPatchParameterfv __rglgen_glPatchParameterfv
#define glBindTransformFeedback __rglgen_glBindTransformFeedback
#define glDeleteTransformFeedbacks __rglgen_glDeleteTransformFeedbacks
#define glGenTransformFeedbacks __rglgen_glGenTransformFeedbacks
#define glIsTransformFeedback __rglgen_glIsTransformFeedback
#define glPauseTransformFeedback __rglgen_glPauseTransformFeedback
#define glResumeTransformFeedback __rglgen_glResumeTransformFeedback
#define glDrawTransformFeedback __rglgen_glDrawTransformFeedback
#define glDrawTransformFeedbackStream __rglgen_glDrawTransformFeedbackStream
#define glBeginQueryIndexed __rglgen_glBeginQueryIndexed
#define glEndQueryIndexed __rglgen_glEndQueryIndexed
#define glGetQueryIndexediv __rglgen_glGetQueryIndexediv
#define glReleaseShaderCompiler __rglgen_glReleaseShaderCompiler
#define glShaderBinary __rglgen_glShaderBinary
#define glGetShaderPrecisionFormat __rglgen_glGetShaderPrecisionFormat
#define glDepthRangef __rglgen_glDepthRangef
#define glClearDepthf __rglgen_glClearDepthf
#define glGetProgramBinary __rglgen_glGetProgramBinary
#define glProgramBinary __rglgen_glProgramBinary
#define glProgramParameteri __rglgen_glProgramParameteri
#define glUseProgramStages __rglgen_glUseProgramStages
#define glActiveShaderProgram __rglgen_glActiveShaderProgram
#define glCreateShaderProgramv __rglgen_glCreateShaderProgramv
#define glBindProgramPipeline __rglgen_glBindProgramPipeline
#define glDeleteProgramPipelines __rglgen_glDeleteProgramPipelines
#define glGenProgramPipelines __rglgen_glGenProgramPipelines
#define glIsProgramPipeline __rglgen_glIsProgramPipeline
#define glGetProgramPipelineiv __rglgen_glGetProgramPipelineiv
#define glProgramUniform1i __rglgen_glProgramUniform1i
#define glProgramUniform1iv __rglgen_glProgramUniform1iv
#define glProgramUniform1f __rglgen_glProgramUniform1f
#define glProgramUniform1fv __rglgen_glProgramUniform1fv
#define glProgramUniform1d __rglgen_glProgramUniform1d
#define glProgramUniform1dv __rglgen_glProgramUniform1dv
#define glProgramUniform1ui __rglgen_glProgramUniform1ui
#define glProgramUniform1uiv __rglgen_glProgramUniform1uiv
#define glProgramUniform2i __rglgen_glProgramUniform2i
#define glProgramUniform2iv __rglgen_glProgramUniform2iv
#define glProgramUniform2f __rglgen_glProgramUniform2f
#define glProgramUniform2fv __rglgen_glProgramUniform2fv
#define glProgramUniform2d __rglgen_glProgramUniform2d
#define glProgramUniform2dv __rglgen_glProgramUniform2dv
#define glProgramUniform2ui __rglgen_glProgramUniform2ui
#define glProgramUniform2uiv __rglgen_glProgramUniform2uiv
#define glProgramUniform3i __rglgen_glProgramUniform3i
#define glProgramUniform3iv __rglgen_glProgramUniform3iv
#define glProgramUniform3f __rglgen_glProgramUniform3f
#define glProgramUniform3fv __rglgen_glProgramUniform3fv
#define glProgramUniform3d __rglgen_glProgramUniform3d
#define glProgramUniform3dv __rglgen_glProgramUniform3dv
#define glProgramUniform3ui __rglgen_glProgramUniform3ui
#define glProgramUniform3uiv __rglgen_glProgramUniform3uiv
#define glProgramUniform4i __rglgen_glProgramUniform4i
#define glProgramUniform4iv __rglgen_glProgramUniform4iv
#define glProgramUniform4f __rglgen_glProgramUniform4f
#define glProgramUniform4fv __rglgen_glProgramUniform4fv
#define glProgramUniform4d __rglgen_glProgramUniform4d
#define glProgramUniform4dv __rglgen_glProgramUniform4dv
#define glProgramUniform4ui __rglgen_glProgramUniform4ui
#define glProgramUniform4uiv __rglgen_glProgramUniform4uiv
#define glProgramUniformMatrix2fv __rglgen_glProgramUniformMatrix2fv
#define glProgramUniformMatrix3fv __rglgen_glProgramUniformMatrix3fv
#define glProgramUniformMatrix4fv __rglgen_glProgramUniformMatrix4fv
#define glProgramUniformMatrix2dv __rglgen_glProgramUniformMatrix2dv
#define glProgramUniformMatrix3dv __rglgen_glProgramUniformMatrix3dv
#define glProgramUniformMatrix4dv __rglgen_glProgramUniformMatrix4dv
#define glProgramUniformMatrix2x3fv __rglgen_glProgramUniformMatrix2x3fv
#define glProgramUniformMatrix3x2fv __rglgen_glProgramUniformMatrix3x2fv
#define glProgramUniformMatrix2x4fv __rglgen_glProgramUniformMatrix2x4fv
#define glProgramUniformMatrix4x2fv __rglgen_glProgramUniformMatrix4x2fv
#define glProgramUniformMatrix3x4fv __rglgen_glProgramUniformMatrix3x4fv
#define glProgramUniformMatrix4x3fv __rglgen_glProgramUniformMatrix4x3fv
#define glProgramUniformMatrix2x3dv __rglgen_glProgramUniformMatrix2x3dv
#define glProgramUniformMatrix3x2dv __rglgen_glProgramUniformMatrix3x2dv
#define glProgramUniformMatrix2x4dv __rglgen_glProgramUniformMatrix2x4dv
#define glProgramUniformMatrix4x2dv __rglgen_glProgramUniformMatrix4x2dv
#define glProgramUniformMatrix3x4dv __rglgen_glProgramUniformMatrix3x4dv
#define glProgramUniformMatrix4x3dv __rglgen_glProgramUniformMatrix4x3dv
#define glValidateProgramPipeline __rglgen_glValidateProgramPipeline
#define glGetProgramPipelineInfoLog __rglgen_glGetProgramPipelineInfoLog
#define glVertexAttribL1d __rglgen_glVertexAttribL1d
#define glVertexAttribL2d __rglgen_glVertexAttribL2d
#define glVertexAttribL3d __rglgen_glVertexAttribL3d
#define glVertexAttribL4d __rglgen_glVertexAttribL4d
#define glVertexAttribL1dv __rglgen_glVertexAttribL1dv
#define glVertexAttribL2dv __rglgen_glVertexAttribL2dv
#define glVertexAttribL3dv __rglgen_glVertexAttribL3dv
#define glVertexAttribL4dv __rglgen_glVertexAttribL4dv
#define glVertexAttribLPointer __rglgen_glVertexAttribLPointer
#define glGetVertexAttribLdv __rglgen_glGetVertexAttribLdv
#define glViewportArrayv __rglgen_glViewportArrayv
#define glViewportIndexedf __rglgen_glViewportIndexedf
#define glViewportIndexedfv __rglgen_glViewportIndexedfv
#define glScissorArrayv __rglgen_glScissorArrayv
#define glScissorIndexed __rglgen_glScissorIndexed
#define glScissorIndexedv __rglgen_glScissorIndexedv
#define glDepthRangeArrayv __rglgen_glDepthRangeArrayv
#define glDepthRangeIndexed __rglgen_glDepthRangeIndexed
#define glGetFloati_v __rglgen_glGetFloati_v
#define glGetDoublei_v __rglgen_glGetDoublei_v
#define glDrawArraysInstancedBaseInstance __rglgen_glDrawArraysInstancedBaseInstance
#define glDrawElementsInstancedBaseInstance __rglgen_glDrawElementsInstancedBaseInstance
#define glDrawElementsInstancedBaseVertexBaseInstance __rglgen_glDrawElementsInstancedBaseVertexBaseInstance
#define glGetInternalformativ __rglgen_glGetInternalformativ
#define glGetActiveAtomicCounterBufferiv __rglgen_glGetActiveAtomicCounterBufferiv
#define glBindImageTexture __rglgen_glBindImageTexture
#define glMemoryBarrier __rglgen_glMemoryBarrier
#define glTexStorage1D __rglgen_glTexStorage1D
#define glTexStorage2D __rglgen_glTexStorage2D
#define glTexStorage3D __rglgen_glTexStorage3D
#define glDrawTransformFeedbackInstanced __rglgen_glDrawTransformFeedbackInstanced
#define glDrawTransformFeedbackStreamInstanced __rglgen_glDrawTransformFeedbackStreamInstanced
#define glClearBufferData __rglgen_glClearBufferData
#define glClearBufferSubData __rglgen_glClearBufferSubData
#define glDispatchCompute __rglgen_glDispatchCompute
#define glDispatchComputeIndirect __rglgen_glDispatchComputeIndirect
#define glCopyImageSubData __rglgen_glCopyImageSubData
#define glFramebufferParameteri __rglgen_glFramebufferParameteri
#define glGetFramebufferParameteriv __rglgen_glGetFramebufferParameteriv
#define glGetInternalformati64v __rglgen_glGetInternalformati64v
#define glInvalidateTexSubImage __rglgen_glInvalidateTexSubImage
#define glInvalidateTexImage __rglgen_glInvalidateTexImage
#define glInvalidateBufferSubData __rglgen_glInvalidateBufferSubData
#define glInvalidateBufferData __rglgen_glInvalidateBufferData
#define glInvalidateFramebuffer __rglgen_glInvalidateFramebuffer
#define glInvalidateSubFramebuffer __rglgen_glInvalidateSubFramebuffer
#define glMultiDrawArraysIndirect __rglgen_glMultiDrawArraysIndirect
#define glMultiDrawElementsIndirect __rglgen_glMultiDrawElementsIndirect
#define glGetProgramInterfaceiv __rglgen_glGetProgramInterfaceiv
#define glGetProgramResourceIndex __rglgen_glGetProgramResourceIndex
#define glGetProgramResourceName __rglgen_glGetProgramResourceName
#define glGetProgramResourceiv __rglgen_glGetProgramResourceiv
#define glGetProgramResourceLocation __rglgen_glGetProgramResourceLocation
#define glGetProgramResourceLocationIndex __rglgen_glGetProgramResourceLocationIndex
#define glShaderStorageBlockBinding __rglgen_glShaderStorageBlockBinding
#define glTexBufferRange __rglgen_glTexBufferRange
#define glTexStorage2DMultisample __rglgen_glTexStorage2DMultisample
#define glTexStorage3DMultisample __rglgen_glTexStorage3DMultisample
#define glTextureView __rglgen_glTextureView
#define glBindVertexBuffer __rglgen_glBindVertexBuffer
#define glVertexAttribFormat __rglgen_glVertexAttribFormat
#define glVertexAttribIFormat __rglgen_glVertexAttribIFormat
#define glVertexAttribLFormat __rglgen_glVertexAttribLFormat
#define glVertexAttribBinding __rglgen_glVertexAttribBinding
#define glVertexBindingDivisor __rglgen_glVertexBindingDivisor
#define glDebugMessageControl __rglgen_glDebugMessageControl
#define glDebugMessageInsert __rglgen_glDebugMessageInsert
#define glDebugMessageCallback __rglgen_glDebugMessageCallback
#define glGetDebugMessageLog __rglgen_glGetDebugMessageLog
#define glPushDebugGroup __rglgen_glPushDebugGroup
#define glPopDebugGroup __rglgen_glPopDebugGroup
#define glObjectLabel __rglgen_glObjectLabel
#define glGetObjectLabel __rglgen_glGetObjectLabel
#define glObjectPtrLabel __rglgen_glObjectPtrLabel
#define glGetObjectPtrLabel __rglgen_glGetObjectPtrLabel
#define glBufferStorage __rglgen_glBufferStorage
#define glClearTexImage __rglgen_glClearTexImage
#define glClearTexSubImage __rglgen_glClearTexSubImage
#define glBindBuffersBase __rglgen_glBindBuffersBase
#define glBindBuffersRange __rglgen_glBindBuffersRange
#define glBindTextures __rglgen_glBindTextures
#define glBindSamplers __rglgen_glBindSamplers
#define glBindImageTextures __rglgen_glBindImageTextures
#define glBindVertexBuffers __rglgen_glBindVertexBuffers
#define glGetTextureHandleARB __rglgen_glGetTextureHandleARB
#define glGetTextureSamplerHandleARB __rglgen_glGetTextureSamplerHandleARB
#define glMakeTextureHandleResidentARB __rglgen_glMakeTextureHandleResidentARB
#define glMakeTextureHandleNonResidentARB __rglgen_glMakeTextureHandleNonResidentARB
#define glGetImageHandleARB __rglgen_glGetImageHandleARB
#define glMakeImageHandleResidentARB __rglgen_glMakeImageHandleResidentARB
#define glMakeImageHandleNonResidentARB __rglgen_glMakeImageHandleNonResidentARB
#define glUniformHandleui64ARB __rglgen_glUniformHandleui64ARB
#define glUniformHandleui64vARB __rglgen_glUniformHandleui64vARB
#define glProgramUniformHandleui64ARB __rglgen_glProgramUniformHandleui64ARB
#define glProgramUniformHandleui64vARB __rglgen_glProgramUniformHandleui64vARB
#define glIsTextureHandleResidentARB __rglgen_glIsTextureHandleResidentARB
#define glIsImageHandleResidentARB __rglgen_glIsImageHandleResidentARB
#define glVertexAttribL1ui64ARB __rglgen_glVertexAttribL1ui64ARB
#define glVertexAttribL1ui64vARB __rglgen_glVertexAttribL1ui64vARB
#define glGetVertexAttribLui64vARB __rglgen_glGetVertexAttribLui64vARB
#define glCreateSyncFromCLeventARB __rglgen_glCreateSyncFromCLeventARB
#define glClampColorARB __rglgen_glClampColorARB
#define glDispatchComputeGroupSizeARB __rglgen_glDispatchComputeGroupSizeARB
#define glDebugMessageControlARB __rglgen_glDebugMessageControlARB
#define glDebugMessageInsertARB __rglgen_glDebugMessageInsertARB
#define glDebugMessageCallbackARB __rglgen_glDebugMessageCallbackARB
#define glGetDebugMessageLogARB __rglgen_glGetDebugMessageLogARB
#define glDrawBuffersARB __rglgen_glDrawBuffersARB
#define glBlendEquationiARB __rglgen_glBlendEquationiARB
#define glBlendEquationSeparateiARB __rglgen_glBlendEquationSeparateiARB
#define glBlendFunciARB __rglgen_glBlendFunciARB
#define glBlendFuncSeparateiARB __rglgen_glBlendFuncSeparateiARB
#define glDrawArraysInstancedARB __rglgen_glDrawArraysInstancedARB
#define glDrawElementsInstancedARB __rglgen_glDrawElementsInstancedARB
#define glProgramStringARB __rglgen_glProgramStringARB
#define glBindProgramARB __rglgen_glBindProgramARB
#define glDeleteProgramsARB __rglgen_glDeleteProgramsARB
#define glGenProgramsARB __rglgen_glGenProgramsARB
#define glProgramEnvParameter4dARB __rglgen_glProgramEnvParameter4dARB
#define glProgramEnvParameter4dvARB __rglgen_glProgramEnvParameter4dvARB
#define glProgramEnvParameter4fARB __rglgen_glProgramEnvParameter4fARB
#define glProgramEnvParameter4fvARB __rglgen_glProgramEnvParameter4fvARB
#define glProgramLocalParameter4dARB __rglgen_glProgramLocalParameter4dARB
#define glProgramLocalParameter4dvARB __rglgen_glProgramLocalParameter4dvARB
#define glProgramLocalParameter4fARB __rglgen_glProgramLocalParameter4fARB
#define glProgramLocalParameter4fvARB __rglgen_glProgramLocalParameter4fvARB
#define glGetProgramEnvParameterdvARB __rglgen_glGetProgramEnvParameterdvARB
#define glGetProgramEnvParameterfvARB __rglgen_glGetProgramEnvParameterfvARB
#define glGetProgramLocalParameterdvARB __rglgen_glGetProgramLocalParameterdvARB
#define glGetProgramLocalParameterfvARB __rglgen_glGetProgramLocalParameterfvARB
#define glGetProgramivARB __rglgen_glGetProgramivARB
#define glGetProgramStringARB __rglgen_glGetProgramStringARB
#define glIsProgramARB __rglgen_glIsProgramARB
#define glProgramParameteriARB __rglgen_glProgramParameteriARB
#define glFramebufferTextureARB __rglgen_glFramebufferTextureARB
#define glFramebufferTextureLayerARB __rglgen_glFramebufferTextureLayerARB
#define glFramebufferTextureFaceARB __rglgen_glFramebufferTextureFaceARB
#define glColorTable __rglgen_glColorTable
#define glColorTableParameterfv __rglgen_glColorTableParameterfv
#define glColorTableParameteriv __rglgen_glColorTableParameteriv
#define glCopyColorTable __rglgen_glCopyColorTable
#define glGetColorTable __rglgen_glGetColorTable
#define glGetColorTableParameterfv __rglgen_glGetColorTableParameterfv
#define glGetColorTableParameteriv __rglgen_glGetColorTableParameteriv
#define glColorSubTable __rglgen_glColorSubTable
#define glCopyColorSubTable __rglgen_glCopyColorSubTable
#define glConvolutionFilter1D __rglgen_glConvolutionFilter1D
#define glConvolutionFilter2D __rglgen_glConvolutionFilter2D
#define glConvolutionParameterf __rglgen_glConvolutionParameterf
#define glConvolutionParameterfv __rglgen_glConvolutionParameterfv
#define glConvolutionParameteri __rglgen_glConvolutionParameteri
#define glConvolutionParameteriv __rglgen_glConvolutionParameteriv
#define glCopyConvolutionFilter1D __rglgen_glCopyConvolutionFilter1D
#define glCopyConvolutionFilter2D __rglgen_glCopyConvolutionFilter2D
#define glGetConvolutionFilter __rglgen_glGetConvolutionFilter
#define glGetConvolutionParameterfv __rglgen_glGetConvolutionParameterfv
#define glGetConvolutionParameteriv __rglgen_glGetConvolutionParameteriv
#define glGetSeparableFilter __rglgen_glGetSeparableFilter
#define glSeparableFilter2D __rglgen_glSeparableFilter2D
#define glGetHistogram __rglgen_glGetHistogram
#define glGetHistogramParameterfv __rglgen_glGetHistogramParameterfv
#define glGetHistogramParameteriv __rglgen_glGetHistogramParameteriv
#define glGetMinmax __rglgen_glGetMinmax
#define glGetMinmaxParameterfv __rglgen_glGetMinmaxParameterfv
#define glGetMinmaxParameteriv __rglgen_glGetMinmaxParameteriv
#define glHistogram __rglgen_glHistogram
#define glMinmax __rglgen_glMinmax
#define glResetHistogram __rglgen_glResetHistogram
#define glResetMinmax __rglgen_glResetMinmax
#define glMultiDrawArraysIndirectCountARB __rglgen_glMultiDrawArraysIndirectCountARB
#define glMultiDrawElementsIndirectCountARB __rglgen_glMultiDrawElementsIndirectCountARB
#define glVertexAttribDivisorARB __rglgen_glVertexAttribDivisorARB
#define glCurrentPaletteMatrixARB __rglgen_glCurrentPaletteMatrixARB
#define glMatrixIndexubvARB __rglgen_glMatrixIndexubvARB
#define glMatrixIndexusvARB __rglgen_glMatrixIndexusvARB
#define glMatrixIndexuivARB __rglgen_glMatrixIndexuivARB
#define glMatrixIndexPointerARB __rglgen_glMatrixIndexPointerARB
#define glSampleCoverageARB __rglgen_glSampleCoverageARB
#define glActiveTextureARB __rglgen_glActiveTextureARB
#define glClientActiveTextureARB __rglgen_glClientActiveTextureARB
#define glMultiTexCoord1dARB __rglgen_glMultiTexCoord1dARB
#define glMultiTexCoord1dvARB __rglgen_glMultiTexCoord1dvARB
#define glMultiTexCoord1fARB __rglgen_glMultiTexCoord1fARB
#define glMultiTexCoord1fvARB __rglgen_glMultiTexCoord1fvARB
#define glMultiTexCoord1iARB __rglgen_glMultiTexCoord1iARB
#define glMultiTexCoord1ivARB __rglgen_glMultiTexCoord1ivARB
#define glMultiTexCoord1sARB __rglgen_glMultiTexCoord1sARB
#define glMultiTexCoord1svARB __rglgen_glMultiTexCoord1svARB
#define glMultiTexCoord2dARB __rglgen_glMultiTexCoord2dARB
#define glMultiTexCoord2dvARB __rglgen_glMultiTexCoord2dvARB
#define glMultiTexCoord2fARB __rglgen_glMultiTexCoord2fARB
#define glMultiTexCoord2fvARB __rglgen_glMultiTexCoord2fvARB
#define glMultiTexCoord2iARB __rglgen_glMultiTexCoord2iARB
#define glMultiTexCoord2ivARB __rglgen_glMultiTexCoord2ivARB
#define glMultiTexCoord2sARB __rglgen_glMultiTexCoord2sARB
#define glMultiTexCoord2svARB __rglgen_glMultiTexCoord2svARB
#define glMultiTexCoord3dARB __rglgen_glMultiTexCoord3dARB
#define glMultiTexCoord3dvARB __rglgen_glMultiTexCoord3dvARB
#define glMultiTexCoord3fARB __rglgen_glMultiTexCoord3fARB
#define glMultiTexCoord3fvARB __rglgen_glMultiTexCoord3fvARB
#define glMultiTexCoord3iARB __rglgen_glMultiTexCoord3iARB
#define glMultiTexCoord3ivARB __rglgen_glMultiTexCoord3ivARB
#define glMultiTexCoord3sARB __rglgen_glMultiTexCoord3sARB
#define glMultiTexCoord3svARB __rglgen_glMultiTexCoord3svARB
#define glMultiTexCoord4dARB __rglgen_glMultiTexCoord4dARB
#define glMultiTexCoord4dvARB __rglgen_glMultiTexCoord4dvARB
#define glMultiTexCoord4fARB __rglgen_glMultiTexCoord4fARB
#define glMultiTexCoord4fvARB __rglgen_glMultiTexCoord4fvARB
#define glMultiTexCoord4iARB __rglgen_glMultiTexCoord4iARB
#define glMultiTexCoord4ivARB __rglgen_glMultiTexCoord4ivARB
#define glMultiTexCoord4sARB __rglgen_glMultiTexCoord4sARB
#define glMultiTexCoord4svARB __rglgen_glMultiTexCoord4svARB
#define glGenQueriesARB __rglgen_glGenQueriesARB
#define glDeleteQueriesARB __rglgen_glDeleteQueriesARB
#define glIsQueryARB __rglgen_glIsQueryARB
#define glBeginQueryARB __rglgen_glBeginQueryARB
#define glEndQueryARB __rglgen_glEndQueryARB
#define glGetQueryivARB __rglgen_glGetQueryivARB
#define glGetQueryObjectivARB __rglgen_glGetQueryObjectivARB
#define glGetQueryObjectuivARB __rglgen_glGetQueryObjectuivARB
#define glPointParameterfARB __rglgen_glPointParameterfARB
#define glPointParameterfvARB __rglgen_glPointParameterfvARB
#define glGetGraphicsResetStatusARB __rglgen_glGetGraphicsResetStatusARB
#define glGetnTexImageARB __rglgen_glGetnTexImageARB
#define glReadnPixelsARB __rglgen_glReadnPixelsARB
#define glGetnCompressedTexImageARB __rglgen_glGetnCompressedTexImageARB
#define glGetnUniformfvARB __rglgen_glGetnUniformfvARB
#define glGetnUniformivARB __rglgen_glGetnUniformivARB
#define glGetnUniformuivARB __rglgen_glGetnUniformuivARB
#define glGetnUniformdvARB __rglgen_glGetnUniformdvARB
#define glGetnMapdvARB __rglgen_glGetnMapdvARB
#define glGetnMapfvARB __rglgen_glGetnMapfvARB
#define glGetnMapivARB __rglgen_glGetnMapivARB
#define glGetnPixelMapfvARB __rglgen_glGetnPixelMapfvARB
#define glGetnPixelMapuivARB __rglgen_glGetnPixelMapuivARB
#define glGetnPixelMapusvARB __rglgen_glGetnPixelMapusvARB
#define glGetnPolygonStippleARB __rglgen_glGetnPolygonStippleARB
#define glGetnColorTableARB __rglgen_glGetnColorTableARB
#define glGetnConvolutionFilterARB __rglgen_glGetnConvolutionFilterARB
#define glGetnSeparableFilterARB __rglgen_glGetnSeparableFilterARB
#define glGetnHistogramARB __rglgen_glGetnHistogramARB
#define glGetnMinmaxARB __rglgen_glGetnMinmaxARB
#define glMinSampleShadingARB __rglgen_glMinSampleShadingARB
#define glDeleteObjectARB __rglgen_glDeleteObjectARB
#define glGetHandleARB __rglgen_glGetHandleARB
#define glDetachObjectARB __rglgen_glDetachObjectARB
#define glCreateShaderObjectARB __rglgen_glCreateShaderObjectARB
#define glShaderSourceARB __rglgen_glShaderSourceARB
#define glCompileShaderARB __rglgen_glCompileShaderARB
#define glCreateProgramObjectARB __rglgen_glCreateProgramObjectARB
#define glAttachObjectARB __rglgen_glAttachObjectARB
#define glLinkProgramARB __rglgen_glLinkProgramARB
#define glUseProgramObjectARB __rglgen_glUseProgramObjectARB
#define glValidateProgramARB __rglgen_glValidateProgramARB
#define glUniform1fARB __rglgen_glUniform1fARB
#define glUniform2fARB __rglgen_glUniform2fARB
#define glUniform3fARB __rglgen_glUniform3fARB
#define glUniform4fARB __rglgen_glUniform4fARB
#define glUniform1iARB __rglgen_glUniform1iARB
#define glUniform2iARB __rglgen_glUniform2iARB
#define glUniform3iARB __rglgen_glUniform3iARB
#define glUniform4iARB __rglgen_glUniform4iARB
#define glUniform1fvARB __rglgen_glUniform1fvARB
#define glUniform2fvARB __rglgen_glUniform2fvARB
#define glUniform3fvARB __rglgen_glUniform3fvARB
#define glUniform4fvARB __rglgen_glUniform4fvARB
#define glUniform1ivARB __rglgen_glUniform1ivARB
#define glUniform2ivARB __rglgen_glUniform2ivARB
#define glUniform3ivARB __rglgen_glUniform3ivARB
#define glUniform4ivARB __rglgen_glUniform4ivARB
#define glUniformMatrix2fvARB __rglgen_glUniformMatrix2fvARB
#define glUniformMatrix3fvARB __rglgen_glUniformMatrix3fvARB
#define glUniformMatrix4fvARB __rglgen_glUniformMatrix4fvARB
#define glGetObjectParameterfvARB __rglgen_glGetObjectParameterfvARB
#define glGetObjectParameterivARB __rglgen_glGetObjectParameterivARB
#define glGetInfoLogARB __rglgen_glGetInfoLogARB
#define glGetAttachedObjectsARB __rglgen_glGetAttachedObjectsARB
#define glGetUniformLocationARB __rglgen_glGetUniformLocationARB
#define glGetActiveUniformARB __rglgen_glGetActiveUniformARB
#define glGetUniformfvARB __rglgen_glGetUniformfvARB
#define glGetUniformivARB __rglgen_glGetUniformivARB
#define glGetShaderSourceARB __rglgen_glGetShaderSourceARB
#define glNamedStringARB __rglgen_glNamedStringARB
#define glDeleteNamedStringARB __rglgen_glDeleteNamedStringARB
#define glCompileShaderIncludeARB __rglgen_glCompileShaderIncludeARB
#define glIsNamedStringARB __rglgen_glIsNamedStringARB
#define glGetNamedStringARB __rglgen_glGetNamedStringARB
#define glGetNamedStringivARB __rglgen_glGetNamedStringivARB
#define glTexPageCommitmentARB __rglgen_glTexPageCommitmentARB
#define glTexBufferARB __rglgen_glTexBufferARB
#define glCompressedTexImage3DARB __rglgen_glCompressedTexImage3DARB
#define glCompressedTexImage2DARB __rglgen_glCompressedTexImage2DARB
#define glCompressedTexImage1DARB __rglgen_glCompressedTexImage1DARB
#define glCompressedTexSubImage3DARB __rglgen_glCompressedTexSubImage3DARB
#define glCompressedTexSubImage2DARB __rglgen_glCompressedTexSubImage2DARB
#define glCompressedTexSubImage1DARB __rglgen_glCompressedTexSubImage1DARB
#define glGetCompressedTexImageARB __rglgen_glGetCompressedTexImageARB
#define glLoadTransposeMatrixfARB __rglgen_glLoadTransposeMatrixfARB
#define glLoadTransposeMatrixdARB __rglgen_glLoadTransposeMatrixdARB
#define glMultTransposeMatrixfARB __rglgen_glMultTransposeMatrixfARB
#define glMultTransposeMatrixdARB __rglgen_glMultTransposeMatrixdARB
#define glWeightbvARB __rglgen_glWeightbvARB
#define glWeightsvARB __rglgen_glWeightsvARB
#define glWeightivARB __rglgen_glWeightivARB
#define glWeightfvARB __rglgen_glWeightfvARB
#define glWeightdvARB __rglgen_glWeightdvARB
#define glWeightubvARB __rglgen_glWeightubvARB
#define glWeightusvARB __rglgen_glWeightusvARB
#define glWeightuivARB __rglgen_glWeightuivARB
#define glWeightPointerARB __rglgen_glWeightPointerARB
#define glVertexBlendARB __rglgen_glVertexBlendARB
#define glBindBufferARB __rglgen_glBindBufferARB
#define glDeleteBuffersARB __rglgen_glDeleteBuffersARB
#define glGenBuffersARB __rglgen_glGenBuffersARB
#define glIsBufferARB __rglgen_glIsBufferARB
#define glBufferDataARB __rglgen_glBufferDataARB
#define glBufferSubDataARB __rglgen_glBufferSubDataARB
#define glGetBufferSubDataARB __rglgen_glGetBufferSubDataARB
#define glMapBufferARB __rglgen_glMapBufferARB
#define glUnmapBufferARB __rglgen_glUnmapBufferARB
#define glGetBufferParameterivARB __rglgen_glGetBufferParameterivARB
#define glGetBufferPointervARB __rglgen_glGetBufferPointervARB
#define glVertexAttrib1dARB __rglgen_glVertexAttrib1dARB
#define glVertexAttrib1dvARB __rglgen_glVertexAttrib1dvARB
#define glVertexAttrib1fARB __rglgen_glVertexAttrib1fARB
#define glVertexAttrib1fvARB __rglgen_glVertexAttrib1fvARB
#define glVertexAttrib1sARB __rglgen_glVertexAttrib1sARB
#define glVertexAttrib1svARB __rglgen_glVertexAttrib1svARB
#define glVertexAttrib2dARB __rglgen_glVertexAttrib2dARB
#define glVertexAttrib2dvARB __rglgen_glVertexAttrib2dvARB
#define glVertexAttrib2fARB __rglgen_glVertexAttrib2fARB
#define glVertexAttrib2fvARB __rglgen_glVertexAttrib2fvARB
#define glVertexAttrib2sARB __rglgen_glVertexAttrib2sARB
#define glVertexAttrib2svARB __rglgen_glVertexAttrib2svARB
#define glVertexAttrib3dARB __rglgen_glVertexAttrib3dARB
#define glVertexAttrib3dvARB __rglgen_glVertexAttrib3dvARB
#define glVertexAttrib3fARB __rglgen_glVertexAttrib3fARB
#define glVertexAttrib3fvARB __rglgen_glVertexAttrib3fvARB
#define glVertexAttrib3sARB __rglgen_glVertexAttrib3sARB
#define glVertexAttrib3svARB __rglgen_glVertexAttrib3svARB
#define glVertexAttrib4NbvARB __rglgen_glVertexAttrib4NbvARB
#define glVertexAttrib4NivARB __rglgen_glVertexAttrib4NivARB
#define glVertexAttrib4NsvARB __rglgen_glVertexAttrib4NsvARB
#define glVertexAttrib4NubARB __rglgen_glVertexAttrib4NubARB
#define glVertexAttrib4NubvARB __rglgen_glVertexAttrib4NubvARB
#define glVertexAttrib4NuivARB __rglgen_glVertexAttrib4NuivARB
#define glVertexAttrib4NusvARB __rglgen_glVertexAttrib4NusvARB
#define glVertexAttrib4bvARB __rglgen_glVertexAttrib4bvARB
#define glVertexAttrib4dARB __rglgen_glVertexAttrib4dARB
#define glVertexAttrib4dvARB __rglgen_glVertexAttrib4dvARB
#define glVertexAttrib4fARB __rglgen_glVertexAttrib4fARB
#define glVertexAttrib4fvARB __rglgen_glVertexAttrib4fvARB
#define glVertexAttrib4ivARB __rglgen_glVertexAttrib4ivARB
#define glVertexAttrib4sARB __rglgen_glVertexAttrib4sARB
#define glVertexAttrib4svARB __rglgen_glVertexAttrib4svARB
#define glVertexAttrib4ubvARB __rglgen_glVertexAttrib4ubvARB
#define glVertexAttrib4uivARB __rglgen_glVertexAttrib4uivARB
#define glVertexAttrib4usvARB __rglgen_glVertexAttrib4usvARB
#define glVertexAttribPointerARB __rglgen_glVertexAttribPointerARB
#define glEnableVertexAttribArrayARB __rglgen_glEnableVertexAttribArrayARB
#define glDisableVertexAttribArrayARB __rglgen_glDisableVertexAttribArrayARB
#define glGetVertexAttribdvARB __rglgen_glGetVertexAttribdvARB
#define glGetVertexAttribfvARB __rglgen_glGetVertexAttribfvARB
#define glGetVertexAttribivARB __rglgen_glGetVertexAttribivARB
#define glGetVertexAttribPointervARB __rglgen_glGetVertexAttribPointervARB
#define glBindAttribLocationARB __rglgen_glBindAttribLocationARB
#define glGetActiveAttribARB __rglgen_glGetActiveAttribARB
#define glGetAttribLocationARB __rglgen_glGetAttribLocationARB
#define glWindowPos2dARB __rglgen_glWindowPos2dARB
#define glWindowPos2dvARB __rglgen_glWindowPos2dvARB
#define glWindowPos2fARB __rglgen_glWindowPos2fARB
#define glWindowPos2fvARB __rglgen_glWindowPos2fvARB
#define glWindowPos2iARB __rglgen_glWindowPos2iARB
#define glWindowPos2ivARB __rglgen_glWindowPos2ivARB
#define glWindowPos2sARB __rglgen_glWindowPos2sARB
#define glWindowPos2svARB __rglgen_glWindowPos2svARB
#define glWindowPos3dARB __rglgen_glWindowPos3dARB
#define glWindowPos3dvARB __rglgen_glWindowPos3dvARB
#define glWindowPos3fARB __rglgen_glWindowPos3fARB
#define glWindowPos3fvARB __rglgen_glWindowPos3fvARB
#define glWindowPos3iARB __rglgen_glWindowPos3iARB
#define glWindowPos3ivARB __rglgen_glWindowPos3ivARB
#define glWindowPos3sARB __rglgen_glWindowPos3sARB
#define glWindowPos3svARB __rglgen_glWindowPos3svARB
#define glMultiTexCoord1bOES __rglgen_glMultiTexCoord1bOES
#define glMultiTexCoord1bvOES __rglgen_glMultiTexCoord1bvOES
#define glMultiTexCoord2bOES __rglgen_glMultiTexCoord2bOES
#define glMultiTexCoord2bvOES __rglgen_glMultiTexCoord2bvOES
#define glMultiTexCoord3bOES __rglgen_glMultiTexCoord3bOES
#define glMultiTexCoord3bvOES __rglgen_glMultiTexCoord3bvOES
#define glMultiTexCoord4bOES __rglgen_glMultiTexCoord4bOES
#define glMultiTexCoord4bvOES __rglgen_glMultiTexCoord4bvOES
#define glTexCoord1bOES __rglgen_glTexCoord1bOES
#define glTexCoord1bvOES __rglgen_glTexCoord1bvOES
#define glTexCoord2bOES __rglgen_glTexCoord2bOES
#define glTexCoord2bvOES __rglgen_glTexCoord2bvOES
#define glTexCoord3bOES __rglgen_glTexCoord3bOES
#define glTexCoord3bvOES __rglgen_glTexCoord3bvOES
#define glTexCoord4bOES __rglgen_glTexCoord4bOES
#define glTexCoord4bvOES __rglgen_glTexCoord4bvOES
#define glVertex2bOES __rglgen_glVertex2bOES
#define glVertex2bvOES __rglgen_glVertex2bvOES
#define glVertex3bOES __rglgen_glVertex3bOES
#define glVertex3bvOES __rglgen_glVertex3bvOES
#define glVertex4bOES __rglgen_glVertex4bOES
#define glVertex4bvOES __rglgen_glVertex4bvOES
#define glAlphaFuncxOES __rglgen_glAlphaFuncxOES
#define glClearColorxOES __rglgen_glClearColorxOES
#define glClearDepthxOES __rglgen_glClearDepthxOES
#define glClipPlanexOES __rglgen_glClipPlanexOES
#define glColor4xOES __rglgen_glColor4xOES
#define glDepthRangexOES __rglgen_glDepthRangexOES
#define glFogxOES __rglgen_glFogxOES
#define glFogxvOES __rglgen_glFogxvOES
#define glFrustumxOES __rglgen_glFrustumxOES
#define glGetClipPlanexOES __rglgen_glGetClipPlanexOES
#define glGetFixedvOES __rglgen_glGetFixedvOES
#define glGetTexEnvxvOES __rglgen_glGetTexEnvxvOES
#define glGetTexParameterxvOES __rglgen_glGetTexParameterxvOES
#define glLightModelxOES __rglgen_glLightModelxOES
#define glLightModelxvOES __rglgen_glLightModelxvOES
#define glLightxOES __rglgen_glLightxOES
#define glLightxvOES __rglgen_glLightxvOES
#define glLineWidthxOES __rglgen_glLineWidthxOES
#define glLoadMatrixxOES __rglgen_glLoadMatrixxOES
#define glMaterialxOES __rglgen_glMaterialxOES
#define glMaterialxvOES __rglgen_glMaterialxvOES
#define glMultMatrixxOES __rglgen_glMultMatrixxOES
#define glMultiTexCoord4xOES __rglgen_glMultiTexCoord4xOES
#define glNormal3xOES __rglgen_glNormal3xOES
#define glOrthoxOES __rglgen_glOrthoxOES
#define glPointParameterxvOES __rglgen_glPointParameterxvOES
#define glPointSizexOES __rglgen_glPointSizexOES
#define glPolygonOffsetxOES __rglgen_glPolygonOffsetxOES
#define glRotatexOES __rglgen_glRotatexOES
#define glSampleCoverageOES __rglgen_glSampleCoverageOES
#define glScalexOES __rglgen_glScalexOES
#define glTexEnvxOES __rglgen_glTexEnvxOES
#define glTexEnvxvOES __rglgen_glTexEnvxvOES
#define glTexParameterxOES __rglgen_glTexParameterxOES
#define glTexParameterxvOES __rglgen_glTexParameterxvOES
#define glTranslatexOES __rglgen_glTranslatexOES
#define glAccumxOES __rglgen_glAccumxOES
#define glBitmapxOES __rglgen_glBitmapxOES
#define glBlendColorxOES __rglgen_glBlendColorxOES
#define glClearAccumxOES __rglgen_glClearAccumxOES
#define glColor3xOES __rglgen_glColor3xOES
#define glColor3xvOES __rglgen_glColor3xvOES
#define glColor4xvOES __rglgen_glColor4xvOES
#define glConvolutionParameterxOES __rglgen_glConvolutionParameterxOES
#define glConvolutionParameterxvOES __rglgen_glConvolutionParameterxvOES
#define glEvalCoord1xOES __rglgen_glEvalCoord1xOES
#define glEvalCoord1xvOES __rglgen_glEvalCoord1xvOES
#define glEvalCoord2xOES __rglgen_glEvalCoord2xOES
#define glEvalCoord2xvOES __rglgen_glEvalCoord2xvOES
#define glFeedbackBufferxOES __rglgen_glFeedbackBufferxOES
#define glGetConvolutionParameterxvOES __rglgen_glGetConvolutionParameterxvOES
#define glGetHistogramParameterxvOES __rglgen_glGetHistogramParameterxvOES
#define glGetLightxOES __rglgen_glGetLightxOES
#define glGetMapxvOES __rglgen_glGetMapxvOES
#define glGetMaterialxOES __rglgen_glGetMaterialxOES
#define glGetPixelMapxv __rglgen_glGetPixelMapxv
#define glGetTexGenxvOES __rglgen_glGetTexGenxvOES
#define glGetTexLevelParameterxvOES __rglgen_glGetTexLevelParameterxvOES
#define glIndexxOES __rglgen_glIndexxOES
#define glIndexxvOES __rglgen_glIndexxvOES
#define glLoadTransposeMatrixxOES __rglgen_glLoadTransposeMatrixxOES
#define glMap1xOES __rglgen_glMap1xOES
#define glMap2xOES __rglgen_glMap2xOES
#define glMapGrid1xOES __rglgen_glMapGrid1xOES
#define glMapGrid2xOES __rglgen_glMapGrid2xOES
#define glMultTransposeMatrixxOES __rglgen_glMultTransposeMatrixxOES
#define glMultiTexCoord1xOES __rglgen_glMultiTexCoord1xOES
#define glMultiTexCoord1xvOES __rglgen_glMultiTexCoord1xvOES
#define glMultiTexCoord2xOES __rglgen_glMultiTexCoord2xOES
#define glMultiTexCoord2xvOES __rglgen_glMultiTexCoord2xvOES
#define glMultiTexCoord3xOES __rglgen_glMultiTexCoord3xOES
#define glMultiTexCoord3xvOES __rglgen_glMultiTexCoord3xvOES
#define glMultiTexCoord4xvOES __rglgen_glMultiTexCoord4xvOES
#define glNormal3xvOES __rglgen_glNormal3xvOES
#define glPassThroughxOES __rglgen_glPassThroughxOES
#define glPixelMapx __rglgen_glPixelMapx
#define glPixelStorex __rglgen_glPixelStorex
#define glPixelTransferxOES __rglgen_glPixelTransferxOES
#define glPixelZoomxOES __rglgen_glPixelZoomxOES
#define glPrioritizeTexturesxOES __rglgen_glPrioritizeTexturesxOES
#define glRasterPos2xOES __rglgen_glRasterPos2xOES
#define glRasterPos2xvOES __rglgen_glRasterPos2xvOES
#define glRasterPos3xOES __rglgen_glRasterPos3xOES
#define glRasterPos3xvOES __rglgen_glRasterPos3xvOES
#define glRasterPos4xOES __rglgen_glRasterPos4xOES
#define glRasterPos4xvOES __rglgen_glRasterPos4xvOES
#define glRectxOES __rglgen_glRectxOES
#define glRectxvOES __rglgen_glRectxvOES
#define glTexCoord1xOES __rglgen_glTexCoord1xOES
#define glTexCoord1xvOES __rglgen_glTexCoord1xvOES
#define glTexCoord2xOES __rglgen_glTexCoord2xOES
#define glTexCoord2xvOES __rglgen_glTexCoord2xvOES
#define glTexCoord3xOES __rglgen_glTexCoord3xOES
#define glTexCoord3xvOES __rglgen_glTexCoord3xvOES
#define glTexCoord4xOES __rglgen_glTexCoord4xOES
#define glTexCoord4xvOES __rglgen_glTexCoord4xvOES
#define glTexGenxOES __rglgen_glTexGenxOES
#define glTexGenxvOES __rglgen_glTexGenxvOES
#define glVertex2xOES __rglgen_glVertex2xOES
#define glVertex2xvOES __rglgen_glVertex2xvOES
#define glVertex3xOES __rglgen_glVertex3xOES
#define glVertex3xvOES __rglgen_glVertex3xvOES
#define glVertex4xOES __rglgen_glVertex4xOES
#define glVertex4xvOES __rglgen_glVertex4xvOES
#define glQueryMatrixxOES __rglgen_glQueryMatrixxOES
#define glClearDepthfOES __rglgen_glClearDepthfOES
#define glClipPlanefOES __rglgen_glClipPlanefOES
#define glDepthRangefOES __rglgen_glDepthRangefOES
#define glFrustumfOES __rglgen_glFrustumfOES
#define glGetClipPlanefOES __rglgen_glGetClipPlanefOES
#define glOrthofOES __rglgen_glOrthofOES
#define glImageTransformParameteriHP __rglgen_glImageTransformParameteriHP
#define glImageTransformParameterfHP __rglgen_glImageTransformParameterfHP
#define glImageTransformParameterivHP __rglgen_glImageTransformParameterivHP
#define glImageTransformParameterfvHP __rglgen_glImageTransformParameterfvHP
#define glGetImageTransformParameterivHP __rglgen_glGetImageTransformParameterivHP
#define glGetImageTransformParameterfvHP __rglgen_glGetImageTransformParameterfvHP

extern RGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;
extern RGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;
extern RGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;
extern RGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;
extern RGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;
extern RGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;
extern RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;
extern RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;
extern RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;
extern RGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;
extern RGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;
extern RGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;
extern RGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;
extern RGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;
extern RGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;
extern RGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;
extern RGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;
extern RGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;
extern RGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;
extern RGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;
extern RGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;
extern RGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;
extern RGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;
extern RGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;
extern RGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;
extern RGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;
extern RGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;
extern RGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;
extern RGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;
extern RGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;
extern RGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;
extern RGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;
extern RGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;
extern RGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;
extern RGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;
extern RGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;
extern RGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;
extern RGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;
extern RGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;
extern RGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;
extern RGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;
extern RGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;
extern RGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;
extern RGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;
extern RGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;
extern RGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;
extern RGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;
extern RGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;
extern RGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;
extern RGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;
extern RGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;
extern RGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;
extern RGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;
extern RGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;
extern RGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;
extern RGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;
extern RGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;
extern RGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;
extern RGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;
extern RGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;
extern RGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;
extern RGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;
extern RGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;
extern RGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;
extern RGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;
extern RGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;
extern RGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;
extern RGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;
extern RGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;
extern RGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;
extern RGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;
extern RGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;
extern RGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;
extern RGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;
extern RGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;
extern RGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;
extern RGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;
extern RGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;
extern RGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;
extern RGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;
extern RGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;
extern RGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;
extern RGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;
extern RGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;
extern RGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;
extern RGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;
extern RGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;
extern RGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;
extern RGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;
extern RGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;
extern RGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;
extern RGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;
extern RGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;
extern RGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;
extern RGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;
extern RGLSYMGLISQUERYPROC __rglgen_glIsQuery;
extern RGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;
extern RGLSYMGLENDQUERYPROC __rglgen_glEndQuery;
extern RGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;
extern RGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;
extern RGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;
extern RGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;
extern RGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;
extern RGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;
extern RGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;
extern RGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;
extern RGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;
extern RGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;
extern RGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;
extern RGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;
extern RGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;
extern RGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;
extern RGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;
extern RGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;
extern RGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;
extern RGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;
extern RGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;
extern RGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;
extern RGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;
extern RGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;
extern RGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;
extern RGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;
extern RGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;
extern RGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;
extern RGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;
extern RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;
extern RGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;
extern RGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;
extern RGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;
extern RGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;
extern RGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;
extern RGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;
extern RGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;
extern RGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;
extern RGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;
extern RGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;
extern RGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;
extern RGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;
extern RGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;
extern RGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;
extern RGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;
extern RGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;
extern RGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;
extern RGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;
extern RGLSYMGLISSHADERPROC __rglgen_glIsShader;
extern RGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;
extern RGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;
extern RGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;
extern RGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;
extern RGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;
extern RGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;
extern RGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;
extern RGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;
extern RGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;
extern RGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;
extern RGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;
extern RGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;
extern RGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;
extern RGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;
extern RGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;
extern RGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;
extern RGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;
extern RGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;
extern RGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;
extern RGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;
extern RGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;
extern RGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;
extern RGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;
extern RGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;
extern RGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;
extern RGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;
extern RGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;
extern RGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;
extern RGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;
extern RGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;
extern RGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;
extern RGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;
extern RGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;
extern RGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;
extern RGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;
extern RGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;
extern RGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;
extern RGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;
extern RGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;
extern RGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;
extern RGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;
extern RGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;
extern RGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;
extern RGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;
extern RGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;
extern RGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;
extern RGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;
extern RGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;
extern RGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;
extern RGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;
extern RGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;
extern RGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;
extern RGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;
extern RGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;
extern RGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;
extern RGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;
extern RGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;
extern RGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;
extern RGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;
extern RGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;
extern RGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;
extern RGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;
extern RGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;
extern RGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;
extern RGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;
extern RGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;
extern RGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;
extern RGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;
extern RGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;
extern RGLSYMGLENABLEIPROC __rglgen_glEnablei;
extern RGLSYMGLDISABLEIPROC __rglgen_glDisablei;
extern RGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;
extern RGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;
extern RGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;
extern RGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;
extern RGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;
extern RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;
extern RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;
extern RGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;
extern RGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;
extern RGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;
extern RGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;
extern RGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;
extern RGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;
extern RGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;
extern RGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;
extern RGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;
extern RGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;
extern RGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;
extern RGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;
extern RGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;
extern RGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;
extern RGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;
extern RGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;
extern RGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;
extern RGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;
extern RGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;
extern RGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;
extern RGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;
extern RGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;
extern RGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;
extern RGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;
extern RGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;
extern RGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;
extern RGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;
extern RGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;
extern RGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;
extern RGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;
extern RGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;
extern RGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;
extern RGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;
extern RGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;
extern RGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;
extern RGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;
extern RGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;
extern RGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;
extern RGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;
extern RGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;
extern RGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;
extern RGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;
extern RGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;
extern RGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;
extern RGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;
extern RGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;
extern RGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;
extern RGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;
extern RGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;
extern RGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;
extern RGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;
extern RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;
extern RGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;
extern RGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;
extern RGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;
extern RGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;
extern RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;
extern RGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;
extern RGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;
extern RGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;
extern RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;
extern RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;
extern RGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;
extern RGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;
extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;
extern RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;
extern RGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;
extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;
extern RGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;
extern RGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;
extern RGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;
extern RGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;
extern RGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;
extern RGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;
extern RGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;
extern RGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;
extern RGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;
extern RGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;
extern RGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;
extern RGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;
extern RGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;
extern RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;
extern RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;
extern RGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;
extern RGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;
extern RGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;
extern RGLSYMGLISSYNCPROC __rglgen_glIsSync;
extern RGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;
extern RGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;
extern RGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;
extern RGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;
extern RGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;
extern RGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;
extern RGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;
extern RGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;
extern RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;
extern RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;
extern RGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;
extern RGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;
extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;
extern RGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;
extern RGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;
extern RGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;
extern RGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;
extern RGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;
extern RGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;
extern RGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;
extern RGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;
extern RGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;
extern RGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;
extern RGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;
extern RGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;
extern RGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;
extern RGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;
extern RGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;
extern RGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;
extern RGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;
extern RGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;
extern RGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;
extern RGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;
extern RGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;
extern RGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;
extern RGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;
extern RGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;
extern RGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;
extern RGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;
extern RGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;
extern RGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;
extern RGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;
extern RGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;
extern RGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;
extern RGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;
extern RGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;
extern RGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;
extern RGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;
extern RGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;
extern RGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;
extern RGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;
extern RGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;
extern RGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;
extern RGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;
extern RGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;
extern RGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;
extern RGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;
extern RGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;
extern RGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;
extern RGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;
extern RGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;
extern RGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;
extern RGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;
extern RGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;
extern RGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;
extern RGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;
extern RGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;
extern RGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;
extern RGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;
extern RGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;
extern RGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;
extern RGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;
extern RGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;
extern RGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;
extern RGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;
extern RGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;
extern RGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;
extern RGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;
extern RGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;
extern RGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;
extern RGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;
extern RGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;
extern RGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;
extern RGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;
extern RGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;
extern RGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;
extern RGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;
extern RGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;
extern RGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;
extern RGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;
extern RGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;
extern RGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;
extern RGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;
extern RGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;
extern RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;
extern RGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;
extern RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;
extern RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;
extern RGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;
extern RGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;
extern RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;
extern RGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;
extern RGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;
extern RGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;
extern RGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;
extern RGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;
extern RGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;
extern RGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;
extern RGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;
extern RGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;
extern RGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;
extern RGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;
extern RGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;
extern RGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;
extern RGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;
extern RGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;
extern RGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;
extern RGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;
extern RGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;
extern RGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;
extern RGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;
extern RGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;
extern RGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;
extern RGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;
extern RGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;
extern RGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;
extern RGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;
extern RGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;
extern RGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;
extern RGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;
extern RGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;
extern RGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;
extern RGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;
extern RGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;
extern RGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;
extern RGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;
extern RGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;
extern RGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;
extern RGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;
extern RGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;
extern RGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;
extern RGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;
extern RGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;
extern RGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;
extern RGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;
extern RGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;
extern RGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;
extern RGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;
extern RGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;
extern RGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;
extern RGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;
extern RGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;
extern RGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;
extern RGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;
extern RGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;
extern RGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;
extern RGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;
extern RGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;
extern RGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;
extern RGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;
extern RGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;
extern RGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;
extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;
extern RGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;
extern RGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;
extern RGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;
extern RGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;
extern RGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;
extern RGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;
extern RGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;
extern RGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;
extern RGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;
extern RGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;
extern RGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;
extern RGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;
extern RGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;
extern RGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;
extern RGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;
extern RGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;
extern RGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;
extern RGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;
extern RGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;
extern RGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;
extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;
extern RGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;
extern RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;
extern RGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;
extern RGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;
extern RGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;
extern RGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;
extern RGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;
extern RGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;
extern RGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;
extern RGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;
extern RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;
extern RGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;
extern RGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;
extern RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;
extern RGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;
extern RGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;
extern RGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;
extern RGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;
extern RGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;
extern RGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;
extern RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;
extern RGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;
extern RGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;
extern RGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;
extern RGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;
extern RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;
extern RGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;
extern RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;
extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;
extern RGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;
extern RGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;
extern RGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;
extern RGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;
extern RGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;
extern RGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;
extern RGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;
extern RGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;
extern RGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;
extern RGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;
extern RGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;
extern RGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;
extern RGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;
extern RGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;
extern RGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;
extern RGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;
extern RGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;
extern RGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;
extern RGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;
extern RGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;
extern RGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;
extern RGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;
extern RGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;
extern RGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;
extern RGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;
extern RGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;
extern RGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;
extern RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;
extern RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;
extern RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;
extern RGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;
extern RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;
extern RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;
extern RGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;
extern RGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;
extern RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;
extern RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;
extern RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;
extern RGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;
extern RGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;
extern RGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;
extern RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;
extern RGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;
extern RGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;
extern RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;
extern RGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;
extern RGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;
extern RGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;
extern RGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;
extern RGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;
extern RGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;
extern RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;
extern RGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;
extern RGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;
extern RGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;
extern RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;
extern RGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;
extern RGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;
extern RGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;
extern RGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;
extern RGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;
extern RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;
extern RGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;
extern RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;
extern RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;
extern RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;
extern RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;
extern RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;
extern RGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;
extern RGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;
extern RGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;
extern RGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;
extern RGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;
extern RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;
extern RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;
extern RGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;
extern RGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;
extern RGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;
extern RGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;
extern RGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;
extern RGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;
extern RGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;
extern RGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;
extern RGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;
extern RGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;
extern RGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;
extern RGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;
extern RGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;
extern RGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;
extern RGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;
extern RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;
extern RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;
extern RGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;
extern RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;
extern RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;
extern RGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;
extern RGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;
extern RGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;
extern RGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;
extern RGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;
extern RGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;
extern RGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;
extern RGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;
extern RGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;
extern RGLSYMGLMINMAXPROC __rglgen_glMinmax;
extern RGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;
extern RGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;
extern RGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;
extern RGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;
extern RGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;
extern RGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;
extern RGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;
extern RGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;
extern RGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;
extern RGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;
extern RGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;
extern RGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;
extern RGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;
extern RGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;
extern RGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;
extern RGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;
extern RGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;
extern RGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;
extern RGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;
extern RGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;
extern RGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;
extern RGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;
extern RGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;
extern RGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;
extern RGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;
extern RGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;
extern RGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;
extern RGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;
extern RGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;
extern RGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;
extern RGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;
extern RGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;
extern RGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;
extern RGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;
extern RGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;
extern RGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;
extern RGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;
extern RGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;
extern RGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;
extern RGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;
extern RGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;
extern RGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;
extern RGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;
extern RGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;
extern RGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;
extern RGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;
extern RGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;
extern RGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;
extern RGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;
extern RGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;
extern RGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;
extern RGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;
extern RGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;
extern RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;
extern RGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;
extern RGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;
extern RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;
extern RGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;
extern RGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;
extern RGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;
extern RGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;
extern RGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;
extern RGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;
extern RGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;
extern RGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;
extern RGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;
extern RGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;
extern RGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;
extern RGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;
extern RGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;
extern RGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;
extern RGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;
extern RGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;
extern RGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;
extern RGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;
extern RGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;
extern RGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;
extern RGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;
extern RGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;
extern RGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;
extern RGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;
extern RGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;
extern RGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;
extern RGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;
extern RGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;
extern RGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;
extern RGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;
extern RGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;
extern RGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;
extern RGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;
extern RGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;
extern RGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;
extern RGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;
extern RGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;
extern RGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;
extern RGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;
extern RGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;
extern RGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;
extern RGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;
extern RGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;
extern RGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;
extern RGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;
extern RGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;
extern RGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;
extern RGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;
extern RGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;
extern RGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;
extern RGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;
extern RGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;
extern RGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;
extern RGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;
extern RGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;
extern RGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;
extern RGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;
extern RGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;
extern RGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;
extern RGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;
extern RGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;
extern RGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;
extern RGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;
extern RGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;
extern RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;
extern RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;
extern RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;
extern RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;
extern RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;
extern RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;
extern RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;
extern RGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;
extern RGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;
extern RGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;
extern RGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;
extern RGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;
extern RGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;
extern RGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;
extern RGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;
extern RGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;
extern RGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;
extern RGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;
extern RGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;
extern RGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;
extern RGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;
extern RGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;
extern RGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;
extern RGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;
extern RGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;
extern RGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;
extern RGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;
extern RGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;
extern RGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;
extern RGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;
extern RGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;
extern RGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;
extern RGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;
extern RGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;
extern RGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;
extern RGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;
extern RGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;
extern RGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;
extern RGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;
extern RGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;
extern RGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;
extern RGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;
extern RGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;
extern RGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;
extern RGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;
extern RGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;
extern RGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;
extern RGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;
extern RGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;
extern RGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;
extern RGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;
extern RGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;
extern RGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;
extern RGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;
extern RGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;
extern RGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;
extern RGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;
extern RGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;
extern RGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;
extern RGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;
extern RGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;
extern RGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;
extern RGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;
extern RGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;
extern RGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;
extern RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;
extern RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;
extern RGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;
extern RGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;
extern RGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;
extern RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;
extern RGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;
extern RGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;
extern RGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;
extern RGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;
extern RGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;
extern RGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;
extern RGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;
extern RGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;
extern RGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;
extern RGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;
extern RGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;
extern RGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;
extern RGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;
extern RGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;
extern RGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;
extern RGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;
extern RGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;
extern RGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;
extern RGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;
extern RGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;
extern RGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;
extern RGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;
extern RGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;
extern RGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;
extern RGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;
extern RGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;
extern RGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;
extern RGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;
extern RGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;
extern RGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;
extern RGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;
extern RGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;
extern RGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;
extern RGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;
extern RGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;
extern RGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;
extern RGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;
extern RGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;
extern RGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;
extern RGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;
extern RGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;
extern RGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;
extern RGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;
extern RGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;
extern RGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;
extern RGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;
extern RGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;
extern RGLSYMGLFOGXOESPROC __rglgen_glFogxOES;
extern RGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;
extern RGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;
extern RGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;
extern RGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;
extern RGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;
extern RGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;
extern RGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;
extern RGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;
extern RGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;
extern RGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;
extern RGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;
extern RGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;
extern RGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;
extern RGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;
extern RGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;
extern RGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;
extern RGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;
extern RGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;
extern RGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;
extern RGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;
extern RGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;
extern RGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;
extern RGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;
extern RGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;
extern RGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;
extern RGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;
extern RGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;
extern RGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;
extern RGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;
extern RGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;
extern RGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;
extern RGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;
extern RGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;
extern RGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;
extern RGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;
extern RGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;
extern RGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;
extern RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;
extern RGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;
extern RGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;
extern RGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;
extern RGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;
extern RGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;
extern RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;
extern RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;
extern RGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;
extern RGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;
extern RGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;
extern RGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;
extern RGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;
extern RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;
extern RGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;
extern RGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;
extern RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;
extern RGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;
extern RGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;
extern RGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;
extern RGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;
extern RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;
extern RGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;
extern RGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;
extern RGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;
extern RGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;
extern RGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;
extern RGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;
extern RGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;
extern RGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;
extern RGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;
extern RGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;
extern RGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;
extern RGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;
extern RGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;
extern RGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;
extern RGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;
extern RGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;
extern RGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;
extern RGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;
extern RGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;
extern RGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;
extern RGLSYMGLRECTXOESPROC __rglgen_glRectxOES;
extern RGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;
extern RGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;
extern RGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;
extern RGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;
extern RGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;
extern RGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;
extern RGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;
extern RGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;
extern RGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;
extern RGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;
extern RGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;
extern RGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;
extern RGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;
extern RGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;
extern RGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;
extern RGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;
extern RGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;
extern RGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;
extern RGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;
extern RGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;
extern RGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;
extern RGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;
extern RGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;
extern RGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;
extern RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;
extern RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;
extern RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;
extern RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;
extern RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;
extern RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;

struct rglgen_sym_map { const char *sym; void *ptr; };
extern const struct rglgen_sym_map rglgen_symbol_map[];
#ifdef __cplusplus
}
#endif
#endif

./include/libretro-common/include/glsym/glsym.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GLSYM_H__
#define __LIBRETRO_SDK_GLSYM_H__

#include "rglgen.h"

#ifndef HAVE_PSGL
#if defined(HAVE_OPENGLES2)
#include "glsym_es2.h"
#elif defined(HAVE_OPENGLES3)
#include "glsym_es3.h"
#else
#ifdef HAVE_LIBNX
#include "switch/nx_glsym.h"
#endif
#include "glsym_gl.h"
#endif
#endif

#ifdef HAVE_GLSYM_PRIVATE
#include "glsym_private.h"
#endif

#endif

./include/libretro-common/include/glsym/rglgen.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_H__
#define RGLGEN_H__

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <retro_common_api.h>

#include "rglgen_headers.h"

RETRO_BEGIN_DECLS

struct rglgen_sym_map;

typedef void (*rglgen_func_t)(void);
typedef rglgen_func_t (*rglgen_proc_address_t)(const char*);
void rglgen_resolve_symbols(rglgen_proc_address_t proc);
void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
      const struct rglgen_sym_map *map);

RETRO_END_DECLS

#endif

./include/libretro-common/include/glsym/rglgen_headers.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_HEADERS_H__
#define RGLGEN_HEADERS_H__

#ifdef HAVE_EGL
#include <EGL/egl.h>
#include <EGL/eglext.h>
#endif

#include "rglgen_private_headers.h"

#ifndef GL_MAP_WRITE_BIT
#define GL_MAP_WRITE_BIT 0x0002
#endif

#ifndef GL_MAP_INVALIDATE_BUFFER_BIT
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#endif

#ifndef GL_RED_INTEGER
#define GL_RED_INTEGER 0x8D94
#endif

#ifndef GL_BGRA_EXT
#define GL_BGRA_EXT GL_BGRA
#endif

#ifndef GL_LUMINANCE_ALPHA
#define GL_LUMINANCE_ALPHA 0x190A
#endif

#endif

./include/libretro-common/include/glsym/rglgen_private_headers.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_PRIVATE_HEADERS_H__
#define RGLGEN_PRIVATE_HEADERS_H__

#if defined(IOS)

#if defined(HAVE_OPENGLES3)
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#else
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#endif

#elif defined(__APPLE__)
#include <compat/apple_compat.h>
#if MAC_OS_X_VERSION_10_7
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#else
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#endif
#elif defined(HAVE_PSGL)
#include <PSGL/psgl.h>
#include <GLES/glext.h>
#elif defined(HAVE_OPENGL_MODERN)
#include <GL3/gl3.h>
#include <GL3/gl3ext.h>
#elif defined(HAVE_OPENGLES3)
#include <GLES3/gl3.h>
#define __gl2_h_
#include <GLES2/gl2ext.h>
#elif defined(HAVE_OPENGLES2)
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#elif defined(HAVE_OPENGLES1)
#include <GLES/gl.h>
#include <GLES/glext.h>
#else
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#ifndef HAVE_LIBNX
#include <GL/gl.h>
#include <GL/glext.h>
#else
/* We need to avoid including <GL/gl.h> on this platform */
#include "switch/nx_gl.h"
#include <GL/glext.h>
#endif /* SWITCH */
#endif

#endif

./include/libretro-common/include/glsym/switch/nx_gl.h

/* Copyright (C) 2018-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (nx_gl.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __NX_GL_H__
#define __NX_GL_H__

#ifdef __cplusplus
extern "C" {
#endif

#ifndef APIENTRY
#define APIENTRY
#endif

#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif

/* GL.h types */
typedef unsigned int	GLenum;
typedef unsigned char	GLboolean;
typedef unsigned int	GLbitfield;
typedef void		GLvoid;
typedef signed char	GLbyte;		/* 1-byte signed */
typedef short		GLshort;	/* 2-byte signed */
typedef int		GLint;		/* 4-byte signed */
typedef unsigned char	GLubyte;	/* 1-byte unsigned */
typedef unsigned short	GLushort;	/* 2-byte unsigned */
typedef unsigned int	GLuint;		/* 4-byte unsigned */
typedef int		GLsizei;	/* 4-byte signed */
typedef float		GLfloat;	/* single precision float */
typedef float		GLclampf;	/* single precision float in [0,1] */
typedef double		GLdouble;	/* double precision float */
typedef double		GLclampd;	/* double precision float in [0,1] */

/* GL.h defines */
#define GL_ARB_imaging   1
#define GL_FALSE                                0
#define GL_TRUE                                 1
#define GL_BYTE                                 0x1400
#define GL_UNSIGNED_BYTE                        0x1401
#define GL_SHORT                                0x1402
#define GL_UNSIGNED_SHORT                       0x1403
#define GL_INT                                  0x1404
#define GL_UNSIGNED_INT                         0x1405
#define GL_FLOAT                                0x1406
#define GL_2_BYTES                              0x1407
#define GL_3_BYTES                              0x1408
#define GL_4_BYTES                              0x1409
#define GL_DOUBLE                               0x140A
#define GL_POINTS                               0x0000
#define GL_LINES                                0x0001
#define GL_LINE_LOOP                            0x0002
#define GL_LINE_STRIP                           0x0003
#define GL_TRIANGLES                            0x0004
#define GL_TRIANGLE_STRIP                       0x0005
#define GL_TRIANGLE_FAN                         0x0006
#define GL_QUADS                                0x0007
#define GL_QUAD_STRIP                           0x0008
#define GL_POLYGON                              0x0009
#define GL_VERTEX_ARRAY                         0x8074
#define GL_NORMAL_ARRAY                         0x8075
#define GL_COLOR_ARRAY                          0x8076
#define GL_INDEX_ARRAY                          0x8077
#define GL_TEXTURE_COORD_ARRAY                  0x8078
#define GL_EDGE_FLAG_ARRAY                      0x8079
#define GL_VERTEX_ARRAY_SIZE                    0x807A
#define GL_VERTEX_ARRAY_TYPE                    0x807B
#define GL_VERTEX_ARRAY_STRIDE                  0x807C
#define GL_NORMAL_ARRAY_TYPE                    0x807E
#define GL_NORMAL_ARRAY_STRIDE                  0x807F
#define GL_COLOR_ARRAY_SIZE                     0x8081
#define GL_COLOR_ARRAY_TYPE                     0x8082
#define GL_COLOR_ARRAY_STRIDE                   0x8083
#define GL_INDEX_ARRAY_TYPE                     0x8085
#define GL_INDEX_ARRAY_STRIDE                   0x8086
#define GL_TEXTURE_COORD_ARRAY_SIZE             0x8088
#define GL_TEXTURE_COORD_ARRAY_TYPE             0x8089
#define GL_TEXTURE_COORD_ARRAY_STRIDE           0x808A
#define GL_EDGE_FLAG_ARRAY_STRIDE               0x808C
#define GL_VERTEX_ARRAY_POINTER                 0x808E
#define GL_NORMAL_ARRAY_POINTER                 0x808F
#define GL_COLOR_ARRAY_POINTER                  0x8090
#define GL_INDEX_ARRAY_POINTER                  0x8091
#define GL_TEXTURE_COORD_ARRAY_POINTER          0x8092
#define GL_EDGE_FLAG_ARRAY_POINTER              0x8093
#define GL_V2F                                  0x2A20
#define GL_V3F                                  0x2A21
#define GL_C4UB_V2F                             0x2A22
#define GL_C4UB_V3F                             0x2A23
#define GL_C3F_V3F                              0x2A24
#define GL_N3F_V3F                              0x2A25
#define GL_C4F_N3F_V3F                          0x2A26
#define GL_T2F_V3F                              0x2A27
#define GL_T4F_V4F                              0x2A28
#define GL_T2F_C4UB_V3F                         0x2A29
#define GL_T2F_C3F_V3F                          0x2A2A
#define GL_T2F_N3F_V3F                          0x2A2B
#define GL_T2F_C4F_N3F_V3F                      0x2A2C
#define GL_T4F_C4F_N3F_V4F                      0x2A2D
#define GL_MATRIX_MODE                          0x0BA0
#define GL_MODELVIEW                            0x1700
#define GL_PROJECTION                           0x1701
#define GL_TEXTURE                              0x1702
#define GL_POINT_SMOOTH                         0x0B10
#define GL_POINT_SIZE                           0x0B11
#define GL_POINT_SIZE_GRANULARITY               0x0B13
#define GL_POINT_SIZE_RANGE                     0x0B12
#define GL_LINE_SMOOTH                          0x0B20
#define GL_LINE_STIPPLE                         0x0B24
#define GL_LINE_STIPPLE_PATTERN                 0x0B25
#define GL_LINE_STIPPLE_REPEAT                  0x0B26
#define GL_LINE_WIDTH                           0x0B21
#define GL_LINE_WIDTH_GRANULARITY               0x0B23
#define GL_LINE_WIDTH_RANGE                     0x0B22
#define GL_POINT                                0x1B00
#define GL_LINE                                 0x1B01
#define GL_FILL                                 0x1B02
#define GL_CW                                   0x0900
#define GL_CCW                                  0x0901
#define GL_FRONT                                0x0404
#define GL_BACK                                 0x0405
#define GL_POLYGON_MODE                         0x0B40
#define GL_POLYGON_SMOOTH                       0x0B41
#define GL_POLYGON_STIPPLE                      0x0B42
#define GL_EDGE_FLAG                            0x0B43
#define GL_CULL_FACE                            0x0B44
#define GL_CULL_FACE_MODE                       0x0B45
#define GL_FRONT_FACE                           0x0B46
#define GL_POLYGON_OFFSET_FACTOR                0x8038
#define GL_POLYGON_OFFSET_UNITS                 0x2A00
#define GL_POLYGON_OFFSET_POINT                 0x2A01
#define GL_POLYGON_OFFSET_LINE                  0x2A02
#define GL_POLYGON_OFFSET_FILL                  0x8037
#define GL_COMPILE                              0x1300
#define GL_COMPILE_AND_EXECUTE                  0x1301
#define GL_LIST_BASE                            0x0B32
#define GL_LIST_INDEX                           0x0B33
#define GL_LIST_MODE                            0x0B30
#define GL_NEVER                                0x0200
#define GL_LESS                                 0x0201
#define GL_EQUAL                                0x0202
#define GL_LEQUAL                               0x0203
#define GL_GREATER                              0x0204
#define GL_NOTEQUAL                             0x0205
#define GL_GEQUAL                               0x0206
#define GL_ALWAYS                               0x0207
#define GL_DEPTH_TEST                           0x0B71
#define GL_DEPTH_BITS                           0x0D56
#define GL_DEPTH_CLEAR_VALUE                    0x0B73
#define GL_DEPTH_FUNC                           0x0B74
#define GL_DEPTH_RANGE                          0x0B70
#define GL_DEPTH_WRITEMASK                      0x0B72
#define GL_DEPTH_COMPONENT                      0x1902
#define GL_LIGHTING                             0x0B50
#define GL_LIGHT0                               0x4000
#define GL_LIGHT1                               0x4001
#define GL_LIGHT2                               0x4002
#define GL_LIGHT3                               0x4003
#define GL_LIGHT4                               0x4004
#define GL_LIGHT5                               0x4005
#define GL_LIGHT6                               0x4006
#define GL_LIGHT7                               0x4007
#define GL_SPOT_EXPONENT                        0x1205
#define GL_SPOT_CUTOFF                          0x1206
#define GL_CONSTANT_ATTENUATION                 0x1207
#define GL_LINEAR_ATTENUATION                   0x1208
#define GL_QUADRATIC_ATTENUATION                0x1209
#define GL_AMBIENT                              0x1200
#define GL_DIFFUSE                              0x1201
#define GL_SPECULAR                             0x1202
#define GL_SHININESS                            0x1601
#define GL_EMISSION                             0x1600
#define GL_POSITION                             0x1203
#define GL_SPOT_DIRECTION                       0x1204
#define GL_AMBIENT_AND_DIFFUSE                  0x1602
#define GL_COLOR_INDEXES                        0x1603
#define GL_LIGHT_MODEL_TWO_SIDE                 0x0B52
#define GL_LIGHT_MODEL_LOCAL_VIEWER             0x0B51
#define GL_LIGHT_MODEL_AMBIENT                  0x0B53
#define GL_FRONT_AND_BACK                       0x0408
#define GL_SHADE_MODEL                          0x0B54
#define GL_FLAT                                 0x1D00
#define GL_SMOOTH                               0x1D01
#define GL_COLOR_MATERIAL                       0x0B57
#define GL_COLOR_MATERIAL_FACE                  0x0B55
#define GL_COLOR_MATERIAL_PARAMETER             0x0B56
#define GL_NORMALIZE                            0x0BA1
#define GL_CLIP_PLANE0                          0x3000
#define GL_CLIP_PLANE1                          0x3001
#define GL_CLIP_PLANE2                          0x3002
#define GL_CLIP_PLANE3                          0x3003
#define GL_CLIP_PLANE4                          0x3004
#define GL_CLIP_PLANE5                          0x3005
#define GL_ACCUM_RED_BITS                       0x0D58
#define GL_ACCUM_GREEN_BITS                     0x0D59
#define GL_ACCUM_BLUE_BITS                      0x0D5A
#define GL_ACCUM_ALPHA_BITS                     0x0D5B
#define GL_ACCUM_CLEAR_VALUE                    0x0B80
#define GL_ACCUM                                0x0100
#define GL_ADD                                  0x0104
#define GL_LOAD                                 0x0101
#define GL_MULT                                 0x0103
#define GL_RETURN                               0x0102
#define GL_ALPHA_TEST                           0x0BC0
#define GL_ALPHA_TEST_REF                       0x0BC2
#define GL_ALPHA_TEST_FUNC                      0x0BC1
#define GL_BLEND                                0x0BE2
#define GL_BLEND_SRC                            0x0BE1
#define GL_BLEND_DST                            0x0BE0
#define GL_ZERO                                 0
#define GL_ONE                                  1
#define GL_SRC_COLOR                            0x0300
#define GL_ONE_MINUS_SRC_COLOR                  0x0301
#define GL_SRC_ALPHA                            0x0302
#define GL_ONE_MINUS_SRC_ALPHA                  0x0303
#define GL_DST_ALPHA                            0x0304
#define GL_ONE_MINUS_DST_ALPHA                  0x0305
#define GL_DST_COLOR                            0x0306
#define GL_ONE_MINUS_DST_COLOR                  0x0307
#define GL_SRC_ALPHA_SATURATE                   0x0308
#define GL_FEEDBACK                             0x1C01
#define GL_RENDER                               0x1C00
#define GL_SELECT                               0x1C02
#define GL_2D                                   0x0600
#define GL_3D                                   0x0601
#define GL_3D_COLOR                             0x0602
#define GL_3D_COLOR_TEXTURE                     0x0603
#define GL_4D_COLOR_TEXTURE                     0x0604
#define GL_POINT_TOKEN                          0x0701
#define GL_LINE_TOKEN                           0x0702
#define GL_LINE_RESET_TOKEN                     0x0707
#define GL_POLYGON_TOKEN                        0x0703
#define GL_BITMAP_TOKEN                         0x0704
#define GL_DRAW_PIXEL_TOKEN                     0x0705
#define GL_COPY_PIXEL_TOKEN                     0x0706
#define GL_PASS_THROUGH_TOKEN                   0x0700
#define GL_FEEDBACK_BUFFER_POINTER              0x0DF0
#define GL_FEEDBACK_BUFFER_SIZE                 0x0DF1
#define GL_FEEDBACK_BUFFER_TYPE                 0x0DF2
#define GL_SELECTION_BUFFER_POINTER             0x0DF3
#define GL_SELECTION_BUFFER_SIZE                0x0DF4
#define GL_FOG                                  0x0B60
#define GL_FOG_MODE                             0x0B65
#define GL_FOG_DENSITY                          0x0B62
#define GL_FOG_COLOR                            0x0B66
#define GL_FOG_INDEX                            0x0B61
#define GL_FOG_START                            0x0B63
#define GL_FOG_END                              0x0B64
#define GL_LINEAR                               0x2601
#define GL_EXP                                  0x0800
#define GL_EXP2                                 0x0801
#define GL_LOGIC_OP                             0x0BF1
#define GL_INDEX_LOGIC_OP                       0x0BF1
#define GL_COLOR_LOGIC_OP                       0x0BF2
#define GL_LOGIC_OP_MODE                        0x0BF0
#define GL_CLEAR                                0x1500
#define GL_SET                                  0x150F
#define GL_COPY                                 0x1503
#define GL_COPY_INVERTED                        0x150C
#define GL_NOOP                                 0x1505
#define GL_INVERT                               0x150A
#define GL_AND                                  0x1501
#define GL_NAND                                 0x150E
#define GL_OR                                   0x1507
#define GL_NOR                                  0x1508
#define GL_XOR                                  0x1506
#define GL_EQUIV                                0x1509
#define GL_AND_REVERSE                          0x1502
#define GL_AND_INVERTED                         0x1504
#define GL_OR_REVERSE                           0x150B
#define GL_OR_INVERTED                          0x150D
#define GL_STENCIL_BITS                         0x0D57
#define GL_STENCIL_TEST                         0x0B90
#define GL_STENCIL_CLEAR_VALUE                  0x0B91
#define GL_STENCIL_FUNC                         0x0B92
#define GL_STENCIL_VALUE_MASK                   0x0B93
#define GL_STENCIL_FAIL                         0x0B94
#define GL_STENCIL_PASS_DEPTH_FAIL              0x0B95
#define GL_STENCIL_PASS_DEPTH_PASS              0x0B96
#define GL_STENCIL_REF                          0x0B97
#define GL_STENCIL_WRITEMASK                    0x0B98
#define GL_STENCIL_INDEX                        0x1901
#define GL_KEEP                                 0x1E00
#define GL_REPLACE                              0x1E01
#define GL_INCR                                 0x1E02
#define GL_DECR                                 0x1E03
#define GL_NONE                                 0
#define GL_LEFT                                 0x0406
#define GL_RIGHT                                0x0407
#define GL_FRONT_LEFT                           0x0400
#define GL_FRONT_RIGHT                          0x0401
#define GL_BACK_LEFT                            0x0402
#define GL_BACK_RIGHT                           0x0403
#define GL_AUX0                                 0x0409
#define GL_AUX1                                 0x040A
#define GL_AUX2                                 0x040B
#define GL_AUX3                                 0x040C
#define GL_COLOR_INDEX                          0x1900
#define GL_RED                                  0x1903
#define GL_GREEN                                0x1904
#define GL_BLUE                                 0x1905
#define GL_ALPHA                                0x1906
#define GL_LUMINANCE                            0x1909
#define GL_LUMINANCE_ALPHA                      0x190A
#define GL_ALPHA_BITS                           0x0D55
#define GL_RED_BITS                             0x0D52
#define GL_GREEN_BITS                           0x0D53
#define GL_BLUE_BITS                            0x0D54
#define GL_INDEX_BITS                           0x0D51
#define GL_SUBPIXEL_BITS                        0x0D50
#define GL_AUX_BUFFERS                          0x0C00
#define GL_READ_BUFFER                          0x0C02
#define GL_DRAW_BUFFER                          0x0C01
#define GL_DOUBLEBUFFER                         0x0C32
#define GL_STEREO                               0x0C33
#define GL_BITMAP                               0x1A00
#define GL_COLOR                                0x1800
#define GL_DEPTH                                0x1801
#define GL_STENCIL                              0x1802
#define GL_DITHER                               0x0BD0
#define GL_RGB                                  0x1907
#define GL_RGBA                                 0x1908
#define GL_MAX_LIST_NESTING                     0x0B31
#define GL_MAX_EVAL_ORDER                       0x0D30
#define GL_MAX_LIGHTS                           0x0D31
#define GL_MAX_CLIP_PLANES                      0x0D32
#define GL_MAX_TEXTURE_SIZE                     0x0D33
#define GL_MAX_PIXEL_MAP_TABLE                  0x0D34
#define GL_MAX_ATTRIB_STACK_DEPTH               0x0D35
#define GL_MAX_MODELVIEW_STACK_DEPTH            0x0D36
#define GL_MAX_NAME_STACK_DEPTH                 0x0D37
#define GL_MAX_PROJECTION_STACK_DEPTH           0x0D38
#define GL_MAX_TEXTURE_STACK_DEPTH              0x0D39
#define GL_MAX_VIEWPORT_DIMS                    0x0D3A
#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH        0x0D3B
#define GL_ATTRIB_STACK_DEPTH                   0x0BB0
#define GL_CLIENT_ATTRIB_STACK_DEPTH            0x0BB1
#define GL_COLOR_CLEAR_VALUE                    0x0C22
#define GL_COLOR_WRITEMASK                      0x0C23
#define GL_CURRENT_INDEX                        0x0B01
#define GL_CURRENT_COLOR                        0x0B00
#define GL_CURRENT_NORMAL                       0x0B02
#define GL_CURRENT_RASTER_COLOR                 0x0B04
#define GL_CURRENT_RASTER_DISTANCE              0x0B09
#define GL_CURRENT_RASTER_INDEX                 0x0B05
#define GL_CURRENT_RASTER_POSITION              0x0B07
#define GL_CURRENT_RASTER_TEXTURE_COORDS        0x0B06
#define GL_CURRENT_RASTER_POSITION_VALID        0x0B08
#define GL_CURRENT_TEXTURE_COORDS               0x0B03
#define GL_INDEX_CLEAR_VALUE                    0x0C20
#define GL_INDEX_MODE                           0x0C30
#define GL_INDEX_WRITEMASK                      0x0C21
#define GL_MODELVIEW_MATRIX                     0x0BA6
#define GL_MODELVIEW_STACK_DEPTH                0x0BA3
#define GL_NAME_STACK_DEPTH                     0x0D70
#define GL_PROJECTION_MATRIX                    0x0BA7
#define GL_PROJECTION_STACK_DEPTH               0x0BA4
#define GL_RENDER_MODE                          0x0C40
#define GL_RGBA_MODE                            0x0C31
#define GL_TEXTURE_MATRIX                       0x0BA8
#define GL_TEXTURE_STACK_DEPTH                  0x0BA5
#define GL_VIEWPORT                             0x0BA2
#define GL_AUTO_NORMAL                          0x0D80
#define GL_MAP1_COLOR_4                         0x0D90
#define GL_MAP1_INDEX                           0x0D91
#define GL_MAP1_NORMAL                          0x0D92
#define GL_MAP1_TEXTURE_COORD_1                 0x0D93
#define GL_MAP1_TEXTURE_COORD_2                 0x0D94
#define GL_MAP1_TEXTURE_COORD_3                 0x0D95
#define GL_MAP1_TEXTURE_COORD_4                 0x0D96
#define GL_MAP1_VERTEX_3                        0x0D97
#define GL_MAP1_VERTEX_4                        0x0D98
#define GL_MAP2_COLOR_4                         0x0DB0
#define GL_MAP2_INDEX                           0x0DB1
#define GL_MAP2_NORMAL                          0x0DB2
#define GL_MAP2_TEXTURE_COORD_1                 0x0DB3
#define GL_MAP2_TEXTURE_COORD_2                 0x0DB4
#define GL_MAP2_TEXTURE_COORD_3                 0x0DB5
#define GL_MAP2_TEXTURE_COORD_4                 0x0DB6
#define GL_MAP2_VERTEX_3                        0x0DB7
#define GL_MAP2_VERTEX_4                        0x0DB8
#define GL_MAP1_GRID_DOMAIN                     0x0DD0
#define GL_MAP1_GRID_SEGMENTS                   0x0DD1
#define GL_MAP2_GRID_DOMAIN                     0x0DD2
#define GL_MAP2_GRID_SEGMENTS                   0x0DD3
#define GL_COEFF                                0x0A00
#define GL_ORDER                                0x0A01
#define GL_DOMAIN                               0x0A02
#define GL_PERSPECTIVE_CORRECTION_HINT          0x0C50
#define GL_POINT_SMOOTH_HINT                    0x0C51
#define GL_LINE_SMOOTH_HINT                     0x0C52
#define GL_POLYGON_SMOOTH_HINT                  0x0C53
#define GL_FOG_HINT                             0x0C54
#define GL_DONT_CARE                            0x1100
#define GL_FASTEST                              0x1101
#define GL_NICEST                               0x1102
#define GL_SCISSOR_BOX                          0x0C10
#define GL_SCISSOR_TEST                         0x0C11
#define GL_MAP_COLOR                            0x0D10
#define GL_MAP_STENCIL                          0x0D11
#define GL_INDEX_SHIFT                          0x0D12
#define GL_INDEX_OFFSET                         0x0D13
#define GL_RED_SCALE                            0x0D14
#define GL_RED_BIAS                             0x0D15
#define GL_GREEN_SCALE                          0x0D18
#define GL_GREEN_BIAS                           0x0D19
#define GL_BLUE_SCALE                           0x0D1A
#define GL_BLUE_BIAS                            0x0D1B
#define GL_ALPHA_SCALE                          0x0D1C
#define GL_ALPHA_BIAS                           0x0D1D
#define GL_DEPTH_SCALE                          0x0D1E
#define GL_DEPTH_BIAS                           0x0D1F
#define GL_PIXEL_MAP_S_TO_S_SIZE                0x0CB1
#define GL_PIXEL_MAP_I_TO_I_SIZE                0x0CB0
#define GL_PIXEL_MAP_I_TO_R_SIZE                0x0CB2
#define GL_PIXEL_MAP_I_TO_G_SIZE                0x0CB3
#define GL_PIXEL_MAP_I_TO_B_SIZE                0x0CB4
#define GL_PIXEL_MAP_I_TO_A_SIZE                0x0CB5
#define GL_PIXEL_MAP_R_TO_R_SIZE                0x0CB6
#define GL_PIXEL_MAP_G_TO_G_SIZE                0x0CB7
#define GL_PIXEL_MAP_B_TO_B_SIZE                0x0CB8
#define GL_PIXEL_MAP_A_TO_A_SIZE                0x0CB9
#define GL_PIXEL_MAP_S_TO_S                     0x0C71
#define GL_PIXEL_MAP_I_TO_I                     0x0C70
#define GL_PIXEL_MAP_I_TO_R                     0x0C72
#define GL_PIXEL_MAP_I_TO_G                     0x0C73
#define GL_PIXEL_MAP_I_TO_B                     0x0C74
#define GL_PIXEL_MAP_I_TO_A                     0x0C75
#define GL_PIXEL_MAP_R_TO_R                     0x0C76
#define GL_PIXEL_MAP_G_TO_G                     0x0C77
#define GL_PIXEL_MAP_B_TO_B                     0x0C78
#define GL_PIXEL_MAP_A_TO_A                     0x0C79
#define GL_PACK_ALIGNMENT                       0x0D05
#define GL_PACK_LSB_FIRST                       0x0D01
#define GL_PACK_ROW_LENGTH                      0x0D02
#define GL_PACK_SKIP_PIXELS                     0x0D04
#define GL_PACK_SKIP_ROWS                       0x0D03
#define GL_PACK_SWAP_BYTES                      0x0D00
#define GL_UNPACK_ALIGNMENT                     0x0CF5
#define GL_UNPACK_LSB_FIRST                     0x0CF1
#define GL_UNPACK_ROW_LENGTH                    0x0CF2
#define GL_UNPACK_SKIP_PIXELS                   0x0CF4
#define GL_UNPACK_SKIP_ROWS                     0x0CF3
#define GL_UNPACK_SWAP_BYTES                    0x0CF0
#define GL_ZOOM_X                               0x0D16
#define GL_ZOOM_Y                               0x0D17
#define GL_TEXTURE_ENV                          0x2300
#define GL_TEXTURE_ENV_MODE                     0x2200
#define GL_TEXTURE_1D                           0x0DE0
#define GL_TEXTURE_2D                           0x0DE1
#define GL_TEXTURE_WRAP_S                       0x2802
#define GL_TEXTURE_WRAP_T                       0x2803
#define GL_TEXTURE_MAG_FILTER                   0x2800
#define GL_TEXTURE_MIN_FILTER                   0x2801
#define GL_TEXTURE_ENV_COLOR                    0x2201
#define GL_TEXTURE_GEN_S                        0x0C60
#define GL_TEXTURE_GEN_T                        0x0C61
#define GL_TEXTURE_GEN_R                        0x0C62
#define GL_TEXTURE_GEN_Q                        0x0C63
#define GL_TEXTURE_GEN_MODE                     0x2500
#define GL_TEXTURE_BORDER_COLOR                 0x1004
#define GL_TEXTURE_WIDTH                        0x1000
#define GL_TEXTURE_HEIGHT                       0x1001
#define GL_TEXTURE_BORDER                       0x1005
#define GL_TEXTURE_COMPONENTS                   0x1003
#define GL_TEXTURE_RED_SIZE                     0x805C
#define GL_TEXTURE_GREEN_SIZE                   0x805D
#define GL_TEXTURE_BLUE_SIZE                    0x805E
#define GL_TEXTURE_ALPHA_SIZE                   0x805F
#define GL_TEXTURE_LUMINANCE_SIZE               0x8060
#define GL_TEXTURE_INTENSITY_SIZE               0x8061
#define GL_NEAREST_MIPMAP_NEAREST               0x2700
#define GL_NEAREST_MIPMAP_LINEAR                0x2702
#define GL_LINEAR_MIPMAP_NEAREST                0x2701
#define GL_LINEAR_MIPMAP_LINEAR                 0x2703
#define GL_OBJECT_LINEAR                        0x2401
#define GL_OBJECT_PLANE                         0x2501
#define GL_EYE_LINEAR                           0x2400
#define GL_EYE_PLANE                            0x2502
#define GL_SPHERE_MAP                           0x2402
#define GL_DECAL                                0x2101
#define GL_MODULATE                             0x2100
#define GL_NEAREST                              0x2600
#define GL_REPEAT                               0x2901
#define GL_CLAMP                                0x2900
#define GL_S                                    0x2000
#define GL_T                                    0x2001
#define GL_R                                    0x2002
#define GL_Q                                    0x2003
#define GL_VENDOR                               0x1F00
#define GL_RENDERER                             0x1F01
#define GL_VERSION                              0x1F02
#define GL_EXTENSIONS                           0x1F03
#define GL_NO_ERROR                             0
#define GL_INVALID_ENUM                         0x0500
#define GL_INVALID_VALUE                        0x0501
#define GL_INVALID_OPERATION                    0x0502
#define GL_STACK_OVERFLOW                       0x0503
#define GL_STACK_UNDERFLOW                      0x0504
#define GL_OUT_OF_MEMORY                        0x0505
#define GL_CURRENT_BIT                          0x00000001
#define GL_POINT_BIT                            0x00000002
#define GL_LINE_BIT                             0x00000004
#define GL_POLYGON_BIT                          0x00000008
#define GL_POLYGON_STIPPLE_BIT                  0x00000010
#define GL_PIXEL_MODE_BIT                       0x00000020
#define GL_LIGHTING_BIT                         0x00000040
#define GL_FOG_BIT                              0x00000080
#define GL_DEPTH_BUFFER_BIT                     0x00000100
#define GL_ACCUM_BUFFER_BIT                     0x00000200
#define GL_STENCIL_BUFFER_BIT                   0x00000400
#define GL_VIEWPORT_BIT                         0x00000800
#define GL_TRANSFORM_BIT                        0x00001000
#define GL_ENABLE_BIT                           0x00002000
#define GL_COLOR_BUFFER_BIT                     0x00004000
#define GL_HINT_BIT                             0x00008000
#define GL_EVAL_BIT                             0x00010000
#define GL_LIST_BIT                             0x00020000
#define GL_TEXTURE_BIT                          0x00040000
#define GL_SCISSOR_BIT                          0x00080000
#define GL_ALL_ATTRIB_BITS                      0xFFFFFFFF
#define GL_PROXY_TEXTURE_1D                     0x8063
#define GL_PROXY_TEXTURE_2D                     0x8064
#define GL_TEXTURE_PRIORITY                     0x8066
#define GL_TEXTURE_RESIDENT                     0x8067
#define GL_TEXTURE_BINDING_1D                   0x8068
#define GL_TEXTURE_BINDING_2D                   0x8069
#define GL_TEXTURE_INTERNAL_FORMAT              0x1003
#define GL_ALPHA4                               0x803B
#define GL_ALPHA8                               0x803C
#define GL_ALPHA12                              0x803D
#define GL_ALPHA16                              0x803E
#define GL_LUMINANCE4                           0x803F
#define GL_LUMINANCE8                           0x8040
#define GL_LUMINANCE12                          0x8041
#define GL_LUMINANCE16                          0x8042
#define GL_LUMINANCE4_ALPHA4                    0x8043
#define GL_LUMINANCE6_ALPHA2                    0x8044
#define GL_LUMINANCE8_ALPHA8                    0x8045
#define GL_LUMINANCE12_ALPHA4                   0x8046
#define GL_LUMINANCE12_ALPHA12                  0x8047
#define GL_LUMINANCE16_ALPHA16                  0x8048
#define GL_INTENSITY                            0x8049
#define GL_INTENSITY4                           0x804A
#define GL_INTENSITY8                           0x804B
#define GL_INTENSITY12                          0x804C
#define GL_INTENSITY16                          0x804D
#define GL_R3_G3_B2                             0x2A10
#define GL_RGB4                                 0x804F
#define GL_RGB5                                 0x8050
#define GL_RGB8                                 0x8051
#define GL_RGB10                                0x8052
#define GL_RGB12                                0x8053
#define GL_RGB16                                0x8054
#define GL_RGBA2                                0x8055
#define GL_RGBA4                                0x8056
#define GL_RGB5_A1                              0x8057
#define GL_RGBA8                                0x8058
#define GL_RGB10_A2                             0x8059
#define GL_RGBA12                               0x805A
#define GL_RGBA16                               0x805B
#define GL_CLIENT_PIXEL_STORE_BIT               0x00000001
#define GL_CLIENT_VERTEX_ARRAY_BIT              0x00000002
#define GL_ALL_CLIENT_ATTRIB_BITS               0xFFFFFFFF
#define GL_CLIENT_ALL_ATTRIB_BITS               0xFFFFFFFF
#define GL_RESCALE_NORMAL                       0x803A
#define GL_CLAMP_TO_EDGE                        0x812F
#define GL_MAX_ELEMENTS_VERTICES                0x80E8
#define GL_MAX_ELEMENTS_INDICES                 0x80E9
#define GL_BGR                                  0x80E0
#define GL_BGRA                                 0x80E1
#define GL_UNSIGNED_BYTE_3_3_2                  0x8032
#define GL_UNSIGNED_BYTE_2_3_3_REV              0x8362
#define GL_UNSIGNED_SHORT_5_6_5                 0x8363
#define GL_UNSIGNED_SHORT_5_6_5_REV             0x8364
#define GL_UNSIGNED_SHORT_4_4_4_4               0x8033
#define GL_UNSIGNED_SHORT_4_4_4_4_REV           0x8365
#define GL_UNSIGNED_SHORT_5_5_5_1               0x8034
#define GL_UNSIGNED_SHORT_1_5_5_5_REV           0x8366
#define GL_UNSIGNED_INT_8_8_8_8                 0x8035
#define GL_UNSIGNED_INT_8_8_8_8_REV             0x8367
#define GL_UNSIGNED_INT_10_10_10_2              0x8036
#define GL_UNSIGNED_INT_2_10_10_10_REV          0x8368
#define GL_LIGHT_MODEL_COLOR_CONTROL            0x81F8
#define GL_SINGLE_COLOR                         0x81F9
#define GL_SEPARATE_SPECULAR_COLOR              0x81FA
#define GL_TEXTURE_MIN_LOD                      0x813A
#define GL_TEXTURE_MAX_LOD                      0x813B
#define GL_TEXTURE_BASE_LEVEL                   0x813C
#define GL_TEXTURE_MAX_LEVEL                    0x813D
#define GL_SMOOTH_POINT_SIZE_RANGE              0x0B12
#define GL_SMOOTH_POINT_SIZE_GRANULARITY        0x0B13
#define GL_SMOOTH_LINE_WIDTH_RANGE              0x0B22
#define GL_SMOOTH_LINE_WIDTH_GRANULARITY        0x0B23
#define GL_ALIASED_POINT_SIZE_RANGE             0x846D
#define GL_ALIASED_LINE_WIDTH_RANGE             0x846E
#define GL_PACK_SKIP_IMAGES                     0x806B
#define GL_PACK_IMAGE_HEIGHT                    0x806C
#define GL_UNPACK_SKIP_IMAGES                   0x806D
#define GL_UNPACK_IMAGE_HEIGHT                  0x806E
#define GL_TEXTURE_3D                           0x806F
#define GL_PROXY_TEXTURE_3D                     0x8070
#define GL_TEXTURE_DEPTH                        0x8071
#define GL_TEXTURE_WRAP_R                       0x8072
#define GL_MAX_3D_TEXTURE_SIZE                  0x8073
#define GL_TEXTURE_BINDING_3D                   0x806A
#define GL_CONSTANT_COLOR                       0x8001
#define GL_ONE_MINUS_CONSTANT_COLOR             0x8002
#define GL_CONSTANT_ALPHA                       0x8003
#define GL_ONE_MINUS_CONSTANT_ALPHA             0x8004
#define GL_COLOR_TABLE                          0x80D0
#define GL_POST_CONVOLUTION_COLOR_TABLE         0x80D1
#define GL_POST_COLOR_MATRIX_COLOR_TABLE        0x80D2
#define GL_PROXY_COLOR_TABLE                    0x80D3
#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE   0x80D4
#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE  0x80D5
#define GL_COLOR_TABLE_SCALE                    0x80D6
#define GL_COLOR_TABLE_BIAS                     0x80D7
#define GL_COLOR_TABLE_FORMAT                   0x80D8
#define GL_COLOR_TABLE_WIDTH                    0x80D9
#define GL_COLOR_TABLE_RED_SIZE                 0x80DA
#define GL_COLOR_TABLE_GREEN_SIZE               0x80DB
#define GL_COLOR_TABLE_BLUE_SIZE                0x80DC
#define GL_COLOR_TABLE_ALPHA_SIZE               0x80DD
#define GL_COLOR_TABLE_LUMINANCE_SIZE           0x80DE
#define GL_COLOR_TABLE_INTENSITY_SIZE           0x80DF
#define GL_CONVOLUTION_1D                       0x8010
#define GL_CONVOLUTION_2D                       0x8011
#define GL_SEPARABLE_2D                         0x8012
#define GL_CONVOLUTION_BORDER_MODE              0x8013
#define GL_CONVOLUTION_FILTER_SCALE             0x8014
#define GL_CONVOLUTION_FILTER_BIAS              0x8015
#define GL_REDUCE                               0x8016
#define GL_CONVOLUTION_FORMAT                   0x8017
#define GL_CONVOLUTION_WIDTH                    0x8018
#define GL_CONVOLUTION_HEIGHT                   0x8019
#define GL_MAX_CONVOLUTION_WIDTH                0x801A
#define GL_MAX_CONVOLUTION_HEIGHT               0x801B
#define GL_POST_CONVOLUTION_RED_SCALE           0x801C
#define GL_POST_CONVOLUTION_GREEN_SCALE         0x801D
#define GL_POST_CONVOLUTION_BLUE_SCALE          0x801E
#define GL_POST_CONVOLUTION_ALPHA_SCALE         0x801F
#define GL_POST_CONVOLUTION_RED_BIAS            0x8020
#define GL_POST_CONVOLUTION_GREEN_BIAS          0x8021
#define GL_POST_CONVOLUTION_BLUE_BIAS           0x8022
#define GL_POST_CONVOLUTION_ALPHA_BIAS          0x8023
#define GL_CONSTANT_BORDER                      0x8151
#define GL_REPLICATE_BORDER                     0x8153
#define GL_CONVOLUTION_BORDER_COLOR             0x8154
#define GL_COLOR_MATRIX                         0x80B1
#define GL_COLOR_MATRIX_STACK_DEPTH             0x80B2
#define GL_MAX_COLOR_MATRIX_STACK_DEPTH         0x80B3
#define GL_POST_COLOR_MATRIX_RED_SCALE          0x80B4
#define GL_POST_COLOR_MATRIX_GREEN_SCALE        0x80B5
#define GL_POST_COLOR_MATRIX_BLUE_SCALE         0x80B6
#define GL_POST_COLOR_MATRIX_ALPHA_SCALE        0x80B7
#define GL_POST_COLOR_MATRIX_RED_BIAS           0x80B8
#define GL_POST_COLOR_MATRIX_GREEN_BIAS         0x80B9
#define GL_POST_COLOR_MATRIX_BLUE_BIAS          0x80BA
#define GL_POST_COLOR_MATRIX_ALPHA_BIAS         0x80BB
#define GL_HISTOGRAM                            0x8024
#define GL_PROXY_HISTOGRAM                      0x8025
#define GL_HISTOGRAM_WIDTH                      0x8026
#define GL_HISTOGRAM_FORMAT                     0x8027
#define GL_HISTOGRAM_RED_SIZE                   0x8028
#define GL_HISTOGRAM_GREEN_SIZE                 0x8029
#define GL_HISTOGRAM_BLUE_SIZE                  0x802A
#define GL_HISTOGRAM_ALPHA_SIZE                 0x802B
#define GL_HISTOGRAM_LUMINANCE_SIZE             0x802C
#define GL_HISTOGRAM_SINK                       0x802D
#define GL_MINMAX                               0x802E
#define GL_MINMAX_FORMAT                        0x802F
#define GL_MINMAX_SINK                          0x8030
#define GL_TABLE_TOO_LARGE                      0x8031
#define GL_BLEND_EQUATION                       0x8009
#define GL_MIN                                  0x8007
#define GL_MAX                                  0x8008
#define GL_FUNC_ADD                             0x8006
#define GL_FUNC_SUBTRACT                        0x800A
#define GL_FUNC_REVERSE_SUBTRACT                0x800B
#define GL_BLEND_COLOR                          0x8005
#define GL_TEXTURE0                             0x84C0
#define GL_TEXTURE1                             0x84C1
#define GL_TEXTURE2                             0x84C2
#define GL_TEXTURE3                             0x84C3
#define GL_TEXTURE4                             0x84C4
#define GL_TEXTURE5                             0x84C5
#define GL_TEXTURE6                             0x84C6
#define GL_TEXTURE7                             0x84C7
#define GL_TEXTURE8                             0x84C8
#define GL_TEXTURE9                             0x84C9
#define GL_TEXTURE10                            0x84CA
#define GL_TEXTURE11                            0x84CB
#define GL_TEXTURE12                            0x84CC
#define GL_TEXTURE13                            0x84CD
#define GL_TEXTURE14                            0x84CE
#define GL_TEXTURE15                            0x84CF
#define GL_TEXTURE16                            0x84D0
#define GL_TEXTURE17                            0x84D1
#define GL_TEXTURE18                            0x84D2
#define GL_TEXTURE19                            0x84D3
#define GL_TEXTURE20                            0x84D4
#define GL_TEXTURE21                            0x84D5
#define GL_TEXTURE22                            0x84D6
#define GL_TEXTURE23                            0x84D7
#define GL_TEXTURE24                            0x84D8
#define GL_TEXTURE25                            0x84D9
#define GL_TEXTURE26                            0x84DA
#define GL_TEXTURE27                            0x84DB
#define GL_TEXTURE28                            0x84DC
#define GL_TEXTURE29                            0x84DD
#define GL_TEXTURE30                            0x84DE
#define GL_TEXTURE31                            0x84DF
#define GL_ACTIVE_TEXTURE                       0x84E0
#define GL_CLIENT_ACTIVE_TEXTURE                0x84E1
#define GL_MAX_TEXTURE_UNITS                    0x84E2
#define GL_NORMAL_MAP                           0x8511
#define GL_REFLECTION_MAP                       0x8512
#define GL_TEXTURE_CUBE_MAP                     0x8513
#define GL_TEXTURE_BINDING_CUBE_MAP             0x8514
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X          0x8515
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X          0x8516
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y          0x8517
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y          0x8518
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z          0x8519
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z          0x851A
#define GL_PROXY_TEXTURE_CUBE_MAP               0x851B
#define GL_MAX_CUBE_MAP_TEXTURE_SIZE            0x851C
#define GL_COMPRESSED_ALPHA                     0x84E9
#define GL_COMPRESSED_LUMINANCE                 0x84EA
#define GL_COMPRESSED_LUMINANCE_ALPHA           0x84EB
#define GL_COMPRESSED_INTENSITY                 0x84EC
#define GL_COMPRESSED_RGB                       0x84ED
#define GL_COMPRESSED_RGBA                      0x84EE
#define GL_TEXTURE_COMPRESSION_HINT             0x84EF
#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE        0x86A0
#define GL_TEXTURE_COMPRESSED                   0x86A1
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS       0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS           0x86A3
#define GL_MULTISAMPLE                          0x809D
#define GL_SAMPLE_ALPHA_TO_COVERAGE             0x809E
#define GL_SAMPLE_ALPHA_TO_ONE                  0x809F
#define GL_SAMPLE_COVERAGE                      0x80A0
#define GL_SAMPLE_BUFFERS                       0x80A8
#define GL_SAMPLES                              0x80A9
#define GL_SAMPLE_COVERAGE_VALUE                0x80AA
#define GL_SAMPLE_COVERAGE_INVERT               0x80AB
#define GL_MULTISAMPLE_BIT                      0x20000000
#define GL_TRANSPOSE_MODELVIEW_MATRIX           0x84E3
#define GL_TRANSPOSE_PROJECTION_MATRIX          0x84E4
#define GL_TRANSPOSE_TEXTURE_MATRIX             0x84E5
#define GL_TRANSPOSE_COLOR_MATRIX               0x84E6
#define GL_COMBINE                              0x8570
#define GL_COMBINE_RGB                          0x8571
#define GL_COMBINE_ALPHA                        0x8572
#define GL_SOURCE0_RGB                          0x8580
#define GL_SOURCE1_RGB                          0x8581
#define GL_SOURCE2_RGB                          0x8582
#define GL_SOURCE0_ALPHA                        0x8588
#define GL_SOURCE1_ALPHA                        0x8589
#define GL_SOURCE2_ALPHA                        0x858A
#define GL_OPERAND0_RGB                         0x8590
#define GL_OPERAND1_RGB                         0x8591
#define GL_OPERAND2_RGB                         0x8592
#define GL_OPERAND0_ALPHA                       0x8598
#define GL_OPERAND1_ALPHA                       0x8599
#define GL_OPERAND2_ALPHA                       0x859A
#define GL_RGB_SCALE                            0x8573
#define GL_ADD_SIGNED                           0x8574
#define GL_INTERPOLATE                          0x8575
#define GL_SUBTRACT                             0x84E7
#define GL_CONSTANT                             0x8576
#define GL_PRIMARY_COLOR                        0x8577
#define GL_PREVIOUS                             0x8578
#define GL_DOT3_RGB                             0x86AE
#define GL_DOT3_RGBA                            0x86AF
#define GL_CLAMP_TO_BORDER                      0x812D
#define GL_ARB_multitexture 1
#define GL_TEXTURE0_ARB                         0x84C0
#define GL_TEXTURE1_ARB                         0x84C1
#define GL_TEXTURE2_ARB                         0x84C2
#define GL_TEXTURE3_ARB                         0x84C3
#define GL_TEXTURE4_ARB                         0x84C4
#define GL_TEXTURE5_ARB                         0x84C5
#define GL_TEXTURE6_ARB                         0x84C6
#define GL_TEXTURE7_ARB                         0x84C7
#define GL_TEXTURE8_ARB                         0x84C8
#define GL_TEXTURE9_ARB                         0x84C9
#define GL_TEXTURE10_ARB                        0x84CA
#define GL_TEXTURE11_ARB                        0x84CB
#define GL_TEXTURE12_ARB                        0x84CC
#define GL_TEXTURE13_ARB                        0x84CD
#define GL_TEXTURE14_ARB                        0x84CE
#define GL_TEXTURE15_ARB                        0x84CF
#define GL_TEXTURE16_ARB                        0x84D0
#define GL_TEXTURE17_ARB                        0x84D1
#define GL_TEXTURE18_ARB                        0x84D2
#define GL_TEXTURE19_ARB                        0x84D3
#define GL_TEXTURE20_ARB                        0x84D4
#define GL_TEXTURE21_ARB                        0x84D5
#define GL_TEXTURE22_ARB                        0x84D6
#define GL_TEXTURE23_ARB                        0x84D7
#define GL_TEXTURE24_ARB                        0x84D8
#define GL_TEXTURE25_ARB                        0x84D9
#define GL_TEXTURE26_ARB                        0x84DA
#define GL_TEXTURE27_ARB                        0x84DB
#define GL_TEXTURE28_ARB                        0x84DC
#define GL_TEXTURE29_ARB                        0x84DD
#define GL_TEXTURE30_ARB                        0x84DE
#define GL_TEXTURE31_ARB                        0x84DF
#define GL_ACTIVE_TEXTURE_ARB                   0x84E0
#define GL_CLIENT_ACTIVE_TEXTURE_ARB            0x84E1
#define GL_MAX_TEXTURE_UNITS_ARB                0x84E2
#define GL_MESA_packed_depth_stencil 1
#define GL_DEPTH_STENCIL_MESA                   0x8750
#define GL_UNSIGNED_INT_24_8_MESA               0x8751
#define GL_UNSIGNED_INT_8_24_REV_MESA           0x8752
#define GL_UNSIGNED_SHORT_15_1_MESA             0x8753
#define GL_UNSIGNED_SHORT_1_15_REV_MESA         0x8754
#define GL_ATI_blend_equation_separate 1
#define GL_ALPHA_BLEND_EQUATION_ATI             0x883D
#define GL_OES_EGL_image 1

#ifdef __cplusplus
}
#endif

#endif /* __NX_GL_H__ */

./include/libretro-common/include/glsym/switch/nx_glsym.h

#ifndef __NX_GLSYM_H__
#define __NX_GLSYM_H__

#ifdef __cplusplus
extern "C" {
#endif

typedef void *GLeglImageOES;
typedef void (APIENTRYP RGLSYMGLCLEARINDEXPROC) ( GLfloat c );
typedef void (APIENTRYP RGLSYMGLCLEARCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
typedef void (APIENTRYP RGLSYMGLCLEARPROC) ( GLbitfield mask );
typedef void (APIENTRYP RGLSYMGLINDEXMASKPROC) ( GLuint mask );
typedef void (APIENTRYP RGLSYMGLCOLORMASKPROC) ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha );
typedef void (APIENTRYP RGLSYMGLALPHAFUNCPROC) ( GLenum func, GLclampf ref );
typedef void (APIENTRYP RGLSYMGLBLENDFUNCPROC) ( GLenum sfactor, GLenum dfactor );
typedef void (APIENTRYP RGLSYMGLLOGICOPPROC) ( GLenum opcode );
typedef void (APIENTRYP RGLSYMGLCULLFACEPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLFRONTFACEPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLPOINTSIZEPROC) ( GLfloat size );
typedef void (APIENTRYP RGLSYMGLLINEWIDTHPROC) ( GLfloat width );
typedef void (APIENTRYP RGLSYMGLLINESTIPPLEPROC) ( GLint factor, GLushort pattern );
typedef void (APIENTRYP RGLSYMGLPOLYGONMODEPROC) ( GLenum face, GLenum mode );
typedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETPROC) ( GLfloat factor, GLfloat units );
typedef void (APIENTRYP RGLSYMGLPOLYGONSTIPPLEPROC) ( const GLubyte *mask );
typedef void (APIENTRYP RGLSYMGLGETPOLYGONSTIPPLEPROC) ( GLubyte *mask );
typedef void (APIENTRYP RGLSYMGLEDGEFLAGPROC) ( GLboolean flag );
typedef void (APIENTRYP RGLSYMGLEDGEFLAGVPROC) ( const GLboolean *flag );
typedef void (APIENTRYP RGLSYMGLSCISSORPROC) ( GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLCLIPPLANEPROC) ( GLenum plane, const GLdouble *equation );
typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEPROC) ( GLenum plane, GLdouble *equation );
typedef void (APIENTRYP RGLSYMGLDRAWBUFFERPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLREADBUFFERPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLENABLEPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLDISABLEPROC) ( GLenum cap );
typedef GLboolean (APIENTRYP RGLSYMGLISENABLEDPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLENABLECLIENTSTATEPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLDISABLECLIENTSTATEPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLGETBOOLEANVPROC) ( GLenum pname, GLboolean *params );
typedef void (APIENTRYP RGLSYMGLGETDOUBLEVPROC) ( GLenum pname, GLdouble *params );
typedef void (APIENTRYP RGLSYMGLGETFLOATVPROC) ( GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETINTEGERVPROC) ( GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLPUSHATTRIBPROC) ( GLbitfield mask );
typedef void (APIENTRYP RGLSYMGLPOPATTRIBPROC) ( void );
typedef void (APIENTRYP RGLSYMGLPUSHCLIENTATTRIBPROC) ( GLbitfield mask );
typedef void (APIENTRYP RGLSYMGLPOPCLIENTATTRIBPROC) ( void );
typedef GLint (APIENTRYP RGLSYMGLRENDERMODEPROC) ( GLenum mode );
typedef GLenum (APIENTRYP RGLSYMGLGETERRORPROC) ( void );
typedef const GLubyte * (APIENTRYP RGLSYMGLGETSTRINGPROC) ( GLenum name );
typedef void (APIENTRYP RGLSYMGLFINISHPROC) ( void );
typedef void (APIENTRYP RGLSYMGLFLUSHPROC) ( void );
typedef void (APIENTRYP RGLSYMGLHINTPROC) ( GLenum target, GLenum mode );
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHPROC) ( GLclampd depth );
typedef void (APIENTRYP RGLSYMGLDEPTHFUNCPROC) ( GLenum func );
typedef void (APIENTRYP RGLSYMGLDEPTHMASKPROC) ( GLboolean flag );
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEPROC) ( GLclampd near_val, GLclampd far_val );
typedef void (APIENTRYP RGLSYMGLCLEARACCUMPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
typedef void (APIENTRYP RGLSYMGLACCUMPROC) ( GLenum op, GLfloat value );
typedef void (APIENTRYP RGLSYMGLMATRIXMODEPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLORTHOPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );
typedef void (APIENTRYP RGLSYMGLFRUSTUMPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );
typedef void (APIENTRYP RGLSYMGLVIEWPORTPROC) ( GLint x, GLint y, GLsizei width, GLsizei height );
typedef void (APIENTRYP RGLSYMGLPUSHMATRIXPROC) ( void );
typedef void (APIENTRYP RGLSYMGLPOPMATRIXPROC) ( void );
typedef void (APIENTRYP RGLSYMGLLOADIDENTITYPROC) ( void );
typedef void (APIENTRYP RGLSYMGLLOADMATRIXDPROC) ( const GLdouble *m );
typedef void (APIENTRYP RGLSYMGLLOADMATRIXFPROC) ( const GLfloat *m );
typedef void (APIENTRYP RGLSYMGLMULTMATRIXDPROC) ( const GLdouble *m );
typedef void (APIENTRYP RGLSYMGLMULTMATRIXFPROC) ( const GLfloat *m );
typedef void (APIENTRYP RGLSYMGLROTATEDPROC) ( GLdouble angle, GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLROTATEFPROC) ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLSCALEDPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLSCALEFPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLTRANSLATEDPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLTRANSLATEFPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef GLboolean (APIENTRYP RGLSYMGLISLISTPROC) ( GLuint list );
typedef void (APIENTRYP RGLSYMGLDELETELISTSPROC) ( GLuint list, GLsizei range );
typedef GLuint (APIENTRYP RGLSYMGLGENLISTSPROC) ( GLsizei range );
typedef void (APIENTRYP RGLSYMGLNEWLISTPROC) ( GLuint list, GLenum mode );
typedef void (APIENTRYP RGLSYMGLENDLISTPROC) ( void );
typedef void (APIENTRYP RGLSYMGLCALLLISTPROC) ( GLuint list );
typedef void (APIENTRYP RGLSYMGLCALLLISTSPROC) ( GLsizei n, GLenum type, const GLvoid *lists );
typedef void (APIENTRYP RGLSYMGLLISTBASEPROC) ( GLuint base );
typedef void (APIENTRYP RGLSYMGLBEGINPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLENDPROC) ( void );
typedef void (APIENTRYP RGLSYMGLVERTEX2DPROC) ( GLdouble x, GLdouble y );
typedef void (APIENTRYP RGLSYMGLVERTEX2FPROC) ( GLfloat x, GLfloat y );
typedef void (APIENTRYP RGLSYMGLVERTEX2IPROC) ( GLint x, GLint y );
typedef void (APIENTRYP RGLSYMGLVERTEX2SPROC) ( GLshort x, GLshort y );
typedef void (APIENTRYP RGLSYMGLVERTEX3DPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLVERTEX3FPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLVERTEX3IPROC) ( GLint x, GLint y, GLint z );
typedef void (APIENTRYP RGLSYMGLVERTEX3SPROC) ( GLshort x, GLshort y, GLshort z );
typedef void (APIENTRYP RGLSYMGLVERTEX4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
typedef void (APIENTRYP RGLSYMGLVERTEX4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
typedef void (APIENTRYP RGLSYMGLVERTEX4IPROC) ( GLint x, GLint y, GLint z, GLint w );
typedef void (APIENTRYP RGLSYMGLVERTEX4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );
typedef void (APIENTRYP RGLSYMGLVERTEX2DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLVERTEX2FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLVERTEX2IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLVERTEX2SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3BPROC) ( GLbyte nx, GLbyte ny, GLbyte nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3DPROC) ( GLdouble nx, GLdouble ny, GLdouble nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3FPROC) ( GLfloat nx, GLfloat ny, GLfloat nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3IPROC) ( GLint nx, GLint ny, GLint nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3SPROC) ( GLshort nx, GLshort ny, GLshort nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3BVPROC) ( const GLbyte *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLINDEXDPROC) ( GLdouble c );
typedef void (APIENTRYP RGLSYMGLINDEXFPROC) ( GLfloat c );
typedef void (APIENTRYP RGLSYMGLINDEXIPROC) ( GLint c );
typedef void (APIENTRYP RGLSYMGLINDEXSPROC) ( GLshort c );
typedef void (APIENTRYP RGLSYMGLINDEXUBPROC) ( GLubyte c );
typedef void (APIENTRYP RGLSYMGLINDEXDVPROC) ( const GLdouble *c );
typedef void (APIENTRYP RGLSYMGLINDEXFVPROC) ( const GLfloat *c );
typedef void (APIENTRYP RGLSYMGLINDEXIVPROC) ( const GLint *c );
typedef void (APIENTRYP RGLSYMGLINDEXSVPROC) ( const GLshort *c );
typedef void (APIENTRYP RGLSYMGLINDEXUBVPROC) ( const GLubyte *c );
typedef void (APIENTRYP RGLSYMGLCOLOR3BPROC) ( GLbyte red, GLbyte green, GLbyte blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3DPROC) ( GLdouble red, GLdouble green, GLdouble blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3FPROC) ( GLfloat red, GLfloat green, GLfloat blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3IPROC) ( GLint red, GLint green, GLint blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3SPROC) ( GLshort red, GLshort green, GLshort blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3UBPROC) ( GLubyte red, GLubyte green, GLubyte blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3UIPROC) ( GLuint red, GLuint green, GLuint blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3USPROC) ( GLushort red, GLushort green, GLushort blue );
typedef void (APIENTRYP RGLSYMGLCOLOR4BPROC) ( GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4DPROC) ( GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4FPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4IPROC) ( GLint red, GLint green, GLint blue, GLint alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4SPROC) ( GLshort red, GLshort green, GLshort blue, GLshort alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4UBPROC) ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4UIPROC) ( GLuint red, GLuint green, GLuint blue, GLuint alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4USPROC) ( GLushort red, GLushort green, GLushort blue, GLushort alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR3BVPROC) ( const GLbyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3UBVPROC) ( const GLubyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3UIVPROC) ( const GLuint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3USVPROC) ( const GLushort *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4BVPROC) ( const GLbyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4UBVPROC) ( const GLubyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4UIVPROC) ( const GLuint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4USVPROC) ( const GLushort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1DPROC) ( GLdouble s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1FPROC) ( GLfloat s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1IPROC) ( GLint s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1SPROC) ( GLshort s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2DPROC) ( GLdouble s, GLdouble t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2FPROC) ( GLfloat s, GLfloat t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2IPROC) ( GLint s, GLint t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2SPROC) ( GLshort s, GLshort t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3DPROC) ( GLdouble s, GLdouble t, GLdouble r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3FPROC) ( GLfloat s, GLfloat t, GLfloat r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3IPROC) ( GLint s, GLint t, GLint r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3SPROC) ( GLshort s, GLshort t, GLshort r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4DPROC) ( GLdouble s, GLdouble t, GLdouble r, GLdouble q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4FPROC) ( GLfloat s, GLfloat t, GLfloat r, GLfloat q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4IPROC) ( GLint s, GLint t, GLint r, GLint q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4SPROC) ( GLshort s, GLshort t, GLshort r, GLshort q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2DPROC) ( GLdouble x, GLdouble y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2FPROC) ( GLfloat x, GLfloat y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2IPROC) ( GLint x, GLint y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2SPROC) ( GLshort x, GLshort y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3DPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3FPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3IPROC) ( GLint x, GLint y, GLint z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3SPROC) ( GLshort x, GLshort y, GLshort z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4IPROC) ( GLint x, GLint y, GLint z, GLint w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRECTDPROC) ( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 );
typedef void (APIENTRYP RGLSYMGLRECTFPROC) ( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 );
typedef void (APIENTRYP RGLSYMGLRECTIPROC) ( GLint x1, GLint y1, GLint x2, GLint y2 );
typedef void (APIENTRYP RGLSYMGLRECTSPROC) ( GLshort x1, GLshort y1, GLshort x2, GLshort y2 );
typedef void (APIENTRYP RGLSYMGLRECTDVPROC) ( const GLdouble *v1, const GLdouble *v2 );
typedef void (APIENTRYP RGLSYMGLRECTFVPROC) ( const GLfloat *v1, const GLfloat *v2 );
typedef void (APIENTRYP RGLSYMGLRECTIVPROC) ( const GLint *v1, const GLint *v2 );
typedef void (APIENTRYP RGLSYMGLRECTSVPROC) ( const GLshort *v1, const GLshort *v2 );
typedef void (APIENTRYP RGLSYMGLVERTEXPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLNORMALPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLCOLORPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLINDEXPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLTEXCOORDPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLEDGEFLAGPOINTERPROC) ( GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLGETPOINTERVPROC) ( GLenum pname, GLvoid **params );
typedef void (APIENTRYP RGLSYMGLARRAYELEMENTPROC) ( GLint i );
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSPROC) ( GLenum mode, GLint first, GLsizei count );
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSPROC) ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices );
typedef void (APIENTRYP RGLSYMGLINTERLEAVEDARRAYSPROC) ( GLenum format, GLsizei stride, const GLvoid *pointer );
typedef void (APIENTRYP RGLSYMGLSHADEMODELPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLLIGHTFPROC) ( GLenum light, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLLIGHTIPROC) ( GLenum light, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLLIGHTFVPROC) ( GLenum light, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLLIGHTIVPROC) ( GLenum light, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETLIGHTFVPROC) ( GLenum light, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETLIGHTIVPROC) ( GLenum light, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELFVPROC) ( GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELIVPROC) ( GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLMATERIALFPROC) ( GLenum face, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLMATERIALIPROC) ( GLenum face, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLMATERIALFVPROC) ( GLenum face, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLMATERIALIVPROC) ( GLenum face, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETMATERIALFVPROC) ( GLenum face, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETMATERIALIVPROC) ( GLenum face, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLCOLORMATERIALPROC) ( GLenum face, GLenum mode );
typedef void (APIENTRYP RGLSYMGLPIXELZOOMPROC) ( GLfloat xfactor, GLfloat yfactor );
typedef void (APIENTRYP RGLSYMGLPIXELSTOREFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLPIXELSTOREIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLPIXELMAPFVPROC) ( GLenum map, GLsizei mapsize, const GLfloat *values );
typedef void (APIENTRYP RGLSYMGLPIXELMAPUIVPROC) ( GLenum map, GLsizei mapsize, const GLuint *values );
typedef void (APIENTRYP RGLSYMGLPIXELMAPUSVPROC) ( GLenum map, GLsizei mapsize, const GLushort *values );
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPFVPROC) ( GLenum map, GLfloat *values );
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPUIVPROC) ( GLenum map, GLuint *values );
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPUSVPROC) ( GLenum map, GLushort *values );
typedef void (APIENTRYP RGLSYMGLBITMAPPROC) ( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap );
typedef void (APIENTRYP RGLSYMGLREADPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLDRAWPIXELSPROC) ( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLCOPYPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type );
typedef void (APIENTRYP RGLSYMGLSTENCILFUNCPROC) ( GLenum func, GLint ref, GLuint mask );
typedef void (APIENTRYP RGLSYMGLSTENCILMASKPROC) ( GLuint mask );
typedef void (APIENTRYP RGLSYMGLSTENCILOPPROC) ( GLenum fail, GLenum zfail, GLenum zpass );
typedef void (APIENTRYP RGLSYMGLCLEARSTENCILPROC) ( GLint s );
typedef void (APIENTRYP RGLSYMGLTEXGENDPROC) ( GLenum coord, GLenum pname, GLdouble param );
typedef void (APIENTRYP RGLSYMGLTEXGENFPROC) ( GLenum coord, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLTEXGENIPROC) ( GLenum coord, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLTEXGENDVPROC) ( GLenum coord, GLenum pname, const GLdouble *params );
typedef void (APIENTRYP RGLSYMGLTEXGENFVPROC) ( GLenum coord, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLTEXGENIVPROC) ( GLenum coord, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXGENDVPROC) ( GLenum coord, GLenum pname, GLdouble *params );
typedef void (APIENTRYP RGLSYMGLGETTEXGENFVPROC) ( GLenum coord, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETTEXGENIVPROC) ( GLenum coord, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLTEXENVFPROC) ( GLenum target, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLTEXENVIPROC) ( GLenum target, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLTEXENVFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLTEXENVIVPROC) ( GLenum target, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXENVFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETTEXENVIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERFPROC) ( GLenum target, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIPROC) ( GLenum target, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERFVPROC) ( GLenum target, GLint level, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERIVPROC) ( GLenum target, GLint level, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLTEXIMAGE1DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLTEXIMAGE2DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLGETTEXIMAGEPROC) ( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLGENTEXTURESPROC) ( GLsizei n, GLuint *textures );
typedef void (APIENTRYP RGLSYMGLDELETETEXTURESPROC) ( GLsizei n, const GLuint *textures);
typedef void (APIENTRYP RGLSYMGLBINDTEXTUREPROC) ( GLenum target, GLuint texture );
typedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESPROC) ( GLsizei n, const GLuint *textures, const GLclampf *priorities );
typedef GLboolean (APIENTRYP RGLSYMGLARETEXTURESRESIDENTPROC) ( GLsizei n, const GLuint *textures, GLboolean *residences );
typedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREPROC) ( GLuint texture );
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border );
typedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border );
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height );
typedef void (APIENTRYP RGLSYMGLMAP1DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points );
typedef void (APIENTRYP RGLSYMGLMAP1FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points );
typedef void (APIENTRYP RGLSYMGLMAP2DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points );
typedef void (APIENTRYP RGLSYMGLMAP2FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points );
typedef void (APIENTRYP RGLSYMGLGETMAPDVPROC) ( GLenum target, GLenum query, GLdouble *v );
typedef void (APIENTRYP RGLSYMGLGETMAPFVPROC) ( GLenum target, GLenum query, GLfloat *v );
typedef void (APIENTRYP RGLSYMGLGETMAPIVPROC) ( GLenum target, GLenum query, GLint *v );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1DPROC) ( GLdouble u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1FPROC) ( GLfloat u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1DVPROC) ( const GLdouble *u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1FVPROC) ( const GLfloat *u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2DPROC) ( GLdouble u, GLdouble v );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2FPROC) ( GLfloat u, GLfloat v );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2DVPROC) ( const GLdouble *u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2FVPROC) ( const GLfloat *u );
typedef void (APIENTRYP RGLSYMGLMAPGRID1DPROC) ( GLint un, GLdouble u1, GLdouble u2 );
typedef void (APIENTRYP RGLSYMGLMAPGRID1FPROC) ( GLint un, GLfloat u1, GLfloat u2 );
typedef void (APIENTRYP RGLSYMGLMAPGRID2DPROC) ( GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2 );
typedef void (APIENTRYP RGLSYMGLMAPGRID2FPROC) ( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 );
typedef void (APIENTRYP RGLSYMGLEVALPOINT1PROC) ( GLint i );
typedef void (APIENTRYP RGLSYMGLEVALPOINT2PROC) ( GLint i, GLint j );
typedef void (APIENTRYP RGLSYMGLEVALMESH1PROC) ( GLenum mode, GLint i1, GLint i2 );
typedef void (APIENTRYP RGLSYMGLEVALMESH2PROC) ( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 );
typedef void (APIENTRYP RGLSYMGLFOGFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLFOGIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLFOGFVPROC) ( GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLFOGIVPROC) ( GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERPROC) ( GLsizei size, GLenum type, GLfloat *buffer );
typedef void (APIENTRYP RGLSYMGLPASSTHROUGHPROC) ( GLfloat token );
typedef void (APIENTRYP RGLSYMGLSELECTBUFFERPROC) ( GLsizei size, GLuint *buffer );
typedef void (APIENTRYP RGLSYMGLINITNAMESPROC) ( void );
typedef void (APIENTRYP RGLSYMGLLOADNAMEPROC) ( GLuint name );
typedef void (APIENTRYP RGLSYMGLPUSHNAMEPROC) ( GLuint name );
typedef void (APIENTRYP RGLSYMGLPOPNAMEPROC) ( void );
typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) ( GLenum mode, GLuint start,GLuint end, GLsizei count, GLenum type, const GLvoid *indices );
typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height );
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table );
typedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) ( GLenum target, GLenum format, GLenum type, GLvoid *table );
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
typedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) ( GLenum target, GLsizei width, GLenum internalformat, GLboolean sink );
typedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) ( GLenum target );
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values );
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLMINMAXPROC) ( GLenum target, GLenum internalformat,GLboolean sink );
typedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) ( GLenum target );
typedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values );
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLenum format, GLenum type,const GLvoid *image );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *image );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) ( GLenum target, GLenum pname,GLfloat params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) ( GLenum target, GLenum pname,GLint params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,const GLint *params );
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width,GLsizei height);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *image );
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,GLint *params );
typedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *row, const GLvoid *column );
typedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *row, GLvoid *column, GLvoid *span );
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) ( GLenum texture );
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) ( GLenum texture );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) ( GLenum target, GLint lod, GLvoid *img );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) ( GLenum target, GLdouble s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) ( GLenum target, GLfloat s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) ( GLenum target, GLint s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) ( GLenum target, GLshort s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) ( GLenum target, GLdouble s, GLdouble t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) ( GLenum target, GLfloat s, GLfloat t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) ( GLenum target, GLint s, GLint t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) ( GLenum target, GLshort s, GLshort t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) ( GLenum target, GLint s, GLint t, GLint r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) ( GLenum target, GLint s, GLint t, GLint r, GLint q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r, GLshort q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) ( GLclampf value, GLboolean invert );
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
typedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);

RGLSYMGLCLEARINDEXPROC glClearIndex;
RGLSYMGLCLEARCOLORPROC glClearColor;
RGLSYMGLCLEARPROC glClear;
RGLSYMGLINDEXMASKPROC glIndexMask;
RGLSYMGLCOLORMASKPROC glColorMask;
RGLSYMGLALPHAFUNCPROC glAlphaFunc;
RGLSYMGLBLENDFUNCPROC glBlendFunc;
RGLSYMGLLOGICOPPROC glLogicOp;
RGLSYMGLCULLFACEPROC glCullFace;
RGLSYMGLFRONTFACEPROC glFrontFace;
RGLSYMGLPOINTSIZEPROC glPointSize;
RGLSYMGLLINEWIDTHPROC glLineWidth;
RGLSYMGLLINESTIPPLEPROC glLineStipple;
RGLSYMGLPOLYGONMODEPROC glPolygonMode;
RGLSYMGLPOLYGONOFFSETPROC glPolygonOffset;
RGLSYMGLPOLYGONSTIPPLEPROC glPolygonStipple;
RGLSYMGLGETPOLYGONSTIPPLEPROC glGetPolygonStipple;
RGLSYMGLEDGEFLAGPROC glEdgeFlag;
RGLSYMGLEDGEFLAGVPROC glEdgeFlagv;
RGLSYMGLSCISSORPROC glScissor;
RGLSYMGLCLIPPLANEPROC glClipPlane;
RGLSYMGLGETCLIPPLANEPROC glGetClipPlane;
RGLSYMGLDRAWBUFFERPROC glDrawBuffer;
RGLSYMGLREADBUFFERPROC glReadBuffer;
RGLSYMGLENABLEPROC glEnable;
RGLSYMGLDISABLEPROC glDisable;
RGLSYMGLISENABLEDPROC glIsEnabled;
RGLSYMGLENABLECLIENTSTATEPROC glEnableClientState;
RGLSYMGLDISABLECLIENTSTATEPROC glDisableClientState;
RGLSYMGLGETBOOLEANVPROC glGetBooleanv;
RGLSYMGLGETDOUBLEVPROC glGetDoublev;
RGLSYMGLGETFLOATVPROC glGetFloatv;
RGLSYMGLGETINTEGERVPROC glGetIntegerv;
RGLSYMGLPUSHATTRIBPROC glPushAttrib;
RGLSYMGLPOPATTRIBPROC glPopAttrib;
RGLSYMGLPUSHCLIENTATTRIBPROC glPushClientAttrib;
RGLSYMGLPOPCLIENTATTRIBPROC glPopClientAttrib;
RGLSYMGLRENDERMODEPROC glRenderMode;
RGLSYMGLGETERRORPROC glGetError;
RGLSYMGLGETSTRINGPROC glGetString;
RGLSYMGLFINISHPROC glFinish;
RGLSYMGLFLUSHPROC glFlush;
RGLSYMGLHINTPROC glHint;
RGLSYMGLCLEARDEPTHPROC glClearDepth;
RGLSYMGLDEPTHFUNCPROC glDepthFunc;
RGLSYMGLDEPTHMASKPROC glDepthMask;
RGLSYMGLDEPTHRANGEPROC glDepthRange;
RGLSYMGLCLEARACCUMPROC glClearAccum;
RGLSYMGLACCUMPROC glAccum;
RGLSYMGLMATRIXMODEPROC glMatrixMode;
RGLSYMGLORTHOPROC glOrtho;
RGLSYMGLFRUSTUMPROC glFrustum;
RGLSYMGLVIEWPORTPROC glViewport;
RGLSYMGLPUSHMATRIXPROC glPushMatrix;
RGLSYMGLPOPMATRIXPROC glPopMatrix;
RGLSYMGLLOADIDENTITYPROC glLoadIdentity;
RGLSYMGLLOADMATRIXDPROC glLoadMatrixd;
RGLSYMGLLOADMATRIXFPROC glLoadMatrixf;
RGLSYMGLMULTMATRIXDPROC glMultMatrixd;
RGLSYMGLMULTMATRIXFPROC glMultMatrixf;
RGLSYMGLROTATEDPROC glRotated;
RGLSYMGLROTATEFPROC glRotatef;
RGLSYMGLSCALEDPROC glScaled;
RGLSYMGLSCALEFPROC glScalef;
RGLSYMGLTRANSLATEDPROC glTranslated;
RGLSYMGLTRANSLATEFPROC glTranslatef;
RGLSYMGLISLISTPROC glIsList;
RGLSYMGLDELETELISTSPROC glDeleteLists;
RGLSYMGLGENLISTSPROC glGenLists;
RGLSYMGLNEWLISTPROC glNewList;
RGLSYMGLENDLISTPROC glEndList;
RGLSYMGLCALLLISTPROC glCallList;
RGLSYMGLCALLLISTSPROC glCallLists;
RGLSYMGLLISTBASEPROC glListBase;
RGLSYMGLBEGINPROC glBegin;
RGLSYMGLENDPROC glEnd;
RGLSYMGLVERTEX2DPROC glVertex2d;
RGLSYMGLVERTEX2FPROC glVertex2f;
RGLSYMGLVERTEX2IPROC glVertex2i;
RGLSYMGLVERTEX2SPROC glVertex2s;
RGLSYMGLVERTEX3DPROC glVertex3d;
RGLSYMGLVERTEX3FPROC glVertex3f;
RGLSYMGLVERTEX3IPROC glVertex3i;
RGLSYMGLVERTEX3SPROC glVertex3s;
RGLSYMGLVERTEX4DPROC glVertex4d;
RGLSYMGLVERTEX4FPROC glVertex4f;
RGLSYMGLVERTEX4IPROC glVertex4i;
RGLSYMGLVERTEX4SPROC glVertex4s;
RGLSYMGLVERTEX2DVPROC glVertex2dv;
RGLSYMGLVERTEX2FVPROC glVertex2fv;
RGLSYMGLVERTEX2IVPROC glVertex2iv;
RGLSYMGLVERTEX2SVPROC glVertex2sv;
RGLSYMGLVERTEX3DVPROC glVertex3dv;
RGLSYMGLVERTEX3FVPROC glVertex3fv;
RGLSYMGLVERTEX3IVPROC glVertex3iv;
RGLSYMGLVERTEX3SVPROC glVertex3sv;
RGLSYMGLVERTEX4DVPROC glVertex4dv;
RGLSYMGLVERTEX4FVPROC glVertex4fv;
RGLSYMGLVERTEX4IVPROC glVertex4iv;
RGLSYMGLVERTEX4SVPROC glVertex4sv;
RGLSYMGLNORMAL3BPROC glNormal3b;
RGLSYMGLNORMAL3DPROC glNormal3d;
RGLSYMGLNORMAL3FPROC glNormal3f;
RGLSYMGLNORMAL3IPROC glNormal3i;
RGLSYMGLNORMAL3SPROC glNormal3s;
RGLSYMGLNORMAL3BVPROC glNormal3bv;
RGLSYMGLNORMAL3DVPROC glNormal3dv;
RGLSYMGLNORMAL3FVPROC glNormal3fv;
RGLSYMGLNORMAL3IVPROC glNormal3iv;
RGLSYMGLNORMAL3SVPROC glNormal3sv;
RGLSYMGLINDEXDPROC glIndexd;
RGLSYMGLINDEXFPROC glIndexf;
RGLSYMGLINDEXIPROC glIndexi;
RGLSYMGLINDEXSPROC glIndexs;
RGLSYMGLINDEXUBPROC glIndexub;
RGLSYMGLINDEXDVPROC glIndexdv;
RGLSYMGLINDEXFVPROC glIndexfv;
RGLSYMGLINDEXIVPROC glIndexiv;
RGLSYMGLINDEXSVPROC glIndexsv;
RGLSYMGLINDEXUBVPROC glIndexubv;
RGLSYMGLCOLOR3BPROC glColor3b;
RGLSYMGLCOLOR3DPROC glColor3d;
RGLSYMGLCOLOR3FPROC glColor3f;
RGLSYMGLCOLOR3IPROC glColor3i;
RGLSYMGLCOLOR3SPROC glColor3s;
RGLSYMGLCOLOR3UBPROC glColor3ub;
RGLSYMGLCOLOR3UIPROC glColor3ui;
RGLSYMGLCOLOR3USPROC glColor3us;
RGLSYMGLCOLOR4BPROC glColor4b;
RGLSYMGLCOLOR4DPROC glColor4d;
RGLSYMGLCOLOR4FPROC glColor4f;
RGLSYMGLCOLOR4IPROC glColor4i;
RGLSYMGLCOLOR4SPROC glColor4s;
RGLSYMGLCOLOR4UBPROC glColor4ub;
RGLSYMGLCOLOR4UIPROC glColor4ui;
RGLSYMGLCOLOR4USPROC glColor4us;
RGLSYMGLCOLOR3BVPROC glColor3bv;
RGLSYMGLCOLOR3DVPROC glColor3dv;
RGLSYMGLCOLOR3FVPROC glColor3fv;
RGLSYMGLCOLOR3IVPROC glColor3iv;
RGLSYMGLCOLOR3SVPROC glColor3sv;
RGLSYMGLCOLOR3UBVPROC glColor3ubv;
RGLSYMGLCOLOR3UIVPROC glColor3uiv;
RGLSYMGLCOLOR3USVPROC glColor3usv;
RGLSYMGLCOLOR4BVPROC glColor4bv;
RGLSYMGLCOLOR4DVPROC glColor4dv;
RGLSYMGLCOLOR4FVPROC glColor4fv;
RGLSYMGLCOLOR4IVPROC glColor4iv;
RGLSYMGLCOLOR4SVPROC glColor4sv;
RGLSYMGLCOLOR4UBVPROC glColor4ubv;
RGLSYMGLCOLOR4UIVPROC glColor4uiv;
RGLSYMGLCOLOR4USVPROC glColor4usv;
RGLSYMGLTEXCOORD1DPROC glTexCoord1d;
RGLSYMGLTEXCOORD1FPROC glTexCoord1f;
RGLSYMGLTEXCOORD1IPROC glTexCoord1i;
RGLSYMGLTEXCOORD1SPROC glTexCoord1s;
RGLSYMGLTEXCOORD2DPROC glTexCoord2d;
RGLSYMGLTEXCOORD2FPROC glTexCoord2f;
RGLSYMGLTEXCOORD2IPROC glTexCoord2i;
RGLSYMGLTEXCOORD2SPROC glTexCoord2s;
RGLSYMGLTEXCOORD3DPROC glTexCoord3d;
RGLSYMGLTEXCOORD3FPROC glTexCoord3f;
RGLSYMGLTEXCOORD3IPROC glTexCoord3i;
RGLSYMGLTEXCOORD3SPROC glTexCoord3s;
RGLSYMGLTEXCOORD4DPROC glTexCoord4d;
RGLSYMGLTEXCOORD4FPROC glTexCoord4f;
RGLSYMGLTEXCOORD4IPROC glTexCoord4i;
RGLSYMGLTEXCOORD4SPROC glTexCoord4s;
RGLSYMGLTEXCOORD1DVPROC glTexCoord1dv;
RGLSYMGLTEXCOORD1FVPROC glTexCoord1fv;
RGLSYMGLTEXCOORD1IVPROC glTexCoord1iv;
RGLSYMGLTEXCOORD1SVPROC glTexCoord1sv;
RGLSYMGLTEXCOORD2DVPROC glTexCoord2dv;
RGLSYMGLTEXCOORD2FVPROC glTexCoord2fv;
RGLSYMGLTEXCOORD2IVPROC glTexCoord2iv;
RGLSYMGLTEXCOORD2SVPROC glTexCoord2sv;
RGLSYMGLTEXCOORD3DVPROC glTexCoord3dv;
RGLSYMGLTEXCOORD3FVPROC glTexCoord3fv;
RGLSYMGLTEXCOORD3IVPROC glTexCoord3iv;
RGLSYMGLTEXCOORD3SVPROC glTexCoord3sv;
RGLSYMGLTEXCOORD4DVPROC glTexCoord4dv;
RGLSYMGLTEXCOORD4FVPROC glTexCoord4fv;
RGLSYMGLTEXCOORD4IVPROC glTexCoord4iv;
RGLSYMGLTEXCOORD4SVPROC glTexCoord4sv;
RGLSYMGLRASTERPOS2DPROC glRasterPos2d;
RGLSYMGLRASTERPOS2FPROC glRasterPos2f;
RGLSYMGLRASTERPOS2IPROC glRasterPos2i;
RGLSYMGLRASTERPOS2SPROC glRasterPos2s;
RGLSYMGLRASTERPOS3DPROC glRasterPos3d;
RGLSYMGLRASTERPOS3FPROC glRasterPos3f;
RGLSYMGLRASTERPOS3IPROC glRasterPos3i;
RGLSYMGLRASTERPOS3SPROC glRasterPos3s;
RGLSYMGLRASTERPOS4DPROC glRasterPos4d;
RGLSYMGLRASTERPOS4FPROC glRasterPos4f;
RGLSYMGLRASTERPOS4IPROC glRasterPos4i;
RGLSYMGLRASTERPOS4SPROC glRasterPos4s;
RGLSYMGLRASTERPOS2DVPROC glRasterPos2dv;
RGLSYMGLRASTERPOS2FVPROC glRasterPos2fv;
RGLSYMGLRASTERPOS2IVPROC glRasterPos2iv;
RGLSYMGLRASTERPOS2SVPROC glRasterPos2sv;
RGLSYMGLRASTERPOS3DVPROC glRasterPos3dv;
RGLSYMGLRASTERPOS3FVPROC glRasterPos3fv;
RGLSYMGLRASTERPOS3IVPROC glRasterPos3iv;
RGLSYMGLRASTERPOS3SVPROC glRasterPos3sv;
RGLSYMGLRASTERPOS4DVPROC glRasterPos4dv;
RGLSYMGLRASTERPOS4FVPROC glRasterPos4fv;
RGLSYMGLRASTERPOS4IVPROC glRasterPos4iv;
RGLSYMGLRASTERPOS4SVPROC glRasterPos4sv;
RGLSYMGLRECTDPROC glRectd;
RGLSYMGLRECTFPROC glRectf;
RGLSYMGLRECTIPROC glRecti;
RGLSYMGLRECTSPROC glRects;
RGLSYMGLRECTDVPROC glRectdv;
RGLSYMGLRECTFVPROC glRectfv;
RGLSYMGLRECTIVPROC glRectiv;
RGLSYMGLRECTSVPROC glRectsv;
RGLSYMGLVERTEXPOINTERPROC glVertexPointer;
RGLSYMGLNORMALPOINTERPROC glNormalPointer;
RGLSYMGLCOLORPOINTERPROC glColorPointer;
RGLSYMGLINDEXPOINTERPROC glIndexPointer;
RGLSYMGLTEXCOORDPOINTERPROC glTexCoordPointer;
RGLSYMGLEDGEFLAGPOINTERPROC glEdgeFlagPointer;
RGLSYMGLGETPOINTERVPROC glGetPointerv;
RGLSYMGLARRAYELEMENTPROC glArrayElement;
RGLSYMGLDRAWARRAYSPROC glDrawArrays;
RGLSYMGLDRAWELEMENTSPROC glDrawElements;
RGLSYMGLINTERLEAVEDARRAYSPROC glInterleavedArrays;
RGLSYMGLSHADEMODELPROC glShadeModel;
RGLSYMGLLIGHTFPROC glLightf;
RGLSYMGLLIGHTIPROC glLighti;
RGLSYMGLLIGHTFVPROC glLightfv;
RGLSYMGLLIGHTIVPROC glLightiv;
RGLSYMGLGETLIGHTFVPROC glGetLightfv;
RGLSYMGLGETLIGHTIVPROC glGetLightiv;
RGLSYMGLLIGHTMODELFPROC glLightModelf;
RGLSYMGLLIGHTMODELIPROC glLightModeli;
RGLSYMGLLIGHTMODELFVPROC glLightModelfv;
RGLSYMGLLIGHTMODELIVPROC glLightModeliv;
RGLSYMGLMATERIALFPROC glMaterialf;
RGLSYMGLMATERIALIPROC glMateriali;
RGLSYMGLMATERIALFVPROC glMaterialfv;
RGLSYMGLMATERIALIVPROC glMaterialiv;
RGLSYMGLGETMATERIALFVPROC glGetMaterialfv;
RGLSYMGLGETMATERIALIVPROC glGetMaterialiv;
RGLSYMGLCOLORMATERIALPROC glColorMaterial;
RGLSYMGLPIXELZOOMPROC glPixelZoom;
RGLSYMGLPIXELSTOREFPROC glPixelStoref;
RGLSYMGLPIXELSTOREIPROC glPixelStorei;
RGLSYMGLPIXELTRANSFERFPROC glPixelTransferf;
RGLSYMGLPIXELTRANSFERIPROC glPixelTransferi;
RGLSYMGLPIXELMAPFVPROC glPixelMapfv;
RGLSYMGLPIXELMAPUIVPROC glPixelMapuiv;
RGLSYMGLPIXELMAPUSVPROC glPixelMapusv;
RGLSYMGLGETPIXELMAPFVPROC glGetPixelMapfv;
RGLSYMGLGETPIXELMAPUIVPROC glGetPixelMapuiv;
RGLSYMGLGETPIXELMAPUSVPROC glGetPixelMapusv;
RGLSYMGLBITMAPPROC glBitmap;
RGLSYMGLREADPIXELSPROC glReadPixels;
RGLSYMGLDRAWPIXELSPROC glDrawPixels;
RGLSYMGLCOPYPIXELSPROC glCopyPixels;
RGLSYMGLSTENCILFUNCPROC glStencilFunc;
RGLSYMGLSTENCILMASKPROC glStencilMask;
RGLSYMGLSTENCILOPPROC glStencilOp;
RGLSYMGLCLEARSTENCILPROC glClearStencil;
RGLSYMGLTEXGENDPROC glTexGend;
RGLSYMGLTEXGENFPROC glTexGenf;
RGLSYMGLTEXGENIPROC glTexGeni;
RGLSYMGLTEXGENDVPROC glTexGendv;
RGLSYMGLTEXGENFVPROC glTexGenfv;
RGLSYMGLTEXGENIVPROC glTexGeniv;
RGLSYMGLGETTEXGENDVPROC glGetTexGendv;
RGLSYMGLGETTEXGENFVPROC glGetTexGenfv;
RGLSYMGLGETTEXGENIVPROC glGetTexGeniv;
RGLSYMGLTEXENVFPROC glTexEnvf;
RGLSYMGLTEXENVIPROC glTexEnvi;
RGLSYMGLTEXENVFVPROC glTexEnvfv;
RGLSYMGLTEXENVIVPROC glTexEnviv;
RGLSYMGLGETTEXENVFVPROC glGetTexEnvfv;
RGLSYMGLGETTEXENVIVPROC glGetTexEnviv;
RGLSYMGLTEXPARAMETERFPROC glTexParameterf;
RGLSYMGLTEXPARAMETERIPROC glTexParameteri;
RGLSYMGLTEXPARAMETERFVPROC glTexParameterfv;
RGLSYMGLTEXPARAMETERIVPROC glTexParameteriv;
RGLSYMGLGETTEXPARAMETERFVPROC glGetTexParameterfv;
RGLSYMGLGETTEXPARAMETERIVPROC glGetTexParameteriv;
RGLSYMGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv;
RGLSYMGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv;
RGLSYMGLTEXIMAGE1DPROC glTexImage1D;
RGLSYMGLTEXIMAGE2DPROC glTexImage2D;
RGLSYMGLGETTEXIMAGEPROC glGetTexImage;
RGLSYMGLGENTEXTURESPROC glGenTextures;
RGLSYMGLDELETETEXTURESPROC glDeleteTextures;
RGLSYMGLBINDTEXTUREPROC glBindTexture;
RGLSYMGLPRIORITIZETEXTURESPROC glPrioritizeTextures;
RGLSYMGLARETEXTURESRESIDENTPROC glAreTexturesResident;
RGLSYMGLISTEXTUREPROC glIsTexture;
RGLSYMGLTEXSUBIMAGE1DPROC glTexSubImage1D;
RGLSYMGLTEXSUBIMAGE2DPROC glTexSubImage2D;
RGLSYMGLCOPYTEXIMAGE1DPROC glCopyTexImage1D;
RGLSYMGLCOPYTEXIMAGE2DPROC glCopyTexImage2D;
RGLSYMGLCOPYTEXSUBIMAGE1DPROC glCopyTexSubImage1D;
RGLSYMGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D;
RGLSYMGLMAP1DPROC glMap1d;
RGLSYMGLMAP1FPROC glMap1f;
RGLSYMGLMAP2DPROC glMap2d;
RGLSYMGLMAP2FPROC glMap2f;
RGLSYMGLGETMAPDVPROC glGetMapdv;
RGLSYMGLGETMAPFVPROC glGetMapfv;
RGLSYMGLGETMAPIVPROC glGetMapiv;
RGLSYMGLEVALCOORD1DPROC glEvalCoord1d;
RGLSYMGLEVALCOORD1FPROC glEvalCoord1f;
RGLSYMGLEVALCOORD1DVPROC glEvalCoord1dv;
RGLSYMGLEVALCOORD1FVPROC glEvalCoord1fv;
RGLSYMGLEVALCOORD2DPROC glEvalCoord2d;
RGLSYMGLEVALCOORD2FPROC glEvalCoord2f;
RGLSYMGLEVALCOORD2DVPROC glEvalCoord2dv;
RGLSYMGLEVALCOORD2FVPROC glEvalCoord2fv;
RGLSYMGLMAPGRID1DPROC glMapGrid1d;
RGLSYMGLMAPGRID1FPROC glMapGrid1f;
RGLSYMGLMAPGRID2DPROC glMapGrid2d;
RGLSYMGLMAPGRID2FPROC glMapGrid2f;
RGLSYMGLEVALPOINT1PROC glEvalPoint1;
RGLSYMGLEVALPOINT2PROC glEvalPoint2;
RGLSYMGLEVALMESH1PROC glEvalMesh1;
RGLSYMGLEVALMESH2PROC glEvalMesh2;
RGLSYMGLFOGFPROC glFogf;
RGLSYMGLFOGIPROC glFogi;
RGLSYMGLFOGFVPROC glFogfv;
RGLSYMGLFOGIVPROC glFogiv;
RGLSYMGLFEEDBACKBUFFERPROC glFeedbackBuffer;
RGLSYMGLPASSTHROUGHPROC glPassThrough;
RGLSYMGLSELECTBUFFERPROC glSelectBuffer;
RGLSYMGLINITNAMESPROC glInitNames;
RGLSYMGLLOADNAMEPROC glLoadName;
RGLSYMGLPUSHNAMEPROC glPushName;
RGLSYMGLPOPNAMEPROC glPopName;
RGLSYMGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
RGLSYMGLTEXIMAGE3DPROC glTexImage3D;
RGLSYMGLTEXSUBIMAGE3DPROC glTexSubImage3D;
RGLSYMGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D;
RGLSYMGLCOLORTABLEPROC glColorTable;
RGLSYMGLCOLORSUBTABLEPROC glColorSubTable;
RGLSYMGLCOLORTABLEPARAMETERIVPROC glColorTableParameteriv;
RGLSYMGLCOLORTABLEPARAMETERFVPROC glColorTableParameterfv;
RGLSYMGLCOPYCOLORSUBTABLEPROC glCopyColorSubTable;
RGLSYMGLCOPYCOLORTABLEPROC glCopyColorTable;
RGLSYMGLGETCOLORTABLEPROC glGetColorTable;
RGLSYMGLGETCOLORTABLEPARAMETERFVPROC glGetColorTableParameterfv;
RGLSYMGLGETCOLORTABLEPARAMETERIVPROC glGetColorTableParameteriv;
RGLSYMGLBLENDEQUATIONPROC glBlendEquation;
RGLSYMGLBLENDCOLORPROC glBlendColor;
RGLSYMGLHISTOGRAMPROC glHistogram;
RGLSYMGLRESETHISTOGRAMPROC glResetHistogram;
RGLSYMGLGETHISTOGRAMPROC glGetHistogram;
RGLSYMGLGETHISTOGRAMPARAMETERFVPROC glGetHistogramParameterfv;
RGLSYMGLGETHISTOGRAMPARAMETERIVPROC glGetHistogramParameteriv;
RGLSYMGLMINMAXPROC glMinmax;
RGLSYMGLRESETMINMAXPROC glResetMinmax;
RGLSYMGLGETMINMAXPROC glGetMinmax;
RGLSYMGLGETMINMAXPARAMETERFVPROC glGetMinmaxParameterfv;
RGLSYMGLGETMINMAXPARAMETERIVPROC glGetMinmaxParameteriv;
RGLSYMGLCONVOLUTIONFILTER1DPROC glConvolutionFilter1D;
RGLSYMGLCONVOLUTIONFILTER2DPROC glConvolutionFilter2D;
RGLSYMGLCONVOLUTIONPARAMETERFPROC glConvolutionParameterf;
RGLSYMGLCONVOLUTIONPARAMETERFVPROC glConvolutionParameterfv;
RGLSYMGLCONVOLUTIONPARAMETERIPROC glConvolutionParameteri;
RGLSYMGLCONVOLUTIONPARAMETERIVPROC glConvolutionParameteriv;
RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC glCopyConvolutionFilter1D;
RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC glCopyConvolutionFilter2D;
RGLSYMGLGETCONVOLUTIONFILTERPROC glGetConvolutionFilter;
RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC glGetConvolutionParameterfv;
RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC glGetConvolutionParameteriv;
RGLSYMGLSEPARABLEFILTER2DPROC glSeparableFilter2D;
RGLSYMGLGETSEPARABLEFILTERPROC glGetSeparableFilter;
RGLSYMGLACTIVETEXTUREPROC glActiveTexture;
RGLSYMGLCLIENTACTIVETEXTUREPROC glClientActiveTexture;
RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;
RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D;
RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
RGLSYMGLMULTITEXCOORD1DPROC glMultiTexCoord1d;
RGLSYMGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv;
RGLSYMGLMULTITEXCOORD1FPROC glMultiTexCoord1f;
RGLSYMGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv;
RGLSYMGLMULTITEXCOORD1IPROC glMultiTexCoord1i;
RGLSYMGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv;
RGLSYMGLMULTITEXCOORD1SPROC glMultiTexCoord1s;
RGLSYMGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv;
RGLSYMGLMULTITEXCOORD2DPROC glMultiTexCoord2d;
RGLSYMGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv;
RGLSYMGLMULTITEXCOORD2FPROC glMultiTexCoord2f;
RGLSYMGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv;
RGLSYMGLMULTITEXCOORD2IPROC glMultiTexCoord2i;
RGLSYMGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv;
RGLSYMGLMULTITEXCOORD2SPROC glMultiTexCoord2s;
RGLSYMGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv;
RGLSYMGLMULTITEXCOORD3DPROC glMultiTexCoord3d;
RGLSYMGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv;
RGLSYMGLMULTITEXCOORD3FPROC glMultiTexCoord3f;
RGLSYMGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv;
RGLSYMGLMULTITEXCOORD3IPROC glMultiTexCoord3i;
RGLSYMGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv;
RGLSYMGLMULTITEXCOORD3SPROC glMultiTexCoord3s;
RGLSYMGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv;
RGLSYMGLMULTITEXCOORD4DPROC glMultiTexCoord4d;
RGLSYMGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv;
RGLSYMGLMULTITEXCOORD4FPROC glMultiTexCoord4f;
RGLSYMGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv;
RGLSYMGLMULTITEXCOORD4IPROC glMultiTexCoord4i;
RGLSYMGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv;
RGLSYMGLMULTITEXCOORD4SPROC glMultiTexCoord4s;
RGLSYMGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv;
RGLSYMGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd;
RGLSYMGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf;
RGLSYMGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd;
RGLSYMGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf;
RGLSYMGLSAMPLECOVERAGEPROC glSampleCoverage;
RGLSYMGLACTIVETEXTUREARBPROC glActiveTextureARB;
RGLSYMGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
RGLSYMGLMULTITEXCOORD1DARBPROC glMultiTexCoord1dARB;
RGLSYMGLMULTITEXCOORD1DVARBPROC glMultiTexCoord1dvARB;
RGLSYMGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB;
RGLSYMGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fvARB;
RGLSYMGLMULTITEXCOORD1IARBPROC glMultiTexCoord1iARB;
RGLSYMGLMULTITEXCOORD1IVARBPROC glMultiTexCoord1ivARB;
RGLSYMGLMULTITEXCOORD1SARBPROC glMultiTexCoord1sARB;
RGLSYMGLMULTITEXCOORD1SVARBPROC glMultiTexCoord1svARB;
RGLSYMGLMULTITEXCOORD2DARBPROC glMultiTexCoord2dARB;
RGLSYMGLMULTITEXCOORD2DVARBPROC glMultiTexCoord2dvARB;
RGLSYMGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;
RGLSYMGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB;
RGLSYMGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB;
RGLSYMGLMULTITEXCOORD2IVARBPROC glMultiTexCoord2ivARB;
RGLSYMGLMULTITEXCOORD2SARBPROC glMultiTexCoord2sARB;
RGLSYMGLMULTITEXCOORD2SVARBPROC glMultiTexCoord2svARB;
RGLSYMGLMULTITEXCOORD3DARBPROC glMultiTexCoord3dARB;
RGLSYMGLMULTITEXCOORD3DVARBPROC glMultiTexCoord3dvARB;
RGLSYMGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB;
RGLSYMGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB;
RGLSYMGLMULTITEXCOORD3IARBPROC glMultiTexCoord3iARB;
RGLSYMGLMULTITEXCOORD3IVARBPROC glMultiTexCoord3ivARB;
RGLSYMGLMULTITEXCOORD3SARBPROC glMultiTexCoord3sARB;
RGLSYMGLMULTITEXCOORD3SVARBPROC glMultiTexCoord3svARB;
RGLSYMGLMULTITEXCOORD4DARBPROC glMultiTexCoord4dARB;
RGLSYMGLMULTITEXCOORD4DVARBPROC glMultiTexCoord4dvARB;
RGLSYMGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB;
RGLSYMGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB;
RGLSYMGLMULTITEXCOORD4IARBPROC glMultiTexCoord4iARB;
RGLSYMGLMULTITEXCOORD4IVARBPROC glMultiTexCoord4ivARB;
RGLSYMGLMULTITEXCOORD4SARBPROC glMultiTexCoord4sARB;
RGLSYMGLMULTITEXCOORD4SVARBPROC glMultiTexCoord4svARB;
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
RGLSYMGLBINDTEXTURESPROC glBindTextures;

#ifdef __cplusplus
}
#endif
#endif /* __NX_GLSYM_H__ */

./include/libretro-common/include/libchdr/bitstream.h

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    bitstream.h

    Helper classes for reading/writing at the bit level.

***************************************************************************/

#pragma once

#ifndef __BITSTREAM_H__
#define __BITSTREAM_H__

#include <stdint.h>

/***************************************************************************
 *  TYPE DEFINITIONS
 ***************************************************************************
 */

/* helper class for reading from a bit buffer */
struct bitstream
{
	uint32_t          buffer;       /* current bit accumulator */
	int               bits;         /* number of bits in the accumulator */
	const uint8_t *   read;         /* read pointer */
	uint32_t          doffset;      /* byte offset within the data */
	uint32_t          dlength;      /* length of the data */
};

struct bitstream* 	create_bitstream(const void *src, uint32_t srclength);
int 				bitstream_overflow(struct bitstream* bitstream);
uint32_t 			bitstream_read_offset(struct bitstream* bitstream);

uint32_t 			bitstream_read(struct bitstream* bitstream, int numbits);
uint32_t 			bitstream_peek(struct bitstream* bitstream, int numbits);
void 				bitstream_remove(struct bitstream* bitstream, int numbits);
uint32_t 			bitstream_flush(struct bitstream* bitstream);

#endif

./include/libretro-common/include/libchdr/cdrom.h

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    cdrom.h

    Generic MAME cd-rom implementation

***************************************************************************/

#pragma once

#ifndef __CDROM_H__
#define __CDROM_H__

#include <stdint.h>
#include <libchdr/chdconfig.h>

/***************************************************************************
    CONSTANTS
***************************************************************************/

/* tracks are padded to a multiple of this many frames */
#define CD_TRACK_PADDING   	(4)
#define CD_MAX_TRACKS           (99)    /* AFAIK the theoretical limit */
#define CD_MAX_SECTOR_DATA      (2352)
#define CD_MAX_SUBCODE_DATA     (96)

#define CD_FRAME_SIZE           (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)
#define CD_FRAMES_PER_HUNK      (8)

#define CD_METADATA_WORDS       (1+(CD_MAX_TRACKS * 6))

enum
{
	CD_TRACK_MODE1 = 0,         /* mode 1 2048 bytes/sector */
	CD_TRACK_MODE1_RAW,         /* mode 1 2352 bytes/sector */
	CD_TRACK_MODE2,             /* mode 2 2336 bytes/sector */
	CD_TRACK_MODE2_FORM1,       /* mode 2 2048 bytes/sector */
	CD_TRACK_MODE2_FORM2,       /* mode 2 2324 bytes/sector */
	CD_TRACK_MODE2_FORM_MIX,    /* mode 2 2336 bytes/sector */
	CD_TRACK_MODE2_RAW,         /* mode 2 2352 bytes / sector */
	CD_TRACK_AUDIO,         /* redbook audio track 2352 bytes/sector (588 samples) */

	CD_TRACK_RAW_DONTCARE       /* special flag for cdrom_read_data: just return me whatever is there */
};

enum
{
	CD_SUB_NORMAL = 0,          /* "cooked" 96 bytes per sector */
	CD_SUB_RAW,                 /* raw uninterleaved 96 bytes per sector */
	CD_SUB_NONE                 /* no subcode data stored */
};

#define CD_FLAG_GDROM   0x00000001  /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */
#define CD_FLAG_GDROMLE 0x00000002  /* legacy GD-ROM, with little-endian CDDA data */

/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

#ifdef WANT_RAW_DATA_SECTOR
/* ECC utilities */
int ecc_verify(const uint8_t *sector);
void ecc_generate(uint8_t *sector);
void ecc_clear(uint8_t *sector);
#endif



/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

static INLINE uint32_t msf_to_lba(uint32_t msf)
{
	return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0);
}

static INLINE uint32_t lba_to_msf(uint32_t lba)
{
	uint8_t m, s, f;

	m = lba / (60 * 75);
	lba -= m * (60 * 75);
	s = lba / 75;
	f = lba % 75;

	return ((m / 10) << 20) | ((m % 10) << 16) |
			((s / 10) << 12) | ((s % 10) <<  8) |
			((f / 10) <<  4) | ((f % 10) <<  0);
}

/**
 * segacd needs it like this.. investigate
 * Angelo also says PCE tracks often start playing at the
 * wrong address.. related?
 **/
static INLINE uint32_t lba_to_msf_alt(int lba)
{
	uint32_t ret = 0;

	ret |= ((lba / (60 * 75))&0xff)<<16;
	ret |= (((lba / 75) % 60)&0xff)<<8;
	ret |= ((lba % 75)&0xff)<<0;

	return ret;
}

#endif  /* __CDROM_H__ */

./include/libretro-common/include/libchdr/chd.h

/***************************************************************************

    chd.h

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#pragma once

#ifndef __CHD_H__
#define __CHD_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <libchdr/coretypes.h>
#include <libchdr/chdconfig.h>

/***************************************************************************

    Compressed Hunks of Data header format. All numbers are stored in
    Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2)
    bytes long.

    V1 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t hunksize;      // 512-byte sectors per hunk
    [ 28] uint32_t totalhunks;    // total # of hunks represented
    [ 32] uint32_t cylinders;     // number of cylinders on hard disk
    [ 36] uint32_t heads;         // number of heads on hard disk
    [ 40] uint32_t sectors;       // number of sectors on hard disk
    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data
    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file
    [ 76] (V1 header length)

    V2 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t hunksize;      // seclen-byte sectors per hunk
    [ 28] uint32_t totalhunks;    // total # of hunks represented
    [ 32] uint32_t cylinders;     // number of cylinders on hard disk
    [ 36] uint32_t heads;         // number of heads on hard disk
    [ 40] uint32_t sectors;       // number of sectors on hard disk
    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data
    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file
    [ 76] uint32_t seclen;        // number of bytes per sector
    [ 80] (V2 header length)

    V3 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t totalhunks;    // total # of hunks represented
    [ 28] uint64_t logicalbytes;  // logical size of the data (in bytes)
    [ 36] uint64_t metaoffset;    // offset to the first blob of metadata
    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data
    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file
    [ 76] uint32_t hunkbytes;     // number of bytes per hunk
    [ 80] uint8_t  sha1[20];      // SHA1 checksum of raw data
    [100] uint8_t  parentsha1[20];// SHA1 checksum of parent file
    [120] (V3 header length)

    V4 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t totalhunks;    // total # of hunks represented
    [ 28] uint64_t logicalbytes;  // logical size of the data (in bytes)
    [ 36] uint64_t metaoffset;    // offset to the first blob of metadata
    [ 44] uint32_t hunkbytes;     // number of bytes per hunk
    [ 48] uint8_t  sha1[20];      // combined raw+meta SHA1
    [ 68] uint8_t  parentsha1[20];// combined raw+meta SHA1 of parent
    [ 88] uint8_t  rawsha1[20];   // raw data SHA1
    [108] (V4 header length)

    Flags:
        0x00000001 - set if this drive has a parent
        0x00000002 - set if this drive allows writes

   =========================================================================

    V5 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t_t version;       // drive format version
    [ 16] uint32_t_t compressors[4];// which custom compressors are used?
    [ 32] uint64_t_t logicalbytes;  // logical size of the data (in bytes)
    [ 40] uint64_t_t mapoffset;     // offset to the map
    [ 48] uint64_t_t metaoffset;    // offset to the first blob of metadata
    [ 56] uint32_t_t hunkbytes;     // number of bytes per hunk (512k maximum)
    [ 60] uint32_t_t unitbytes;     // number of bytes per unit within each hunk
    [ 64] uint8_t_t  rawsha1[20];   // raw data SHA1
    [ 84] uint8_t_t  sha1[20];      // combined raw+meta SHA1
    [104] uint8_t_t  parentsha1[20];// combined raw+meta SHA1 of parent
    [124] (V5 header length)

    If parentsha1 != 0, we have a parent (no need for flags)
    If compressors[0] == 0, we are uncompressed (including maps)

    V5 uncompressed map format:

    [  0] uint32_t_t offset;        // starting offset / hunk size

    V5 compressed map format header:

    [  0] uint32_t_t length;        // length of compressed map
    [  4] UINT48 datastart;     // offset of first block
    [ 10] uint16_t crc;           // crc-16 of the map
    [ 12] uint8_t_t lengthbits;     // bits used to encode complength
    [ 13] uint8_t_t hunkbits;       // bits used to encode self-refs
    [ 14] uint8_t_t parentunitbits; // bits used to encode parent unit refs
    [ 15] uint8_t_t reserved;       // future use
    [ 16] (compressed header length)

    Each compressed map entry, once expanded, looks like:

    [  0] uint8_t_t compression;    // compression type
    [  1] UINT24 complength;    // compressed length
    [  4] UINT48 offset;        // offset
    [ 10] uint16_t crc;           // crc-16 of the data

***************************************************************************/


/***************************************************************************
    CONSTANTS
***************************************************************************/

/* header information */
#define CHD_HEADER_VERSION			5
#define CHD_V1_HEADER_SIZE			76
#define CHD_V2_HEADER_SIZE			80
#define CHD_V3_HEADER_SIZE			120
#define CHD_V4_HEADER_SIZE			108
#define CHD_V5_HEADER_SIZE          124

#define CHD_MAX_HEADER_SIZE			CHD_V5_HEADER_SIZE

/* checksumming information */
#define CHD_MD5_BYTES				16
#define CHD_SHA1_BYTES				20

/* CHD global flags */
#define CHDFLAGS_HAS_PARENT			0x00000001
#define CHDFLAGS_IS_WRITEABLE		0x00000002
#define CHDFLAGS_UNDEFINED			0xfffffffc

#define CHD_MAKE_TAG(a,b,c,d)       (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))

/* compression types */
#define CHDCOMPRESSION_NONE			0
#define CHDCOMPRESSION_ZLIB			1
#define CHDCOMPRESSION_ZLIB_PLUS	2
#define CHDCOMPRESSION_AV			3

#define CHD_CODEC_NONE 0
#define CHD_CODEC_ZLIB				CHD_MAKE_TAG('z','l','i','b')
#define CHD_CODEC_LZMA				CHD_MAKE_TAG('l','z','m','a')
#define CHD_CODEC_HUFFMAN 			CHD_MAKE_TAG('h','u','f','f')
#define CHD_CODEC_FLAC				CHD_MAKE_TAG('f','l','a','c')
#define CHD_CODEC_ZSTD				CHD_MAKE_TAG('z', 's', 't', 'd')
/* general codecs with CD frontend */
#define CHD_CODEC_CD_ZLIB			CHD_MAKE_TAG('c','d','z','l')
#define CHD_CODEC_CD_LZMA			CHD_MAKE_TAG('c','d','l','z')
#define CHD_CODEC_CD_FLAC			CHD_MAKE_TAG('c','d','f','l')
#define CHD_CODEC_CD_ZSTD			CHD_MAKE_TAG('c','d','z','s')

/* A/V codec configuration parameters */
#define AV_CODEC_COMPRESS_CONFIG	1
#define AV_CODEC_DECOMPRESS_CONFIG	2

/* metadata parameters */
#define CHDMETATAG_WILDCARD			0
#define CHD_METAINDEX_APPEND		((uint32_t)-1)

/* metadata flags */
#define CHD_MDFLAGS_CHECKSUM		0x01		/* indicates data is checksummed */

/* standard hard disk metadata */
#define HARD_DISK_METADATA_TAG		CHD_MAKE_TAG('G','D','D','D')
#define HARD_DISK_METADATA_FORMAT	"CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"

/* hard disk identify information */
#define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T')

/* hard disk key information */
#define HARD_DISK_KEY_METADATA_TAG	CHD_MAKE_TAG('K','E','Y',' ')

/* pcmcia CIS information */
#define PCMCIA_CIS_METADATA_TAG		CHD_MAKE_TAG('C','I','S',' ')

/* standard CD-ROM metadata */
#define CDROM_OLD_METADATA_TAG		CHD_MAKE_TAG('C','H','C','D')
#define CDROM_TRACK_METADATA_TAG	CHD_MAKE_TAG('C','H','T','R')
#define CDROM_TRACK_METADATA_FORMAT	"TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
#define CDROM_TRACK_METADATA2_TAG	CHD_MAKE_TAG('C','H','T','2')
#define CDROM_TRACK_METADATA2_FORMAT	"TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
#define GDROM_OLD_METADATA_TAG		CHD_MAKE_TAG('C','H','G','T')
#define GDROM_TRACK_METADATA_TAG	CHD_MAKE_TAG('C', 'H', 'G', 'D')
#define GDROM_TRACK_METADATA_FORMAT	"TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"

/* standard A/V metadata */
#define AV_METADATA_TAG				CHD_MAKE_TAG('A','V','A','V')
#define AV_METADATA_FORMAT			"FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"

/* A/V laserdisc frame metadata */
#define AV_LD_METADATA_TAG			CHD_MAKE_TAG('A','V','L','D')

/* DVD metadata */
#define DVD_METADATA_TAG			CHD_MAKE_TAG('D','V','D',' ')

/* CHD open values */
#define CHD_OPEN_READ				1
#define CHD_OPEN_READWRITE			2

/* error types */
enum _chd_error
{
	CHDERR_NONE,
	CHDERR_NO_INTERFACE,
	CHDERR_OUT_OF_MEMORY,
	CHDERR_INVALID_FILE,
	CHDERR_INVALID_PARAMETER,
	CHDERR_INVALID_DATA,
	CHDERR_FILE_NOT_FOUND,
	CHDERR_REQUIRES_PARENT,
	CHDERR_FILE_NOT_WRITEABLE,
	CHDERR_READ_ERROR,
	CHDERR_WRITE_ERROR,
	CHDERR_CODEC_ERROR,
	CHDERR_INVALID_PARENT,
	CHDERR_HUNK_OUT_OF_RANGE,
	CHDERR_DECOMPRESSION_ERROR,
	CHDERR_COMPRESSION_ERROR,
	CHDERR_CANT_CREATE_FILE,
	CHDERR_CANT_VERIFY,
	CHDERR_NOT_SUPPORTED,
	CHDERR_METADATA_NOT_FOUND,
	CHDERR_INVALID_METADATA_SIZE,
	CHDERR_UNSUPPORTED_VERSION,
	CHDERR_VERIFY_INCOMPLETE,
	CHDERR_INVALID_METADATA,
	CHDERR_INVALID_STATE,
	CHDERR_OPERATION_PENDING,
	CHDERR_NO_ASYNC_OPERATION,
	CHDERR_UNSUPPORTED_FORMAT
};
typedef enum _chd_error chd_error;



/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

/* opaque types */
typedef struct _chd_file chd_file;


/* extract header structure (NOT the on-disk header structure) */
typedef struct _chd_header chd_header;
struct _chd_header
{
	uint32_t		length;						/* length of header data */
	uint32_t		version;					/* drive format version */
	uint32_t		flags;						/* flags field */
	uint32_t		compression[4];				/* compression type */
	uint32_t		hunkbytes;					/* number of bytes per hunk */
	uint32_t		totalhunks;					/* total # of hunks represented */
	uint64_t		logicalbytes;				/* logical size of the data */
	uint64_t		metaoffset;					/* offset in file of first metadata */
	uint64_t		mapoffset;					/* TOOD V5 */
	uint8_t		md5[CHD_MD5_BYTES];			/* overall MD5 checksum */
	uint8_t		parentmd5[CHD_MD5_BYTES];	/* overall MD5 checksum of parent */
	uint8_t		sha1[CHD_SHA1_BYTES];		/* overall SHA1 checksum */
	uint8_t		rawsha1[CHD_SHA1_BYTES];	/* SHA1 checksum of raw data */
	uint8_t		parentsha1[CHD_SHA1_BYTES];	/* overall SHA1 checksum of parent */
	uint32_t		unitbytes;					/* TODO V5 */
	uint64_t		unitcount;					/* TODO V5 */
    uint32_t      hunkcount;                  /* TODO V5 */

    /* map information */
    uint32_t      mapentrybytes;              /* length of each entry in a map (V5) */
    uint8_t*      rawmap;                     /* raw map data */

	uint32_t		obsolete_cylinders;			/* obsolete field -- do not use! */
	uint32_t		obsolete_sectors;			/* obsolete field -- do not use! */
	uint32_t		obsolete_heads;				/* obsolete field -- do not use! */
	uint32_t		obsolete_hunksize;			/* obsolete field -- do not use! */
};


/* structure for returning information about a verification pass */
typedef struct _chd_verify_result chd_verify_result;
struct _chd_verify_result
{
	uint8_t		md5[CHD_MD5_BYTES];			/* overall MD5 checksum */
	uint8_t		sha1[CHD_SHA1_BYTES];		/* overall SHA1 checksum */
	uint8_t		rawsha1[CHD_SHA1_BYTES];	/* SHA1 checksum of raw data */
	uint8_t		metasha1[CHD_SHA1_BYTES];	/* SHA1 checksum of metadata */
};



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

#ifdef _MSC_VER
#ifdef CHD_DLL
#ifdef CHD_DLL_EXPORTS
#define CHD_EXPORT __declspec(dllexport)
#else
#define CHD_EXPORT __declspec(dllimport)
#endif
#else
#define CHD_EXPORT
#endif
#else
#define CHD_EXPORT __attribute__ ((visibility("default")))
#endif

/* ----- CHD file management ----- */

/* create a new CHD file fitting the given description */
/* chd_error chd_create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */

/* same as chd_create(), but accepts an already-opened core_file object */
/* chd_error chd_create_file(core_file *file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */

/* open an existing CHD file */
CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd);
CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd);
CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);

/* precache underlying file */
CHD_EXPORT chd_error chd_precache(chd_file *chd);

/* close a CHD file */
CHD_EXPORT void chd_close(chd_file *chd);

/* return the associated core_file */
CHD_EXPORT core_file *chd_core_file(chd_file *chd);

/* return an error string for the given CHD error */
CHD_EXPORT const char *chd_error_string(chd_error err);



/* ----- CHD header management ----- */

/* return a pointer to the extracted CHD header data */
CHD_EXPORT const chd_header *chd_get_header(chd_file *chd);

/* read CHD header data from file into the pointed struct */
CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header);



/* ----- core data read/write ----- */

/* read one hunk from the CHD file */
CHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer);



/* ----- metadata management ----- */

/* get indexed metadata of a particular sort */
CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, uint32_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags);




/* ----- codec interfaces ----- */

/* set internal codec parameters */
CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config);

/* return a string description of a codec */
CHD_EXPORT const char *chd_get_codec_name(uint32_t codec);

#ifdef __cplusplus
}
#endif

#endif /* __CHD_H__ */

./include/libretro-common/include/libchdr/coretypes.h

#ifndef __CORETYPES_H__
#define __CORETYPES_H__

#include <stdint.h>
#include <stdio.h>
#include <retro_miscellaneous.h>
#ifdef USE_LIBRETRO_VFS
#include <streams/file_stream_transforms.h>
#endif

typedef uint64_t UINT64;
#ifndef OSD_CPU_H
typedef uint32_t UINT32;
typedef uint16_t UINT16;
typedef uint8_t UINT8;
#endif

typedef int64_t INT64;
#ifndef OSD_CPU_H
typedef int32_t INT32;
typedef int16_t INT16;
typedef int8_t INT8;
#endif

#ifndef ARRAY_LENGTH
#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))
#endif

typedef struct chd_core_file {
	/*
	 * arbitrary pointer to data the implementation uses to implement the below functions
	 */
	void *argp;

	/*
	 * return the size of a given file as a 64-bit unsigned integer.
	 * the position of the file pointer after calling this function is
	 * undefined because many implementations will seek to the end of the
	 * file and call ftell.
	 *
	 * on error, (uint64_t)-1 is returned.
	 */
	uint64_t(*fsize)(struct chd_core_file*);

	/*
	 * should match the behavior of fread, except the FILE* argument at the end
	 * will be replaced with a struct chd_core_file*.
	 */
	size_t(*fread)(void*,size_t,size_t,struct chd_core_file*);

	/* closes the given file. */
	int (*fclose)(struct chd_core_file*);

	/* fseek clone. */
	int (*fseek)(struct chd_core_file*, int64_t, int);
} core_file;

static INLINE int core_fclose(core_file *fp) {
	return fp->fclose(fp);
}

static INLINE size_t core_fread(core_file *fp, void *ptr, size_t len) {
	return fp->fread(ptr, 1, len, fp);
}

static INLINE int core_fseek(core_file* fp, int64_t offset, int whence) {
	return fp->fseek(fp, offset, whence);
}

static INLINE uint64_t core_fsize(core_file *fp)
{
	return fp->fsize(fp);
}

#endif

./include/libretro-common/include/libchdr/flac.h

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    flac.h

    FLAC compression wrappers

***************************************************************************/

#pragma once

#ifndef __FLAC_H__
#define __FLAC_H__

#include <stdint.h>

#include <libchdr/libchdr_zlib.h>

/***************************************************************************
 *  TYPE DEFINITIONS
 ***************************************************************************
 */

typedef struct _flac_decoder flac_decoder;
struct _flac_decoder {
		/* output state */
	void *                  decoder;				/* actual encoder */
	uint32_t                sample_rate;			/* decoded sample rate */
	uint8_t                 channels;				/* decoded number of channels */
	uint8_t                 bits_per_sample;		/* decoded bits per sample */
	uint32_t                compressed_offset;		/* current offset in compressed data */
	const uint8_t *         compressed_start;		/* start of compressed data */
	uint32_t                compressed_length;		/* length of compressed data */
	const uint8_t *         compressed2_start;		/* start of compressed data */
	uint32_t                compressed2_length;		/* length of compressed data */
	int16_t *               uncompressed_start[8];	/* pointer to start of uncompressed data (up to 8 streams) */
	uint32_t                uncompressed_offset;	/* current position in uncompressed data */
	uint32_t                uncompressed_length;	/* length of uncompressed data */
	int                    	uncompressed_swap;		/* swap uncompressed sample data */
	uint8_t                 custom_header[0x2a];	/* custom header */
};

/* ======================> flac_decoder */

int 		flac_decoder_init(flac_decoder* decoder);
void 		flac_decoder_free(flac_decoder* decoder);
int 		flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);
int 		flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);
uint32_t 	flac_decoder_finish(flac_decoder* decoder);

/* codec-private data for the FLAC codec */
typedef struct _flac_codec_data flac_codec_data;
struct _flac_codec_data {
	/* internal state */
	int		native_endian;
	flac_decoder	decoder;
};

/* codec-private data for the CDFL codec */
typedef struct _cdfl_codec_data cdfl_codec_data;
struct _cdfl_codec_data {
	/* internal state */
	int		swap_endian;
	flac_decoder	decoder;
#ifdef WANT_SUBCODE
	zlib_codec_data		subcode_decompressor;
#endif
	uint8_t*	buffer;
};

#endif /* __FLAC_H__ */

./include/libretro-common/include/libchdr/huffman.h

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    huffman.h

    Static Huffman compression and decompression helpers.

***************************************************************************/

#pragma once

#ifndef __HUFFMAN_H__
#define __HUFFMAN_H__

#include <libchdr/bitstream.h>


/***************************************************************************
 *  CONSTANTS
 ***************************************************************************
 */

enum huffman_error
{
	HUFFERR_NONE = 0,
	HUFFERR_TOO_MANY_BITS,
	HUFFERR_INVALID_DATA,
	HUFFERR_INPUT_BUFFER_TOO_SMALL,
	HUFFERR_OUTPUT_BUFFER_TOO_SMALL,
	HUFFERR_INTERNAL_INCONSISTENCY,
	HUFFERR_TOO_MANY_CONTEXTS
};

/***************************************************************************
 *  TYPE DEFINITIONS
 ***************************************************************************
 */

typedef uint16_t lookup_value;

/* a node in the huffman tree */
struct node_t
{
	struct node_t*		parent;		/* pointer to parent node */
	uint32_t			count;		/* number of hits on this node */
	uint32_t			weight;		/* assigned weight of this node */
	uint32_t			bits;		/* bits used to encode the node */
	uint8_t				numbits;	/* number of bits needed for this node */
};

/* ======================> huffman_context_base */

/* context class for decoding */
struct huffman_decoder
{
	/* internal state */
	uint32_t			numcodes;             /* number of total codes being processed */
	uint8_t				maxbits;           /* maximum bits per code */
	uint8_t 			prevdata;             /* value of the previous data (for delta-RLE encoding) */
	int             	rleremaining;         /* number of RLE bytes remaining (for delta-RLE encoding) */
	lookup_value *  	lookup;               /* pointer to the lookup table */
	struct node_t *     huffnode;             /* array of nodes */
	uint32_t *      	datahisto;            /* histogram of data values */

	/* array versions of the info we need */
#if 0
	node_t*			huffnode_array; /* [_NumCodes]; */
	lookup_value*	lookup_array; /* [1 << _MaxBits]; */
#endif
};

/* ======================> huffman_decoder */

struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);
void delete_huffman_decoder(struct huffman_decoder* decoder);

/* single item operations */
uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);

enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);
enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf);

int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight);
enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder);
enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder);

void huffman_build_lookup_table(struct huffman_decoder* decoder);

#endif

./include/libretro-common/include/libchdr/libchdr_zlib.h

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    libchr_zlib.h

    Zlib compression wrappers

***************************************************************************/

#pragma once

#ifndef __LIBCHDR_ZLIB_H__
#define __LIBCHDR_ZLIB_H__

#include <stdint.h>

#include <zlib.h>
#include "coretypes.h"
#include "chd.h"

#define MAX_ZLIB_ALLOCS				64

/* codec-private data for the ZLIB codec */

typedef struct _zlib_allocator zlib_allocator;
struct _zlib_allocator
{
	uint32_t *				allocptr[MAX_ZLIB_ALLOCS];
	uint32_t *				allocptr2[MAX_ZLIB_ALLOCS];
};

typedef struct _zlib_codec_data zlib_codec_data;
struct _zlib_codec_data
{
	z_stream				inflater;
	zlib_allocator			allocator;
};

/* codec-private data for the CDZL codec */
typedef struct _cdzl_codec_data cdzl_codec_data;
struct _cdzl_codec_data {
	/* internal state */
	zlib_codec_data		base_decompressor;
#ifdef WANT_SUBCODE
	zlib_codec_data		subcode_decompressor;
#endif
	uint8_t*			buffer;
};

extern chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
extern void zlib_codec_free(void *codec);
extern chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
extern void zlib_allocator_free(voidpf opaque);

/* zlib compression codec */
chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);

void zlib_codec_free(void *codec);

chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);

void zlib_fast_free(voidpf opaque, voidpf address);

/* cdzl compression codec */
chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);

void cdzl_codec_free(void* codec);

chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

#endif /* __LIBCHDR_ZLIB_H__ */

./include/libretro-common/include/libchdr/lzma.h

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    lzma.h

    LZMA compression wrappers

***************************************************************************/

#pragma once

#ifndef __LIBCHDR_LZMA_H__
#define __LIBCHDR_LZMA_H__

#include <stdint.h>

#include <LzmaEnc.h>
#include <LzmaDec.h>

#include <libchdr/libchdr_zlib.h>

/* codec-private data for the LZMA codec */
#define MAX_LZMA_ALLOCS 64

typedef struct _lzma_allocator lzma_allocator;
struct _lzma_allocator
{
	void *(*Alloc)(void *p, size_t size);
 	void (*Free)(void *p, void *address); /* address can be 0 */
	void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
	uint32_t*	allocptr[MAX_LZMA_ALLOCS];
	uint32_t*	allocptr2[MAX_LZMA_ALLOCS];
};

typedef struct _lzma_codec_data lzma_codec_data;
struct _lzma_codec_data
{
	CLzmaDec		decoder;
	lzma_allocator	allocator;
};

/* codec-private data for the CDLZ codec */
typedef struct _cdlz_codec_data cdlz_codec_data;
struct _cdlz_codec_data {
	/* internal state */
	lzma_codec_data		base_decompressor;
#ifdef WANT_SUBCODE
	zlib_codec_data		subcode_decompressor;
#endif
	uint8_t*			buffer;
};

chd_error lzma_codec_init(void* codec, uint32_t hunkbytes);

void lzma_codec_free(void* codec);

/*-------------------------------------------------
 *  decompress - decompress data using the LZMA
 *  codec
 *-------------------------------------------------
 */

chd_error lzma_codec_decompress(void* codec, const uint8_t *src,
      uint32_t complen, uint8_t *dest, uint32_t destlen);

chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);

void cdlz_codec_free(void* codec);

chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

#endif /* __LIBCHDR_LZMA_H__ */

./include/libretro-common/include/libchdr/minmax.h

/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    minmax.h

***************************************************************************/

#pragma once

#ifndef __MINMAX_H__
#define __MINMAX_H__

#if defined(RARCH_INTERNAL) || defined(__LIBRETRO__)
#include <retro_miscellaneous.h>
#else
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif

#endif

./include/libretro-common/include/libco.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (libco.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBCO_H
#define LIBCO_H

#include <retro_common_api.h>

#ifdef LIBCO_C
  #ifdef LIBCO_MP
    #define thread_local __thread
  #else
    #define thread_local
  #endif
#endif

RETRO_BEGIN_DECLS

typedef void* cothread_t;

/**
 * co_active:
 *
 * Gets the currently active context.
 *
 * Returns: active context.
 **/
cothread_t co_active(void);

/**
 * co_create:
 * @int                : stack size
 * @funcptr            : thread entry function callback
 *
 * Create a co_thread.
 *
 * Returns: cothread if successful, otherwise NULL.
 */
cothread_t co_create(unsigned int, void (*)(void));

/**
 * co_delete:
 * @cothread           : cothread object
 *
 * Frees a co_thread.
 */
void co_delete(cothread_t cothread);

/**
 * co_switch:
 * @cothread           : cothread object to switch to
 *
 * Do a context switch to @cothread.
 */
void co_switch(cothread_t cothread);

RETRO_END_DECLS

/* ifndef LIBCO_H */
#endif

./include/libretro-common/include/libretro_d3d.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_d3d.h)
 * ---------------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the
 * "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_DIRECT3D_H__
#define LIBRETRO_DIRECT3D_H__

#include "libretro.h"

#ifdef HAVE_D3D11
#include "libretro_d3d11.h"
#endif

#ifdef HAVE_D3D12
#include "libretro_d3d12.h"
#endif

#endif /* LIBRETRO_DIRECT3D_H__ */

./include/libretro-common/include/libretro_dspfilter.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_dspfilter.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_DSPFILTER_API_H__
#define LIBRETRO_DSPFILTER_API_H__

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#define DSPFILTER_SIMD_SSE      (1 << 0)
#define DSPFILTER_SIMD_SSE2     (1 << 1)
#define DSPFILTER_SIMD_VMX      (1 << 2)
#define DSPFILTER_SIMD_VMX128   (1 << 3)
#define DSPFILTER_SIMD_AVX      (1 << 4)
#define DSPFILTER_SIMD_NEON     (1 << 5)
#define DSPFILTER_SIMD_SSE3     (1 << 6)
#define DSPFILTER_SIMD_SSSE3    (1 << 7)
#define DSPFILTER_SIMD_MMX      (1 << 8)
#define DSPFILTER_SIMD_MMXEXT   (1 << 9)
#define DSPFILTER_SIMD_SSE4     (1 << 10)
#define DSPFILTER_SIMD_SSE42    (1 << 11)
#define DSPFILTER_SIMD_AVX2     (1 << 12)
#define DSPFILTER_SIMD_VFPU     (1 << 13)
#define DSPFILTER_SIMD_PS       (1 << 14)

/* A bit-mask of all supported SIMD instruction sets.
 * Allows an implementation to pick different
 * dspfilter_implementation structs.
 */
typedef unsigned dspfilter_simd_mask_t;

/* Dynamic library endpoint. */
typedef const struct dspfilter_implementation *(
      *dspfilter_get_implementation_t)(dspfilter_simd_mask_t mask);

/* The same SIMD mask argument is forwarded to create() callback
 * as well to avoid having to keep lots of state around. */
const struct dspfilter_implementation *dspfilter_get_implementation(
      dspfilter_simd_mask_t mask);

#define DSPFILTER_API_VERSION 1

struct dspfilter_info
{
   /* Input sample rate that the DSP plugin receives. */
   float input_rate;
};

struct dspfilter_output
{
   /* The DSP plugin has to provide the buffering for the
    * output samples or reuse the input buffer directly.
    *
    * The samples are laid out in interleaving order: LRLRLRLR
    * The range of the samples are [-1.0, 1.0].
    *
    * It is not necessary to manually clip values. */
   float *samples;

   /* Frames which the DSP plugin outputted for the current process.
    *
    * One frame is here defined as a combined sample of
    * left and right channels.
    *
    * (I.e. 44.1kHz, 16bit stereo will have
    * 88.2k samples/sec and 44.1k frames/sec.)
    */
   unsigned frames;
};

struct dspfilter_input
{
   /* Input data for the DSP. The samples are interleaved in order: LRLRLRLR
    *
    * It is valid for a DSP plug to use this buffer for output as long as
    * the output size is less or equal to the input.
    *
    * This is useful for filters which can output one sample for each
    * input sample and do not need to maintain its own buffers.
    *
    * Block based filters must provide their own buffering scheme.
    *
    * The input size is not bound, but it can be safely assumed that it
    * will not exceed ~100ms worth of audio at a time. */
   float *samples;

   /* Number of frames for input data.
    * One frame is here defined as a combined sample of
    * left and right channels.
    *
    * (I.e. 44.1kHz, 16bit stereo will have
    * 88.2k samples/sec and 44.1k frames/sec.)
    */
   unsigned frames;
};

/* Returns true if config key was found. Otherwise,
 * returns false, and sets value to default value.
 */
typedef int (*dspfilter_config_get_float_t)(void *userdata,
      const char *key, float *value, float default_value);

typedef int (*dspfilter_config_get_int_t)(void *userdata,
      const char *key, int *value, int default_value);

/* Allocates an array with values. free() with dspfilter_config_free_t. */
typedef int (*dspfilter_config_get_float_array_t)(void *userdata,
      const char *key, float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values);

typedef int (*dspfilter_config_get_int_array_t)(void *userdata,
      const char *key, int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values);

typedef int (*dspfilter_config_get_string_t)(void *userdata,
      const char *key, char **output, const char *default_output);

/* Calls free() in host runtime. Sometimes needed on Windows.
 * free() on NULL is fine. */
typedef void (*dspfilter_config_free_t)(void *ptr);

struct dspfilter_config
{
   dspfilter_config_get_float_t get_float;
   dspfilter_config_get_int_t get_int;

   dspfilter_config_get_float_array_t get_float_array;
   dspfilter_config_get_int_array_t get_int_array;

   dspfilter_config_get_string_t get_string;
   /* Avoid problems where DSP plug and host are
    * linked against different C runtimes. */
   dspfilter_config_free_t free;
};

/* Creates a handle of the plugin. Returns NULL if failed. */
typedef void *(*dspfilter_init_t)(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata);

/* Frees the handle. */
typedef void (*dspfilter_free_t)(void *data);

/* Processes input data.
 * The plugin is allowed to return variable sizes for output data. */
typedef void (*dspfilter_process_t)(void *data,
      struct dspfilter_output *output, const struct dspfilter_input *input);

struct dspfilter_implementation
{
   dspfilter_init_t     init;
   dspfilter_process_t  process;
   dspfilter_free_t     free;

   /* Must be DSPFILTER_API_VERSION */
   unsigned api_version;

   /* Human readable identifier of implementation. */
   const char *ident;

   /* Computer-friendly short version of ident.
    * Lower case, no spaces and special characters, etc. */
   const char *short_ident;
};

RETRO_END_DECLS

#endif

./include/libretro-common/include/libretro_gskit_ps2.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_d3d.h)
 * ---------------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the
 * "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_GSKIT_PS2_H_
#define LIBRETRO_GSKIT_PS2_H_

#include "libretro.h"

#if defined(PS2)

#include <gsKit.h>

#define RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION 2

struct retro_hw_ps2_insets
{
  float top;
  float left;
  float bottom;
  float right;
};

#define empty_ps2_insets (struct retro_hw_ps2_insets){0.f, 0.f, 0.f, 0.f}

struct retro_hw_render_interface_gskit_ps2
{
  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2. */
  enum retro_hw_render_interface_type interface_type;
  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION. */
  unsigned interface_version;

  /* Opaque handle to the GSKit_PS2 backend in the frontend
   * which must be passed along to all function pointers
   * in this interface.
   */
   GSTEXTURE *coreTexture;
   struct retro_hw_ps2_insets padding;
};
typedef struct retro_hw_render_interface_gskit_ps2 RETRO_HW_RENDER_INTEFACE_GSKIT_PS2;

#endif

#endif /* LIBRETRO_GSKIT_PS2_H_ */

./include/libretro-common/include/libretro.h

/*!
 * libretro.h is a simple API that allows for the creation of games and emulators.
 *
 * @file libretro.h
 * @version 1
 * @author libretro
 * @copyright Copyright (C) 2010-2024 The RetroArch team
 *
 * @paragraph LICENSE
 * The following license statement only applies to this libretro API header (libretro.h).
 *
 * Copyright (C) 2010-2024 The RetroArch team
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_H__
#define LIBRETRO_H__

#include <stdint.h>
#include <stddef.h>
#include <limits.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef __cplusplus
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode
 * as it isn't C99-compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include <stdbool.h>
#endif
#endif

#ifndef RETRO_CALLCONV
#  if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__)
#    define RETRO_CALLCONV __attribute__((cdecl))
#  elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64)
#    define RETRO_CALLCONV __cdecl
#  else
#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */
#  endif
#endif

#ifndef RETRO_API
#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
#    ifdef RETRO_IMPORT_SYMBOLS
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)
#      endif
#    else
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)
#      endif
#    endif
#  else
#      if defined(__GNUC__) && __GNUC__ >= 4
#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
#      else
#        define RETRO_API RETRO_CALLCONV
#      endif
#  endif
#endif

/**
 * The major version of the libretro API and ABI.
 * Cores may support multiple versions,
 * or they may reject cores with unsupported versions.
 * It is only incremented for incompatible API/ABI changes;
 * this generally implies a function was removed or changed,
 * or that a \c struct had fields removed or changed.
 * @note A design goal of libretro is to avoid having to increase this value at all costs.
 * This is why there are APIs that are "extended" or "V2".
 */
#define RETRO_API_VERSION         1

/**
 * @defgroup RETRO_DEVICE Input Devices
 * @brief Libretro's fundamental device abstractions.
 *
 * Libretro's input system consists of abstractions over standard device types,
 * such as a joypad (with or without analog), mouse, keyboard, light gun, or an abstract pointer.
 * Instead of managing input devices themselves,
 * cores need only to map their own concept of a controller to libretro's abstractions.
 * This makes it possible for frontends to map the abstract types to a real input device
 * without having to worry about the correct use of arbitrary (real) controller layouts.
 * @{
 */

#define RETRO_DEVICE_TYPE_SHIFT         8
#define RETRO_DEVICE_MASK               ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)

/**
 * Defines an ID for a subclass of a known device type.
 *
 * To define a subclass ID, use this macro like so:
 * @code{c}
 * #define RETRO_DEVICE_SUPER_SCOPE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)
 * #define RETRO_DEVICE_JUSTIFIER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)
 * @endcode
 *
 * Correct use of this macro allows a frontend to select a suitable physical device
 * to map to the emulated device.
 *
 * @note Cores must use the base ID when polling for input,
 * and frontends must only accept the base ID for this purpose.
 * Polling for input using subclass IDs is reserved for future definition.
 *
 * @param base One of the \ref RETRO_DEVICE "base device types".
 * @param id A unique ID, with respect to \c base.
 * Must be a non-negative integer.
 * @return A unique subclass ID.
 * @see retro_controller_description
 * @see retro_set_controller_port_device
 */
#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)

/**
 * @defgroup RETRO_DEVICE Input Device Classes
 * @{
 */

/**
 * Indicates no input.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * all other arguments are ignored and zero is returned.
 *
 * @see retro_input_state_t
 */
#define RETRO_DEVICE_NONE         0

/**
 * An abstraction around a game controller, known as a "RetroPad".
 *
 * The RetroPad is modelled after a SNES controller,
 * but with additional L2/R2/L3/R3 buttons
 * (similar to a PlayStation controller).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button (including D-Pad directions) to query.
 * The result of said query will be 1 if the button is down, 0 if not.
 *
 * There is one exception; if \c RETRO_DEVICE_ID_JOYPAD_MASK is queried
 * (and the frontend supports this query),
 * the result will be a bitmask of all pressed buttons.
 *
 * @see retro_input_state_t
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_ID_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 */
#define RETRO_DEVICE_JOYPAD       1

/**
 * An abstraction around a mouse, similar to the SNES Mouse but with more buttons.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button or axis to query.
 * For buttons, the result of said query
 * will be 1 if the button is down or 0 if not.
 * For mouse wheel axes, the result
 * will be 1 if the wheel was rotated in that direction and 0 if not.
 * For the mouse pointer axis, the result will be thee mouse's movement
 * relative to the last poll.
 * The core is responsible for tracking the mouse's position,
 * and the frontend is responsible for preventing interference
 * by the real hardware pointer (if applicable).
 *
 * @note This should only be used for cores that emulate mouse input,
 * such as for home computers
 * or consoles with mouse attachments.
 * Cores that emulate light guns should use \c RETRO_DEVICE_LIGHTGUN,
 * and cores that emulate touch screens should use \c RETRO_DEVICE_POINTER.
 *
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_DEVICE_LIGHTGUN
 */
#define RETRO_DEVICE_MOUSE        2

/**
 * An abstraction around a keyboard.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the key to poll.
 *
 * @note This should only be used for cores that emulate keyboard input,
 * such as for home computers
 * or consoles with keyboard attachments.
 * Cores that emulate gamepads should use \c RETRO_DEVICE_JOYPAD or \c RETRO_DEVICE_ANALOG,
 * and leave keyboard compatibility to the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK
 * @see retro_key
 */
#define RETRO_DEVICE_KEYBOARD     3

/**
 * An abstraction around a light gun, similar to the PlayStation's Guncon.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes one of several possible inputs.
 *
 * The gun's coordinates are reported in screen space (similar to the pointer)
 * in the range of [-0x8000, 0x7fff].
 * Zero is the center of the game's screen
 * and -0x8000 represents out-of-bounds.
 * The trigger and various auxiliary buttons are also reported.
 *
 * @note A forced off-screen shot can be requested for auto-reloading
 * function in some games.
 *
 * @see RETRO_DEVICE_POINTER
 */
#define RETRO_DEVICE_LIGHTGUN     4

/**
 * An extension of the RetroPad that supports analog input.
 *
 * The analog RetroPad provides two virtual analog sticks (similar to DualShock controllers)
 * and allows any button to be treated as analog (similar to Xbox shoulder triggers).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes an analog axis or an analog button.
 *
 * Analog axes are reported in the range of [-0x8000, 0x7fff],
 * with the X axis being positive towards the right
 * and the Y axis being positive towards the bottom.
 *
 * Analog buttons are reported in the range of [0, 0x7fff],
 * where 0 is unpressed and 0x7fff is fully pressed.
 *
 * @note Cores should only use this type if they need analog input.
 * Otherwise, \c RETRO_DEVICE_JOYPAD should be used.
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ANALOG       5

/**
 * Input Device: Pointer.
 *
 * Abstracts the concept of a pointing mechanism, e.g. touch.
 * This allows libretro to query in absolute coordinates where on the
 * screen a mouse (or something similar) is being placed.
 * For a touch centric device, coordinates reported are the coordinates
 * of the press.
 *
 * Coordinates in X and Y are reported as:
 * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
 * and 0x7fff corresponds to the far right/bottom of the screen.
 * The "screen" is here defined as area that is passed to the frontend and
 * later displayed on the monitor. If the pointer is outside this screen,
 * such as in the black surrounding areas when actual display is larger,
 * edge position is reported. An explicit edge detection is also provided,
 * that will return 1 if the pointer is near the screen edge or actually outside it.
 *
 * The frontend is free to scale/resize this screen as it sees fit, however,
 * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
 * game image, etc.
 *
 * To check if the pointer coordinates are valid (e.g. a touch display
 * actually being touched), \c RETRO_DEVICE_ID_POINTER_PRESSED returns 1 or 0.
 *
 * If using a mouse on a desktop, \c RETRO_DEVICE_ID_POINTER_PRESSED will
 * usually correspond to the left mouse button, but this is a frontend decision.
 * \c RETRO_DEVICE_ID_POINTER_PRESSED will only return 1 if the pointer is
 * inside the game screen.
 *
 * For multi-touch, the index variable can be used to successively query
 * more presses.
 * If index = 0 returns true for \c _PRESSED, coordinates can be extracted
 * with \c _X, \c _Y for index = 0. One can then query \c _PRESSED, \c _X, \c _Y with
 * index = 1, and so on.
 * Eventually \c _PRESSED will return false for an index. No further presses
 * are registered at this point.
 *
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_ID_POINTER_X
 * @see RETRO_DEVICE_ID_POINTER_Y
 * @see RETRO_DEVICE_ID_POINTER_PRESSED
 */
#define RETRO_DEVICE_POINTER      6

/** @} */

/** @defgroup RETRO_DEVICE_ID_JOYPAD RetroPad Input
 * @brief Digital buttons for the RetroPad.
 *
 * Button placement is comparable to that of a SNES controller,
 * combined with the shoulder buttons of a PlayStation controller.
 * These values can also be used for the \c id field of \c RETRO_DEVICE_INDEX_ANALOG_BUTTON
 * to represent analog buttons (usually shoulder triggers).
 * @{
 */

/** The equivalent of the SNES controller's south face button. */
#define RETRO_DEVICE_ID_JOYPAD_B        0

/** The equivalent of the SNES controller's west face button. */
#define RETRO_DEVICE_ID_JOYPAD_Y        1

/** The equivalent of the SNES controller's left-center button. */
#define RETRO_DEVICE_ID_JOYPAD_SELECT   2

/** The equivalent of the SNES controller's right-center button. */
#define RETRO_DEVICE_ID_JOYPAD_START    3

/** Up on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_UP       4

/** Down on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_DOWN     5

/** Left on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_LEFT     6

/** Right on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7

/** The equivalent of the SNES controller's east face button. */
#define RETRO_DEVICE_ID_JOYPAD_A        8

/** The equivalent of the SNES controller's north face button. */
#define RETRO_DEVICE_ID_JOYPAD_X        9

/** The equivalent of the SNES controller's left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L       10

/** The equivalent of the SNES controller's right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R       11

/** The equivalent of the PlayStation's rear left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L2      12

/** The equivalent of the PlayStation's rear right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R2      13

/**
 * The equivalent of the PlayStation's left analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_L3      14

/**
 * The equivalent of the PlayStation's right analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_R3      15

/**
 * Represents a bitmask that describes the state of all \c RETRO_DEVICE_ID_JOYPAD button constants,
 * rather than the state of a single button.
 *
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ID_JOYPAD_MASK    256

/** @} */

/** @defgroup RETRO_DEVICE_ID_ANALOG Analog RetroPad Input
 * @{
 */

/* Index / Id values for ANALOG device. */
#define RETRO_DEVICE_INDEX_ANALOG_LEFT       0
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT      1
#define RETRO_DEVICE_INDEX_ANALOG_BUTTON     2
#define RETRO_DEVICE_ID_ANALOG_X             0
#define RETRO_DEVICE_ID_ANALOG_Y             1

/** @} */

/* Id values for MOUSE. */
#define RETRO_DEVICE_ID_MOUSE_X                0
#define RETRO_DEVICE_ID_MOUSE_Y                1
#define RETRO_DEVICE_ID_MOUSE_LEFT             2
#define RETRO_DEVICE_ID_MOUSE_RIGHT            3
#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4
#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5
#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8
#define RETRO_DEVICE_ID_MOUSE_BUTTON_4         9
#define RETRO_DEVICE_ID_MOUSE_BUTTON_5         10

/* Id values for LIGHTGUN. */
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X        13 /*Absolute Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y        14 /*Absolute Position*/
/** Indicates if lightgun points off the screen or near the edge */
#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN    15 /*Status Check*/
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER          2
#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD          16 /*Forced off-screen shot*/
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A            3
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B            4
#define RETRO_DEVICE_ID_LIGHTGUN_START            6
#define RETRO_DEVICE_ID_LIGHTGUN_SELECT           7
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C            8
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP          9
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN       10
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT       11
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT      12
/* deprecated */
#define RETRO_DEVICE_ID_LIGHTGUN_X                0 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_Y                1 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR           3 /*Use Aux:A instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO            4 /*Use Aux:B instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE            5 /*Use Start instead*/

/* Id values for POINTER. */
#define RETRO_DEVICE_ID_POINTER_X             0
#define RETRO_DEVICE_ID_POINTER_Y             1
#define RETRO_DEVICE_ID_POINTER_PRESSED       2
#define RETRO_DEVICE_ID_POINTER_COUNT         3
/** Indicates if pointer is off the screen or near the edge */
#define RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN 15
/** @} */

/* Returned from retro_get_region(). */
#define RETRO_REGION_NTSC  0
#define RETRO_REGION_PAL   1

/**
 * Identifiers for supported languages.
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 */
enum retro_language
{
   RETRO_LANGUAGE_ENGLISH             = 0,
   RETRO_LANGUAGE_JAPANESE            = 1,
   RETRO_LANGUAGE_FRENCH              = 2,
   RETRO_LANGUAGE_SPANISH             = 3,
   RETRO_LANGUAGE_GERMAN              = 4,
   RETRO_LANGUAGE_ITALIAN             = 5,
   RETRO_LANGUAGE_DUTCH               = 6,
   RETRO_LANGUAGE_PORTUGUESE_BRAZIL   = 7,
   RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,
   RETRO_LANGUAGE_RUSSIAN             = 9,
   RETRO_LANGUAGE_KOREAN              = 10,
   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,
   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 12,
   RETRO_LANGUAGE_ESPERANTO           = 13,
   RETRO_LANGUAGE_POLISH              = 14,
   RETRO_LANGUAGE_VIETNAMESE          = 15,
   RETRO_LANGUAGE_ARABIC              = 16,
   RETRO_LANGUAGE_GREEK               = 17,
   RETRO_LANGUAGE_TURKISH             = 18,
   RETRO_LANGUAGE_SLOVAK              = 19,
   RETRO_LANGUAGE_PERSIAN             = 20,
   RETRO_LANGUAGE_HEBREW              = 21,
   RETRO_LANGUAGE_ASTURIAN            = 22,
   RETRO_LANGUAGE_FINNISH             = 23,
   RETRO_LANGUAGE_INDONESIAN          = 24,
   RETRO_LANGUAGE_SWEDISH             = 25,
   RETRO_LANGUAGE_UKRAINIAN           = 26,
   RETRO_LANGUAGE_CZECH               = 27,
   RETRO_LANGUAGE_CATALAN_VALENCIA    = 28,
   RETRO_LANGUAGE_CATALAN             = 29,
   RETRO_LANGUAGE_BRITISH_ENGLISH     = 30,
   RETRO_LANGUAGE_HUNGARIAN           = 31,
   RETRO_LANGUAGE_BELARUSIAN          = 32,
   RETRO_LANGUAGE_GALICIAN            = 33,
   RETRO_LANGUAGE_NORWEGIAN           = 34,
   RETRO_LANGUAGE_IRISH               = 35,
   RETRO_LANGUAGE_LAST,

   /** Defined to ensure that <tt>sizeof(retro_language) == sizeof(int)</tt>. Do not use. */
   RETRO_LANGUAGE_DUMMY          = INT_MAX
};

/** @defgroup RETRO_MEMORY Memory Types
 * @{
 */

/* Passed to retro_get_memory_data/size().
 * If the memory type doesn't apply to the
 * implementation NULL/0 can be returned.
 */
#define RETRO_MEMORY_MASK        0xff

/* Regular save RAM. This RAM is usually found on a game cartridge,
 * backed up by a battery.
 * If save game data is too complex for a single memory buffer,
 * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
 * callback can be used. */
#define RETRO_MEMORY_SAVE_RAM    0

/* Some games have a built-in clock to keep track of time.
 * This memory is usually just a couple of bytes to keep track of time.
 */
#define RETRO_MEMORY_RTC         1

/* System ram lets a frontend peek into a game systems main RAM. */
#define RETRO_MEMORY_SYSTEM_RAM  2

/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
#define RETRO_MEMORY_VIDEO_RAM   3

/** @} */

/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
enum retro_key
{
   RETROK_UNKNOWN        = 0,
   RETROK_FIRST          = 0,
   RETROK_BACKSPACE      = 8,
   RETROK_TAB            = 9,
   RETROK_CLEAR          = 12,
   RETROK_RETURN         = 13,
   RETROK_PAUSE          = 19,
   RETROK_ESCAPE         = 27,
   RETROK_SPACE          = 32,
   RETROK_EXCLAIM        = 33,
   RETROK_QUOTEDBL       = 34,
   RETROK_HASH           = 35,
   RETROK_DOLLAR         = 36,
   RETROK_AMPERSAND      = 38,
   RETROK_QUOTE          = 39,
   RETROK_LEFTPAREN      = 40,
   RETROK_RIGHTPAREN     = 41,
   RETROK_ASTERISK       = 42,
   RETROK_PLUS           = 43,
   RETROK_COMMA          = 44,
   RETROK_MINUS          = 45,
   RETROK_PERIOD         = 46,
   RETROK_SLASH          = 47,
   RETROK_0              = 48,
   RETROK_1              = 49,
   RETROK_2              = 50,
   RETROK_3              = 51,
   RETROK_4              = 52,
   RETROK_5              = 53,
   RETROK_6              = 54,
   RETROK_7              = 55,
   RETROK_8              = 56,
   RETROK_9              = 57,
   RETROK_COLON          = 58,
   RETROK_SEMICOLON      = 59,
   RETROK_LESS           = 60,
   RETROK_EQUALS         = 61,
   RETROK_GREATER        = 62,
   RETROK_QUESTION       = 63,
   RETROK_AT             = 64,
   RETROK_LEFTBRACKET    = 91,
   RETROK_BACKSLASH      = 92,
   RETROK_RIGHTBRACKET   = 93,
   RETROK_CARET          = 94,
   RETROK_UNDERSCORE     = 95,
   RETROK_BACKQUOTE      = 96,
   RETROK_a              = 97,
   RETROK_b              = 98,
   RETROK_c              = 99,
   RETROK_d              = 100,
   RETROK_e              = 101,
   RETROK_f              = 102,
   RETROK_g              = 103,
   RETROK_h              = 104,
   RETROK_i              = 105,
   RETROK_j              = 106,
   RETROK_k              = 107,
   RETROK_l              = 108,
   RETROK_m              = 109,
   RETROK_n              = 110,
   RETROK_o              = 111,
   RETROK_p              = 112,
   RETROK_q              = 113,
   RETROK_r              = 114,
   RETROK_s              = 115,
   RETROK_t              = 116,
   RETROK_u              = 117,
   RETROK_v              = 118,
   RETROK_w              = 119,
   RETROK_x              = 120,
   RETROK_y              = 121,
   RETROK_z              = 122,
   RETROK_LEFTBRACE      = 123,
   RETROK_BAR            = 124,
   RETROK_RIGHTBRACE     = 125,
   RETROK_TILDE          = 126,
   RETROK_DELETE         = 127,

   RETROK_KP0            = 256,
   RETROK_KP1            = 257,
   RETROK_KP2            = 258,
   RETROK_KP3            = 259,
   RETROK_KP4            = 260,
   RETROK_KP5            = 261,
   RETROK_KP6            = 262,
   RETROK_KP7            = 263,
   RETROK_KP8            = 264,
   RETROK_KP9            = 265,
   RETROK_KP_PERIOD      = 266,
   RETROK_KP_DIVIDE      = 267,
   RETROK_KP_MULTIPLY    = 268,
   RETROK_KP_MINUS       = 269,
   RETROK_KP_PLUS        = 270,
   RETROK_KP_ENTER       = 271,
   RETROK_KP_EQUALS      = 272,

   RETROK_UP             = 273,
   RETROK_DOWN           = 274,
   RETROK_RIGHT          = 275,
   RETROK_LEFT           = 276,
   RETROK_INSERT         = 277,
   RETROK_HOME           = 278,
   RETROK_END            = 279,
   RETROK_PAGEUP         = 280,
   RETROK_PAGEDOWN       = 281,

   RETROK_F1             = 282,
   RETROK_F2             = 283,
   RETROK_F3             = 284,
   RETROK_F4             = 285,
   RETROK_F5             = 286,
   RETROK_F6             = 287,
   RETROK_F7             = 288,
   RETROK_F8             = 289,
   RETROK_F9             = 290,
   RETROK_F10            = 291,
   RETROK_F11            = 292,
   RETROK_F12            = 293,
   RETROK_F13            = 294,
   RETROK_F14            = 295,
   RETROK_F15            = 296,

   RETROK_NUMLOCK        = 300,
   RETROK_CAPSLOCK       = 301,
   RETROK_SCROLLOCK      = 302,
   RETROK_RSHIFT         = 303,
   RETROK_LSHIFT         = 304,
   RETROK_RCTRL          = 305,
   RETROK_LCTRL          = 306,
   RETROK_RALT           = 307,
   RETROK_LALT           = 308,
   RETROK_RMETA          = 309,
   RETROK_LMETA          = 310,
   RETROK_LSUPER         = 311,
   RETROK_RSUPER         = 312,
   RETROK_MODE           = 313,
   RETROK_COMPOSE        = 314,

   RETROK_HELP           = 315,
   RETROK_PRINT          = 316,
   RETROK_SYSREQ         = 317,
   RETROK_BREAK          = 318,
   RETROK_MENU           = 319,
   RETROK_POWER          = 320,
   RETROK_EURO           = 321,
   RETROK_UNDO           = 322,
   RETROK_OEM_102        = 323,

   RETROK_BROWSER_BACK      = 324,
   RETROK_BROWSER_FORWARD   = 325,
   RETROK_BROWSER_REFRESH   = 326,
   RETROK_BROWSER_STOP      = 327,
   RETROK_BROWSER_SEARCH    = 328,
   RETROK_BROWSER_FAVORITES = 329,
   RETROK_BROWSER_HOME      = 330,
   RETROK_VOLUME_MUTE       = 331,
   RETROK_VOLUME_DOWN       = 332,
   RETROK_VOLUME_UP         = 333,
   RETROK_MEDIA_NEXT        = 334,
   RETROK_MEDIA_PREV        = 335,
   RETROK_MEDIA_STOP        = 336,
   RETROK_MEDIA_PLAY_PAUSE  = 337,
   RETROK_LAUNCH_MAIL       = 338,
   RETROK_LAUNCH_MEDIA      = 339,
   RETROK_LAUNCH_APP1       = 340,
   RETROK_LAUNCH_APP2       = 341,

   RETROK_LAST,

   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

enum retro_mod
{
   RETROKMOD_NONE       = 0x0000,

   RETROKMOD_SHIFT      = 0x01,
   RETROKMOD_CTRL       = 0x02,
   RETROKMOD_ALT        = 0x04,
   RETROKMOD_META       = 0x08,

   RETROKMOD_NUMLOCK    = 0x10,
   RETROKMOD_CAPSLOCK   = 0x20,
   RETROKMOD_SCROLLOCK  = 0x40,

   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

/**
 * @defgroup RETRO_ENVIRONMENT Environment Callbacks
 * @{
 */

/**
 * This bit indicates that the associated environment call is experimental,
 * and may be changed or removed in the future.
 * Frontends should mask out this bit before handling the environment call.
 */
#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000

/** Frontend-internal environment callbacks should include this bit. */
#define RETRO_ENVIRONMENT_PRIVATE 0x20000

/* Environment commands. */
/**
 * Requests the frontend to set the screen rotation.
 *
 * @param[in] data <tt>const unsigned*</tt>.
 * Valid values are 0, 1, 2, and 3.
 * These numbers respectively set the screen rotation to 0, 90, 180, and 270 degrees counter-clockwise.
 * @returns \c true if the screen rotation was set successfully.
 */
#define RETRO_ENVIRONMENT_SET_ROTATION  1

/**
 * Queries whether the core should use overscan or not.
 *
 * @param[out] data <tt>bool*</tt>.
 * Set to \c true if the core should use overscan,
 * \c false if it should be cropped away.
 * @returns \c true if the environment call is available.
 * Does \em not indicate whether overscan should be used.
 * @deprecated As of 2019 this callback is considered deprecated in favor of
 * using core options to manage overscan in a more nuanced, core-specific way.
 */
#define RETRO_ENVIRONMENT_GET_OVERSCAN  2

/**
 * Queries whether the frontend supports frame duping,
 * in the form of passing \c NULL to the video frame callback.
 *
 * @param[out] data <tt>bool*</tt>.
 * Set to \c true if the frontend supports frame duping.
 * @returns \c true if the environment call is available.
 * @see retro_video_refresh_t
 */
#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3

/*
 * Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
 * and reserved to avoid possible ABI clash.
 */

/**
 * @brief Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * \code{.c}
 * void set_message_example(void)
 * {
 *    struct retro_message msg;
 *    msg.frames = 60 * 5; // 5 seconds
 *    msg.msg = "Hello world!";
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
 * }
 * \endcode
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT for new code,
 * as it offers more features.
 * Only use this environment call for compatibility with older cores or frontends.
 *
 * @param[in] data <tt>const struct retro_message*</tt>.
 * Details about the message to show to the user.
 * Behavior is undefined if <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see retro_message
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 * @note The frontend must make its own copy of the message and the underlying string.
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE   6

/**
 * Requests the frontend to shutdown the core.
 * Should only be used if the core can exit on its own,
 * such as from a menu item in a game
 * or an emulated power-off in an emulator.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_SHUTDOWN      7

/**
 * Gives a hint to the frontend of how demanding this core is on the system.
 * For example, reporting a level of 2 means that
 * this implementation should run decently on frontends
 * of level 2 and above.
 *
 * It can be used by the frontend to potentially warn
 * about too demanding implementations.
 *
 * The levels are "floating".
 *
 * This function can be called on a per-game basis,
 * as a core may have different demands for different games or settings.
 * If called, it should be called in <tt>retro_load_game()</tt>.
 * @param[in] data <tt>const unsigned*</tt>.
*/
#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8

/**
 * Returns the path to the frontend's system directory,
 * which can be used to store system-specific configuration
 * such as BIOS files or cached data.
 *
 * @param[out] data <tt>const char**</tt>.
 * Pointer to the \c char* in which the system directory will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no system directory is defined,
 * in which case the core should find an alternative directory.
 * @return \c true if the environment call is available,
 * even if the value returned in \c data is <tt>NULL</tt>.
 * @note Historically, some cores would use this folder for save data such as memory cards or SRAM.
 * This is now discouraged in favor of \c RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY.
 * @see RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9

/**
 * Sets the internal pixel format used by the frontend for rendering.
 * The default pixel format is \c RETRO_PIXEL_FORMAT_0RGB1555 for compatibility reasons,
 * although it's considered deprecated and shouldn't be used by new code.
 *
 * @param[in] data <tt>const enum retro_pixel_format *</tt>.
 * Pointer to the pixel format to use.
 * @returns \c true if the pixel format was set successfully,
 * \c false if it's not supported or this callback is unavailable.
 * @note This function should be called inside \c retro_load_game()
 * or <tt>retro_get_system_av_info()</tt>.
 * @see retro_pixel_format
 */
#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10

/**
 * Sets an array of input descriptors for the frontend
 * to present to the user for configuring the core's controls.
 *
 * This function can be called at any time,
 * preferably early in the core's life cycle.
 * Ideally, no later than \c retro_load_game().
 *
 * @param[in] data <tt>const struct retro_input_descriptor *</tt>.
 * An array of input descriptors terminated by one whose
 * \c retro_input_descriptor::description field is set to \c NULL.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is recognized.
 * @see retro_input_descriptor
 */
#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11

/**
 * Sets a callback function used to notify the core about keyboard events.
 * This should only be used for cores that specifically need keyboard input,
 * such as for home computer emulators or games with text entry.
 *
 * @param[in] data <tt>const struct retro_keyboard_callback *</tt>.
 * Pointer to the callback function.
 * Behavior is undefined if <tt>NULL</tt>.
 * @return \c true if the environment call is recognized.
 * @see retro_keyboard_callback
 * @see retro_key
 */
#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12

/**
 * Sets an interface that the frontend can use to insert and remove disks
 * from the emulated console's disk drive.
 * Can be used for optical disks, floppy disks, or any other game storage medium
 * that can be swapped at runtime.
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * over this environment call, as it supports additional features.
 * Only use this callback to maintain compatibility
 * with older cores or frontends.
 *
 * @param[in] data <tt>const struct retro_disk_control_callback *</tt>.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_callback
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13

/**
 * Requests that a frontend enable a particular hardware rendering API.
 *
 * If successful, the frontend will create a context (and other related resources)
 * that the core can use for rendering.
 * The framebuffer will be at least as large as
 * the maximum dimensions provided in <tt>retro_get_system_av_info</tt>.
 *
 * @param[in, out] data <tt>struct retro_hw_render_callback *</tt>.
 * Pointer to the hardware render callback struct.
 * Used to define callbacks for the hardware-rendering life cycle,
 * as well as to request a particular rendering API.
 * @return \c true if the environment call is recognized
 * and the requested rendering API is supported.
 * \c false if \c data is \c NULL
 * or the frontend can't provide the requested rendering API.
 * @see retro_hw_render_callback
 * @see retro_video_refresh_t
 * @see RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER
 * @note Should be called in <tt>retro_load_game()</tt>.
 * @note If HW rendering is used, pass only \c RETRO_HW_FRAME_BUFFER_VALID or
 * \c NULL to <tt>retro_video_refresh_t</tt>.
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER 14

/**
 * Retrieves a core option's value from the frontend.
 * \c retro_variable::key should be set to an option key
 * that was previously set in \c RETRO_ENVIRONMENT_SET_VARIABLES
 * (or a similar environment call).
 *
 * @param[in,out] data <tt>struct retro_variable *</tt>.
 * Pointer to a single \c retro_variable struct.
 * See the documentation for \c retro_variable for details
 * on which fields are set by the frontend or core.
 * May be \c NULL.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL or the key it specifies is not found.
 * @note Passing \c NULL in to \c data can be useful to
 * test for support of this environment call without looking up any variables.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE 15

/**
 * Notifies the frontend of the core's available options.
 *
 * The core may check these options later using \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * The frontend may also present these options to the user
 * in its own configuration UI.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment.
 * The core may later call this function again
 * to communicate updated options to the frontend,
 * but the number of core options must not change.
 *
 * Here's an example that sets two options.
 *
 * @code
 * void set_variables_example(void)
 * {
 *    struct retro_variable options[] = {
 *        { "foo_speedhack", "Speed hack; false|true" }, // false by default
 *        { "foo_displayscale", "Display scale factor; 1|2|3|4" }, // 1 by default
 *        { NULL, NULL },
 *    };
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, &options);
 * }
 * @endcode
 *
 * The possible values will generally be displayed and stored as-is by the frontend.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 for new code,
 * as it offers more features such as categories and translation.
 * Only use this environment call to maintain compatibility
 * with older frontends or cores.
 * @note Keep the available options (and their possible values) as low as possible;
 * it should be feasible to cycle through them without a keyboard.
 * @param[in] data <tt>const struct retro_variable *</tt>.
 * Pointer to an array of \c retro_variable structs that define available core options,
 * terminated by a <tt>{ NULL, NULL }</tt> element.
 * The frontend must maintain its own copy of this array.
 *
 * @returns \c true if the environment call is available,
 * even if \c data is <tt>NULL</tt>.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_VARIABLES 16

/**
 * Queries whether at least one core option was updated by the frontend
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * This typically means that the user opened the core options menu and made some changes.
 *
 * Cores usually call this each frame before the core's main emulation logic.
 * Specific options can then be queried with \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 *
 * @param[out] data <tt>bool *</tt>.
 * Set to \c true if at least one core option was updated
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * Behavior is undefined if this pointer is \c NULL.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17

/**
 * Notifies the frontend that this core can run without loading any content,
 * such as when emulating a console that has built-in software.
 * When a core is loaded without content,
 * \c retro_load_game receives an argument of <tt>NULL</tt>.
 * This should be called within \c retro_set_environment() only.
 *
 * @param[in] data <tt>const bool *</tt>.
 * Pointer to a single \c bool that indicates whether this frontend can run without content.
 * Can point to a value of \c false but this isn't necessary,
 * as contentless support is opt-in.
 * The behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see retro_load_game
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18

/**
 * Retrieves the absolute path from which this core was loaded.
 * Useful when loading assets from paths relative to the core,
 * as is sometimes the case when using <tt>RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME</tt>.
 *
 * @param[out] data <tt>const char **</tt>.
 * Pointer to a string in which the core's path will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if the core is statically linked to the frontend
 * or if the core's path otherwise cannot be determined.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19

/* Environment call 20 was an obsolete version of SET_AUDIO_CALLBACK.
 * It was not used by any known core at the time, and was removed from the API.
 * The number 20 is reserved to prevent ABI clashes.
 */

/**
 * Sets a callback that notifies the core of how much time has passed
 * since the last iteration of <tt>retro_run</tt>.
 * If the frontend is not running the core in real time
 * (e.g. it's frame-stepping or running in slow motion),
 * then the reference value will be provided to the callback instead.
 *
 * @param[in] data <tt>const struct retro_frame_time_callback *</tt>.
 * Pointer to a single \c retro_frame_time_callback struct.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @note Frontends may disable this environment call in certain situations.
 * It will return \c false in those cases.
 * @see retro_frame_time_callback
 */
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21

/**
 * Registers a set of functions that the frontend can use
 * to tell the core it's ready for audio output.
 *
 * It is intended for games that feature asynchronous audio.
 * It should not be used for emulators unless their audio is asynchronous.
 *
 *
 * The callback only notifies about writability; the libretro core still
 * has to call the normal audio callbacks
 * to write audio. The audio callbacks must be called from within the
 * notification callback.
 * The amount of audio data to write is up to the core.
 * Generally, the audio callback will be called continuously in a loop.
 *
 * A frontend may disable this callback in certain situations.
 * The core must be able to render audio with the "normal" interface.
 *
 * @param[in] data <tt>const struct retro_audio_callback *</tt>.
 * Pointer to a set of functions that the frontend will call to notify the core
 * when it's ready to receive audio data.
 * May be \c NULL, in which case the frontend will return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @warning The provided callbacks can be invoked from any thread,
 * so their implementations \em must be thread-safe.
 * @note If a core uses this callback,
 * it should also use <tt>RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK</tt>.
 * @see retro_audio_callback
 * @see retro_audio_sample_t
 * @see retro_audio_sample_batch_t
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22

/**
 * Gets an interface that a core can use to access a controller's rumble motors.
 *
 * The interface supports two independently-controlled motors,
 * one strong and one weak.
 *
 * Should be called from either \c retro_init() or \c retro_load_game(),
 * but not from \c retro_set_environment().
 *
 * @param[out] data <tt>struct retro_rumble_interface *</tt>.
 * Pointer to the interface struct.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the current device doesn't support vibration.
 * @see retro_rumble_interface
 * @defgroup GET_RUMBLE_INTERFACE Rumble Interface
 */
#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23

/**
 * Returns the frontend's supported input device types.
 *
 * The supported device types are returned as a bitmask,
 * with each value of \ref RETRO_DEVICE corresponding to a bit.
 *
 * Should only be called in \c retro_run().
 *
 * @code
 * #define REQUIRED_DEVICES ((1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG))
 * void get_input_device_capabilities_example(void)
 * {
 *    uint64_t capabilities;
 *    environ_cb(RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES, &capabilities);
 *    if ((capabilities & REQUIRED_DEVICES) == REQUIRED_DEVICES)
 *      printf("Joypad and analog device types are supported");
 * }
 * @endcode
 *
 * @param[out] data <tt>uint64_t *</tt>.
 * Pointer to a bitmask of supported input device types.
 * If the frontend supports a particular \c RETRO_DEVICE_* type,
 * then the bit <tt>(1 << RETRO_DEVICE_*)</tt> will be set.
 *
 * Each bit represents a \c RETRO_DEVICE constant,
 * e.g. bit 1 represents \c RETRO_DEVICE_JOYPAD,
 * bit 2 represents \c RETRO_DEVICE_MOUSE, and so on.
 *
 * Bits that do not correspond to known device types will be set to zero
 * and are reserved for future use.
 *
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note If the frontend supports multiple input drivers,
 * availability of this environment call (and the reported capabilities)
 * may depend on the active driver.
 * @see RETRO_DEVICE
 */
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24

/**
 * Returns an interface that the core can use to access and configure available sensors,
 * such as an accelerometer or gyroscope.
 *
 * @param[out] data <tt>struct retro_sensor_interface *</tt>.
 * Pointer to the sensor interface that the frontend will populate.
 * Behavior is undefined if is \c NULL.
 * @returns \c true if the environment call is available,
 * even if the device doesn't have any supported sensors.
 * @see retro_sensor_interface
 * @see retro_sensor_action
 * @see RETRO_SENSOR
 * @addtogroup RETRO_SENSOR
 */
#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface to the device's video camera.
 *
 * The frontend delivers new video frames via a user-defined callback
 * that runs in the same thread as \c retro_run().
 * Should be called in \c retro_load_game().
 *
 * @param[in,out] data <tt>struct retro_camera_callback *</tt>.
 * Pointer to the camera driver interface.
 * Some fields in the struct must be filled in by the core,
 * others are provided by the frontend.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available,
 * even if an actual camera isn't.
 * @note This API only supports one video camera at a time.
 * If the device provides multiple cameras (e.g. inner/outer cameras on a phone),
 * the frontend will choose one to use.
 * @see retro_camera_callback
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for cross-platform logging.
 * Certain platforms don't have a console or <tt>stderr</tt>,
 * or they have their own preferred logging methods.
 * The frontend itself may also display log output.
 *
 * @attention This should not be used for information that the player must immediately see,
 * such as major errors or warnings.
 * In most cases, this is best for information that will help you (the developer)
 * identify problems when debugging or providing support.
 * Unless a core or frontend is intended for advanced users,
 * the player might not check (or even know about) their logs.
 *
 * @param[out] data <tt>struct retro_log_callback *</tt>.
 * Pointer to the callback where the function pointer will be saved.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see retro_log_callback
 * @note Cores can fall back to \c stderr if this interface is not available.
 */
#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27

/**
 * Returns an interface that the core can use for profiling code
 * and to access performance-related information.
 *
 * This callback supports performance counters, a high-resolution timer,
 * and listing available CPU features (mostly SIMD instructions).
 *
 * @param[out] data <tt>struct retro_perf_callback *</tt>.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @see retro_perf_callback
 */
#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28

/**
 * Returns an interface that the core can use to retrieve the device's location,
 * including its current latitude and longitude.
 *
 * @param[out] data <tt>struct retro_location_callback *</tt>.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is available,
 * even if there's no location information available.
 * @see retro_location_callback
 */
#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29

/**
 * @deprecated An obsolete alias to \c RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY kept for compatibility.
 * @see RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY
 **/
#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30

/**
 * Returns the frontend's "core assets" directory,
 * which can be used to store assets that the core needs
 * such as art assets or level data.
 *
 * @param[out] data <tt>const char **</tt>.
 * Pointer to a string in which the core assets directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no core assets directory is defined,
 * in which case the core should find an alternative directory.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is <tt>NULL</tt>.
 */
#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30

/**
 * Returns the frontend's save data directory, if available.
 * This directory should be used to store game-specific save data,
 * including memory card images.
 *
 * Although libretro provides an interface for cores to expose SRAM to the frontend,
 * not all cores can support it correctly.
 * In this case, cores should use this environment callback
 * to save their game data to disk manually.
 *
 * Cores that use this environment callback
 * should flush their save data to disk periodically and when unloading.
 *
 * @param[out] data <tt>const char **</tt>.
 * Pointer to the string in which the save data directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May return \c NULL if no save data directory is defined.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is <tt>NULL</tt>.
 * @note Early libretro cores used \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY for save data.
 * This is still supported for backwards compatibility,
 * but new cores should use this environment call instead.
 * \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY should be used for game-agnostic data
 * such as BIOS files or core-specific configuration.
 * @note The returned directory may or may not be the same
 * as the one used for \c retro_get_memory_data.
 *
 * @see retro_get_memory_data
 * @see RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31

/**
 * Sets new video and audio parameters for the core.
 * This can only be called from within <tt>retro_run</tt>.
 *
 * This environment call may entail a full reinitialization of the frontend's audio/video drivers,
 * hence it should \em only be used if the core needs to make drastic changes
 * to audio/video parameters.
 *
 * This environment call should \em not be used when:
 * <ul>
 * <li>Changing the emulated system's internal resolution,
 * within the limits defined by the existing values of \c max_width and \c max_height.
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY instead,
 * and adjust \c retro_get_system_av_info to account for
 * supported scale factors and screen layouts
 * when computing \c max_width and \c max_height.
 * Only use this environment call if \c max_width or \c max_height needs to increase.
 * <li>Adjusting the screen's aspect ratio,
 * e.g. when changing the layout of the screen(s).
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY or \c RETRO_ENVIRONMENT_SET_ROTATION instead.
 * </ul>
 *
 * The frontend will reinitialize its audio and video drivers within this callback;
 * after that happens, audio and video callbacks will target the newly-initialized driver,
 * even within the same \c retro_run call.
 *
 * This callback makes it possible to support configurable resolutions
 * while avoiding the need to compute the "worst case" values of \c max_width and \c max_height.
 *
 * @param[in] data <tt>const struct retro_system_av_info *</tt>.
 * Pointer to the new video and audio parameters that the frontend should adopt.
 * @returns \c true if the environment call is available
 * and the new av_info struct was accepted.
 * \c false if the environment call is unavailable or \c data is <tt>NULL</tt>.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 */
#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32

/**
 * Provides an interface that a frontend can use
 * to get function pointers from the core.
 *
 * This allows cores to define their own extensions to the libretro API,
 * or to expose implementations of a frontend's libretro extensions.
 *
 * @param[in] data <tt>const struct retro_get_proc_address_interface *</tt>.
 * Pointer to the interface that the frontend can use to get function pointers from the core.
 * The frontend must maintain its own copy of this interface.
 * @returns \c true if the environment call is available
 * and the returned interface was accepted.
 * @note The provided interface may be called at any time,
 * even before this environment call returns.
 * @note Extensions should be prefixed with the name of the frontend or core that defines them.
 * For example, a frontend named "foo" that defines a debugging extension
 * should expect the core to define functions prefixed with "foo_debug_".
 * @warning If a core wants to use this environment call,
 * it \em must do so from within \c retro_set_environment().
 * @see retro_get_proc_address_interface
 */
#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33

/**
 * Registers a core's ability to handle "subsystems",
 * which are secondary platforms that augment a core's primary emulated hardware.
 *
 * A core doesn't need to emulate a secondary platform
 * in order to use it as a subsystem;
 * as long as it can load a secondary file for some practical use,
 * then this environment call is most likely suitable.
 *
 * Possible use cases of a subsystem include:
 *
 * \li Installing software onto an emulated console's internal storage,
 * such as the Nintendo DSi.
 * \li Emulating accessories that are used to support another console's games,
 * such as the Super Game Boy or the N64 Transfer Pak.
 * \li Inserting a secondary ROM into a console
 * that features multiple cartridge ports,
 * such as the Nintendo DS's Slot-2.
 * \li Loading a save data file created and used by another core.
 *
 * Cores should \em not use subsystems for:
 *
 * \li Emulators that support multiple "primary" platforms,
 * such as a Game Boy/Game Boy Advance core
 * or a Sega Genesis/Sega CD/32X core.
 * Use \c retro_system_content_info_override, \c retro_system_info,
 * and/or runtime detection instead.
 * \li Selecting different memory card images.
 * Use dynamically-populated core options instead.
 * \li Different variants of a single console,
 * such the Game Boy vs. the Game Boy Color.
 * Use core options or runtime detection instead.
 * \li Games that span multiple disks.
 * Use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * and m3u-formatted playlists instead.
 * \li Console system files (BIOS, firmware, etc.).
 * Use \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 * and a common naming convention instead.
 *
 * When the frontend loads a game via a subsystem,
 * it must call \c retro_load_game_special() instead of \c retro_load_game().
 *
 * @param[in] data <tt>const struct retro_subsystem_info *</tt>.
 * Pointer to an array of subsystem descriptors,
 * terminated by a zeroed-out \c retro_subsystem_info struct.
 * The frontend should maintain its own copy
 * of this array and the strings within it.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @note This environment call \em must be called from within \c retro_set_environment(),
 * as frontends may need the registered information before loading a game.
 * @see retro_subsystem_info
 * @see retro_load_game_special
 */
#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34

/**
 * Declares one or more types of controllers supported by this core.
 * The frontend may then allow the player to select one of these controllers in its menu.
 *
 * Many consoles had controllers that came in different versions,
 * were extensible with peripherals,
 * or could be held in multiple ways;
 * this environment call can be used to represent these differences
 * and adjust the core's behavior to match.
 *
 * Possible use cases include:
 *
 * \li Supporting different classes of a single controller that supported their own sets of games.
 *     For example, the SNES had two different lightguns (the Super Scope and the Justifier)
 *     whose games were incompatible with each other.
 * \li Representing a platform's alternative controllers.
 *     For example, several platforms had music/rhythm games that included controllers
 *     shaped like musical instruments.
 * \li Representing variants of a standard controller with additional inputs.
 *     For example, numerous consoles in the 90's introduced 6-button controllers for fighting games,
 *     steering wheels for racing games,
 *     or analog sticks for 3D platformers.
 * \li Representing add-ons for consoles or standard controllers.
 *     For example, the 3DS had a Circle Pad Pro attachment that added a second analog stick.
 * \li Selecting different configurations for a single controller.
 *     For example, the Wii Remote could be held sideways like a traditional game pad
 *     or in one hand like a wand.
 * \li Providing multiple ways to simulate the experience of using a particular controller.
 *     For example, the Game Boy Advance featured several games
 *     with motion or light sensors in their cartridges;
 *     a core could provide controller configurations
 *     that allow emulating the sensors with either analog axes
 *     or with their host device's sensors.
 *
 * Should be called in retro_load_game.
 * The frontend must maintain its own copy of the provided array,
 * including all strings and subobjects.
 * A core may exclude certain controllers for known incompatible games.
 *
 * When the frontend changes the active device for a particular port,
 * it must call \c retro_set_controller_port_device() with that port's index
 * and one of the IDs defined in its retro_controller_info::types field.
 *
 * Input ports are generally associated with different players
 * (and the frontend's UI may reflect this with "Player 1" labels),
 * but this is not required.
 * Some games use multiple controllers for a single player,
 * or some cores may use port indexes to represent an emulated console's
 * alternative input peripherals.
 *
 * @param[in] data <tt>const struct retro_controller_info *</tt>.
 * Pointer to an array of controller types defined by this core,
 * terminated by a zeroed-out \c retro_controller_info.
 * Each element of this array represents a controller port on the emulated device.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_controller_info
 * @see retro_set_controller_port_device
 * @see RETRO_DEVICE_SUBCLASS
 */
#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35

/**
 * Notifies the frontend of the address spaces used by the core's emulated hardware,
 * and of the memory maps within these spaces.
 * This can be used by the frontend to provide cheats, achievements, or debugging capabilities.
 * Should only be used by emulators, as it makes little sense for game engines.
 *
 * @note Cores should also expose these address spaces
 * through retro_get_memory_data and \c retro_get_memory_size if applicable;
 * this environment call is not intended to replace those two functions,
 * as the emulated hardware may feature memory regions outside of its own address space
 * that are nevertheless useful for the frontend.
 *
 * @param[in] data <tt>const struct retro_memory_map *</tt>.
 * Pointer to a single memory-map listing.
 * The frontend must maintain its own copy of this object and its contents,
 * including strings and nested objects.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_memory_map
 * @see retro_get_memory_data
 * @see retro_memory_descriptor
 */
#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Resizes the viewport without reinitializing the video driver.
 *
 * Similar to \c RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
 * but any changes that would require video reinitialization will not be performed.
 * Can only be called from within \c retro_run().
 *
 * This environment call allows a core to revise the size of the viewport at will,
 * which can be useful for emulated platforms that support dynamic resolution changes
 * or for cores that support multiple screen layouts.
 *
 * A frontend must guarantee that this environment call completes in
 * constant time.
 *
 * @param[in] data <tt>const struct retro_game_geometry *</tt>.
 * Pointer to the new video parameters that the frontend should adopt.
 * \c retro_game_geometry::max_width and \c retro_game_geometry::max_height
 * will be ignored.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @return \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 */
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37

/**
 * Returns the name of the user, if possible.
 * This callback is suitable for cores that offer personalization,
 * such as online facilities or user profiles on the emulated system.
 * @param[out] data <tt>const char **</tt>.
 * Pointer to the user name string.
 * May be \c NULL, in which case the core should use a default name.
 * The returned pointer is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the frontend couldn't provide a name.
 */
#define RETRO_ENVIRONMENT_GET_USERNAME 38

/**
 * Returns the frontend's configured language.
 * It can be used to localize the core's UI,
 * or to customize the emulated firmware if applicable.
 *
 * @param[out] data <tt>retro_language *</tt>.
 * Pointer to the language identifier.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note The returned language may not be the same as the operating system's language.
 * Cores should fall back to the operating system's language (or to English)
 * if the environment call is unavailable or the returned language is unsupported.
 * @see retro_language
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_GET_LANGUAGE 39

/**
 * Returns a frontend-managed framebuffer
 * that the core may render directly into
 *
 * This environment call is provided as an optimization
 * for cores that use software rendering
 * (i.e. that don't use \refitem RETRO_ENVIRONMENT_SET_HW_RENDER "a graphics hardware API");
 * specifically, the intended use case is to allow a core
 * to render directly into frontend-managed video memory,
 * avoiding the bandwidth use that copying a whole framebuffer from core to video memory entails.
 *
 * Must be called every frame if used,
 * as this may return a different framebuffer each frame
 * (e.g. for swap chains).
 * However, a core may render to a different buffer even if this call succeeds.
 *
 * @param[in,out] data <tt>struct retro_framebuffer *</tt>.
 * Pointer to a frontend's frame buffer and accompanying data.
 * Some fields are set by the core, others are set by the frontend.
 * Only guaranteed to be valid for the duration of the current \c retro_run call,
 * and must not be used afterwards.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call was recognized
 * and the framebuffer was successfully returned.
 * @see retro_framebuffer
 */
#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface for accessing the data of specific rendering APIs.
 * Not all hardware rendering APIs support or need this.
 *
 * The details of these interfaces are specific to each rendering API.
 *
 * @note \c retro_hw_render_callback::context_reset must be called by the frontend
 * before this environment call can be used.
 * Additionally, the contents of the returned interface are invalidated
 * after \c retro_hw_render_callback::context_destroyed has been called.
 * @param[out] data <tt>const struct retro_hw_render_interface **</tt>.
 * The render interface for the currently-enabled hardware rendering API, if any.
 * The frontend will store a pointer to the interface at the address provided here.
 * The returned interface is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available,
 * the active graphics API has a libretro rendering interface,
 * and the frontend is able to return said interface.
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see retro_hw_render_interface
 * @note Since not every libretro-supported hardware rendering API
 * has a \c retro_hw_render_interface implementation,
 * a result of \c false is not necessarily an error.
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Explicitly notifies the frontend of whether this core supports achievements.
 * The core must expose its emulated address space via
 * \c retro_get_memory_data or \c RETRO_ENVIRONMENT_GET_MEMORY_MAPS.
 * Must be called before the first call to <tt>retro_run</tt>.
 *
 * If \ref retro_get_memory_data returns a valid address
 * but this environment call is not used,
 * the frontend (at its discretion) may or may not opt in the core to its achievements support.
 * whether this core is opted in to the frontend's achievement support
 * is left to the frontend's discretion.
 * @param[in] data <tt>const bool *</tt>.
 * Pointer to a single \c bool that indicates whether this core supports achievements.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 * @see retro_get_memory_data
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Defines an interface that the frontend can use
 * to ask the core for the parameters it needs for a hardware rendering context.
 * The exact semantics depend on \ref RETRO_ENVIRONMENT_SET_HW_RENDER "the active rendering API".
 * Will be used some time after \c RETRO_ENVIRONMENT_SET_HW_RENDER is called,
 * but before \c retro_hw_render_callback::context_reset is called.
 *
 * @param[in] data <tt>const struct retro_hw_render_context_negotiation_interface *</tt>.
 * Pointer to the context negotiation interface.
 * Will be populated by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported,
 * even if the current graphics API doesn't use
 * a context negotiation interface (in which case the argument is ignored).
 * @see retro_hw_render_context_negotiation_interface
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Notifies the frontend of any quirks associated with serialization.
 *
 * Should be set in either \c retro_init or \c retro_load_game, but not both.
 * @param[in, out] data <tt>uint64_t *</tt>.
 * Pointer to the core's serialization quirks.
 * The frontend will set the flags of the quirks it supports
 * and clear the flags of those it doesn't.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported.
 * @see retro_serialize
 * @see retro_unserialize
 * @see RETRO_SERIALIZATION_QUIRK
 */
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44

/**
 * The frontend will try to use a "shared" context when setting up a hardware context.
 * Mostly applicable to OpenGL.
 *
 * In order for this to have any effect,
 * the core must call \c RETRO_ENVIRONMENT_SET_HW_RENDER at some point
 * if it hasn't already.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available
 * and the frontend supports shared hardware contexts.
 */
#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use to access the file system.
 * Should be called as early as possible.
 *
 * @param[in,out] data <tt>struct retro_vfs_interface_info *</tt>.
 * Information about the desired VFS interface,
 * as well as the interface itself.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available
 * and the frontend can provide a VFS interface of the requested version or newer.
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 */
#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use
 * to set the state of any accessible device LEDs.
 *
 * @param[out] data <tt>struct retro_led_interface *</tt>.
 * Pointer to the LED interface that the frontend will populate.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL
 * or no LEDs are accessible.
 * @see retro_led_interface
 */
#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns hints about certain steps that the core may skip for this frame.
 *
 * A frontend may not need a core to generate audio or video in certain situations;
 * this environment call sets a bitmask that indicates
 * which steps the core may skip for this frame.
 *
 * This can be used to increase performance for some frontend features.
 *
 * @note Emulation accuracy should not be compromised;
 * for example, if a core emulates a platform that supports display capture
 * (i.e. looking at its own VRAM), then it should perform its rendering as normal
 * unless it can prove that the emulated game is not using display capture.
 *
 * @param[out] data <tt>retro_av_enable_flags *</tt>.
 * Pointer to the bitmask of steps that the frontend will skip.
 * Other bits are set to zero and are reserved for future use.
 * If \c NULL, the frontend will only return whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * regardless of the value output to \c data.
 * If \c false, the core should assume that the frontend will not skip any steps.
 * @see retro_av_enable_flags
 */
#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for raw MIDI I/O.
 *
 * @param[out] data <tt>struct retro_midi_interface *</tt>.
 * Pointer to the MIDI interface.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_midi_interface
 */
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend if it's currently in fast-forward mode.
 * @param[out] data <tt>bool *</tt>.
 * Set to \c true if the frontend is currently fast-forwarding its main loop.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if this environment call is available,
 * regardless of the value returned in \c data.
 *
 * @see RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE
 */
#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the refresh rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal refresh rate.
 *
 * @param[out] data <tt>float *</tt>.
 * Pointer to the \c float in which the frontend will store its target refresh rate.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns whether the frontend can return the state of all buttons at once as a bitmask,
 * rather than requiring a series of individual calls to \c retro_input_state_t.
 *
 * If this callback returns \c true,
 * you can get the state of all buttons by passing \c RETRO_DEVICE_ID_JOYPAD_MASK
 * as the \c id parameter to \c retro_input_state_t.
 * Bit #N represents the RETRO_DEVICE_ID_JOYPAD constant of value N,
 * e.g. <tt>(1 << RETRO_DEVICE_ID_JOYPAD_A)</tt> represents the A button.
 *
 * @param data Ignored.
 * @returns \c true if the frontend can report the complete digital joypad state as a bitmask.
 * @see retro_input_state_t
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 */
#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the version of the core options API supported by the frontend.
 *
 * Over the years, libretro has used several interfaces
 * for allowing cores to define customizable options.
 * \ref SET_CORE_OPTIONS_V2 "Version 2 of the interface"
 * is currently preferred due to its extra features,
 * but cores and frontends should strive to support
 * versions \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS "1"
 * and \ref RETRO_ENVIRONMENT_SET_VARIABLES "0" as well.
 * This environment call provides the information that cores need for that purpose.
 *
 * If this environment call returns \c false,
 * then the core should assume version 0 of the core options API.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the integer that will store the frontend's
 * supported core options API version.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_VARIABLES
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52

/**
 * @copybrief RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 *
 * @deprecated This environment call has been superseded
 * by RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
 * which supports categorizing options into groups.
 * This environment call should only be used to maintain compatibility
 * with older cores and frontends.
 *
 * This environment call is intended to replace \c RETRO_ENVIRONMENT_SET_VARIABLES,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 1.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * Example entry:
 * @code
 * {
 *     "foo_option",
 *     "Speed hack coprocessor X",
 *     "Provides increased performance at the expense of reduced accuracy",
 *     {
 *         { "false",    NULL },
 *         { "true",     NULL },
 *         { "unstable", "Turbo (Unstable)" },
 *         { NULL, NULL },
 *     },
 *     "false"
 * }
 * @endcode
 *
 * @param[in] data <tt>const struct retro_core_option_definition *</tt>.
 * Pointer to one or more core option definitions,
 * terminated by a \ref retro_core_option_definition whose values are all zero.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available.
 *
 * @see retro_core_option_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * that supports internationalization.
 *
 * @deprecated This environment call has been superseded
 * by \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
 * which supports categorizing options into groups
 * (plus translating the groups themselves).
 * Only use this environment call to maintain compatibility
 * with older cores and frontends.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_intl for some important details.
 *
 * @param[in] data <tt>const struct retro_core_options_intl *</tt>.
 * Pointer to a core's option values and their translations.
 * @see retro_core_options_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54

/**
 * Notifies the frontend that it should show or hide the named core option.
 *
 * Some core options aren't relevant in all scenarios,
 * such as a submenu for hardware rendering flags
 * when the software renderer is configured.
 * This environment call asks the frontend to stop (or start)
 * showing the named core option to the player.
 * This is only a hint, not a requirement;
 * the frontend may ignore this environment call.
 * By default, all core options are visible.
 *
 * @note This environment call must \em only affect a core option's visibility,
 * not its functionality or availability.
 * \ref RETRO_ENVIRONMENT_GET_VARIABLE "Getting an invisible core option"
 * must behave normally.
 *
 * @param[in] data <tt>const struct retro_core_option_display *</tt>.
 * Pointer to a descriptor for the option that the frontend should show or hide.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL
 * or the specified option doesn't exist.
 * @see retro_core_option_display
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55

/**
 * Returns the frontend's preferred hardware rendering API.
 * Cores should use this information to decide which API to use with \c RETRO_ENVIRONMENT_SET_HW_RENDER.
 * @param[out] data <tt>retro_hw_context_type *</tt>.
 * Pointer to the hardware context type.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * This value will be set even if the environment call returns <tt>false</tt>,
 * unless the frontend doesn't implement it.
 * @returns \c true if the environment call is available
 * and the frontend is able to use a hardware rendering API besides the one returned.
 * If \c false is returned and the core cannot use the preferred rendering API,
 * then it should exit or fall back to software rendering.
 * @note The returned value does not indicate which API is currently in use.
 * For example, the frontend may return \c RETRO_HW_CONTEXT_OPENGL
 * while a Direct3D context from a previous session is active;
 * this would signal that the frontend's current preference is for OpenGL,
 * possibly because the user changed their frontend's video driver while a game is running.
 * @see retro_hw_context_type
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56

/**
 * Returns the minimum version of the disk control interface supported by the frontend.
 *
 * If this environment call returns \c false or \c data is 0 or greater,
 * then cores may use disk control callbacks
 * with \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
 * If the reported version is 1 or greater,
 * then cores should use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE instead.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the unsigned integer that the frontend's supported disk control interface version will be stored in.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57

/**
 * @copybrief RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 * This version of the disk control interface provides
 * more information about disk images.
 * Should be called in \c retro_init.
 *
 * @param[in] data <tt>const struct retro_disk_control_ext_callback *</tt>.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_ext_callback
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58

/**
 * Returns the version of the message interface supported by the frontend.
 *
 * A version of 0 indicates that the frontend
 * only supports the legacy \c RETRO_ENVIRONMENT_SET_MESSAGE interface.
 * A version of 1 indicates that the frontend
 * supports \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT as well.
 * If this environment call returns \c false,
 * the core should behave as if it had returned 0.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 */
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59

/**
 * Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * This environment call supersedes \c RETRO_ENVIRONMENT_SET_MESSAGE,
 * as it provides many more ways to customize
 * how a message is presented to the player.
 * However, a frontend that supports this environment call
 * must still support \c RETRO_ENVIRONMENT_SET_MESSAGE.
 *
 * @param[in] data <tt>const struct retro_message_ext *</tt>.
 * Pointer to the message to display to the player.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_message_ext
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60

/**
 * Returns the number of active input devices currently provided by the frontend.
 *
 * This may change between frames,
 * but will remain constant for the duration of each frame.
 *
 * If this callback returns \c true,
 * a core need not poll any input device
 * with an index greater than or equal to the returned value.
 *
 * If callback returns \c false,
 * the number of active input devices is unknown.
 * In this case, all input devices should be considered active.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61

/**
 * Registers a callback that the frontend can use to notify the core
 * of the audio output buffer's occupancy.
 * Can be used by a core to attempt frame-skipping to avoid buffer under-runs
 * (i.e. "crackling" sounds).
 *
 * @param[in] data <tt>const struct retro_audio_buffer_status_callback *</tt>.
 * Pointer to the the buffer status callback,
 * or \c NULL to unregister any existing callback.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_audio_buffer_status_callback
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62

/**
 * Requests a minimum frontend audio latency in milliseconds.
 *
 * This is a hint; the frontend may assign a different audio latency
 * to accommodate hardware limits,
 * although it should try to honor requests up to 512ms.
 *
 * This callback has no effect if the requested latency
 * is less than the frontend's current audio latency.
 * If value is zero or \c data is \c NULL,
 * the frontend should set its default audio latency.
 *
 * May be used by a core to increase audio latency and
 * reduce the risk of buffer under-runs (crackling)
 * when performing 'intensive' operations.
 *
 * A core using RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 * to implement audio-buffer-based frame skipping can get good results
 * by setting the audio latency to a high (typically 6x or 8x)
 * integer multiple of the expected frame time.
 *
 * This can only be called from within \c retro_run().
 *
 * @warning This environment call may require the frontend to reinitialize its audio system.
 * This environment call should be used sparingly.
 * If the driver is reinitialized,
 * \ref retro_audio_callback_t "all audio callbacks" will be updated
 * to target the newly-initialized driver.
 *
 * @param[in] data <tt>const unsigned *</tt>.
 * Minimum audio latency, in milliseconds.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63

/**
 * Allows the core to tell the frontend when it should enable fast-forwarding,
 * rather than relying solely on the frontend and user interaction.
 *
 * Possible use cases include:
 *
 * \li Temporarily disabling a core's fastforward support
 *     while investigating a related bug.
 * \li Disabling fastforward during netplay sessions,
 *     or when using an emulated console's network features.
 * \li Automatically speeding up the game when in a loading screen
 *     that cannot be shortened with high-level emulation.
 *
 * @param[in] data <tt>const struct retro_fastforwarding_override *</tt>.
 * Pointer to the parameters that decide when and how
 * the frontend is allowed to enable fast-forward mode.
 * May be \c NULL, in which case the frontend will return \c true
 * without updating the fastforward state,
 * which can be used to detect support for this environment call.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_fastforwarding_override
 * @see RETRO_ENVIRONMENT_GET_FASTFORWARDING
 */
#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64

#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65
                                           /* const struct retro_system_content_info_override * --
                                            * Allows an implementation to override 'global' content
                                            * info parameters reported by retro_get_system_info().
                                            * Overrides also affect subsystem content info parameters
                                            * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.
                                            * This function must be called inside retro_set_environment().
                                            * If callback returns false, content info overrides
                                            * are unsupported by the frontend, and will be ignored.
                                            * If callback returns true, extended game info may be
                                            * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
                                            * in retro_load_game() or retro_load_game_special().
                                            *
                                            * 'data' points to an array of retro_system_content_info_override
                                            * structs terminated by a { NULL, false, false } element.
                                            * If 'data' is NULL, no changes will be made to the frontend;
                                            * a core may therefore pass NULL in order to test whether
                                            * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported
                                            * by the frontend.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_system_content_info_override.
                                            *
                                            * Example:
                                            *
                                            * - struct retro_system_info:
                                            * {
                                            *    "My Core",                      // library_name
                                            *    "v1.0",                         // library_version
                                            *    "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
                                            *    true,                           // need_fullpath
                                            *    false                           // block_extract
                                            * }
                                            *
                                            * - Array of struct retro_system_content_info_override:
                                            * {
                                            *    {
                                            *       "md|sms|gg", // extensions
                                            *       false,       // need_fullpath
                                            *       true         // persistent_data
                                            *    },
                                            *    {
                                            *       "sg",        // extensions
                                            *       false,       // need_fullpath
                                            *       false        // persistent_data
                                            *    },
                                            *    { NULL, false, false }
                                            * }
                                            *
                                            * Result:
                                            * - Files of type m3u, cue, iso, chd will not be
                                            *   loaded by the frontend. Frontend will pass a
                                            *   valid path to the core, and core will handle
                                            *   loading internally
                                            * - Files of type md, sms, gg will be loaded by
                                            *   the frontend. A valid memory buffer will be
                                            *   passed to the core. This memory buffer will
                                            *   remain valid until retro_deinit() returns
                                            * - Files of type sg will be loaded by the frontend.
                                            *   A valid memory buffer will be passed to the core.
                                            *   This memory buffer will remain valid until
                                            *   retro_load_game() (or retro_load_game_special())
                                            *   returns
                                            *
                                            * NOTE: If an extension is listed multiple times in
                                            * an array of retro_system_content_info_override
                                            * structs, only the first instance will be registered
                                            */

#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66
                                           /* const struct retro_game_info_ext ** --
                                            * Allows an implementation to fetch extended game
                                            * information, providing additional content path
                                            * and memory buffer status details.
                                            * This function may only be called inside
                                            * retro_load_game() or retro_load_game_special().
                                            * If callback returns false, extended game information
                                            * is unsupported by the frontend. In this case, only
                                            * regular retro_game_info will be available.
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed
                                            * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
                                            * returns true.
                                            *
                                            * 'data' points to an array of retro_game_info_ext structs.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_game_info_ext.
                                            *
                                            * - If function is called inside retro_load_game(),
                                            *   the retro_game_info_ext array is guaranteed to
                                            *   have a size of 1 - i.e. the returned pointer may
                                            *   be used to access directly the members of the
                                            *   first retro_game_info_ext struct, for example:
                                            *
                                            *      struct retro_game_info_ext *game_info_ext;
                                            *      if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext))
                                            *         printf("Content Directory: %s\n", game_info_ext->dir);
                                            *
                                            * - If the function is called inside retro_load_game_special(),
                                            *   the retro_game_info_ext array is guaranteed to have a
                                            *   size equal to the num_info argument passed to
                                            *   retro_load_game_special()
                                            */

/**
 * Defines a set of core options that can be shown and configured by the frontend,
 * so that the player may customize their gameplay experience to their liking.
 *
 * @note This environment call is intended to replace
 * \c RETRO_ENVIRONMENT_SET_VARIABLES and \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 2.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * @param[in] data <tt>const struct retro_core_options_v2 *</tt>.
 * Pointer to a core's options and their associated categories.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available
 * and the frontend supports categories.
 * Note that this environment call is guaranteed to successfully register
 * the provided core options,
 * so the return value does not indicate success or failure.
 *
 * @see retro_core_options_v2
 * @see retro_core_option_v2_category
 * @see retro_core_option_v2_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 67

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * that supports internationalization.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_v2_intl for some important details.
 *
 * @param[in] data <tt>const struct retro_core_options_v2_intl *</tt>.
 * Pointer to a core's option values and categories,
 * plus a translation for each option and category.
 * @see retro_core_options_v2_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL 68

/**
 * Registers a callback that the frontend can use
 * to notify the core that at least one core option
 * should be made hidden or visible.
 * Allows a frontend to signal that a core must update
 * the visibility of any dynamically hidden core options,
 * and enables the frontend to detect visibility changes.
 * Used by the frontend to update the menu display status
 * of core options without requiring a call of retro_run().
 * Must be called in retro_set_environment().
 *
 * @param[in] data <tt>const struct retro_core_options_update_display_callback *</tt>.
 * The callback that the frontend should use.
 * May be \c NULL, in which case the frontend will unset any existing callback.
 * Can be used to query visibility support.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_core_options_update_display_callback
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69

/**
 * Forcibly sets a core option's value.
 *
 * After changing a core option value with this callback,
 * it will be reflected in the frontend
 * and \ref RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE will return \c true.
 * \ref retro_variable::key must match
 * a \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 "previously-set core option",
 * and \ref retro_variable::value must match one of its defined values.
 *
 * Possible use cases include:
 *
 * @li Allowing the player to set certain core options
 *     without entering the frontend's option menu,
 *     using an in-core hotkey.
 * @li Adjusting invalid combinations of settings.
 * @li Migrating settings from older releases of a core.
 *
 * @param[in] data <tt>const struct retro_variable *</tt>.
 * Pointer to a single option that the core is changing.
 * May be \c NULL, in which case the frontend will return \c true
 * to indicate that this environment call is available.
 * @return \c true if this environment call is available
 * and the option named by \c key was successfully
 * set to the given \c value.
 * \c false if the \c key or \c value fields are \c NULL, empty,
 * or don't match a previously set option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_SET_VARIABLE 70

#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
                                           /* struct retro_throttle_state * --
                                            * Allows an implementation to get details on the actual rate
                                            * the frontend is attempting to call retro_run().
                                            */

/**
 * Returns information about how the frontend will use savestates.
 *
 * @param[out] data <tt>retro_savestate_context *</tt>.
 * Pointer to the current savestate context.
 * May be \c NULL, in which case the environment call
 * will return \c true to indicate its availability.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_savestate_context
 */
#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Before calling \c SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, will query which interface is supported.
 *
 * Frontend looks at \c retro_hw_render_interface_type and returns the maximum supported
 * context negotiation interface version. If the \c retro_hw_render_interface_type is not
 * supported or recognized by the frontend, a version of 0 must be returned in
 * \c retro_hw_render_interface's \c interface_version and \c true is returned by frontend.
 *
 * If this environment call returns true with a \c interface_version greater than 0,
 * a core can always use a negotiation interface version larger than what the frontend returns,
 * but only earlier versions of the interface will be used by the frontend.
 *
 * A frontend must not reject a negotiation interface version that is larger than what the
 * frontend supports. Instead, the frontend will use the older entry points that it recognizes.
 * If this is incompatible with a particular core's requirements, it can error out early.
 *
 * @note Regarding backwards compatibility, this environment call was introduced after Vulkan v1
 * context negotiation. If this environment call is not supported by frontend, i.e. the environment
 * call returns \c false , only Vulkan v1 context negotiation is supported (if Vulkan HW rendering
 * is supported at all). If a core uses Vulkan negotiation interface with version > 1, negotiation
 * may fail unexpectedly. All future updates to the context negotiation interface implies that
 * frontend must support this environment call to query support.
 *
 * @param[out] data <tt>struct retro_hw_render_context_negotiation_interface *</tt>.
 * @return \c true if the environment call is available.
 * @see SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see retro_hw_render_interface_type
 * @see retro_hw_render_context_negotiation_interface
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend whether JIT compilation can be used.
 * Primarily used by iOS and tvOS.
 * @param[out] data <tt>bool *</tt>.
 * Set to \c true if the frontend has verified that JIT compilation is possible.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74

/**
 * Returns an interface that the core can use to receive microphone input.
 *
 * @param[out] data <tt>retro_microphone_interface *</tt>.
 * Pointer to the microphone interface.
 * @return \true if microphone support is available,
 * even if no microphones are plugged in.
 * \c false if microphone support is disabled unavailable,
 * or if \c data is \c NULL.
 * @see retro_microphone_interface
 */
#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/* Environment 76 was an obsolete version of RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
* It was not used by any known core at the time, and was removed from the API. */

/**
 * Returns the device's current power state as reported by the frontend.
 *
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
 *
 * @param[out] data <struct retro_device_power *>.
 * Indicates whether the frontend can provide this information, even if the parameter
 * is \c NULL. If the frontend does not support this functionality, then the provided
 * argument will remain unchanged.
 * @return \c true if the environment call is available.
 * @see retro_device_power
 */
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 78
                                           /* const struct retro_netpacket_callback * --
                                            * When set, a core gains control over network packets sent and
                                            * received during a multiplayer session. This can be used to
                                            * emulate multiplayer games that were originally played on two
                                            * or more separate consoles or computers connected together.
                                            *
                                            * The frontend will take care of connecting players together,
                                            * and the core only needs to send the actual data as needed for
                                            * the emulation, while handshake and connection management happen
                                            * in the background.
                                            *
                                            * When two or more players are connected and this interface has
                                            * been set, time manipulation features (such as pausing, slow motion,
                                            * fast forward, rewinding, save state loading, etc.) are disabled to
                                            * avoid interrupting communication.
                                            *
                                            * Should be set in either retro_init or retro_load_game, but not both.
                                            *
                                            * When not set, a frontend may use state serialization-based
                                            * multiplayer, where a deterministic core supporting multiple
                                            * input devices does not need to take any action on its own.
                                            */

/**
 * Returns the device's current power state as reported by the frontend.
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * The return value indicates whether the frontend can provide this information,
 * even if the parameter is \c NULL.
 *
 * If the frontend does not support this functionality,
 * then the provided argument will remain unchanged.
 * @param[out] data <tt>retro_device_power *</tt>.
 * Pointer to the information that the frontend returns about its power state.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_device_power
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
*/
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the "playlist" directory of the frontend.
 *
 * This directory can be used to store core generated playlists, in case
 * this internal functionality is available (e.g. internal core game detection
 * engine).
 *
 * @param[out] data <tt>const char **</tt>.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_PLAYLIST_DIRECTORY 79

/**
 * Returns the "file browser" start directory of the frontend.
 *
 * This directory can serve as a start directory for the core in case it
 * provides an internal way of loading content.
 *
 * @param[out] data <tt>const char **</tt>.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY 80

/**
 * Returns the audio sample rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal sample rate.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the \c unsigned integer in which the frontend will store its target sample rate.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_SAMPLE_RATE (81 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**@}*/

/**
 * @defgroup GET_VFS_INTERFACE File System Interface
 * @brief File system functionality.
 *
 * @section File Paths
 * File paths passed to all libretro filesystem APIs shall be well formed UNIX-style,
 * using "/" (unquoted forward slash) as the directory separator
 * regardless of the platform's native separator.
 *
 * Paths shall also include at least one forward slash
 * (e.g. use "./game.bin" instead of "game.bin").
 *
 * Other than the directory separator, cores shall not make assumptions about path format.
 * The following paths are all valid:
 * @li \c C:/path/game.bin
 * @li \c http://example.com/game.bin
 * @li \c #game/game.bin
 * @li \c ./game.bin
 *
 * Cores may replace the basename or remove path components from the end, and/or add new components;
 * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request from the front end.
 *
 * The frontend is encouraged to do the best it can when given an ill-formed path,
 * but it is allowed to give up.
 *
 * Frontends are encouraged, but not required, to support native file system paths
 * (including replacing the directory separator, if applicable).
 *
 * Cores are allowed to try using them, but must remain functional if the frontend rejects such requests.
 *
 * Cores are encouraged to use the libretro-common filestream functions for file I/O,
 * as they seamlessly integrate with VFS,
 * deal with directory separator replacement as appropriate
 * and provide platform-specific fallbacks
 * in cases where front ends do not provide their own VFS interface.
 *
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 *
 * @{
 */

/**
 * Opaque file handle.
 * @since VFS API v1
 */
struct retro_vfs_file_handle;

/**
 * Opaque directory handle.
 * @since VFS API v3
 */
struct retro_vfs_dir_handle;

/** @defgroup RETRO_VFS_FILE_ACCESS File Access Flags
 * File access flags.
 * @since VFS API v1
 * @{
 */

/** Opens a file for read-only access. */
#define RETRO_VFS_FILE_ACCESS_READ            (1 << 0)

/**
 * Opens a file for write-only access.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_WRITE           (1 << 1)

/**
 * Opens a file for reading and writing.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_READ_WRITE      (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE)

/**
 * Opens a file without discarding its existing contents.
 * Only meaningful if \c RETRO_VFS_FILE_ACCESS_WRITE is specified.
 */
#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */

/** @} */

/** @defgroup RETRO_VFS_FILE_ACCESS_HINT File Access Hints
 *
 * Hints to the frontend for how a file will be accessed.
 * The VFS implementation may use these to optimize performance,
 * react to external interference (such as concurrent writes),
 * or it may ignore them entirely.
 *
 * Hint flags do not change the behavior of each VFS function
 * unless otherwise noted.
 * @{
 */

/** No particular hints are given. */
#define RETRO_VFS_FILE_ACCESS_HINT_NONE              (0)

/**
 * Indicates that the file will be accessed frequently.
 *
 * The frontend should cache it or map it into memory.
 */
#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS   (1 << 0)

/** @} */

/** @defgroup RETRO_VFS_SEEK_POSITION File Seek Positions
 * File access flags and hints.
 * @{
 */

/**
 * Indicates a seek relative to the start of the file.
 */
#define RETRO_VFS_SEEK_POSITION_START    0

/**
 * Indicates a seek relative to the current stream position.
 */
#define RETRO_VFS_SEEK_POSITION_CURRENT  1

/**
 * Indicates a seek relative to the end of the file.
 * @note The offset passed to \c retro_vfs_seek_t should be negative.
 */
#define RETRO_VFS_SEEK_POSITION_END      2

/** @} */

/** @defgroup RETRO_VFS_STAT File Status Flags
 * File stat flags.
 * @see retro_vfs_stat_t
 * @since VFS API v3
 * @{
 */

/** Indicates that the given path refers to a valid file. */
#define RETRO_VFS_STAT_IS_VALID               (1 << 0)

/** Indicates that the given path refers to a directory. */
#define RETRO_VFS_STAT_IS_DIRECTORY           (1 << 1)

/**
 * Indicates that the given path refers to a character special file,
 * such as \c /dev/null.
 */
#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL   (1 << 2)

/** @} */

/**
 * Returns the path that was used to open this file.
 *
 * @param stream The opened file handle to get the path of.
 * Behavior is undefined if \c NULL or closed.
 * @return The path that was used to open \c stream.
 * The string is owned by \c stream and must not be modified.
 * @since VFS API v1
 * @see filestream_get_path
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);

/**
 * Open a file for reading or writing.
 *
 * @param path The path to open.
 * @param mode A bitwise combination of \c RETRO_VFS_FILE_ACCESS flags.
 * At a minimum, one of \c RETRO_VFS_FILE_ACCESS_READ or \c RETRO_VFS_FILE_ACCESS_WRITE must be specified.
 * @param hints A bitwise combination of \c RETRO_VFS_FILE_ACCESS_HINT flags.
 * @return A handle to the opened file,
 * or \c NULL upon failure.
 * Note that this will return \c NULL if \c path names a directory.
 * The returned file handle must be closed with \c retro_vfs_close_t.
 * @since VFS API v1
 * @see File Paths
 * @see RETRO_VFS_FILE_ACCESS
 * @see RETRO_VFS_FILE_ACCESS_HINT
 * @see retro_vfs_close_t
 * @see filestream_open
 */
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);

/**
 * Close the file and release its resources.
 * All files returned by \c retro_vfs_open_t must be closed with this function.
 *
 * @param stream The file handle to close.
 * Behavior is undefined if already closed.
 * Upon completion of this function, \c stream is no longer valid
 * (even if it returns failure).
 * @return 0 on success, -1 on failure or if \c stream is \c NULL.
 * @see retro_vfs_open_t
 * @see filestream_close
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);

/**
 * Return the size of the file in bytes.
 *
 * @param stream The file to query the size of.
 * @return Size of the file in bytes, or -1 if there was an error.
 * @see filestream_get_size
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);

/**
 * Set the file's length.
 *
 * @param stream The file whose length will be adjusted.
 * @param length The new length of the file, in bytes.
 * If shorter than the original length, the extra bytes will be discarded.
 * If longer, the file's padding is unspecified (and likely platform-dependent).
 * @return 0 on success,
 * -1 on failure.
 * @see filestream_truncate
 * @since VFS API v2
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);

/**
 * Gets the given file's current read/write position.
 * This position is advanced with each call to \c retro_vfs_read_t or \c retro_vfs_write_t.
 *
 * @param stream The file to query the position of.
 * @return The current stream position in bytes
 * or -1 if there was an error.
 * @see filestream_tell
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);

/**
 * Sets the given file handle's current read/write position.
 *
 * @param stream The file to set the position of.
 * @param offset The new position, in bytes.
 * @param seek_position The position to seek from.
 * @return The new position,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see File Seek Positions
 * @see filestream_seek
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);

/**
 * Read data from a file, if it was opened for reading.
 *
 * @param stream The file to read from.
 * @param s The buffer to read into.
 * @param len The number of bytes to read.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes read,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_read
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);

/**
 * Write data to a file, if it was opened for writing.
 *
 * @param stream The file handle to write to.
 * @param s The buffer to write from.
 * @param len The number of bytes to write.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes written,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_write
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);

/**
 * Flush pending writes to the file, if applicable.
 *
 * This does not mean that the changes will be immediately persisted to disk;
 * that may be scheduled for later, depending on the platform.
 *
 * @param stream The file handle to flush.
 * @return 0 on success, -1 on failure.
 * @since VFS API v1
 * @see filestream_flush
 */
typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);

/**
 * Deletes the file at the given path.
 *
 * @param path The path to the file that will be deleted.
 * @return 0 on success, -1 on failure.
 * @see filestream_delete
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);

/**
 * Rename the specified file.
 *
 * @param old_path Path to an existing file.
 * @param new_path The destination path.
 * Must not name an existing file.
 * @return 0 on success, -1 on failure
 * @see filestream_rename
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);

/**
 * Gets information about the given file.
 *
 * @param path The path to the file to query.
 * @param[out] size The reported size of the file in bytes.
 * May be \c NULL, in which case this value is ignored.
 * @return A bitmask of \c RETRO_VFS_STAT flags,
 * or 0 if \c path doesn't refer to a valid file.
 * @see path_stat
 * @see path_get_size
 * @see RETRO_VFS_STAT
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);

/**
 * Creates a directory at the given path.
 *
 * @param dir The desired location of the new directory.
 * @return 0 if the directory was created,
 * -2 if the directory already exists,
 * or -1 if some other error occurred.
 * @see path_mkdir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);

/**
 * Opens a handle to a directory so its contents can be inspected.
 *
 * @param dir The path to the directory to open.
 * Must be an existing directory.
 * @param include_hidden Whether to include hidden files in the directory listing.
 * The exact semantics of this flag will depend on the platform.
 * @return A handle to the opened directory,
 * or \c NULL if there was an error.
 * @see retro_opendir
 * @since VFS API v3
 */
typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);

/**
 * Gets the next dirent ("directory entry")
 * within the given directory.
 *
 * @param[in,out] dirstream The directory to read from.
 * Updated to point to the next file, directory, or other path.
 * @return \c true when the next dirent was retrieved,
 * \c false if there are no more dirents to read.
 * @note This API iterates over all files and directories within \c dirstream.
 * Remember to check what the type of the current dirent is.
 * @note This function does not recurse,
 * i.e. it does not return the contents of subdirectories.
 * @note This may include "." and ".." on Unix-like platforms.
 * @see retro_readdir
 * @see retro_vfs_dirent_is_dir_t
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Gets the filename of the current dirent.
 *
 * The returned string pointer is valid
 * until the next call to \c retro_vfs_readdir_t or \c retro_vfs_closedir_t.
 *
 * @param dirstream The directory to read from.
 * @return The current dirent's name,
 * or \c NULL if there was an error.
 * @note This function only returns the file's \em name,
 * not a complete path to it.
 * @see retro_dirent_get_name
 * @since VFS API v3
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Checks whether the current dirent names a directory.
 *
 * @param dirstream The directory to read from.
 * @return \c true if \c dirstream's current dirent points to a directory,
 * \c false if not or if there was an error.
 * @see retro_dirent_is_dir
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Closes the given directory and release its resources.
 *
 * Must be called on any \c retro_vfs_dir_handle returned by \c retro_vfs_open_t.
 *
 * @param dirstream The directory to close.
 * When this function returns (even failure),
 * \c dirstream will no longer be valid and must not be used.
 * @return 0 on success, -1 on failure.
 * @see retro_closedir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * File system interface exposed by the frontend.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface
{
   /* VFS API v1 */
   /** @copydoc retro_vfs_get_path_t */
	retro_vfs_get_path_t get_path;

   /** @copydoc retro_vfs_open_t */
	retro_vfs_open_t open;

   /** @copydoc retro_vfs_close_t */
	retro_vfs_close_t close;

   /** @copydoc retro_vfs_size_t */
	retro_vfs_size_t size;

   /** @copydoc retro_vfs_tell_t */
	retro_vfs_tell_t tell;

   /** @copydoc retro_vfs_seek_t */
	retro_vfs_seek_t seek;

   /** @copydoc retro_vfs_read_t */
	retro_vfs_read_t read;

   /** @copydoc retro_vfs_write_t */
	retro_vfs_write_t write;

   /** @copydoc retro_vfs_flush_t */
	retro_vfs_flush_t flush;

   /** @copydoc retro_vfs_remove_t */
	retro_vfs_remove_t remove;

   /** @copydoc retro_vfs_rename_t */
	retro_vfs_rename_t rename;
   /* VFS API v2 */

   /** @copydoc retro_vfs_truncate_t */
   retro_vfs_truncate_t truncate;
   /* VFS API v3 */

   /** @copydoc retro_vfs_stat_t */
   retro_vfs_stat_t stat;

   /** @copydoc retro_vfs_mkdir_t */
   retro_vfs_mkdir_t mkdir;

   /** @copydoc retro_vfs_opendir_t */
   retro_vfs_opendir_t opendir;

   /** @copydoc retro_vfs_readdir_t */
   retro_vfs_readdir_t readdir;

   /** @copydoc retro_vfs_dirent_get_name_t */
   retro_vfs_dirent_get_name_t dirent_get_name;

   /** @copydoc retro_vfs_dirent_is_dir_t */
   retro_vfs_dirent_is_dir_t dirent_is_dir;

   /** @copydoc retro_vfs_closedir_t */
   retro_vfs_closedir_t closedir;
};

/**
 * Represents a request by the core for the frontend's file system interface,
 * as well as the interface itself returned by the frontend.
 *
 * You do not need to use these functions directly;
 * you may pass this struct to \c dirent_vfs_init,
 * \c filestream_vfs_init, or \c path_vfs_init
 * so that you can use the wrappers provided by these modules.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface_info
{
   /**
    * The minimum version of the VFS API that the core requires.
    * libretro-common's wrapper API initializers will check this value as well.
    *
    * Set to the core's desired VFS version when requesting an interface,
    * and set by the frontend to indicate its actual API version.
    *
    * If the core asks for a newer VFS API version than the frontend supports,
    * the frontend must return \c false within the \c RETRO_ENVIRONMENT_GET_VFS_INTERFACE call.
    * @since VFS API v1
    */
   uint32_t required_interface_version;

   /**
    * Set by the frontend.
    * The frontend will set this to the VFS interface it provides.
    *
    * The interface is owned by the frontend
    * and must not be modified or freed by the core.
    * @since VFS API v1 */
   struct retro_vfs_interface *iface;
};

/** @} */

/** @defgroup GET_HW_RENDER_INTERFACE Hardware Rendering Interface
 * @{
 */

/**
 * Describes the hardware rendering API supported by
 * a particular subtype of \c retro_hw_render_interface.
 *
 * Not every rendering API supported by libretro has its own interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_interface_type
{
   /**
    * Indicates a \c retro_hw_render_interface for Vulkan.
    * @see retro_hw_render_interface_vulkan
    */
   RETRO_HW_RENDER_INTERFACE_VULKAN     = 0,

   /** Indicates a \c retro_hw_render_interface for Direct3D 9. */
   RETRO_HW_RENDER_INTERFACE_D3D9       = 1,

   /** Indicates a \c retro_hw_render_interface for Direct3D 10. */
   RETRO_HW_RENDER_INTERFACE_D3D10      = 2,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 11.
    * @see retro_hw_render_interface_d3d11
    */
   RETRO_HW_RENDER_INTERFACE_D3D11      = 3,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 12.
    * @see retro_hw_render_interface_d3d12
    */
   RETRO_HW_RENDER_INTERFACE_D3D12      = 4,

   /**
    * Indicates a \c retro_hw_render_interface for
    * the PlayStation's 2 PSKit API.
    * @see retro_hw_render_interface_gskit_ps2
    */
   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2  = 5,

   /** @private Defined to ensure <tt>sizeof(retro_hw_render_interface_type) == sizeof(int)</tt>.
    * Do not use. */
   RETRO_HW_RENDER_INTERFACE_DUMMY      = INT_MAX
};

/**
 * Base render interface type.
 * All \c retro_hw_render_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
struct retro_hw_render_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_interface_type interface_type;

   /**
    * The version of this rendering interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/**
 * @defgroup GET_LED_INTERFACE LED Interface
 * @{
 */

/** @copydoc retro_led_interface::set_led_state */
typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);

/**
 * Interface that the core can use to set the state of available LEDs.
 * @see RETRO_ENVIRONMENT_GET_LED_INTERFACE
 */
struct retro_led_interface
{
   /**
    * Sets the state of an LED.
    *
    * @param led The LED to set the state of.
    * @param state The state to set the LED to.
    * \c true to enable, \c false to disable.
    */
   retro_set_led_state_t set_led_state;
};

/** @} */

/** @defgroup GET_AUDIO_VIDEO_ENABLE Skipped A/V Steps
 * @{
 */

/**
 * Flags that define A/V steps that the core may skip for this frame.
 *
 * @see RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE
 */
enum retro_av_enable_flags
{
   /**
    * If set, the core should render video output with \c retro_video_refresh_t as normal.
    *
    * Otherwise, the frontend will discard any video data received this frame,
    * including frames presented via hardware acceleration.
    * \c retro_video_refresh_t will do nothing.
    *
    * @note After running the frame, the video output of the next frame
    * should be no different than if video was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's graphics pipeline state
    * should not be affected by this flag.
    *
    * @note If emulating a platform that supports display capture
    * (i.e. reading its own VRAM),
    * the core may not be able to completely skip rendering,
    * as the VRAM is part of the graphics pipeline's state.
    */
   RETRO_AV_ENABLE_VIDEO = (1 << 0),

   /**
    * If set, the core should render audio output
    * with \c retro_audio_sample_t or \c retro_audio_sample_batch_t as normal.
    *
    * Otherwise, the frontend will discard any audio data received this frame.
    * The core should skip audio rendering if possible.
    *
    * @note After running the frame, the audio output of the next frame
    * should be no different than if audio was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's audio pipeline state
    * should not be affected by this flag.
    */
   RETRO_AV_ENABLE_AUDIO = (1 << 1),

   /**
    * If set, indicates that any savestates taken this frame
    * are guaranteed to be created by the same binary that will load them,
    * and will not be written to or read from the disk.
    *
    * The core may use these guarantees to:
    *
    * @li Assume that loading state will succeed.
    * @li Update its memory buffers in-place if possible.
    * @li Skip clearing memory.
    * @li Skip resetting the system.
    * @li Skip validation steps.
    *
    * @deprecated Use \c RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT instead,
    * except for compatibility purposes.
    */
   RETRO_AV_ENABLE_FAST_SAVESTATES = (1 << 2),

   /**
    * If set, indicates that the frontend will never need audio from the core.
    * Used by a frontend for implementing runahead via a secondary core instance.
    *
    * The core may stop synthesizing audio if it can do so
    * without compromising emulation accuracy.
    *
    * Audio output for the next frame does not matter,
    * and the frontend will never need an accurate audio state in the future.
    *
    * State will never be saved while this flag is set.
    */
   RETRO_AV_ENABLE_HARD_DISABLE_AUDIO = (1 << 3),

   /**
    * @private Defined to ensure <tt>sizeof(retro_av_enable_flags) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_AV_ENABLE_DUMMY = INT_MAX
};

/** @} */

/**
 * @defgroup GET_MIDI_INTERFACE MIDI Interface
 * @{
 */

/** @copydoc retro_midi_interface::input_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);

/** @copydoc retro_midi_interface::output_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);

/** @copydoc retro_midi_interface::read */
typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);

/** @copydoc retro_midi_interface::write */
typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);

/** @copydoc retro_midi_interface::flush */
typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);

/**
 * Interface that the core can use for raw MIDI I/O.
 */
struct retro_midi_interface
{
   /**
    * Retrieves the current state of MIDI input.
    *
    * @return \c true if MIDI input is enabled.
    */
   retro_midi_input_enabled_t input_enabled;

   /**
    * Retrieves the current state of MIDI output.
    * @return \c true if MIDI output is enabled.
    */
   retro_midi_output_enabled_t output_enabled;

   /**
    * Reads a byte from the MIDI input stream.
    *
    * @param[out] byte The byte received from the input stream.
    * @return \c true if a byte was read,
    * \c false if MIDI input is disabled or \c byte is \c NULL.
    */
   retro_midi_read_t read;

   /**
    * Writes a byte to the output stream.
    *
    * @param byte The byte to write to the output stream.
    * @param delta_time Time since the previous write, in microseconds.
    * @return \c true if c\ byte was written, false otherwise.
    */
   retro_midi_write_t write;

   /**
    * Flushes previously-written data.
    *
    * @return \c true if successful.
    */
   retro_midi_flush_t flush;
};

/** @} */

/** @defgroup SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE Render Context Negotiation
 * @{
 */

/**
 * Describes the hardware rendering API used by
 * a particular subtype of \c retro_hw_render_context_negotiation_interface.
 *
 * Not every rendering API supported by libretro has a context negotiation interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_context_negotiation_interface_type
{
   /**
    * Denotes a context negotiation interface for Vulkan.
    * @see retro_hw_render_context_negotiation_interface_vulkan
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,

   /**
    * @private Defined to ensure <tt>sizeof(retro_hw_render_context_negotiation_interface_type) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX
};

/**
 * Base context negotiation interface type.
 * All \c retro_hw_render_context_negotiation_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 */
struct retro_hw_render_context_negotiation_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_context_negotiation_interface_type interface_type;

   /**
    * The version of this negotiation interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/** @defgroup RETRO_SERIALIZATION_QUIRK Serialization Quirks
 * @{
 */

/**
 * Indicates that serialized state is incomplete in some way.
 *
 * Set if serialization is usable for the common case of saving and loading game state,
 * but should not be relied upon for frame-sensitive frontend features
 * such as netplay or rerecording.
 */
#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0)

/**
 * Indicates that core must spend some time initializing before serialization can be done.
 *
 * \c retro_serialize(), \c retro_unserialize(), and \c retro_serialize_size() will initially fail.
 */
#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1)

/** Set by the core to indicate that serialization size may change within a session. */
#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2)

/** Set by the frontend to acknowledge that it supports variable-sized states. */
#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3)

/** Serialized state can only be loaded during the same session. */
#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4)

/**
 * Serialized state cannot be loaded on an architecture
 * with a different endianness from the one it was saved on.
 */
#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5)

/**
 * Serialized state cannot be loaded on a different platform
 * from the one it was saved on for reasons other than endianness,
 * such as word size dependence.
 */
#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)

/** @} */

/** @defgroup SET_MEMORY_MAPS Memory Descriptors
 * @{
 */

/** @defgroup RETRO_MEMDESC Memory Descriptor Flags
 * Information about how the emulated hardware uses this portion of its address space.
 * @{
 */

/**
 * Indicates that this memory area won't be modified
 * once \c retro_load_game has returned.
 */
#define RETRO_MEMDESC_CONST      (1 << 0)

/**
 * Indicates a memory area with big-endian byte ordering,
 * as opposed to the default of little-endian.
 */
#define RETRO_MEMDESC_BIGENDIAN  (1 << 1)

/**
 * Indicates a memory area that is used for the emulated system's main RAM.
 */
#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2)

/**
 * Indicates a memory area that is used for the emulated system's save RAM,
 * usually found on a game cartridge as battery-backed RAM or flash memory.
 */
#define RETRO_MEMDESC_SAVE_RAM   (1 << 3)

/**
 * Indicates a memory area that is used for the emulated system's video RAM,
 * usually found on a console's GPU (or local equivalent).
 */
#define RETRO_MEMDESC_VIDEO_RAM  (1 << 4)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 2 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_2    (1 << 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 4 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_4    (2 << 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 8 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_8    (3 << 16)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 2 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_2  (1 << 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 4 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_4  (2 << 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 8 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_8  (3 << 24)

/** @} */

/**
 * A mapping from a region of the emulated console's address space
 * to the host's address space.
 *
 * Can be used to map an address in the console's address space
 * to the host's address space, like so:
 *
 * @code
 * void* emu_to_host(void* addr, struct retro_memory_descriptor* descriptor)
 * {
 *     return descriptor->ptr + (addr & ~descriptor->disconnect) - descriptor->start;
 * }
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_descriptor
{
   /**
    * A bitwise \c OR of one or more \ref RETRO_MEMDESC "flags"
    * that describe how the emulated system uses this descriptor's address range.
    *
    * @note If \c ptr is \c NULL,
    * then no flags should be set.
    * @see RETRO_MEMDESC
    */
   uint64_t flags;

   /**
    * Pointer to the start of this memory region's buffer
    * within the \em host's address space.
    * The address listed here must be valid for the duration of the session;
    * it must not be freed or modified by the frontend
    * and it must not be moved by the core.
    *
    * May be \c NULL to indicate a lack of accessible memory
    * at the emulated address given in \c start.
    *
    * @note Overlapping descriptors that include the same byte
    * must have the same \c ptr value.
    */
   void *ptr;

   /**
    * The offset of this memory region,
    * relative to the address given by \c ptr.
    *
    * @note It is recommended to use this field for address calculations
    * instead of performing arithmetic on \c ptr.
    */
   size_t offset;

   /**
    * The starting address of this memory region
    * <em>within the emulated hardware's address space</em>.
    *
    * @note Not represented as a pointer
    * because it's unlikely to be valid on the host device.
    */
   size_t start;

   /**
    * A bitmask that specifies which bits of an address must match
    * the bits of the \ref start address.
    *
    * Combines with \c disconnect to map an address to a memory block.
    *
    * If multiple memory descriptors can claim a particular byte,
    * the first one defined in the \ref retro_memory_descriptor array applies.
    * A bit which is set in \c start must also be set in this.
    *
    * Can be zero, in which case \c start and \c len represent
    * the complete mapping for this region of memory
    * (i.e. each byte is mapped exactly once).
    * In this case, \c len must be a power of two.
    */
   size_t select;

   /**
    * A bitmask of bits that are \em not used for addressing.
    *
    * Any set bits are assumed to be disconnected from
    * the emulated memory chip's address pins,
    * and are therefore ignored when memory-mapping.
    */
   size_t disconnect;

   /**
    * The length of this memory region, in bytes.
    *
    * If applying \ref start and \ref disconnect to an address
    * results in a value higher than this,
    * the highest bit of the address is cleared.
    *
    * If the address is still too high, the next highest bit is cleared.
    * Can be zero, in which case it's assumed to be
    * bounded only by \ref select and \ref disconnect.
    */
   size_t len;

   /**
    * A short name for this address space.
    *
    * Names must meet the following requirements:
    *
    * \li Characters must be in the set <tt>[a-zA-Z0-9_-]</tt>.
    * \li No more than 8 characters, plus a \c NULL terminator.
    * \li Names are case-sensitive, but lowercase characters are discouraged.
    * \li A name must not be the same as another name plus a character in the set \c [A-F0-9]
    *     (i.e. if an address space named "RAM" exists,
    *     then the names "RAM0", "RAM1", ..., "RAMF" are forbidden).
    *     This is to allow addresses to be named by each descriptor unambiguously,
    *     even if the areas overlap.
    * \li May be \c NULL or empty (both are considered equivalent).
    *
    * Here are some examples of pairs of address space names:
    *
    * \li \em blank + \em blank: valid (multiple things may be mapped in the same namespace)
    * \li \c Sp + \c Sp: valid (multiple things may be mapped in the same namespace)
    * \li \c SRAM + \c VRAM: valid (neither is a prefix of the other)
    * \li \c V + \em blank: valid (\c V is not in \c [A-F0-9])
    * \li \c a + \em blank: valid but discouraged (\c a is not in \c [A-F0-9])
    * \li \c a + \c A: valid but discouraged (neither is a prefix of the other)
    * \li \c AR + \em blank: valid (\c R is not in \c [A-F0-9])
    * \li \c ARB + \em blank: valid (there's no \c AR namespace,
    *     so the \c B doesn't cause ambiguity).
    * \li \em blank + \c B: invalid, because it's ambiguous which address space \c B1234 would refer to.
    *
    * The length of the address space's name can't be used to disambugiate,
    * as extra information may be appended to it without a separator.
    */
   const char *addrspace;

   /* TODO: When finalizing this one, add a description field, which should be
    * "WRAM" or something roughly equally long. */

   /* TODO: When finalizing this one, replace 'select' with 'limit', which tells
    * which bits can vary and still refer to the same address (limit = ~select).
    * TODO: limit? range? vary? something else? */

   /* TODO: When finalizing this one, if 'len' is above what 'select' (or
    * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'
    * and 'select' != 0, and the mappings don't tell how the system switches the
    * banks. */

   /* TODO: When finalizing this one, fix the 'len' bit removal order.
    * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.
    * Algorithm: Take bits highest to lowest, but if it goes above len, clear
    * the most recent addition and continue on the next bit.
    * TODO: Can the above be optimized? Is "remove the lowest bit set in both
    * pointer and 'len'" equivalent? */

   /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing
    * the emulated memory in 32-bit chunks, native endian. But that's nothing
    * compared to Darek Mihocka <http://www.emulators.com/docs/nx07_vm101.htm>
    * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE
    * RAM backwards! I'll want to represent both of those, via some flags.
    *
    * I suspect MAME either didn't think of that idea, or don't want the #ifdef.
    * Not sure which, nor do I really care. */

   /* TODO: Some of those flags are unused and/or don't really make sense. Clean
    * them up. */
};

/**
 * A list of regions within the emulated console's address space.
 *
 * The frontend may use the largest value of
 * \ref retro_memory_descriptor::start + \ref retro_memory_descriptor::select
 * in a certain namespace to infer the overall size of the address space.
 * If the address space is larger than that,
 * the last mapping in \ref descriptors should have \ref retro_memory_descriptor::ptr set to \c NULL
 * and \ref retro_memory_descriptor::select should have all bits used in the address space set to 1.
 *
 * Here's an example set of descriptors for the SNES.
 *
 * @code{.c}
 * struct retro_memory_map snes_descriptors = retro_memory_map
 * {
 *    .descriptors = (struct retro_memory_descriptor[])
 *    {
 *       // WRAM; must usually be mapped before the ROM,
 *       // as some SNES ROM mappers try to claim 0x7E0000
 *       { .addrspace="WRAM", .start=0x7E0000, .len=0x20000 },
 *
 *       // SPC700 RAM
 *       { .addrspace="SPC700", .len=0x10000 },
 *
 *       // WRAM mirrors
 *       { .addrspace="WRAM", .start=0x000000, .select=0xC0E000, .len=0x2000 },
 *       { .addrspace="WRAM", .start=0x800000, .select=0xC0E000, .len=0x2000 },
 *
 *       // WRAM mirror, alternate equivalent descriptor
 *       // (Various similar constructions can be created by combining parts of the above two.)
 *       { .addrspace="WRAM", .select=0x40E000, .disconnect=~0x1FFF },
 *
 *       // LoROM (512KB, mirrored a couple of times)
 *       { .addrspace="LoROM", .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="LoROM", .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *
 *       // HiROM (4MB)
 *       { .addrspace="HiROM", .start=0x400000, .select=0x400000, .len=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="HiROM", .start=0x008000, .select=0x408000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // ExHiROM (8MB)
 *       { .addrspace="ExHiROM", .start=0xC00000, .select=0xC00000, .len=4*1024*1024, .offset=0, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x400000, .select=0xC00000, .len=4*1024*1024, .offset=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x808000, .select=0xC08000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x008000, .select=0xC08000, .len=4*1024*1024, .offset=4*1024*1024+0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // Clarifying the full size of the address space
 *       { .select=0xFFFFFF, .ptr=NULL },
 *    },
 *    .num_descriptors = 14,
 * };
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_map
{
   /**
    * Pointer to an array of memory descriptors,
    * each of which describes part of the emulated console's address space.
    */
   const struct retro_memory_descriptor *descriptors;

   /** The number of descriptors in \c descriptors. */
   unsigned num_descriptors;
};

/** @} */

/** @defgroup SET_CONTROLLER_INFO Controller Info
 * @{
 */

/**
 * Details about a controller (or controller configuration)
 * supported by one of a core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_description
{
   /**
    * A human-readable label for the controller or configuration
    * represented by this device type.
    * Most likely the device's original brand name.
    */
   const char *desc;

   /**
    * A unique identifier that will be passed to \c retro_set_controller_port_device()'s \c device parameter.
    * May be the ID of one of \ref RETRO_DEVICE "the generic controller types",
    * or a subclass ID defined with \c RETRO_DEVICE_SUBCLASS.
    *
    * @see RETRO_DEVICE_SUBCLASS
    */
   unsigned id;
};

/**
 * Lists the types of controllers supported by
 * one of core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_info
{

   /**
    * A pointer to an array of device types supported by this controller port.
    *
    * @note Ports that support the same devices
    * may share the same underlying array.
    */
   const struct retro_controller_description *types;

   /** The number of elements in \c types. */
   unsigned num_types;
};

/** @} */

/** @defgroup SET_SUBSYSTEM_INFO Subsystems
 * @{
 */

/**
 * Information about a type of memory associated with a subsystem.
 * Usually used for SRAM (save RAM).
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_get_memory_data
 * @see retro_get_memory_size
 */
struct retro_subsystem_memory_info
{
   /**
    * The file extension the frontend should use
    * to save this memory region to disk, e.g. "srm" or "sav".
    */
   const char *extension;

   /**
    * A constant that identifies this type of memory.
    * Should be at least 0x100 (256) to avoid conflict
    * with the standard libretro memory types,
    * unless a subsystem uses the main platform's memory region.
    * @see RETRO_MEMORY
    */
   unsigned type;
};

/**
 * Information about a type of ROM that a subsystem may use.
 * Subsystems may use one or more ROMs at once,
 * possibly of different types.
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_subsystem_info
 */
struct retro_subsystem_rom_info
{
   /**
    * Human-readable description of what the content represents,
    * e.g. "Game Boy ROM".
    */
   const char *desc;

   /** @copydoc retro_system_info::valid_extensions */
   const char *valid_extensions;

   /** @copydoc retro_system_info::need_fullpath */
   bool need_fullpath;

   /** @copydoc retro_system_info::block_extract */
   bool block_extract;

   /**
    * Indicates whether this particular subsystem ROM is required.
    * If \c true and the user doesn't provide a ROM,
    * the frontend should not load the core.
    * If \c false and the user doesn't provide a ROM,
    * the frontend should pass a zeroed-out \c retro_game_info
    * to the corresponding entry in \c retro_load_game_special().
    */
   bool required;

   /**
    * Pointer to an array of memory descriptors that this subsystem ROM type uses.
    * Useful for secondary cartridges that have their own save data.
    * May be \c NULL, in which case this subsystem ROM's memory is not persisted by the frontend
    * and \c num_memory should be zero.
    */
   const struct retro_subsystem_memory_info *memory;

   /** The number of elements in the array pointed to by \c memory. */
   unsigned num_memory;
};

/**
 * Information about a secondary platform that a core supports.
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 */
struct retro_subsystem_info
{
   /**
    * A human-readable description of the subsystem type,
    * usually the brand name of the original platform
    * (e.g. "Super Game Boy").
    */
   const char *desc;

   /**
    * A short machine-friendly identifier for the subsystem,
    * usually an abbreviation of the platform name.
    * For example, a Super Game Boy subsystem for a SNES core
    * might use an identifier of "sgb".
    * This identifier can be used for command-line interfaces,
    * configuration, or other purposes.
    * Must use lower-case alphabetical characters only (i.e. from a-z).
    */
   const char *ident;

   /**
    * The list of ROM types that this subsystem may use.
    *
    * The first entry is considered to be the "most significant" content,
    * for the purposes of the frontend's categorization.
    * E.g. with Super GameBoy, the first content should be the GameBoy ROM,
    * as it is the most "significant" content to a user.
    *
    * If a frontend creates new files based on the content used (e.g. for savestates),
    * it should derive the filenames from the name of the first ROM in this list.
    *
    * @note \c roms can have a single element,
    * but this is usually a sign that the core should broaden its
    * primary system info instead.
    *
    * @see \c retro_system_info
    */
   const struct retro_subsystem_rom_info *roms;

   /** The length of the array given in \c roms. */
   unsigned num_roms;

   /** A unique identifier passed to retro_load_game_special(). */
   unsigned id;
};

/** @} */

/** @defgroup SET_PROC_ADDRESS_CALLBACK Core Function Pointers
 * @{ */

/**
 * The function pointer type that \c retro_get_proc_address_t returns.
 *
 * Despite the signature shown here, the original function may include any parameters and return type
 * that respects the calling convention and C ABI.
 *
 * The frontend is expected to cast the function pointer to the correct type.
 */
typedef void (RETRO_CALLCONV *retro_proc_address_t)(void);

/**
 * Get a symbol from a libretro core.
 *
 * Cores should only return symbols that serve as libretro extensions.
 * Frontends should not use this to obtain symbols to standard libretro entry points;
 * instead, they should link to the core statically or use \c dlsym (or local equivalent).
 *
 * The symbol name must be equal to the function name.
 * e.g. if <tt>void retro_foo(void);</tt> exists, the symbol in the compiled library must be called \c retro_foo.
 * The returned function pointer must be cast to the corresponding type.
 *
 * @param \c sym The name of the symbol to look up.
 * @return Pointer to the exposed function with the name given in \c sym,
 * or \c NULL if one couldn't be found.
 * @note The frontend is expected to know the returned pointer's type in advance
 * so that it can be cast correctly.
 * @note The core doesn't need to expose every possible function through this interface.
 * It's enough to only expose the ones that it expects the frontend to use.
 * @note The functions exposed through this interface
 * don't need to be publicly exposed in the compiled library
 * (e.g. via \c __declspec(dllexport)).
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);

/**
 * An interface that the frontend can use to get function pointers from the core.
 *
 * @note The returned function pointer will be invalidated once the core is unloaded.
 * How and when that happens is up to the frontend.
 *
 * @see retro_get_proc_address_t
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
struct retro_get_proc_address_interface
{
   /** Set by the core. */
   retro_get_proc_address_t get_proc_address;
};

/** @} */

/** @defgroup GET_LOG_INTERFACE Logging
 * @{
 */

/**
 * The severity of a given message.
 * The frontend may log messages differently depending on the level.
 * It may also ignore log messages of a certain level.
 * @see retro_log_callback
 */
enum retro_log_level
{
   /** The logged message is most likely not interesting to the user. */
   RETRO_LOG_DEBUG = 0,

   /** Information about the core operating normally. */
   RETRO_LOG_INFO,

   /** Indicates a potential problem, possibly one that the core can recover from. */
   RETRO_LOG_WARN,

   /** Indicates a degraded experience, if not failure. */
   RETRO_LOG_ERROR,

   /** Defined to ensure that sizeof(enum retro_log_level) == sizeof(int). Do not use. */
   RETRO_LOG_DUMMY = INT_MAX
};

/**
 * Logs a message to the frontend.
 *
 * @param level The log level of the message.
 * @param fmt The format string to log.
 * Same format as \c printf.
 * Behavior is undefined if this is \c NULL.
 * @param ... Zero or more arguments used by the format string.
 * Behavior is undefined if these don't match the ones expected by \c fmt.
 * @see retro_log_level
 * @see retro_log_callback
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see printf
 */
typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,
      const char *fmt, ...);

/**
 * Details about how to make log messages.
 *
 * @see retro_log_printf_t
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 */
struct retro_log_callback
{
   /**
    * Called when logging a message.
    *
    * @note Set by the frontend.
    */
   retro_log_printf_t log;
};

/** @} */

/** @defgroup GET_PERF_INTERFACE Performance Interface
 * @{
 */

/** @defgroup RETRO_SIMD CPU Features
 * @{
 */

/**
 * Indicates CPU support for the SSE instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE
 */
#define RETRO_SIMD_SSE      (1 << 0)

/**
 * Indicates CPU support for the SSE2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE2
 */
#define RETRO_SIMD_SSE2     (1 << 1)

/** Indicates CPU support for the AltiVec (aka VMX or Velocity Engine) instruction set. */
#define RETRO_SIMD_VMX      (1 << 2)

/** Indicates CPU support for the VMX128 instruction set. Xbox 360 only. */
#define RETRO_SIMD_VMX128   (1 << 3)

/**
 * Indicates CPU support for the AVX instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX
 */
#define RETRO_SIMD_AVX      (1 << 4)

/**
 * Indicates CPU support for the NEON instruction set.
 * @see https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[Neon]
 */
#define RETRO_SIMD_NEON     (1 << 5)

/**
 * Indicates CPU support for the SSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE3
 */
#define RETRO_SIMD_SSE3     (1 << 6)

/**
 * Indicates CPU support for the SSSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSSE3
 */
#define RETRO_SIMD_SSSE3    (1 << 7)

/**
 * Indicates CPU support for the MMX instruction set.
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=MMX
 */
#define RETRO_SIMD_MMX      (1 << 8)

/** Indicates CPU support for the MMXEXT instruction set. */
#define RETRO_SIMD_MMXEXT   (1 << 9)

/**
 * Indicates CPU support for the SSE4 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_1
 */
#define RETRO_SIMD_SSE4     (1 << 10)

/**
 * Indicates CPU support for the SSE4.2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_2
 */
#define RETRO_SIMD_SSE42    (1 << 11)

/**
 * Indicates CPU support for the AVX2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX2
 */
#define RETRO_SIMD_AVX2     (1 << 12)

/** Indicates CPU support for the VFPU instruction set. PS2 and PSP only.
 *
 * @see https://pspdev.github.io/vfpu-docs
 */
#define RETRO_SIMD_VFPU     (1 << 13)

/**
 * Indicates CPU support for Gekko SIMD extensions. GameCube only.
 */
#define RETRO_SIMD_PS       (1 << 14)

/**
 * Indicates CPU support for AES instructions.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#aestechs=AES&othertechs=AES
 */
#define RETRO_SIMD_AES      (1 << 15)

/**
 * Indicates CPU support for the VFPv3 instruction set.
 */
#define RETRO_SIMD_VFPV3    (1 << 16)

/**
 * Indicates CPU support for the VFPv4 instruction set.
 */
#define RETRO_SIMD_VFPV4    (1 << 17)

/** Indicates CPU support for the POPCNT instruction. */
#define RETRO_SIMD_POPCNT   (1 << 18)

/** Indicates CPU support for the MOVBE instruction. */
#define RETRO_SIMD_MOVBE    (1 << 19)

/** Indicates CPU support for the CMOV instruction. */
#define RETRO_SIMD_CMOV     (1 << 20)

/** Indicates CPU support for the ASIMD instruction set. */
#define RETRO_SIMD_ASIMD    (1 << 21)

/** @} */

/**
 * An abstract unit of ticks.
 *
 * Usually nanoseconds or CPU cycles,
 * but it depends on the platform and the frontend.
 */
typedef uint64_t retro_perf_tick_t;

/** Time in microseconds. */
typedef int64_t retro_time_t;

/**
 * A performance counter.
 *
 * Use this to measure the execution time of a region of code.
 * @see retro_perf_callback
 */
struct retro_perf_counter
{
   /**
    * A human-readable identifier for the counter.
    *
    * May be displayed by the frontend.
    * Behavior is undefined if this is \c NULL.
    */
   const char *ident;

   /**
    * The time of the most recent call to \c retro_perf_callback::perf_start
    * on this performance counter.
    *
    * @see retro_perf_start_t
    */
   retro_perf_tick_t start;

   /**
    * The total time spent within this performance counter's measured code,
    * i.e. between calls to \c retro_perf_callback::perf_start and \c retro_perf_callback::perf_stop.
    *
    * Updated after each call to \c retro_perf_callback::perf_stop.
    * @see retro_perf_stop_t
    */
   retro_perf_tick_t total;

   /**
    * The number of times this performance counter has been started.
    *
    * Updated after each call to \c retro_perf_callback::perf_start.
    * @see retro_perf_start_t
    */
   retro_perf_tick_t call_cnt;

   /**
    * \c true if this performance counter has been registered by the frontend.
    * Must be initialized to \c false by the core before registering it.
    * @see retro_perf_register_t
    */
   bool registered;
};

/**
 * @returns The current system time in microseconds.
 * @note Accuracy may vary by platform.
 * The frontend should use the most accurate timer possible.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);

/**
 * @returns The number of ticks since some unspecified epoch.
 * The exact meaning of a "tick" depends on the platform,
 * but it usually refers to nanoseconds or CPU cycles.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);

/**
 * Returns a bitmask of detected CPU features.
 *
 * Use this for runtime dispatching of CPU-specific code.
 *
 * @returns A bitmask of detected CPU features.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see RETRO_SIMD
 */
typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);

/**
 * Asks the frontend to log or display the state of performance counters.
 * How this is done depends on the frontend.
 * Performance counters can be reviewed manually as well.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see retro_perf_counter
 */
typedef void (RETRO_CALLCONV *retro_perf_log_t)(void);

/**
 * Registers a new performance counter.
 *
 * If \c counter has already been registered beforehand,
 * this function does nothing.
 *
 * @param counter The counter to register.
 * \c counter::ident must be set to a unique identifier,
 * and all other values in \c counter must be set to zero or \c false.
 * Behavior is undefined if \c NULL.
 * @post If \c counter is successfully registered,
 * then \c counter::registered will be set to \c true.
 * Otherwise, it will be set to \c false.
 * Registration may fail if the frontend's maximum number of counters (if any) has been reached.
 * @note The counter is owned by the core and must not be freed by the frontend.
 * The frontend must also clean up any references to a core's performance counters
 * before unloading it, otherwise undefined behavior may occur.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);

/**
 * Starts a registered performance counter.
 *
 * Call this just before the code you want to measure.
 *
 * @param counter The counter to start.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);

/**
 * Stops a registered performance counter.
 *
 * Call this just after the code you want to measure.
 *
 * @param counter The counter to stop.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);

/**
 * An interface that the core can use to get performance information.
 *
 * Here's a usage example:
 *
 * @code{.c}
 * #ifdef PROFILING
 * // Wrapper macros to simplify using performance counters.
 * // Optional; tailor these to your project's needs.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
 * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))
 * #else
 * // Exclude the performance counters if profiling is disabled.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_START(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) ((void)0)
 * #endif
 *
 * // Defined somewhere else in the core.
 * extern struct retro_perf_callback perf_cb;
 *
 * void retro_run(void)
 * {
 *    RETRO_PERFORMANCE_INIT(cb, interesting);
 *    RETRO_PERFORMANCE_START(cb, interesting);
 *    interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, interesting);
 *
 *    RETRO_PERFORMANCE_INIT(cb, maybe_slow);
 *    RETRO_PERFORMANCE_START(cb, maybe_slow);
 *    more_interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, maybe_slow);
 * }
 *
 * void retro_deinit(void)
 * {
 *    // Asks the frontend to log the results of all performance counters.
 *    perf_cb.perf_log();
 * }
 * @endcode
 *
 * All functions are set by the frontend.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
struct retro_perf_callback
{
   /** @copydoc retro_perf_get_time_usec_t */
   retro_perf_get_time_usec_t    get_time_usec;

   /** @copydoc retro_perf_get_counter_t */
   retro_get_cpu_features_t      get_cpu_features;

   /** @copydoc retro_perf_get_counter_t */
   retro_perf_get_counter_t      get_perf_counter;

   /** @copydoc retro_perf_register_t */
   retro_perf_register_t         perf_register;

   /** @copydoc retro_perf_start_t */
   retro_perf_start_t            perf_start;

   /** @copydoc retro_perf_stop_t */
   retro_perf_stop_t             perf_stop;

   /** @copydoc retro_perf_log_t */
   retro_perf_log_t              perf_log;
};

/** @} */

/**
 * @defgroup RETRO_SENSOR Sensor Interface
 * @{
 */

/**
 * Defines actions that can be performed on sensors.
 * @note Cores should only enable sensors while they're actively being used;
 * depending on the frontend and platform,
 * enabling these sensors may impact battery life.
 *
 * @see RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE
 * @see retro_sensor_interface
 * @see retro_set_sensor_state_t
 */
enum retro_sensor_action
{
   /** Enables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,

   /** Disables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_DISABLE,

   /** Enables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_ENABLE,

   /** Disables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_DISABLE,

   /** Enables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_ENABLE,

   /** Disables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_DISABLE,

   /** @private Defined to ensure <tt>sizeof(enum retro_sensor_action) == sizeof(int)</tt>. Do not use. */
   RETRO_SENSOR_DUMMY = INT_MAX
};

/** @defgroup RETRO_SENSOR_ID Sensor Value IDs
 * @{
 */
/* Id values for SENSOR types. */

/**
 * Returns the device's acceleration along its local X axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating to the right.
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_X 0

/**
 * Returns the device's acceleration along its local Y axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating upwards,
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Y 1

/**
 * Returns the the device's acceleration along its local Z axis minus the effect of gravity, in m/s^2.
 *
 * Positive values indicate forward acceleration towards the user,
 * assuming the user is looking at the device head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Z 2

/**
 * Returns the angular velocity of the device around its local X axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_X 3

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Y 4

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Z 5

/**
 * Returns the ambient illuminance (light intensity) of the device's environment, in lux.
 *
 * @see https://en.wikipedia.org/wiki/Lux for a table of common lux values.
 */
#define RETRO_SENSOR_ILLUMINANCE 6
/** @} */

/**
 * Adjusts the state of a sensor.
 *
 * @param port The device port of the controller that owns the sensor given in \c action.
 * @param action The action to perform on the sensor.
 * Different devices support different sensors.
 * @param rate The rate at which the underlying sensor should be updated, in Hz.
 * This should be treated as a hint,
 * as some device sensors may not support the requested rate
 * (if it's configurable at all).
 * @returns \c true if the sensor state was successfully adjusted, \c false otherwise.
 * @note If one of the \c RETRO_SENSOR_*_ENABLE actions fails,
 * this likely means that the given sensor is not available
 * on the provided \c port.
 * @see retro_sensor_action
 */
typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
      enum retro_sensor_action action, unsigned rate);

/**
 * Retrieves the current value reported by sensor.
 * @param port The device port of the controller that owns the sensor given in \c id.
 * @param id The sensor value to query.
 * @returns The current sensor value.
 * Exact semantics depend on the value given in \c id,
 * but will return 0 for invalid arguments.
 *
 * @see RETRO_SENSOR_ID
 */
typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);

/**
 * An interface that cores can use to access device sensors.
 *
 * All function pointers are set by the frontend.
 */
struct retro_sensor_interface
{
   /** @copydoc retro_set_sensor_state_t */
   retro_set_sensor_state_t set_sensor_state;

   /** @copydoc retro_sensor_get_input_t */
   retro_sensor_get_input_t get_sensor_input;
};

/** @} */

/** @defgroup GET_CAMERA_INTERFACE Camera Interface
 * @{
 */

/**
 * Denotes the type of buffer in which the camera will store its input.
 *
 * Different camera drivers may support different buffer types.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 * @see retro_camera_callback
 */
enum retro_camera_buffer
{
   /**
    * Indicates that camera frames should be delivered to the core as an OpenGL texture.
    *
    * Requires that the core is using an OpenGL context via \c RETRO_ENVIRONMENT_SET_HW_RENDER.
    *
    * @see retro_camera_frame_opengl_texture_t
    */
   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,

   /**
    * Indicates that camera frames should be delivered to the core as a raw buffer in memory.
    *
    * @see retro_camera_frame_raw_framebuffer_t
    */
   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,

   /**
    * @private Defined to ensure <tt>sizeof(enum retro_camera_buffer) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
};

/**
 * Starts an initialized camera.
 * The camera is disabled by default,
 * and must be enabled with this function before being used.
 *
 * Set by the frontend.
 *
 * @returns \c true if the camera was successfully started, \c false otherwise.
 * Failure may occur if no actual camera is available,
 * or if the frontend doesn't have permission to access it.
 * @note Must be called in \c retro_run().
 * @see retro_camera_callback
 */
typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);

/**
 * Stops the running camera.
 *
 * Set by the frontend.
 *
 * @note Must be called in \c retro_run().
 * @warning The frontend may close the camera on its own when unloading the core,
 * but this behavior is not guaranteed.
 * Cores should clean up the camera before exiting.
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);

/**
 * Called by the frontend to report the state of the camera driver.
 *
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as a raw buffer in memory.
 *
 * Set by the core.
 *
 * @param buffer Pointer to the camera's most recent video frame.
 * Each pixel is in XRGB8888 format.
 * The first pixel represents the top-left corner of the image
 * (i.e. the Y axis goes downward).
 * @param width The width of the frame given in \c buffer, in pixels.
 * @param height The height of the frame given in \c buffer, in pixels.
 * @param pitch The width of the frame given in \c buffer, in bytes.
 * @warning \c buffer may be invalidated when this function returns,
 * so the core should make its own copy of \c buffer if necessary.
 * @see RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
      unsigned width, unsigned height, size_t pitch);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as an OpenGL texture.
 *
 * @param texture_id The ID of the OpenGL texture that represents the camera's most recent frame.
 * Owned by the frontend, and must not be modified by the core.
 * @param texture_target The type of the texture given in \c texture_id.
 * Usually either \c GL_TEXTURE_2D or \c GL_TEXTURE_RECTANGLE,
 * but other types are allowed.
 * @param affine A pointer to a 3x3 column-major affine matrix
 * that can be used to transform pixel coordinates to texture coordinates.
 * After transformation, the bottom-left corner should have coordinates of <tt>(0, 0)</tt>
 * and the top-right corner should have coordinates of <tt>(1, 1)</tt>
 * (or <tt>(width, height)</tt> for \c GL_TEXTURE_RECTANGLE).
 *
 * @note GL-specific typedefs (e.g. \c GLfloat and \c GLuint) are avoided here
 * so that the API doesn't rely on gl.h.
 * @warning \c texture_id and \c affine may be invalidated when this function returns,
 * so the core should make its own copy of them if necessary.
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,
      unsigned texture_target, const float *affine);

/**
 * An interface that the core can use to access a device's camera.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 */
struct retro_camera_callback
{
   /**
    * Requested camera capabilities,
    * given as a bitmask of \c retro_camera_buffer values.
    * Set by the core.
    *
    * Here's a usage example:
    * @code
    * // Requesting support for camera data delivered as both an OpenGL texture and a pixel buffer:
    * struct retro_camera_callback callback;
    * callback.caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);
    * @endcode
    */
   uint64_t caps;

   /**
    * The desired width of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
    * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned width;

   /**
    * The desired height of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
     * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned height;

   /**
    * @copydoc retro_camera_start_t
    * @see retro_camera_callback
    */
   retro_camera_start_t start;

   /**
    * @copydoc retro_camera_stop_t
    * @see retro_camera_callback
    */
   retro_camera_stop_t stop;

   /**
    * @copydoc retro_camera_frame_raw_framebuffer_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;

   /**
    * @copydoc retro_camera_frame_opengl_texture_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_opengl_texture_t frame_opengl_texture;

   /**
    * Core-defined callback invoked by the frontend right after the camera driver is initialized
    * (\em not when calling \c start).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t initialized;

   /**
    * Core-defined callback invoked by the frontend
    * right before the video camera driver is deinitialized
    * (\em not when calling \c stop).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t deinitialized;
};

/** @} */

/** @defgroup GET_LOCATION_INTERFACE Location Interface
 * @{
 */

/** @copydoc retro_location_callback::set_interval */
typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,
      unsigned interval_distance);

/** @copydoc retro_location_callback::start */
typedef bool (RETRO_CALLCONV *retro_location_start_t)(void);

/** @copydoc retro_location_callback::stop */
typedef void (RETRO_CALLCONV *retro_location_stop_t)(void);

/** @copydoc retro_location_callback::get_position */
typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,
      double *horiz_accuracy, double *vert_accuracy);

/** Function type that reports the status of the location service. */
typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);

/**
 * An interface that the core can use to access a device's location.
 *
 * @note It is the frontend's responsibility to request the necessary permissions
 * from the operating system.
 * @see RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE
 */
struct retro_location_callback
{
   /**
    * Starts listening the device's location service.
    *
    * The frontend will report changes to the device's location
    * at the interval defined by \c set_interval.
    * Set by the frontend.
    *
    * @return true if location services were successfully started, false otherwise.
    * Note that this will return \c false if location services are disabled
    * or the frontend doesn't have permission to use them.
    * @note The device's location service may or may not have been enabled
    * before the core calls this function.
    */
   retro_location_start_t         start;

   /**
    * Stop listening to the device's location service.
    *
    * Set by the frontend.
    *
    * @note The location service itself may or may not
    * be turned off by this function,
    * depending on the platform and the frontend.
    * @post The core will stop receiving location service updates.
    */
   retro_location_stop_t          stop;

   /**
    * Returns the device's current coordinates.
    *
    * Set by the frontend.
    *
    * @param[out] lat Pointer to latitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] lon Pointer to longitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] horiz_accuracy Pointer to horizontal accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] vert_accuracy Pointer to vertical accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    */
   retro_location_get_position_t  get_position;

   /**
    * Sets the rate at which the location service should report updates.
    *
    * This is only a hint; the actual rate may differ.
    * Sets the interval of time and/or distance at which to update/poll
    * location-based data.
    *
    * Some platforms may only support one of the two parameters;
    * cores should provide both to ensure compatibility.
    *
    * Set by the frontend.
    *
    * @param interval_ms The desired period of time between location updates, in milliseconds.
    * @param interval_distance The desired distance between location updates, in meters.
    */
   retro_location_set_interval_t  set_interval;

   /** Called when the location service is initialized. Set by the core. Optional. */
   retro_location_lifetime_status_t initialized;

   /** Called when the location service is deinitialized. Set by the core. Optional. */
   retro_location_lifetime_status_t deinitialized;
};

/** @} */

/** @addtogroup GET_RUMBLE_INTERFACE
 * @{ */

/**
 * The type of rumble motor in a controller.
 *
 * Both motors can be controlled independently,
 * and the strong motor does not override the weak motor.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
enum retro_rumble_effect
{
   RETRO_RUMBLE_STRONG = 0,
   RETRO_RUMBLE_WEAK = 1,

   /** @private Defined to ensure <tt>sizeof(enum retro_rumble_effect) == sizeof(int)</tt>. Do not use. */
   RETRO_RUMBLE_DUMMY = INT_MAX
};

/**
 * Requests a rumble state change for a controller.
 * Set by the frontend.
 *
 * @param port The controller port to set the rumble state for.
 * @param effect The rumble motor to set the strength of.
 * @param strength The desired intensity of the rumble motor, ranging from \c 0 to \c 0xffff (inclusive).
 * @return \c true if the requested rumble state was honored.
 * If the controller doesn't support rumble, will return \c false.
 * @note Calling this before the first \c retro_run() may return \c false.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,
      enum retro_rumble_effect effect, uint16_t strength);

/**
 * An interface that the core can use to set the rumble state of a controller.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
struct retro_rumble_interface
{
   /** @copydoc retro_set_rumble_state_t */
   retro_set_rumble_state_t set_rumble_state;
};

/** @} */

/**
 * Called by the frontend to request audio samples.
 * The core should render audio within this function
 * using the callback provided by \c retro_set_audio_sample or \c retro_set_audio_sample_batch.
 *
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_sample_batch_t
 * @see retro_audio_sample_t
 */
typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);

/**
 * Called by the frontend to notify the core that it should pause or resume audio rendering.
 * The initial state of the audio driver after registering this callback is \c false (inactive).
 *
 * @param enabled \c true if the frontend's audio driver is active.
 * If so, the registered audio callback will be called regularly.
 * If not, the audio callback will not be invoked until the next time
 * the frontend calls this function with \c true.
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @note Even if no audio samples are rendered,
 * the core should continue to update its emulated platform's audio engine if necessary.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_callback_t
 */
typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);

/**
 * An interface that the frontend uses to request audio samples from the core.
 * @note To unregister a callback, pass a \c retro_audio_callback_t
 * with both fields set to <tt>NULL</tt>.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 */
struct retro_audio_callback
{
   /** @see retro_audio_callback_t */
   retro_audio_callback_t callback;

   /** @see retro_audio_set_state_callback_t */
   retro_audio_set_state_callback_t set_state;
};

typedef int64_t retro_usec_t;

/**
 * Called right before each iteration of \c retro_run
 * if registered via <tt>RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK</tt>.
 *
 * @param usec Time since the last call to <tt>retro_run</tt>, in microseconds.
 * If the frontend is manipulating the frame time
 * (e.g. via fast-forward or slow motion),
 * this value will be the reference value initially provided to the environment call.
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 * @see retro_frame_time_callback
 */
typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);

/**
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
struct retro_frame_time_callback
{
   /**
    * Called to notify the core of the current frame time.
    * If <tt>NULL</tt>, the frontend will clear its registered callback.
    */
   retro_frame_time_callback_t callback;

   /**
    * The ideal duration of one frame, in microseconds.
    * Compute it as <tt>1000000 / fps</tt>.
    * The frontend will resolve rounding to ensure that framestepping, etc is exact.
    */
   retro_usec_t reference;
};

/** @defgroup SET_AUDIO_BUFFER_STATUS_CALLBACK Audio Buffer Occupancy
 * @{
 */

/**
 * Notifies a libretro core of how full the frontend's audio buffer is.
 * Set by the core, called by the frontend.
 * It will be called right before \c retro_run() every frame.
 *
 * @param active \c true if the frontend's audio buffer is currently in use,
 * \c false if audio is disabled in the frontend.
 * @param occupancy A value between 0 and 100 (inclusive),
 * corresponding to the frontend's audio buffer occupancy percentage.
 * @param underrun_likely \c true if the frontend expects an audio buffer underrun
 * during the next frame, which indicates that a core should attempt frame-skipping.
 */
typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
      bool active, unsigned occupancy, bool underrun_likely);

/**
 * A callback to register with the frontend to receive audio buffer occupancy information.
 */
struct retro_audio_buffer_status_callback
{
   /** @copydoc retro_audio_buffer_status_callback_t */
   retro_audio_buffer_status_callback_t callback;
};

/** @} */

/* Pass this to retro_video_refresh_t if rendering to hardware.
 * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
 * */
#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)

/* Invalidates the current HW context.
 * Any GL state is lost, and must not be deinitialized explicitly.
 * If explicit deinitialization is desired by the libretro core,
 * it should implement context_destroy callback.
 * If called, all GPU resources must be reinitialized.
 * Usually called when frontend reinits video driver.
 * Also called first time video driver is initialized,
 * allowing libretro core to initialize resources.
 */
typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);

/* Gets current framebuffer which is to be rendered to.
 * Could change every frame potentially.
 */
typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);

/* Get a symbol from HW context. */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);

enum retro_hw_context_type
{
   RETRO_HW_CONTEXT_NONE             = 0,
   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
   RETRO_HW_CONTEXT_OPENGL           = 1,
   /* OpenGL ES 2.0. */
   RETRO_HW_CONTEXT_OPENGLES2        = 2,
   /* Modern desktop core GL context. Use version_major/
    * version_minor fields to set GL version. */
   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,
   /* OpenGL ES 3.0 */
   RETRO_HW_CONTEXT_OPENGLES3        = 4,
   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
    * use the corresponding enums directly. */
   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,

   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
   RETRO_HW_CONTEXT_VULKAN           = 6,

   /* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D11            = 7,

   /* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D10            = 8,

   /* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D12            = 9,

   /* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D9             = 10,

   /** Dummy value to ensure sizeof(enum retro_hw_context_type) == sizeof(int). Do not use. */
   RETRO_HW_CONTEXT_DUMMY = INT_MAX
};

struct retro_hw_render_callback
{
   /* Which API to use. Set by libretro core. */
   enum retro_hw_context_type context_type;

   /* Called when a context has been created or when it has been reset.
    * An OpenGL context is only valid after context_reset() has been called.
    *
    * When context_reset is called, OpenGL resources in the libretro
    * implementation are guaranteed to be invalid.
    *
    * It is possible that context_reset is called multiple times during an
    * application lifecycle.
    * If context_reset is called without any notification (context_destroy),
    * the OpenGL context was lost and resources should just be recreated
    * without any attempt to "free" old resources.
    */
   retro_hw_context_reset_t context_reset;

   /* Set by frontend.
    * TODO: This is rather obsolete. The frontend should not
    * be providing preallocated framebuffers. */
   retro_hw_get_current_framebuffer_t get_current_framebuffer;

   /* Set by frontend.
    * Can return all relevant functions, including glClear on Windows. */
   retro_hw_get_proc_address_t get_proc_address;

   /* Set if render buffers should have depth component attached.
    * TODO: Obsolete. */
   bool depth;

   /* Set if stencil buffers should be attached.
    * TODO: Obsolete. */
   bool stencil;

   /* If depth and stencil are true, a packed 24/8 buffer will be added.
    * Only attaching stencil is invalid and will be ignored. */

   /* Use conventional bottom-left origin convention. If false,
    * standard libretro top-left origin semantics are used.
    * TODO: Move to GL specific interface. */
   bool bottom_left_origin;

   /* Major version number for core GL context or GLES 3.1+. */
   unsigned version_major;

   /* Minor version number for core GL context or GLES 3.1+. */
   unsigned version_minor;

   /* If this is true, the frontend will go very far to avoid
    * resetting context in scenarios like toggling fullscreen, etc.
    * TODO: Obsolete? Maybe frontend should just always assume this ...
    */
   bool cache_context;

   /* The reset callback might still be called in extreme situations
    * such as if the context is lost beyond recovery.
    *
    * For optimal stability, set this to false, and allow context to be
    * reset at any time.
    */

   /* A callback to be called before the context is destroyed in a
    * controlled way by the frontend. */
   retro_hw_context_reset_t context_destroy;

   /* OpenGL resources can be deinitialized cleanly at this step.
    * context_destroy can be set to NULL, in which resources will
    * just be destroyed without any notification.
    *
    * Even when context_destroy is non-NULL, it is possible that
    * context_reset is called without any destroy notification.
    * This happens if context is lost by external factors (such as
    * notified by GL_ARB_robustness).
    *
    * In this case, the context is assumed to be already dead,
    * and the libretro implementation must not try to free any OpenGL
    * resources in the subsequent context_reset.
    */

   /* Creates a debug context. */
   bool debug_context;
};

/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
 * Called by the frontend in response to keyboard events.
 * down is set if the key is being pressed, or false if it is being released.
 * keycode is the RETROK value of the char.
 * character is the text character of the pressed key. (UTF-32).
 * key_modifiers is a set of RETROKMOD values or'ed together.
 *
 * The pressed/keycode state can be independent of the character.
 * It is also possible that multiple characters are generated from a
 * single keypress.
 * Keycode events should be treated separately from character events.
 * However, when possible, the frontend should try to synchronize these.
 * If only a character is posted, keycode should be RETROK_UNKNOWN.
 *
 * Similarly if only a keycode event is generated with no corresponding
 * character, character should be 0.
 */
typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,
      uint32_t character, uint16_t key_modifiers);

struct retro_keyboard_callback
{
   retro_keyboard_event_t callback;
};

/** @defgroup SET_DISK_CONTROL_INTERFACE Disk Control
 *
 * Callbacks for inserting and removing disks from the emulated console at runtime.
 * Should be provided by cores that support doing so.
 * Cores should automate this process if possible,
 * but some cases require the player's manual input.
 *
 * The steps for swapping disk images are generally as follows:
 *
 * \li Eject the emulated console's disk drive with \c set_eject_state(true).
 * \li Insert the new disk image with \c set_image_index(index).
 * \li Close the virtual disk tray with \c set_eject_state(false).
 *
 * @{
 */

/**
 * Called by the frontend to open or close the emulated console's virtual disk tray.
 *
 * The frontend may only set the disk image index
 * while the emulated tray is opened.
 *
 * If the emulated console's disk tray is already in the state given by \c ejected,
 * then this function should return \c true without doing anything.
 * The core should return \c false if it couldn't change the disk tray's state;
 * this may happen if the console itself limits when the disk tray can be open or closed
 * (e.g. to wait for the disc to stop spinning).
 *
 * @param ejected \c true if the virtual disk tray should be "ejected",
 * \c false if it should be "closed".
 * @return \c true if the virtual disk tray's state has been set to the given state,
 * false if there was an error.
 * @see retro_get_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);

/**
 * Gets the current ejected state of the disk drive.
 * The initial state is closed, i.e. \c false.
 *
 * @return \c true if the virtual disk tray is "ejected",
 * i.e. it's open and a disk can be inserted.
 * @see retro_set_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);

/**
 * Gets the index of the current disk image,
 * as determined by however the frontend orders disk images
 * (such as m3u-formatted playlists or special directories).
 *
 * @return The index of the current disk image
 * (starting with 0 for the first disk),
 * or a value greater than or equal to \c get_num_images() if no disk is inserted.
 * @see retro_get_num_images_t
 */
typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);

/**
 * Inserts the disk image at the given index into the emulated console's drive.
 * Can only be called while the disk tray is ejected
 * (i.e. \c retro_get_eject_state_t returns \c true).
 *
 * If the emulated disk tray is ejected
 * and already contains the disk image named by \c index,
 * then this function should do nothing and return \c true.
 *
 * @param index The index of the disk image to insert,
 * starting from 0 for the first disk.
 * A value greater than or equal to \c get_num_images()
 * represents the frontend removing the disk without inserting a new one.
 * @return \c true if the disk image was successfully set.
 * \c false if the disk tray isn't ejected or there was another error
 * inserting a new disk image.
 */
typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);

/**
 * @return The number of disk images which are available to use.
 * These are most likely defined in a playlist file.
 */
typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);

struct retro_game_info;

/**
 * Replaces the disk image at the given index with a new disk.
 *
 * Replaces the disk image associated with index.
 * Arguments to pass in info have same requirements as retro_load_game().
 * Virtual disk tray must be ejected when calling this.
 *
 * Passing \c NULL to this function indicates
 * that the frontend has removed this disk image from its internal list.
 * As a result, calls to this function can change the number of available disk indexes.
 *
 * For example, calling <tt>replace_image_index(1, NULL)</tt>
 * will remove the disk image at index 1,
 * and the disk image at index 2 (if any)
 * will be moved to the newly-available index 1.
 *
 * @param index The index of the disk image to replace.
 * @param info Details about the new disk image,
 * or \c NULL if the disk image at the given index should be discarded.
 * The semantics of each field are the same as in \c retro_load_game.
 * @return \c true if the disk image was successfully replaced
 * or removed from the playlist,
 * \c false if the tray is not ejected
 * or if there was an error.
 */
typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
      const struct retro_game_info *info);

/**
 * Adds a new index to the core's internal disk list.
 * This will increment the return value from \c get_num_images() by 1.
 * This image index cannot be used until a disk image has been set
 * with \c replace_image_index.
 *
 * @return \c true if the core has added space for a new disk image
 * and is ready to receive one.
 */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);

/**
 * Sets the disk image that will be inserted into the emulated disk drive
 * before \c retro_load_game is called.
 *
 * \c retro_load_game does not provide a way to ensure
 * that a particular disk image in a playlist is inserted into the console;
 * this function makes up for that.
 * Frontends should call it immediately before \c retro_load_game,
 * and the core should use the arguments
 * to validate the disk image in \c retro_load_game.
 *
 * When content is loaded, the core should verify that the
 * disk specified by \c index can be found at \c path.
 * This is to guard against auto-selecting the wrong image
 * if (for example) the user should modify an existing M3U playlist.
 * We have to let the core handle this because
 * \c set_initial_image() must be called before loading content,
 * i.e. the frontend cannot access image paths in advance
 * and thus cannot perform the error check itself.
 * If \c index is invalid (i.e. <tt>index >= get_num_images()</tt>)
 * or the disk image doesn't match the value given in \c path,
 * the core should ignore the arguments
 * and insert the disk at index 0 into the virtual disk tray.
 *
 * @warning If \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE is called within \c retro_load_game,
 * then this function may not be executed.
 * Set the disk control interface in \c retro_init if possible.
 *
 * @param index The index of the disk image within the playlist to set.
 * @param path The path of the disk image to set as the first.
 * The core should not load this path immediately;
 * instead, it should use it within \c retro_load_game
 * to verify that the correct disk image was loaded.
 * @return \c true if the initial disk index was set,
 * \c false if the arguments are invalid
 * or the core doesn't support this function.
 */
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);

/**
 * Returns the path of the disk image at the given index
 * on the host's file system.
 *
 * @param index The index of the disk image to get the path of.
 * @param s A buffer to store the path in.
 * @param len The size of \c s, in bytes.
 * @return \c true if the disk image's location was successfully
 * queried and copied into \c s,
 * \c false if the index is invalid
 * or the core couldn't locate the disk image.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *s, size_t len);

/**
 * Returns a friendly label for the given disk image.
 *
 * In the simplest case, this may be the disk image's file name
 * with the extension omitted.
 * For cores or games with more complex content requirements,
 * the label can be used to provide information to help the player
 * select a disk image to insert;
 * for example, a core may label different kinds of disks
 * (save data, level disk, installation disk, bonus content, etc.).
 * with names that correspond to in-game prompts,
 * so that the frontend can provide better guidance to the player.
 *
 * @param index The index of the disk image to return a label for.
 * @param s A buffer to store the resulting label in.
 * @param len The length of \c s, in bytes.
 * @return \c true if the disk image at \c index is valid
 * and a label was copied into \c s.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *s, size_t len);

/**
 * An interface that the frontend can use to exchange disks
 * within the emulated console's disk drive.
 *
 * All function pointers are required.
 *
 * @deprecated This struct is superseded by \ref retro_disk_control_ext_callback.
 * Only use this one to maintain compatibility
 * with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * @see retro_disk_control_ext_callback
 */
struct retro_disk_control_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;
};

/**
 * @copybrief retro_disk_control_callback
 *
 * All function pointers are required unless otherwise noted.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
struct retro_disk_control_ext_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;

   /** @copydoc retro_set_initial_image_t
    *
    * Optional; not called if \c NULL.
    *
    * @note The frontend will only try to record/restore the last-used disk index
    * if both \c set_initial_image and \c get_image_path are implemented.
    */
   retro_set_initial_image_t set_initial_image;

   /**
    * @copydoc retro_get_image_path_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_path_t get_image_path;

   /**
    * @copydoc retro_get_image_label_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_label_t get_image_label;
};

/** @} */

/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
 * A core can set it if sending and receiving custom network packets
 * during a multiplayer session is desired.
 */

/* Netpacket flags for retro_netpacket_send_t */
#define RETRO_NETPACKET_UNRELIABLE  0        /* Packet to be sent unreliable, depending on network quality it might not arrive. */
#define RETRO_NETPACKET_RELIABLE    (1 << 0) /* Reliable packets are guaranteed to arrive at the target in the order they were sent. */
#define RETRO_NETPACKET_UNSEQUENCED (1 << 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */
#define RETRO_NETPACKET_FLUSH_HINT  (1 << 2) /* Request the packet and any previously buffered ones to be sent immediately */

/* Broadcast client_id for retro_netpacket_send_t */
#define RETRO_NETPACKET_BROADCAST 0xFFFF

/* Used by the core to send a packet to one or all connected players.
 * A single packet sent via this interface can contain up to 64 KB of data.
 *
 * The client_id RETRO_NETPACKET_BROADCAST sends the packet as a broadcast to
 * all connected players. This is supported from the host as well as clients.
*  Otherwise, the argument indicates the player to send the packet to.
 *
 * A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).
 * Unreliable packets might not be supported by the frontend, but the flags can
 * still be specified. Reliable transmission will be used instead.
 *
 * Calling this with the flag RETRO_NETPACKET_FLUSH_HINT will send off the
 * packet and any previously buffered ones immediately and without blocking.
 * To only flush previously queued packets, buf or len can be passed as NULL/0.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id);

/* Optionally read any incoming packets without waiting for the end of the
 * frame. While polling, retro_netpacket_receive_t and retro_netpacket_stop_t
 * can be called. The core can perform this in a loop to do a blocking read,
 * i.e., wait for incoming data, but needs to handle stop getting called and
 * also give up after a short while to avoid freezing on a connection problem.
 * It is a good idea to manually flush outgoing packets before calling this.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_receive_t)(void);

/* Called by the frontend to signify that a multiplayer session has started.
 * If client_id is 0 the local player is the host of the session and at this
 * point no other player has connected yet.
 *
 * If client_id is > 0 the local player is a client connected to a host and
 * at this point is already fully connected to the host.
 *
 * The core must store the function pointer send_fn and use it whenever it
 * wants to send a packet. Optionally poll_receive_fn can be stored and used
 * when regular receiving between frames is not enough. These function pointers
 * remain valid until the frontend calls retro_netpacket_stop_t.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn, retro_netpacket_poll_receive_t poll_receive_fn);

/* Called by the frontend when a new packet arrives which has been sent from
 * another player with retro_netpacket_send_t. The client_id argument indicates
 * who has sent the packet.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);

/* Called by the frontend when the multiplayer session has ended.
 * Once this gets called the function pointers passed to
 * retro_netpacket_start_t will not be valid anymore.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);

/* Called by the frontend every frame (between calls to retro_run while
 * updating the state of the multiplayer session.
 * This is a good place for the core to call retro_netpacket_send_t from.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);

/* Called by the frontend when a new player connects to the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 * If this function returns false, the newly connected player gets dropped.
 * This can be used for example to limit the number of players.
 */
typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);

/* Called by the frontend when a player leaves or disconnects from the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);

/**
 * A callback interface for giving a core the ability to send and receive custom
 * network packets during a multiplayer session between two or more instances
 * of a libretro frontend.
 *
 * Normally during connection handshake the frontend will compare library_version
 * used by both parties and show a warning if there is a difference. When the core
 * supplies protocol_version, the frontend will check against this instead.
 *
 * @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE
 */
struct retro_netpacket_callback
{
   retro_netpacket_start_t        start;
   retro_netpacket_receive_t      receive;
   retro_netpacket_stop_t         stop;         /* Optional - may be NULL */
   retro_netpacket_poll_t         poll;         /* Optional - may be NULL */
   retro_netpacket_connected_t    connected;    /* Optional - may be NULL */
   retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */
   const char* protocol_version; /* Optional - if not NULL will be used instead of core version to decide if communication is compatible */
};

/**
 * The pixel format used for rendering.
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 */
enum retro_pixel_format
{
   /**
    * 0RGB1555, native endian.
    * Used as the default if \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT is not called.
    * The most significant bit must be set to 0.
    * @deprecated This format remains supported to maintain compatibility.
    * New code should use <tt>RETRO_PIXEL_FORMAT_RGB565</tt> instead.
    * @see RETRO_PIXEL_FORMAT_RGB565
    */
   RETRO_PIXEL_FORMAT_0RGB1555 = 0,

   /**
    * XRGB8888, native endian.
    * The most significant byte (the <tt>X</tt>) is ignored.
    */
   RETRO_PIXEL_FORMAT_XRGB8888 = 1,

   /**
    * RGB565, native endian.
    * This format is recommended if 16-bit pixels are desired,
    * as it is available on a variety of devices and APIs.
    */
   RETRO_PIXEL_FORMAT_RGB565   = 2,

   /** Defined to ensure that <tt>sizeof(retro_pixel_format) == sizeof(int)</tt>. Do not use. */
   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX
};

/** @defgroup GET_SAVESTATE_CONTEXT Savestate Context
 * @{
 */

/**
 * Details about how the frontend will use savestates.
 *
 * @see RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT
 * @see retro_serialize
 */
enum retro_savestate_context
{
   /**
    * Standard savestate written to disk.
    * May be loaded at any time,
    * even in a separate session or on another device.
    *
    * Should not contain any pointers to code or data.
    */
   RETRO_SAVESTATE_CONTEXT_NORMAL                 = 0,

   /**
    * The savestate is guaranteed to be loaded
    * within the same session, address space, and binary.
    * Will not be written to disk or sent over the network;
    * therefore, internal pointers to code or data are acceptable.
    * May still be loaded or saved at any time.
    *
    * @note This context generally implies the use of runahead or rewinding,
    * which may work by taking savestates multiple times per second.
    * Savestate code that runs in this context should be fast.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,

   /**
    * The savestate is guaranteed to be loaded
    * in the same session and by the same binary,
    * but possibly by a different address space
    * (e.g. for "second instance" runahead)
    *
    * Will not be written to disk or sent over the network,
    * but may be loaded in a different address space.
    * Therefore, the savestate <em>must not</em> contain pointers.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY   = 2,

   /**
    * The savestate will not be written to disk,
    * but no other guarantees are made.
    * The savestate will almost certainly be loaded
    * by a separate binary, device, and address space.
    *
    * This context is intended for use with frontends that support rollback netplay.
    * Serialized state should omit any data that would unnecessarily increase bandwidth usage.
    * Must not contain pointers, and integers must be saved in big-endian format.
    * @see retro_endianness.h
    * @see network_stream
    */
   RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY       = 3,

   /**
    * @private Defined to ensure <tt>sizeof(retro_savestate_context) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_SAVESTATE_CONTEXT_UNKNOWN                = INT_MAX
};

/** @} */

/** @defgroup SET_MESSAGE User-Visible Messages
 *
 * @{
 */

/**
 * Defines a message that the frontend will display to the user,
 * as determined by <tt>RETRO_ENVIRONMENT_SET_MESSAGE</tt>.
 *
 * @deprecated This struct is superseded by \ref retro_message_ext,
 * which provides more control over how a message is presented.
 * Only use it for compatibility with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see retro_message_ext
 */
struct retro_message
{
   /**
    * Null-terminated message to be displayed.
    * If \c NULL or empty, the message will be ignored.
    */
   const char *msg;

   /** Duration to display \c msg in frames. */
   unsigned    frames;
};

/**
 * The method that the frontend will use to display a message to the player.
 * @see retro_message_ext
 */
enum retro_message_target
{
   /**
    * Indicates that the frontend should display the given message
    * using all other targets defined by \c retro_message_target at once.
    */
   RETRO_MESSAGE_TARGET_ALL = 0,

   /**
    * Indicates that the frontend should display the given message
    * using the frontend's on-screen display, if available.
    *
    * @attention If the frontend allows players to customize or disable notifications,
    * then they may not see messages sent to this target.
    */
   RETRO_MESSAGE_TARGET_OSD,

   /**
    * Indicates that the frontend should log the message
    * via its usual logging mechanism, if available.
    *
    * This is not intended to be a substitute for \c RETRO_ENVIRONMENT_SET_LOG_INTERFACE.
    * It is intended for the common use case of
    * logging a player-facing message.
    *
    * This target should not be used for messages
    * of type \c RETRO_MESSAGE_TYPE_STATUS or \c RETRO_MESSAGE_TYPE_PROGRESS,
    * as it may add unnecessary noise to a log file.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   RETRO_MESSAGE_TARGET_LOG
};

/**
 * A broad category for the type of message that the frontend will display.
 *
 * Each message type has its own use case,
 * therefore the frontend should present each one differently.
 *
 * @note This is a hint that the frontend may ignore.
 * The frontend should fall back to \c RETRO_MESSAGE_TYPE_NOTIFICATION
 * for message types that it doesn't support.
 */
enum retro_message_type
{
   /**
    * A standard on-screen message.
    *
    * Suitable for a variety of use cases,
    * such as messages about errors
    * or other important events.
    *
    * Frontends that display their own messages
    * should display this type of core-generated message the same way.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION = 0,

   /**
    * An on-screen message that should be visually distinct
    * from \c RETRO_MESSAGE_TYPE_NOTIFICATION messages.
    *
    * The exact meaning of "visually distinct" is left to the frontend,
    * but this usually implies that the frontend shows the message
    * in a way that it doesn't typically use for its own notices.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,

   /**
    * Indicates a frequently-updated status display,
    * rather than a standard notification.
    * Status messages are intended to be displayed permanently while a core is running
    * in a way that doesn't suggest user action is required.
    *
    * Here are some possible use cases for status messages:
    *
    * @li An internal framerate counter.
    * @li Debugging information.
    *     Remember to let the player disable it in the core options.
    * @li Core-specific state, such as when a microphone is active.
    *
    * The status message is displayed for the given duration,
    * unless another status message of equal or greater priority is shown.
    */
   RETRO_MESSAGE_TYPE_STATUS,

   /**
    * Denotes a message that reports the progress
    * of a long-running asynchronous task,
    * such as when a core loads large files from disk or the network.
    *
    * The frontend should display messages of this type as a progress bar
    * (or a progress spinner for indefinite tasks),
    * where \c retro_message_ext::msg is the progress bar's title
    * and \c retro_message_ext::progress sets the progress bar's length.
    *
    * This message type shouldn't be used for tasks that are expected to complete quickly.
    */
   RETRO_MESSAGE_TYPE_PROGRESS
};

/**
 * A core-provided message that the frontend will display to the player.
 *
 * @note The frontend is encouraged store these messages in a queue.
 * However, it should not empty the queue of core-submitted messages upon exit;
 * if a core exits with an error, it may want to use this API
 * to show an error message to the player.
 *
 * The frontend should maintain its own copy of the submitted message
 * and all subobjects, including strings.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 */
struct retro_message_ext
{
   /**
    * The \c NULL-terminated text of a message to show to the player.
    * Must not be \c NULL.
    *
    * @note The frontend must honor newlines in this string
    * when rendering text to \c RETRO_MESSAGE_TARGET_OSD.
    */
   const char *msg;

   /**
    * The duration that \c msg will be displayed on-screen, in milliseconds.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned duration;

   /**
    * The relative importance of this message
    * when targeting \c RETRO_MESSAGE_TARGET_OSD.
    * Higher values indicate higher priority.
    *
    * The frontend should use this to prioritize messages
    * when it can't show all active messages at once,
    * or to remove messages from its queue if it's full.
    *
    * The relative display order of messages with the same priority
    * is left to the frontend's discretion,
    * although we suggest breaking ties
    * in favor of the most recently-submitted message.
    *
    * Frontends may handle deprioritized messages at their discretion;
    * such messages may have their \c duration altered,
    * be hidden without being delayed,
    * or even be discarded entirely.
    *
    * @note In the reference frontend (RetroArch),
    * the same priority values are used for frontend-generated notifications,
    * which are typically between 0 and 3 depending upon importance.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned priority;

   /**
    * The severity level of this message.
    *
    * The frontend may use this to filter or customize messages
    * depending on the player's preferences.
    * Here are some ideas:
    *
    * @li Use this to prioritize errors and warnings
    *     over higher-ranking info and debug messages.
    * @li Render warnings or errors with extra visual feedback,
    *     e.g. with brighter colors or accompanying sound effects.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   enum retro_log_level level;

   /**
    * The intended destination of this message.
    *
    * @see retro_message_target
    */
   enum retro_message_target target;

   /**
    * The intended semantics of this message.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    *
    * @see retro_message_type
    */
   enum retro_message_type type;

   /**
    * The progress of an asynchronous task.
    *
    * A value between 0 and 100 (inclusive) indicates the task's percentage,
    * and a value of -1 indicates a task of unknown completion.
    *
    * @note Since message type is a hint, a frontend may ignore progress values.
    * Where relevant, a core should include progress percentage within the message string,
    * such that the message intent remains clear when displayed
    * as a standard frontend-generated notification.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG and for
    * message types other than \c RETRO_MESSAGE_TYPE_PROGRESS.
    */
   int8_t progress;
};

/** @} */

/* Describes how the libretro implementation maps a libretro input bind
 * to its internal input system through a human readable string.
 * This string can be used to better let a user configure input. */
struct retro_input_descriptor
{
   /* Associates given parameters with a description. */
   unsigned port;
   unsigned device;
   unsigned index;
   unsigned id;

   /* Human readable description for parameters.
    * The pointer must remain valid until
    * retro_unload_game() is called. */
   const char *description;
};

/**
 * Contains basic information about the core.
 *
 * @see retro_get_system_info
 * @warning All pointers are owned by the core
 * and must remain valid throughout its lifetime.
 */
struct retro_system_info
{
   /**
    * Descriptive name of the library.
    *
    * @note Should not contain any version numbers, etc.
    */
   const char *library_name;

   /**
    * Descriptive version of the core.
    */
   const char *library_version;

   /**
    * A pipe-delimited string list of file extensions that this core can load, e.g. "bin|rom|iso".
    * Typically used by a frontend for filtering or core selection.
    */
   const char *valid_extensions;

   /* Libretro cores that need to have direct access to their content
    * files, including cores which use the path of the content files to
    * determine the paths of other files, should set need_fullpath to true.
    *
    * Cores should strive for setting need_fullpath to false,
    * as it allows the frontend to perform patching, etc.
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to have a valid path
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * See also:
    *    - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
    *    - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
    */
   bool        need_fullpath;

   /* If true, the frontend is not allowed to extract any archives before
    * loading the real content.
    * Necessary for certain libretro implementations that load games
    * from zipped archives. */
   bool        block_extract;
};

/* Defines overrides which modify frontend handling of
 * specific content file types.
 * An array of retro_system_content_info_override is
 * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_system_content_info_override
{
   /* A list of file extensions for which the override
    * should apply, delimited by a 'pipe' character
    * (e.g. "md|sms|gg")
    * Permitted file extensions are limited to those
    * included in retro_system_info::valid_extensions
    * and/or retro_subsystem_rom_info::valid_extensions */
   const char *extensions;

   /* Overrides the need_fullpath value set in
    * retro_system_info and/or retro_subsystem_rom_info.
    * To reiterate:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * In addition:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info_ext::full_path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info_ext::archive_path may be NULL
    *    - retro_game_info_ext::archive_file may be NULL
    *    - retro_game_info_ext::dir is guaranteed to contain a valid path
    *      to the directory in which the content file exists
    *    - retro_game_info_ext::name is guaranteed to contain the
    *      basename of the content file, without extension
    *    - retro_game_info_ext::ext is guaranteed to contain the
    *      extension of the content file in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - If retro_game_info_ext::file_in_archive is false:
    *       - retro_game_info_ext::full_path is guaranteed to contain
    *         a valid path to an existent file
    *       - retro_game_info_ext::archive_path may be NULL
    *       - retro_game_info_ext::archive_file may be NULL
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the content file exists
    *       - retro_game_info_ext::name is guaranteed to contain the
    *         basename of the content file, without extension
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file in lower case format
    *    - If retro_game_info_ext::file_in_archive is true:
    *       - retro_game_info_ext::full_path may be NULL
    *       - retro_game_info_ext::archive_path is guaranteed to
    *         contain a valid path to an existent compressed file
    *         inside which the content file is located
    *       - retro_game_info_ext::archive_file is guaranteed to
    *         contain a valid path to an existent content file
    *         inside the compressed file referred to by
    *         retro_game_info_ext::archive_path
    *            e.g. for a compressed file '/path/to/foo.zip'
    *            containing 'bar.sfc'
    *             > retro_game_info_ext::archive_path will be '/path/to/foo.zip'
    *             > retro_game_info_ext::archive_file will be 'bar.sfc'
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the compressed file
    *         (containing the content file) exists
    *       - retro_game_info_ext::name is guaranteed to contain
    *         EITHER
    *         1) the basename of the compressed file (containing
    *            the content file), without extension
    *         OR
    *         2) the basename of the content file inside the
    *            compressed file, without extension
    *         In either case, a core should consider 'name' to
    *         be the canonical name/ID of the the content file
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file inside the compressed file,
    *         in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size are
    *      guaranteed to be valid */
   bool need_fullpath;

   /* If need_fullpath is false, specifies whether the content
    * data buffer available in retro_load_game() is 'persistent'
    *
    * If persistent_data is false and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid only until retro_load_game() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid only until retro_load_game() returns
    *
    * If persistent_data is true and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid until retro_deinit() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid until retro_deinit() returns */
   bool persistent_data;
};

/* Similar to retro_game_info, but provides extended
 * information about the source content file and
 * game memory buffer status.
 * And array of retro_game_info_ext is returned by
 * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_game_info_ext
{
   /* - If file_in_archive is false, contains a valid
    *   path to an existent content file (UTF-8 encoded)
    * - If file_in_archive is true, may be NULL */
   const char *full_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contains a valid path
    *   to an existent compressed file inside which the
    *   content file is located (UTF-8 encoded) */
   const char *archive_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contain a valid path
    *   to an existent content file inside the compressed
    *   file referred to by archive_path (UTF-8 encoded)
    *      e.g. for a compressed file '/path/to/foo.zip'
    *      containing 'bar.sfc'
    *      > archive_path will be '/path/to/foo.zip'
    *      > archive_file will be 'bar.sfc' */
   const char *archive_file;

   /* - If file_in_archive is false, contains a valid path
    *   to the directory in which the content file exists
    *   (UTF-8 encoded)
    * - If file_in_archive is true, contains a valid path
    *   to the directory in which the compressed file
    *   (containing the content file) exists (UTF-8 encoded) */
   const char *dir;

   /* Contains the canonical name/ID of the content file
    * (UTF-8 encoded). Intended for use when identifying
    * 'complementary' content named after the loaded file -
    * i.e. companion data of a different format (a CD image
    * required by a ROM), texture packs, internally handled
    * save files, etc.
    * - If file_in_archive is false, contains the basename
    *   of the content file, without extension
    * - If file_in_archive is true, then string is
    *   implementation specific. A frontend may choose to
    *   set a name value of:
    *   EITHER
    *   1) the basename of the compressed file (containing
    *      the content file), without extension
    *   OR
    *   2) the basename of the content file inside the
    *      compressed file, without extension
    *   RetroArch sets the 'name' value according to (1).
    *   A frontend that supports routine loading of
    *   content from archives containing multiple unrelated
    *   content files may set the 'name' value according
    *   to (2). */
   const char *name;

   /* - If file_in_archive is false, contains the extension
    *   of the content file in lower case format
    * - If file_in_archive is true, contains the extension
    *   of the content file inside the compressed file,
    *   in lower case format */
   const char *ext;

   /* String of implementation specific meta-data. */
   const char *meta;

   /* Memory buffer of loaded game content. Will be NULL:
    * IF
    * - retro_system_info::need_fullpath is true and
    *   retro_system_content_info_override::need_fullpath
    *   is unset
    * OR
    * - retro_system_content_info_override::need_fullpath
    *   is true */
   const void *data;

   /* Size of game content memory buffer, in bytes */
   size_t size;

   /* True if loaded content file is inside a compressed
    * archive */
   bool file_in_archive;

   /* - If data is NULL, value is unset/ignored
    * - If data is non-NULL:
    *   - If persistent_data is false, data and size are
    *     valid only until retro_load_game() returns
    *   - If persistent_data is true, data and size are
    *     are valid until retro_deinit() returns */
   bool persistent_data;
};

/**
 * Parameters describing the size and shape of the video frame.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 * @see retro_get_system_av_info
 */
struct retro_game_geometry
{
   /**
    * Nominal video width of game, in pixels.
    * This will typically be the emulated platform's native video width
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_width;

   /**
    * Nominal video height of game, in pixels.
    * This will typically be the emulated platform's native video height
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_height;

   /**
    * Maximum possible width of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video width.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's widest possible screen layout (e.g. side-by-side).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_width;

   /**
    * Maximum possible height of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video height.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's tallest possible screen layout (e.g. vertical).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_height;    /* Maximum possible height of game. */

   /**
    * Nominal aspect ratio of game.
    * If zero or less,
    * an aspect ratio of <tt>base_width / base_height</tt> is assumed.
    *
    * @note A frontend may ignore this setting.
    */
   float    aspect_ratio;
};

/**
 * Parameters describing the timing of the video and audio.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_timing
{
   /** Video output refresh rate, in frames per second. */
   double fps;

   /** The audio output sample rate, in Hz. */
   double sample_rate;
};

/**
 * Configures how the core's audio and video should be updated.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_av_info
{
   /** Parameters describing the size and shape of the video frame. */
   struct retro_game_geometry geometry;

   /** Parameters describing the timing of the video and audio. */
   struct retro_system_timing timing;
};

/** @defgroup SET_CORE_OPTIONS Core Options
 *  @{
 */

/**
 * Represents \ref RETRO_ENVIRONMENT_GET_VARIABLE "a core option query".
 *
 * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
 * (which is a deprecated API),
 * this \c struct serves as an option definition.
 *
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 */
struct retro_variable
{
   /**
    * A unique key identifying this option.
    *
    * Should be a key for an option that was previously defined
    * with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 or similar.
    *
    * Should be prefixed with the core's name
    * to minimize the risk of collisions with another core's options,
    * as frontends are not required to use a namespacing scheme for storing options.
    * For example, a core named "foo" might define an option named "foo_option".
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is used to define an option
    * named by this key.
    */
   const char *key;

   /**
    * Value to be obtained.
    *
    * Set by the frontend to \c NULL if
    * the option named by \ref key does not exist.
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is set by the core to define the possible values
    * for an option named by \ref key.
    * When used this way, it must be formatted as follows:
    * @li The text before the first ';' is the option's human-readable title.
    * @li A single space follows the ';'.
    * @li The rest of the string is a '|'-delimited list of possible values,
    * with the first one being the default.
    */
   const char *value;
};

/**
 * An argument that's used to show or hide a core option in the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 */
struct retro_core_option_display
{
   /**
    * The key for a core option that was defined with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
    * \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
    * or their legacy equivalents.
    */
   const char *key;

   /**
    * Whether the option named by \c key
    * should be displayed to the player in the frontend's core options menu.
    *
    * @note This value is a hint, \em not a requirement;
    * the frontend is free to ignore this field.
    */
   bool visible;
};

/**
 * The maximum number of choices that can be defined for a given core option.
 *
 * This limit was chosen as a compromise between
 * a core's flexibility and a streamlined user experience.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 *
 * If you need more than 128 choices for a core option,
 * consider simplifying your option structure.
 * Here are some ideas:
 *
 * \li If a core option represents a numeric value,
 *     consider reducing the option's granularity
 *     (e.g. define time limits in increments of 5 seconds instead of 1 second).
 *     Providing a fixed set of values based on experimentation
 *     is also a good idea.
 * \li If a core option represents a dynamically-built list of files,
 *     consider leaving out files that won't be useful.
 *     For example, if a core allows the player to choose a specific BIOS file,
 *     it can omit files of the wrong length or without a valid header.
 *
 * @see retro_core_option_definition
 * @see retro_core_option_v2_definition
 */
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128

/**
 * A descriptor for a particular choice within a core option.
 *
 * @note All option values are represented as strings.
 * If you need to represent any other type,
 * parse the string in \ref value.
 *
 * @see retro_core_option_v2_category
 */
struct retro_core_option_value
{
   /**
    * The option value that the frontend will serialize.
    *
    * Must not be \c NULL or empty.
    * No other hard limits are placed on this value's contents,
    * but here are some suggestions:
    *
    * \li If the value represents a number,
    *     don't include any non-digit characters (units, separators, etc.).
    *     Instead, include that information in \c label.
    *     This will simplify parsing.
    * \li If the value represents a file path,
    *     store it as a relative path with respect to one of the common libretro directories
    *     (e.g. \ref RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY "the system directory"
    *     or \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "the save directory"),
    *     and use forward slashes (\c "/") as directory separators.
    *     This will simplify cloud storage if supported by the frontend,
    *     as the same file may be used on multiple devices.
    */
   const char *value;

   /**
    * Human-readable name for \c value that the frontend should show to players.
    *
    * May be \c NULL, in which case the frontend
    * should display \c value itself.
    *
    * Here are some guidelines for writing a good label:
    *
    * \li Make the option labels obvious
    *     so that they don't need to be explained in the description.
    * \li Keep labels short, and don't use unnecessary words.
    *     For example, "OpenGL" is a better label than "OpenGL Mode".
    * \li If the option represents a number,
    *     consider adding units, separators, or other punctuation
    *     into the label itself.
    *     For example, "5 seconds" is a better label than "5".
    * \li If the option represents a number, use intuitive units
    *     that don't take a lot of digits to express.
    *     For example, prefer "1 minute" over "60 seconds" or "60,000 milliseconds".
    */
   const char *label;
};

/**
 * @copybrief retro_core_option_v2_definition
 *
 * @deprecated Use \ref retro_core_option_v2_definition instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
struct retro_core_option_definition
{
   /** @copydoc retro_core_option_v2_definition::key */
   const char *key;

   /** @copydoc retro_core_option_v2_definition::desc */
   const char *desc;

   /** @copydoc retro_core_option_v2_definition::info */
   const char *info;

   /** @copydoc retro_core_option_v2_definition::values */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /** @copydoc retro_core_option_v2_definition::default_value */
   const char *default_value;
};

#ifdef __PS3__
#undef local
#endif

/**
 * A variant of \ref retro_core_options that supports internationalization.
 *
 * @deprecated Use \ref retro_core_options_v2_intl instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see retro_core_options
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_intl
{
   /** @copydoc retro_core_options_v2_intl::us */
   struct retro_core_option_definition *us;

   /** @copydoc retro_core_options_v2_intl::local */
   struct retro_core_option_definition *local;
};

/**
 * A descriptor for a group of related core options.
 *
 * Here's an example category:
 *
 * @code
 * {
 *     "cpu",
 *     "CPU Emulation",
 *     "Settings for CPU quirks."
 * }
 * @endcode
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_category
{
   /**
    * A string that uniquely identifies this category within the core's options.
    * Any \c retro_core_option_v2_definition whose \c category_key matches this
    * is considered to be within this category.
    * Different cores may use the same category keys,
    * so namespacing them is not necessary.
    * Valid characters are <tt>[a-zA-Z0-9_-]</tt>.
    *
    * Frontends should use this category to organize core options,
    * but may customize this category's presentation in other ways.
    * For example, a frontend may use common keys like "audio" or "gfx"
    * to select an appropriate icon in its UI.
    *
    * Required; must not be \c NULL.
    */
   const char *key;

   /**
    * A brief human-readable name for this category,
    * intended for the frontend to display to the player.
    * This should be a name that's concise and descriptive, such as "Audio" or "Video".
    *
    * Required; must not be \c NULL.
    */
   const char *desc;

   /**
    * A human-readable description for this category,
    * intended for the frontend to display to the player
    * as secondary help text (e.g. a sublabel or a tooltip).
    * Optional; may be \c NULL or an empty string.
    */
   const char *info;
};

/**
 * A descriptor for a particular core option and the values it may take.
 *
 * Supports categorizing options into groups,
 * so as not to overwhelm the player.
 *
 * @see retro_core_option_v2_category
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_definition
{
   /**
    * A unique identifier for this option that cores may use
    * \ref RETRO_ENVIRONMENT_GET_VARIABLE "to query its value from the frontend".
    * Must be unique within this core.
    *
    * Should be unique globally;
    * the recommended method for doing so
    * is to prefix each option with the core's name.
    * For example, an option that controls the resolution for a core named "foo"
    * should be named \c "foo_resolution".
    *
    * Valid key characters are in the set <tt>[a-zA-Z0-9_-]</tt>.
    */
   const char *key;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * Required; must not be \c NULL or empty.
    */
   const char *desc;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version may be slightly more concise than \ref desc,
    * as it can rely on the structure of the options menu.
    * For example, "Interface" is a good \c desc_categorized,
    * as it can be displayed as a sublabel for a "Network" category.
    * For \c desc, "Network Interface" would be more suitable.
    *
    * Optional; if this field or \c category_key is empty or \c NULL,
    * \c desc will be used instead.
    */
   const char *desc_categorized;

   /**
    * A human-readable description of this option and its effects,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * @details Intended to be displayed as secondary help text,
    * such as a tooltip or a sublabel.
    *
    * Here are some suggestions for writing a good description:
    *
    * \li Avoid technical jargon unless this option is meant for advanced users.
    *     If unavoidable, suggest one of the default options for those unsure.
    * \li Don't repeat the option name in the description;
    *     instead, describe what the option name means.
    * \li If an option requires a core restart or game reset to take effect,
    *     be sure to say so.
    * \li Try to make the option labels obvious
    *     so that they don't need to be explained in the description.
    *
    * Optional; may be \c NULL.
    */
   const char *info;

   /**
    * @brief A human-readable description of this option and its effects,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version is provided to accommodate descriptions
    * that reference other options by name,
    * as options may have different user-facing names
    * depending on whether the frontend supports categorization.
    *
    * @copydetails info
    *
    * If empty or \c NULL, \c info will be used instead.
    * Will be ignored if \c category_key is empty or \c NULL.
    */
   const char *info_categorized;

   /**
    * The key of the category that this option belongs to.
    *
    * Optional; if equal to \ref retro_core_option_v2_category::key "a defined category",
    * then this option shall be displayed by the frontend
    * next to other options in this same category,
    * assuming it supports doing so.
    * Option categories are intended to be displayed in a submenu,
    * but this isn't a hard requirement.
    *
    * If \c NULL, empty, or not equal to a defined category,
    * then this option is considered uncategorized
    * and the frontend shall display it outside of any category
    * (most likely at a top-level menu).
    *
    * @see retro_core_option_v2_category
    */
   const char *category_key;

   /**
    * One or more possible values for this option,
    * up to the limit of \ref RETRO_NUM_CORE_OPTION_VALUES_MAX.
    *
    * Terminated by a \c { NULL, NULL } element,
    * although frontends should work even if all elements are used.
    */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /**
    * The default value for this core option.
    * Used if it hasn't been set, e.g. for new cores.
    * Must equal one of the \ref value members in the \c values array,
    * or else this option will be ignored.
    */
   const char *default_value;
};

/**
 * A set of core option descriptors and the categories that group them,
 * suitable for enabling a core to be customized.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
struct retro_core_options_v2
{
   /**
    * An array of \ref retro_core_option_v2_category "option categories",
    * terminated by a zeroed-out category \c struct.
    *
    * Will be ignored if the frontend doesn't support core option categories.
    *
    * If \c NULL or ignored, all options will be treated as uncategorized.
    * This most likely means that a frontend will display them at a top-level menu
    * without any kind of hierarchy or grouping.
    */
   struct retro_core_option_v2_category *categories;

   /**
    * An array of \ref retro_core_option_v2_definition "core option descriptors",
    * terminated by a zeroed-out definition \c struct.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_option_v2_definition *definitions;
};

/**
 * A variant of \ref retro_core_options_v2 that supports internationalization.
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_v2_intl
{
   /**
    * Pointer to a core options set
    * whose text is written in American English.
    *
    * This may be passed to \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 as-is
    * if not using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_options_v2 *us;

   /**
    * Pointer to a core options set
    * whose text is written in one of libretro's \ref retro_language "supported languages",
    * most likely the one returned by \ref RETRO_ENVIRONMENT_GET_LANGUAGE.
    *
    * Structure is the same, but usage is slightly different:
    *
    * \li All text (except for keys and option values)
    *     should be written in whichever language
    *     is returned by \c RETRO_ENVIRONMENT_GET_LANGUAGE.
    * \li All fields besides keys and option values may be \c NULL,
    *     in which case the corresponding string in \c us
    *     is used instead.
    * \li All \ref retro_core_option_v2_definition::default_value "default option values"
    *     are taken from \c us.
    *     The defaults in this field are ignored.
    *
    * May be \c NULL, in which case \c us is used instead.
    */
   struct retro_core_options_v2 *local;
};

/**
 * Called by the frontend to determine if any core option's visibility has changed.
 *
 * Each time a frontend sets a core option,
 * it should call this function to see if
 * any core option should be made visible or invisible.
 *
 * May also be called after \ref retro_load_game "loading a game",
 * to determine what the initial visibility of each option should be.
 *
 * Within this function, the core must update the visibility
 * of any dynamically-hidden options
 * using \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.
 *
 * @note All core options are visible by default,
 * even during this function's first call.
 *
 * @return \c true if any core option's visibility was adjusted
 * since the last call to this function.
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
typedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void);

/**
 * Callback registered by the core for the frontend to use
 * when setting the visibility of each core option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
struct retro_core_options_update_display_callback
{
   /**
    * @copydoc retro_core_options_update_display_callback_t
    *
    * Set by the core.
    */
   retro_core_options_update_display_callback_t callback;
};

/** @} */

struct retro_game_info
{
   const char *path;       /* Path to game, UTF-8 encoded.
                            * Sometimes used as a reference for building other paths.
                            * May be NULL if game was loaded from stdin or similar,
                            * but in this case some cores will be unable to load `data`.
                            * So, it is preferable to fabricate something here instead
                            * of passing NULL, which will help more cores to succeed.
                            * retro_system_info::need_fullpath requires
                            * that this path is valid. */
   const void *data;       /* Memory buffer of loaded game. Will be NULL
                            * if need_fullpath was set. */
   size_t      size;       /* Size of memory buffer. */
   const char *meta;       /* String of implementation specific meta-data. */
};

/** @defgroup GET_CURRENT_SOFTWARE_FRAMEBUFFER Frontend-Owned Framebuffers
 * @{
 */

/** @defgroup RETRO_MEMORY_ACCESS Framebuffer Memory Access Types
 * @{
 */

/** Indicates that core will write to the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_WRITE (1 << 0)

/** Indicates that the core will read from the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_READ (1 << 1)

/** @} */

/** @defgroup RETRO_MEMORY_TYPE Framebuffer Memory Types
 * @{
 */

/**
 * Indicates that the returned framebuffer's memory is cached.
 * If not set, random access to the buffer may be very slow.
 */
#define RETRO_MEMORY_TYPE_CACHED (1 << 0)

/** @} */

/**
 * A frame buffer owned by the frontend that a core may use for rendering.
 *
 * @see GET_CURRENT_SOFTWARE_FRAMEBUFFER
 * @see retro_video_refresh_t
 */
struct retro_framebuffer
{
   /**
    * Pointer to the beginning of the framebuffer provided by the frontend.
    * The initial contents of this buffer are unspecified,
    * as is the means used to map the memory;
    * this may be defined in software,
    * or it may be GPU memory mapped to RAM.
    *
    * If the framebuffer is used,
    * this pointer must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to pass an offset to this pointer.
    *
    * @warning This pointer is only guaranteed to be valid
    * for the duration of the same \c retro_run iteration
    * \ref GET_CURRENT_SOFTWARE_FRAMEBUFFER "that requested the framebuffer".
    * Reuse of this pointer is undefined.
    */
   void *data;

   /**
    * The width of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other width.
    */
   unsigned width;

   /**
    * The height of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other height.
    */
   unsigned height;

   /**
    * The distance between the start of one scanline and the beginning of the next, in bytes.
    * In practice this is usually equal to \c width times the pixel size,
    * but that's not guaranteed.
    * Sometimes called the "stride".
    *
    * @setby{frontend}
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined to try to render \c data with any other pitch.
    */
   size_t pitch;

   /**
    * The pixel format of the returned framebuffer.
    * May be different than the format specified by the core in \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT,
    * e.g. due to conversions.
    * Set by the frontend.
    *
    * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
    */
   enum retro_pixel_format format;

   /**
    * One or more \ref RETRO_MEMORY_ACCESS "memory access flags"
    * that specify how the core will access the memory in \c data.
    *
    * @setby{core}
    */
   unsigned access_flags;

   /**
    * Zero or more \ref RETRO_MEMORY_TYPE "memory type flags"
    * that describe how the framebuffer's memory has been mapped.
    *
    * @setby{frontend}
    */
   unsigned memory_flags;
};

/** @} */

/** @defgroup SET_FASTFORWARDING_OVERRIDE Fast-Forward Override
 * @{
 */

/**
 * Parameters that govern when and how the core takes control
 * of fast-forwarding mode.
 */
struct retro_fastforwarding_override
{
   /**
    * The factor by which the core will be sped up
    * when \c fastforward is \c true.
    * This value is used as follows:
    *
    * @li A value greater than 1.0 will run the core at
    *     the specified multiple of normal speed.
    *     For example, a value of 5.0
    *     combined with a normal target rate of 60 FPS
    *     will result in a target rate of 300 FPS.
    *     The actual rate may be lower if the host's hardware can't keep up.
    * @li A value of 1.0 will run the core at normal speed.
    * @li A value between 0.0 (inclusive) and 1.0 (exclusive)
    *     will run the core as fast as the host system can manage.
    * @li A negative value will let the frontend choose a factor.
    * @li An infinite value or \c NaN results in undefined behavior.
    *
    * @attention Setting this value to less than 1.0 will \em not
    * slow down the core.
    */
   float ratio;

   /**
    * If \c true, the frontend should activate fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool fastforward;

   /**
    * If \c true, the frontend should display an on-screen notification or icon
    * while \c fastforward is \c true (where supported).
    * Otherwise, the frontend should not display any such notification.
    */
   bool notification;

   /**
    * If \c true, the core has exclusive control
    * over enabling and disabling fast-forwarding
    * via the \c fastforward field.
    * The frontend will not be able to start or stop fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool inhibit_toggle;
};

/** @} */

/**
 * During normal operation.
 *
 * @note Rate will be equal to the core's internal FPS.
 */
#define RETRO_THROTTLE_NONE              0

/**
 * While paused or stepping single frames.
 *
 * @note Rate will be 0.
 */
#define RETRO_THROTTLE_FRAME_STEPPING    1

/**
 * During fast forwarding.
 *
 * @note Rate will be 0 if not specifically limited to a maximum speed.
 */
#define RETRO_THROTTLE_FAST_FORWARD      2

/**
 * During slow motion.
 *
 * @note Rate will be less than the core's internal FPS.
 */
#define RETRO_THROTTLE_SLOW_MOTION       3

/**
 * While rewinding recorded save states.
 *
 * @note Rate can vary depending on the rewind speed or be 0 if the frontend
 * is not aiming for a specific rate.
 */
#define RETRO_THROTTLE_REWINDING         4

/**
 * While vsync is active in the video driver, and the target refresh rate is lower than the core's internal FPS.
 *
 * @note Rate is the target refresh rate.
 */
#define RETRO_THROTTLE_VSYNC             5

/**
 * When the frontend does not throttle in any way.
 *
 * @note Rate will be 0. An example could be if no vsync or audio output is active.
 */
#define RETRO_THROTTLE_UNBLOCKED         6

/**
 * Details about the actual rate an implementation is calling \c retro_run() at.
 *
 * @see RETRO_ENVIRONMENT_GET_THROTTLE_STATE
 */
struct retro_throttle_state
{
   /**
    * The current throttling mode.
    *
    * @note Should be one of the \c RETRO_THROTTLE_* values.
    * @see RETRO_THROTTLE_NONE
    * @see RETRO_THROTTLE_FRAME_STEPPING
    * @see RETRO_THROTTLE_FAST_FORWARD
    * @see RETRO_THROTTLE_SLOW_MOTION
    * @see RETRO_THROTTLE_REWINDING
    * @see RETRO_THROTTLE_VSYNC
    * @see RETRO_THROTTLE_UNBLOCKED
    */
   unsigned mode;

   /**
    * How many times per second the frontend aims to call retro_run.
    *
    * @note Depending on the mode, it can be 0 if there is no known fixed rate.
    * This won't be accurate if the total processing time of the core and
    * the frontend is longer than what is available for one frame.
    */
   float rate;
};

/** @defgroup GET_MICROPHONE_INTERFACE Microphone Interface
 * @{
 */

/**
 * Opaque handle to a microphone that's been opened for use.
 * The underlying object is accessed or created with \c retro_microphone_interface_t.
 */
typedef struct retro_microphone retro_microphone_t;

/**
 * Parameters for configuring a microphone.
 * Some of these might not be honored,
 * depending on the available hardware and driver configuration.
 */
typedef struct retro_microphone_params
{
   /**
    * The desired sample rate of the microphone's input, in Hz.
    * The microphone's input will be resampled,
    * so cores can ask for whichever frequency they need.
    *
    * If zero, some reasonable default will be provided by the frontend
    * (usually from its config file).
    *
    * @see retro_get_mic_rate_t
    */
   unsigned rate;
} retro_microphone_params_t;

/**
 * @copydoc retro_microphone_interface::open_mic
 */
typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::close_mic
 */
typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::get_params
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::set_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);

/**
 * @copydoc retro_microphone_interface::get_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::read_mic
 */
typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);

/**
 * The current version of the microphone interface.
 * Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t
 * receive new fields.
 *
 * Frontends using cores built against older mic interface versions
 * should not access fields introduced in newer versions.
 */
#define RETRO_MICROPHONE_INTERFACE_VERSION 1

/**
 * An interface for querying the microphone and accessing data read from it.
 *
 * @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE
 */
struct retro_microphone_interface
{
   /**
    * The version of this microphone interface.
    * Set by the core to request a particular version,
    * and set by the frontend to indicate the returned version.
    * 0 indicates that the interface is invalid or uninitialized.
    */
   unsigned interface_version;

   /**
    * Initializes a new microphone.
    * Assuming that microphone support is enabled and provided by the frontend,
    * cores may call this function whenever necessary.
    * A microphone could be opened throughout a core's lifetime,
    * or it could wait until a microphone is plugged in to the emulated device.
    *
    * The returned handle will be valid until it's freed,
    * even if the audio driver is reinitialized.
    *
    * This function is not guaranteed to be thread-safe.
    *
    * @param[in] args Parameters used to create the microphone.
    * May be \c NULL, in which case the default value of each parameter will be used.
    *
    * @returns Pointer to the newly-opened microphone,
    * or \c NULL if one couldn't be opened.
    * This likely means that no microphone is plugged in and recognized,
    * or the maximum number of supported microphones has been reached.
    *
    * @note Microphones are \em inactive by default;
    * to begin capturing audio, call \c set_mic_state.
    * @see retro_microphone_params_t
    */
   retro_open_mic_t open_mic;

   /**
    * Closes a microphone that was initialized with \c open_mic.
    * Calling this function will stop all microphone activity
    * and free up the resources that it allocated.
    * Afterwards, the handle is invalid and must not be used.
    *
    * A frontend may close opened microphones when unloading content,
    * but this behavior is not guaranteed.
    * Cores should close their microphones when exiting, just to be safe.
    *
    * @param microphone Pointer to the microphone that was allocated by \c open_mic.
    * If \c NULL, this function does nothing.
    *
    * @note The handle might be reused if another microphone is opened later.
    */
   retro_close_mic_t close_mic;

   /**
    * Returns the configured parameters of this microphone.
    * These may differ from what was requested depending on
    * the driver and device configuration.
    *
    * Cores should check these values before they start fetching samples.
    *
    * Will not change after the mic was opened.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose parameters will be retrieved.
    * @param[out] params The parameters object that the
    * microphone's parameters will be copied to.
    *
    * @return \c true if the parameters were retrieved,
    * \c false if there was an error.
    */
   retro_get_mic_params_t get_params;

   /**
    * Enables or disables the given microphone.
    * Microphones are disabled by default
    * and must be explicitly enabled before they can be used.
    * Disabled microphones will not process incoming audio samples,
    * and will therefore have minimal impact on overall performance.
    * Cores may enable microphones throughout their lifetime,
    * or only for periods where they're needed.
    *
    * Cores that accept microphone input should be able to operate without it;
    * we suggest substituting silence in this case.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be adjusted.
    * This will have been provided by \c open_mic.
    * @param state \c true if the microphone should receive audio input,
    * \c false if it should be idle.
    * @returns \c true if the microphone's state was successfully set,
    * \c false if \c microphone is invalid
    * or if there was an error.
    */
   retro_set_mic_state_t set_mic_state;

   /**
    * Queries the active state of a microphone at the given index.
    * Will return whether the microphone is enabled,
    * even if the driver is paused.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be queried.
    * @return \c true if the provided \c microphone is valid and active,
    * \c false if not or if there was an error.
    */
   retro_get_mic_state_t get_mic_state;

   /**
    * Retrieves the input processed by the microphone since the last call.
    * \em Must be called every frame unless \c microphone is disabled,
    * similar to how \c retro_audio_sample_batch_t works.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose recent input will be retrieved.
    * @param[out] samples The buffer that will be used to store the microphone's data.
    * Microphone input is in mono (i.e. one number per sample).
    * Should be large enough to accommodate the expected number of samples per frame;
    * for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.
    * @param[in] num_samples The size of the data buffer in samples (\em not bytes).
    * Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here.
    *
    * @return The number of samples that were copied into \c samples.
    * If \c microphone is pending driver initialization,
    * this function will copy silence of the requested length into \c samples.
    *
    * Will return -1 if the microphone is disabled,
    * the audio driver is paused,
    * or there was an error.
    */
   retro_read_mic_t read_mic;
};

/** @} */

/** @defgroup GET_DEVICE_POWER Device Power
 * @{
 */

/**
 * Describes how a device is being powered.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
enum retro_power_state
{
   /**
    * Indicates that the frontend cannot report its power state at this time,
    * most likely due to a lack of support.
    *
    * \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value;
    * instead, the environment callback will return \c false.
    */
   RETRO_POWERSTATE_UNKNOWN = 0,

   /**
    * Indicates that the device is running on its battery.
    * Usually applies to portable devices such as handhelds, laptops, and smartphones.
    */
   RETRO_POWERSTATE_DISCHARGING,

   /**
    * Indicates that the device's battery is currently charging.
    */
   RETRO_POWERSTATE_CHARGING,

   /**
    * Indicates that the device is connected to a power source
    * and that its battery has finished charging.
    */
   RETRO_POWERSTATE_CHARGED,

   /**
    * Indicates that the device is connected to a power source
    * and that it does not have a battery.
    * This usually suggests a desktop computer or a non-portable game console.
    */
   RETRO_POWERSTATE_PLUGGED_IN
};

/**
 * Indicates that an estimate is not available for the battery level or time remaining,
 * even if the actual power state is known.
 */
#define RETRO_POWERSTATE_NO_ESTIMATE (-1)

/**
 * Describes the power state of the device running the frontend.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
struct retro_device_power
{
   /**
    * The current state of the frontend's power usage.
    */
   enum retro_power_state state;

   /**
    * A rough estimate of the amount of time remaining (in seconds)
    * before the device powers off.
    * This value depends on a variety of factors,
    * so it is not guaranteed to be accurate.
    *
    * Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING.
    * May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate.
    */
   int seconds;

   /**
    * The approximate percentage of battery charge,
    * ranging from 0 to 100 (inclusive).
    * The device may power off before this reaches 0.
    *
    * The user might have configured their device
    * to stop charging before the battery is full,
    * so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state.
    */
   int8_t percent;
};

/** @} */

/**
 * @defgroup Callbacks
 * @{
 */

/**
 * Environment callback to give implementations a way of performing uncommon tasks.
 *
 * @note Extensible.
 *
 * @param cmd The command to run.
 * @param data A pointer to the data associated with the command.
 *
 * @return Varies by callback,
 * but will always return \c false if the command is not recognized.
 *
 * @see RETRO_ENVIRONMENT_SET_ROTATION
 * @see retro_set_environment()
 */
typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);

/**
 * Render a frame.
 *
 * @note For performance reasons, it is highly recommended to have a frame
 * that is packed in memory, i.e. pitch == width * byte_per_pixel.
 * Certain graphic APIs, such as OpenGL ES, do not like textures
 * that are not packed in memory.
 *
 * @param data A pointer to the frame buffer data with a pixel format of 15-bit \c 0RGB1555 native endian, unless changed with \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT.
 * @param width The width of the frame buffer, in pixels.
 * @param height The height frame buffer, in pixels.
 * @param pitch The width of the frame buffer, in bytes.
 *
 * @see retro_set_video_refresh()
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 * @see retro_pixel_format
 */
typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,
      unsigned height, size_t pitch);

/**
 * Renders a single audio frame. Should only be used if implementation generates a single sample at a time.
 *
 * @param left The left audio sample represented as a signed 16-bit native endian.
 * @param right The right audio sample represented as a signed 16-bit native endian.
 *
 * @see retro_set_audio_sample()
 * @see retro_set_audio_sample_batch()
 */
typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);

/**
 * Renders multiple audio frames in one go.
 *
 * @note Only one of the audio callbacks must ever be used.
 *
 * @param data A pointer to the audio sample data pairs to render.
 * @param frames The number of frames that are represented in the data. One frame
 *     is defined as a sample of left and right channels, interleaved.
 *     For example: <tt>int16_t buf[4] = { l, r, l, r };</tt> would be 2 frames.
 *
 * @return The number of frames that were processed.
 *
 * @see retro_set_audio_sample_batch()
 * @see retro_set_audio_sample()
 */
typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,
      size_t frames);

/**
 * Polls input.
 *
 * @see retro_set_input_poll()
 */
typedef void (RETRO_CALLCONV *retro_input_poll_t)(void);

/**
 * Queries for input for player 'port'.
 *
 * @param port Which player 'port' to query.
 * @param device Which device to query for. Will be masked with \c RETRO_DEVICE_MASK.
 * @param index The input index to retrieve.
 * The exact semantics depend on the device type given in \c device.
 * @param id The ID of which value to query, like \c RETRO_DEVICE_ID_JOYPAD_B.
 * @returns Depends on the provided arguments,
 * but will return 0 if their values are unsupported
 * by the frontend or the backing physical device.
 * @note Specialization of devices such as \c RETRO_DEVICE_JOYPAD_MULTITAP that
 * have been set with \c retro_set_controller_port_device() will still use the
 * higher level \c RETRO_DEVICE_JOYPAD to request input.
 *
 * @see retro_set_input_state()
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 */
typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,
      unsigned index, unsigned id);

/**
 * Sets the environment callback.
 *
 * @param cb The function which is used when making environment calls.
 *
 * @note Guaranteed to be called before \c retro_init().
 *
 * @see RETRO_ENVIRONMENT
 */
RETRO_API void retro_set_environment(retro_environment_t cb);

/**
 * Sets the video refresh callback.
 *
 * @param cb The function which is used when rendering a frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_video_refresh(retro_video_refresh_t cb);

/**
 * Sets the audio sample callback.
 *
 * @param cb The function which is used when rendering a single audio frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample(retro_audio_sample_t cb);

/**
 * Sets the audio sample batch callback.
 *
 * @param cb The function which is used when rendering multiple audio frames in one go.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);

/**
 * Sets the input poll callback.
 *
 * @param cb The function which is used to poll the active input.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_poll(retro_input_poll_t cb);

/**
 * Sets the input state callback.
 *
 * @param cb The function which is used to query the input state.
 *
 *@note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_state(retro_input_state_t cb);

/**
 * @}
 */

/**
 * Called by the frontend when initializing a libretro core.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * <ul>
 * <li>Do not assume that the core was loaded by the operating system
 * for the first time within this call.
 * It may have been statically linked or retained from a previous session.
 * Consequently, cores must not rely on global variables being initialized
 * to their default values before this function is called;
 * this also goes for object constructors in C++.
 * <li>Although C++ requires that constructors be called for global variables,
 * it does not require that their destructors be called
 * if stored within a dynamic library's global scope.
 * <li>If the core is statically linked to the frontend,
 * global variables may be initialized when the frontend itself is initially executed.
 * </ul>
 * @see retro_deinit
 */
RETRO_API void retro_init(void);

/**
 * Called by the frontend when deinitializing a libretro core.
 * The core must release all of its allocated resources before this function returns.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * <ul>
 * <li>Do not assume that the operating system will unload the core after this function returns,
 * as the core may be linked statically or retained in memory.
 * Cores should use this function to clean up all allocated resources
 * and reset all global variables to their default states.
 * <li>Do not assume that this core won't be loaded again after this function returns.
 * It may be kept in memory by the frontend for later use,
 * or it may be statically linked.
 * Therefore, all global variables should be reset to their default states within this function.
 * <li>C++ does not require that destructors be called
 * for variables within a dynamic library's global scope.
 * Therefore, global objects that own dynamically-managed resources
 * (such as \c std::string or <tt>std::vector</tt>)
 * should be kept behind pointers that are explicitly deallocated within this function.
 * </ul>
 * @see retro_init
 */
RETRO_API void retro_deinit(void);

/**
 * Retrieves which version of the libretro API is being used.
 *
 * @note This is used to validate ABI compatibility when the API is revised.
 *
 * @return Must return \c RETRO_API_VERSION.
 *
 * @see RETRO_API_VERSION
 */
RETRO_API unsigned retro_api_version(void);

/**
 * Gets statically known system info.
 *
 * @note Can be called at any time, even before retro_init().
 *
 * @param info A pointer to a \c retro_system_info where the info is to be loaded into. This must be statically allocated.
 */
RETRO_API void retro_get_system_info(struct retro_system_info *info);

/**
 * Gets information about system audio/video timings and geometry.
 *
 * @note Can be called only after \c retro_load_game() has successfully completed.
 *
 * @note The implementation of this function might not initialize every variable
 * if needed. For example, \c geom.aspect_ratio might not be initialized if
 * the core doesn't desire a particular aspect ratio.
 *
 * @param info A pointer to a \c retro_system_av_info where the audio/video information should be loaded into.
 *
 * @see retro_system_av_info
 */
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);

/**
 * Sets device to be used for player 'port'.
 *
 * By default, \c RETRO_DEVICE_JOYPAD is assumed to be plugged into all
 * available ports.
 *
 * @note Setting a particular device type is not a guarantee that libretro cores
 * will only poll input based on that particular device type. It is only a
 * hint to the libretro core when a core cannot automatically detect the
 * appropriate input device type on its own. It is also relevant when a
 * core can change its behavior depending on device type.
 *
 * @note As part of the core's implementation of retro_set_controller_port_device,
 * the core should call \c RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
 * frontend if the descriptions for any controls have changed as a
 * result of changing the device type.
 *
 * @param port Which port to set the device for, usually indicates the player number.
 * @param device Which device the given port is using. By default, \c RETRO_DEVICE_JOYPAD is assumed for all ports.
 *
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);

/**
 * Resets the currently-loaded game.
 * Cores should treat this as a soft reset (i.e. an emulated reset button) if possible,
 * but hard resets are acceptable.
 */
RETRO_API void retro_reset(void);

/**
 * Runs the game for one video frame.
 *
 * During \c retro_run(), the \c retro_input_poll_t callback must be called at least once.
 *
 * @note If a frame is not rendered for reasons where a game "dropped" a frame,
 * this still counts as a frame, and \c retro_run() should explicitly dupe
 * a frame if \c RETRO_ENVIRONMENT_GET_CAN_DUPE returns true. In this case,
 * the video callback can take a NULL argument for data.
 *
 * @see retro_input_poll_t
 */
RETRO_API void retro_run(void);

/**
 * Returns the amount of data the implementation requires to serialize internal state (save states).
 *
 * @note Between calls to \c retro_load_game() and \c retro_unload_game(), the
 * returned size is never allowed to be larger than a previous returned
 * value, to ensure that the frontend can allocate a save state buffer once.
 *
 * @return The amount of data the implementation requires to serialize the internal state.
 *
 * @see retro_serialize()
 */
RETRO_API size_t retro_serialize_size(void);

/**
 * Serializes the internal state.
 *
 * @param data A pointer to where the serialized data should be saved to.
 * @param size The size of the memory.
 *
 * @return If failed, or size is lower than \c retro_serialize_size(), it
 * should return false. On success, it will return true.
 *
 * @see retro_serialize_size()
 * @see retro_unserialize()
 */
RETRO_API bool retro_serialize(void *data, size_t len);

/**
 * Unserialize the given state data, and load it into the internal state.
 *
 * @return Returns true if loading the state was successful, false otherwise.
 *
 * @see retro_serialize()
 */
RETRO_API bool retro_unserialize(const void *data, size_t len);

/**
 * Reset all the active cheats to their default disabled state.
 *
 * @see retro_cheat_set()
 */
RETRO_API void retro_cheat_reset(void);

/**
 * Enable or disable a cheat.
 *
 * @param index The index of the cheat to act upon.
 * @param enabled Whether to enable or disable the cheat.
 * @param code A string of the code used for the cheat.
 *
 * @see retro_cheat_reset()
 */
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);

/**
 * Loads a game.
 *
 * @param game A pointer to a \c retro_game_info detailing information about the game to load.
 * May be \c NULL if the core is loaded without content.
 *
 * @return Will return true when the game was loaded successfully, or false otherwise.
 *
 * @see retro_game_info
 * @see RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME
 */
RETRO_API bool retro_load_game(const struct retro_game_info *game);

/**
 * Called when the frontend has loaded one or more "special" content files,
 * typically through subsystems.
 *
 * @note Only necessary for cores that support subsystems.
 * Others may return \c false or delegate to <tt>retro_load_game</tt>.
 *
 * @param game_type The type of game to load,
 * as determined by \c retro_subsystem_info.
 * @param info A pointer to an array of \c retro_game_info objects
 * providing information about the loaded content.
 * @param num_info The number of \c retro_game_info objects passed into the info parameter.
 * @return \c true if loading is successful, false otherwise.
 * If the core returns \c false,
 * the frontend should abort the core
 * and return to its main menu (if applicable).
 *
 * @see RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_load_game()
 * @see retro_subsystem_info
 */
RETRO_API bool retro_load_game_special(
  unsigned game_type,
  const struct retro_game_info *info, size_t num_info
);

/**
 * Unloads the currently loaded game.
 *
 * @note This is called before \c retro_deinit(void).
 *
 * @see retro_load_game()
 * @see retro_deinit()
 */
RETRO_API void retro_unload_game(void);

/**
 * Gets the region of the actively loaded content as either \c RETRO_REGION_NTSC or \c RETRO_REGION_PAL.
 * @note This refers to the region of the content's intended television standard,
 * not necessarily the region of the content's origin.
 * For emulated consoles that don't use either standard
 * (e.g. handhelds or post-HD platforms),
 * the core should return \c RETRO_REGION_NTSC.
 * @return The region of the actively loaded content.
 *
 * @see RETRO_REGION_NTSC
 * @see RETRO_REGION_PAL
 */
RETRO_API unsigned retro_get_region(void);

/**
 * Get a region of memory.
 *
 * @param id The ID for the memory block that's desired to retrieve. Can be \c RETRO_MEMORY_SAVE_RAM, \c RETRO_MEMORY_RTC, \c RETRO_MEMORY_SYSTEM_RAM, or \c RETRO_MEMORY_VIDEO_RAM.
 *
 * @return A pointer to the desired region of memory, or NULL when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API void *retro_get_memory_data(unsigned id);

/**
 * Gets the size of the given region of memory.
 *
 * @param id The ID for the memory block to check the size of. Can be RETRO_MEMORY_SAVE_RAM, RETRO_MEMORY_RTC, RETRO_MEMORY_SYSTEM_RAM, or RETRO_MEMORY_VIDEO_RAM.
 *
 * @return The size of the region in memory, or 0 when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API size_t retro_get_memory_size(unsigned id);

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/include/libretro_vulkan.h

/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_vulkan.h)
 * ---------------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_VULKAN_H__
#define LIBRETRO_VULKAN_H__

#include <libretro.h>
#include <vulkan/vulkan.h>

#define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 5
#define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 2

struct retro_vulkan_image
{
   VkImageView image_view;
   VkImageLayout image_layout;
   VkImageViewCreateInfo create_info;
};

typedef void (*retro_vulkan_set_image_t)(void *handle,
      const struct retro_vulkan_image *image,
      uint32_t num_semaphores,
      const VkSemaphore *semaphores,
      uint32_t src_queue_family);

typedef uint32_t (*retro_vulkan_get_sync_index_t)(void *handle);
typedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void *handle);
typedef void (*retro_vulkan_set_command_buffers_t)(void *handle,
      uint32_t num_cmd,
      const VkCommandBuffer *cmd);
typedef void (*retro_vulkan_wait_sync_index_t)(void *handle);
typedef void (*retro_vulkan_lock_queue_t)(void *handle);
typedef void (*retro_vulkan_unlock_queue_t)(void *handle);
typedef void (*retro_vulkan_set_signal_semaphore_t)(void *handle, VkSemaphore semaphore);

typedef const VkApplicationInfo *(*retro_vulkan_get_application_info_t)(void);

struct retro_vulkan_context
{
   VkPhysicalDevice gpu;
   VkDevice device;
   VkQueue queue;
   uint32_t queue_family_index;
   VkQueue presentation_queue;
   uint32_t presentation_queue_family_index;
};

/* This is only used in v1 of the negotiation interface.
 * It is deprecated since it cannot express PDF2 features or optional extensions. */
typedef bool (*retro_vulkan_create_device_t)(
      struct retro_vulkan_context *context,
      VkInstance instance,
      VkPhysicalDevice gpu,
      VkSurfaceKHR surface,
      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
      const char **required_device_extensions,
      unsigned num_required_device_extensions,
      const char **required_device_layers,
      unsigned num_required_device_layers,
      const VkPhysicalDeviceFeatures *required_features);

typedef void (*retro_vulkan_destroy_device_t)(void);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef VkInstance (*retro_vulkan_create_instance_wrapper_t)(
      void *opaque, const VkInstanceCreateInfo *create_info);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef VkInstance (*retro_vulkan_create_instance_t)(
      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
      const VkApplicationInfo *app,
      retro_vulkan_create_instance_wrapper_t create_instance_wrapper,
      void *opaque);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef VkDevice (*retro_vulkan_create_device_wrapper_t)(
      VkPhysicalDevice gpu, void *opaque,
      const VkDeviceCreateInfo *create_info);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef bool (*retro_vulkan_create_device2_t)(
      struct retro_vulkan_context *context,
      VkInstance instance,
      VkPhysicalDevice gpu,
      VkSurfaceKHR surface,
      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
      retro_vulkan_create_device_wrapper_t create_device_wrapper,
      void *opaque);

/* Note on thread safety:
 * The Vulkan API is heavily designed around multi-threading, and
 * the libretro interface for it should also be threading friendly.
 * A core should be able to build command buffers and submit
 * command buffers to the GPU from any thread.
 */

struct retro_hw_render_context_negotiation_interface_vulkan
{
   /* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN. */
   enum retro_hw_render_context_negotiation_interface_type interface_type;
   /* Usually set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION,
    * but can be lower depending on GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT. */
   unsigned interface_version;

   /* If non-NULL, returns a VkApplicationInfo struct that the frontend can use instead of
    * its "default" application info.
    * VkApplicationInfo::apiVersion also controls the target core Vulkan version for instance level functionality.
    * Lifetime of the returned pointer must remain until the retro_vulkan_context is initialized.
    *
    * NOTE: For optimal compatibility with e.g. Android which is very slow to update its loader,
    * a core version of 1.1 should be requested. Features beyond that can be requested with extensions.
    * Vulkan 1.0 is only appropriate for legacy cores, but is still supported.
    * A frontend is free to bump the instance creation apiVersion as necessary if the frontend requires more advanced core features.
    *
    * v2: This function must not be NULL, and must not return NULL.
    * v1: It was not clearly defined if this function could return NULL.
    *     Frontends should be defensive and provide a default VkApplicationInfo
    *     if this function returns NULL or if this function is NULL.
    */
   retro_vulkan_get_application_info_t get_application_info;

   /* If non-NULL, the libretro core will choose one or more physical devices,
    * create one or more logical devices and create one or more queues.
    * The core must prepare a designated PhysicalDevice, Device, Queue and queue family index
    * which the frontend will use for its internal operation.
    *
    * If gpu is not VK_NULL_HANDLE, the physical device provided to the frontend must be this PhysicalDevice if the call succeeds.
    * The core is still free to use other physical devices for other purposes that are private to the core.
    *
    * The frontend will request certain extensions and layers for a device which is created.
    * The core must ensure that the queue and queue_family_index support GRAPHICS and COMPUTE.
    *
    * If surface is not VK_NULL_HANDLE, the core must consider presentation when creating the queues.
    * If presentation to "surface" is supported on the queue, presentation_queue must be equal to queue.
    * If not, a second queue must be provided in presentation_queue and presentation_queue_index.
    * If surface is not VK_NULL_HANDLE, the instance from frontend will have been created with supported for
    * VK_KHR_surface extension.
    *
    * The core is free to set its own queue priorities.
    * Device provided to frontend is owned by the frontend, but any additional device resources must be freed by core
    * in destroy_device callback.
    *
    * If this function returns true, a PhysicalDevice, Device and Queues are initialized.
    * If false, none of the above have been initialized and the frontend will attempt
    * to fallback to "default" device creation, as if this function was never called.
    */
   retro_vulkan_create_device_t create_device;

   /* If non-NULL, this callback is called similar to context_destroy for HW_RENDER_INTERFACE.
    * However, it will be called even if context_reset was not called.
    * This can happen if the context never succeeds in being created.
    * destroy_device will always be called before the VkInstance
    * of the frontend is destroyed if create_device was called successfully so that the core has a chance of
    * tearing down its own device resources.
    *
    * Only auxiliary resources should be freed here, i.e. resources which are not part of retro_vulkan_context.
    * v2: Auxiliary instance resources created during create_instance can also be freed here.
    */
   retro_vulkan_destroy_device_t destroy_device;

   /* v2 API: If interface_version is < 2, fields below must be ignored.
    * If the frontend does not support interface version 2, the v1 entry points will be used instead. */

   /* If non-NULL, this is called to create an instance, otherwise a VkInstance is created by the frontend.
    * v1 interface bug: The only way to enable instance features is through core versions signalled in VkApplicationInfo.
    * The frontend may request that certain extensions and layers
    * are enabled on the VkInstance. Application may add additional features.
    * If app is non-NULL, apiVersion controls the minimum core version required by the application.
    * Return a VkInstance or VK_NULL_HANDLE. The VkInstance is owned by the frontend.
    *
    * Rather than call vkCreateInstance directly, a core must call the CreateInstance wrapper provided with:
    * VkInstance instance = create_instance_wrapper(opaque, &create_info);
    * If the core wishes to create a private instance for whatever reason (relying on shared memory for example),
    * it may call vkCreateInstance directly. */
   retro_vulkan_create_instance_t create_instance;

   /* If non-NULL and frontend recognizes negotiation interface >= 2, create_device2 takes precedence over create_device.
    * Similar to create_device, but is extended to better understand new core versions and PDF2 feature enablement.
    * Requirements for create_device2 are the same as create_device unless a difference is mentioned.
    *
    * v2 consideration:
    * If the chosen gpu by frontend cannot be supported, a core must return false.
    *
    * NOTE: "Cannot be supported" is intentionally vaguely defined.
    * Refusing to run on an iGPU for a very intensive core with desktop GPU as a minimum spec may be in the gray area.
    * Not supporting optional features is not a good reason to reject a physical device, however.
    *
    * On device creation feature with explicit gpu, a frontend should fall back create_device2 with gpu == VK_NULL_HANDLE and let core
    * decide on a supported device if possible.
    *
    * A core must assume that the explicitly provided GPU is the only guaranteed attempt it has to create a device.
    * A fallback may not be attempted if there are particular reasons why only a specific physical device can work,
    * but these situations should be esoteric and rare in nature, e.g. a libretro frontend is implemented with external memory
    * and only LUID matching would work.
    * Cores and frontends should ensure "best effort" when negotiating like this and appropriate logging is encouraged.
    *
    * v1 note: In the v1 version of create_device, it was never expected that create_device would fail like this,
    * and frontends are not expected to attempt fall backs.
    *
    * Rather than call vkCreateDevice directly, a core must call the CreateDevice wrapper provided with:
    * VkDevice device = create_device_wrapper(gpu, opaque, &create_info);
    * If the core wishes to create a private device for whatever reason (relying on shared memory for example),
    * it may call vkCreateDevice directly.
    *
    * This allows the frontend to add additional extensions that it requires as well as adjust the PDF2 pNext as required.
    * It is also possible adjust the queue create infos in case the frontend desires to allocate some private queues.
    *
    * The get_instance_proc_addr provided in create_device2 must be the same as create_instance.
    *
    * NOTE: The frontend must not disable features requested by application.
    * NOTE: The frontend must not add any robustness features as some API behavior may change (VK_EXT_descriptor_buffer comes to mind).
    * I.e. robustBufferAccess and the like. (nullDescriptor from robustness2 is allowed to be enabled).
    */
   retro_vulkan_create_device2_t create_device2;
};

struct retro_hw_render_interface_vulkan
{
   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */
   enum retro_hw_render_interface_type interface_type;
   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */
   unsigned interface_version;

   /* Opaque handle to the Vulkan backend in the frontend
    * which must be passed along to all function pointers
    * in this interface.
    *
    * The rationale for including a handle here (which libretro v1
    * doesn't currently do in general) is:
    *
    * - Vulkan cores should be able to be freely threaded without lots of fuzz.
    *   This would break frontends which currently rely on TLS
    *   to deal with multiple cores loaded at the same time.
    * - Fixing this in general is TODO for an eventual libretro v2.
    */
   void *handle;

   /* The Vulkan instance the context is using. */
   VkInstance instance;
   /* The physical device used. */
   VkPhysicalDevice gpu;
   /* The logical device used. */
   VkDevice device;

   /* Allows a core to fetch all its needed symbols without having to link
    * against the loader itself. */
   PFN_vkGetDeviceProcAddr get_device_proc_addr;
   PFN_vkGetInstanceProcAddr get_instance_proc_addr;

   /* The queue the core must use to submit data.
    * This queue and index must remain constant throughout the lifetime
    * of the context.
    *
    * This queue will be the queue that supports graphics and compute
    * if the device supports compute.
    */
   VkQueue queue;
   unsigned queue_index;

   /* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID,
    * set which image to use for this frame.
    *
    * If num_semaphores is non-zero, the frontend will wait for the
    * semaphores provided to be signaled before using the results further
    * in the pipeline.
    *
    * Semaphores provided by a single call to set_image will only be
    * waited for once (waiting for a semaphore resets it).
    * E.g. set_image, video_refresh, and then another
    * video_refresh without set_image,
    * but same image will only wait for semaphores once.
    *
    * For this reason, ownership transfer will only occur if semaphores
    * are waited on for a particular frame in the frontend.
    *
    * Using semaphores is optional for synchronization purposes,
    * but if not using
    * semaphores, an image memory barrier in vkCmdPipelineBarrier
    * should be used in the graphics_queue.
    * Example:
    *
    * vkCmdPipelineBarrier(cmd,
    *    srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
    *    dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
    *    image_memory_barrier = {
    *       srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    *       dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
    *    });
    *
    * The use of pipeline barriers instead of semaphores is encouraged
    * as it is simpler and more fine-grained. A layout transition
    * must generally happen anyways which requires a
    * pipeline barrier.
    *
    * The image passed to set_image must have imageUsage flags set to at least
    * VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT.
    * The core will naturally want to use flags such as
    * VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or
    * VK_IMAGE_USAGE_TRANSFER_DST_BIT depending
    * on how the final image is created.
    *
    * The image must also have been created with MUTABLE_FORMAT bit set if
    * 8-bit formats are used, so that the frontend can reinterpret sRGB
    * formats as it sees fit.
    *
    * Images passed to set_image should be created with TILING_OPTIMAL.
    * The image layout should be transitioned to either
    * VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
    * The actual image layout used must be set in image_layout.
    *
    * The image must be a 2D texture which may or not be layered
    * and/or mipmapped.
    *
    * The image must be suitable for linear sampling.
    * While the image_view is typically the only field used,
    * the frontend may want to reinterpret the texture as sRGB vs.
    * non-sRGB for example so the VkImageViewCreateInfo used to
    * create the image view must also be passed in.
    *
    * The data in the pointer to the image struct will not be copied
    * as the pNext field in create_info cannot be reliably deep-copied.
    * The image pointer passed to set_image must be valid until
    * retro_video_refresh_t has returned.
    *
    * If frame duping is used when passing NULL to retro_video_refresh_t,
    * the frontend is free to either use the latest image passed to
    * set_image or reuse the older pointer passed to set_image the
    * frame RETRO_HW_FRAME_BUFFER_VALID was last used.
    *
    * Essentially, the lifetime of the pointer passed to
    * retro_video_refresh_t should be extended if frame duping is used
    * so that the frontend can reuse the older pointer.
    *
    * The image itself however, must not be touched by the core until
    * wait_sync_index has been completed later. The frontend may perform
    * layout transitions on the image, so even read-only access is not defined.
    * The exception to read-only rule is if GENERAL layout is used for the image.
    * In this case, the frontend is not allowed to perform any layout transitions,
    * so concurrent reads from core and frontend are allowed.
    *
    * If frame duping is used, or if set_command_buffers is used,
    * the frontend will not wait for any semaphores.
    *
    * The src_queue_family is used to specify which queue family
    * the image is currently owned by. If using multiple queue families
    * (e.g. async compute), the frontend will need to acquire ownership of the
    * image before rendering with it and release the image afterwards.
    *
    * If src_queue_family is equal to the queue family (queue_index),
    * no ownership transfer will occur.
    * Similarly, if src_queue_family is VK_QUEUE_FAMILY_IGNORED,
    * no ownership transfer will occur.
    *
    * The frontend will always release ownership back to src_queue_family.
    * Waiting for frontend to complete with wait_sync_index() ensures that
    * the frontend has released ownership back to the application.
    * Note that in Vulkan, transferring ownership is a two-part process.
    *
    * Example frame:
    *  - core releases ownership from src_queue_index to queue_index with VkImageMemoryBarrier.
    *  - core calls set_image with src_queue_index.
    *  - Frontend will acquire the image with src_queue_index -> queue_index as well, completing the ownership transfer.
    *  - Frontend renders the frame.
    *  - Frontend releases ownership with queue_index -> src_queue_index.
    *  - Next time image is used, core must acquire ownership from queue_index ...
    *
    * Since the frontend releases ownership, we cannot necessarily dupe the frame because
    * the core needs to make the roundtrip of ownership transfer.
    */
   retro_vulkan_set_image_t set_image;

   /* Get the current sync index for this frame which is obtained in
    * frontend by calling e.g. vkAcquireNextImageKHR before calling
    * retro_run().
    *
    * This index will correspond to which swapchain buffer is currently
    * the active one.
    *
    * Knowing this index is very useful for maintaining safe asynchronous CPU
    * and GPU operation without stalling.
    *
    * The common pattern for synchronization is to receive fences when
    * submitting command buffers to Vulkan (vkQueueSubmit) and add this fence
    * to a list of fences for frame number get_sync_index().
    *
    * Next time we receive the same get_sync_index(), we can wait for the
    * fences from before, which will usually return immediately as the
    * frontend will generally also avoid letting the GPU run ahead too much.
    *
    * After the fence has signaled, we know that the GPU has completed all
    * GPU work related to work submitted in the frame we last saw get_sync_index().
    *
    * This means we can safely reuse or free resources allocated in this frame.
    *
    * In theory, even if we wait for the fences correctly, it is not technically
    * safe to write to the image we earlier passed to the frontend since we're
    * not waiting for the frontend GPU jobs to complete.
    *
    * The frontend will guarantee that the appropriate pipeline barrier
    * in graphics_queue has been used such that
    * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot
    * start until the frontend is done with the image.
    */
   retro_vulkan_get_sync_index_t get_sync_index;

   /* Returns a bitmask of how many swapchain images we currently have
    * in the frontend.
    *
    * If bit #N is set in the return value, get_sync_index can return N.
    * Knowing this value is useful for preallocating per-frame management
    * structures ahead of time.
    *
    * While this value will typically remain constant throughout the
    * applications lifecycle, it may for example change if the frontend
    * suddenly changes fullscreen state and/or latency.
    *
    * If this value ever changes, it is safe to assume that the device
    * is completely idle and all synchronization objects can be deleted
    * right away as desired.
    */
   retro_vulkan_get_sync_index_mask_t get_sync_index_mask;

   /* Instead of submitting the command buffer to the queue first, the core
    * can pass along its command buffer to the frontend, and the frontend
    * will submit the command buffer together with the frontends command buffers.
    *
    * This has the advantage that the overhead of vkQueueSubmit can be
    * amortized into a single call. For this mode, semaphores in set_image
    * will be ignored, so vkCmdPipelineBarrier must be used to synchronize
    * the core and frontend.
    *
    * The command buffers in set_command_buffers are only executed once,
    * even if frame duping is used.
    *
    * If frame duping is used, set_image should be used for the frames
    * which should be duped instead.
    *
    * Command buffers passed to the frontend with set_command_buffers
    * must not actually be submitted to the GPU until retro_video_refresh_t
    * is called.
    *
    * The frontend must submit the command buffer before submitting any
    * other command buffers provided by set_command_buffers. */
   retro_vulkan_set_command_buffers_t set_command_buffers;

   /* Waits on CPU for device activity for the current sync index to complete.
    * This is useful since the core will not have a relevant fence to sync with
    * when the frontend is submitting the command buffers. */
   retro_vulkan_wait_sync_index_t wait_sync_index;

   /* If the core submits command buffers itself to any of the queues provided
    * in this interface, the core must lock and unlock the frontend from
    * racing on the VkQueue.
    *
    * Queue submission can happen on any thread.
    * Even if queue submission happens on the same thread as retro_run(),
    * the lock/unlock functions must still be called.
    *
    * NOTE: Queue submissions are heavy-weight. */
   retro_vulkan_lock_queue_t lock_queue;
   retro_vulkan_unlock_queue_t unlock_queue;

   /* Sets a semaphore which is signaled when the image in set_image can safely be reused.
    * The semaphore is consumed next call to retro_video_refresh_t.
    * The semaphore will be signalled even for duped frames.
    * The semaphore will be signalled only once, so set_signal_semaphore should be called every frame.
    * The semaphore may be VK_NULL_HANDLE, which disables semaphore signalling for next call to retro_video_refresh_t.
    *
    * This is mostly useful to support use cases where you're rendering to a single image that
    * is recycled in a ping-pong fashion with the frontend to save memory (but potentially less throughput).
    */
   retro_vulkan_set_signal_semaphore_t set_signal_semaphore;
};

#endif

./include/libretro-common/include/lists/dir_list.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dir_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_DIR_LIST_H
#define __LIBRETRO_SDK_DIR_LIST_H

#include <retro_common_api.h>
#include <boolean.h>

#include <lists/string_list.h>

RETRO_BEGIN_DECLS

/**
 * dir_list_append:
 * @list               : existing list to append to.
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing, appending to an existing list
 *
 * @return Returns true on success, otherwise false.
 **/
bool dir_list_append(struct string_list *list, const char *dir, const char *ext,
      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);

/**
 * dir_list_new:
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : include compressed files, even when not part of ext.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing.
 *
 * @return pointer to a directory listing of type 'struct string_list *' on success,
 * NULL in case of error. Has to be freed manually.
 **/
struct string_list *dir_list_new(const char *dir, const char *ext,
      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);

/**
 * dir_list_initialize:
 *
 * NOTE: @list must zero initialised before
 * calling this function, otherwise UB.
 **/
bool dir_list_initialize(struct string_list *list,
      const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive);

/**
 * dir_list_sort:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing.
 **/
void dir_list_sort(struct string_list *list, bool dir_first);

/**
 * dir_list_sort_ignore_ext:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing. File extensions are ignored.
 **/
void dir_list_sort_ignore_ext(struct string_list *list, bool dir_first);

/**
 * dir_list_free:
 * @list : pointer to the directory listing
 *
 * Frees a directory listing.
 **/
void dir_list_free(struct string_list *list);

bool dir_list_deinitialize(struct string_list *list);

RETRO_END_DECLS

#endif

./include/libretro-common/include/lists/file_list.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FILE_LIST_H__
#define __LIBRETRO_SDK_FILE_LIST_H__

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

#include <stddef.h>
#include <stdlib.h>

#include <boolean.h>

struct item_file
{
   void *userdata;
   void *actiondata;
   char *path;
   char *label;
   char *alt;
   size_t directory_ptr;
   size_t entry_idx;
   unsigned type;
};

typedef struct file_list
{
   struct item_file *list;

   size_t capacity;
   size_t size;
} file_list_t;

void *file_list_get_userdata_at_offset(const file_list_t *list,
      size_t index);

void *file_list_get_actiondata_at_offset(const file_list_t *list,
      size_t index);

/**
 * @brief frees the list
 *
 * NOTE: This function will also free() the entries actiondata
 * and userdata fields if they are non-null. If you store complex
 * or non-contiguous data there, make sure you free it's fields
 * before calling this function or you might get a memory leak.
 *
 * @param list List to be freed
 */
void file_list_free(file_list_t *list);

bool file_list_deinitialize(file_list_t *list);

/**
 * @brief makes the list big enough to contain at least nitems
 *
 * This function will not change the capacity if nitems is smaller
 * than the current capacity.
 *
 * @param list The list to open for input
 * @param nitems Number of items to reserve space for
 * @return whether or not the operation succeeded
 */
bool file_list_reserve(file_list_t *list, size_t nitems);

bool file_list_append(file_list_t *userdata, const char *path,
      const char *label, unsigned type, size_t current_directory_ptr,
      size_t entry_index);

bool file_list_insert(file_list_t *list,
      const char *path, const char *label,
      unsigned type, size_t directory_ptr,
      size_t entry_idx,
      size_t idx);

void file_list_pop(file_list_t *list, size_t *directory_ptr);

void file_list_clear(file_list_t *list);

void file_list_free_userdata(const file_list_t *list, size_t index);

void file_list_free_actiondata(const file_list_t *list, size_t idx);

void file_list_set_alt_at_offset(file_list_t *list, size_t index,
      const char *alt);

void file_list_sort_on_alt(file_list_t *list);

void file_list_sort_on_type(file_list_t *list);

bool file_list_search(const file_list_t *list, const char *needle,
      size_t *index);

RETRO_END_DECLS

#endif

./include/libretro-common/include/lists/linked_list.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (linked_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_LINKED_LIST_H
#define __LIBRETRO_SDK_LINKED_LIST_H

#include <retro_common_api.h>

#include <boolean.h>
#include <stddef.h>

RETRO_BEGIN_DECLS

/**
 * Represents a linked list. Contains any number of elements.
 */
typedef struct linked_list linked_list_t;

/**
 * Represents an iterator for iterating over a linked list. The iterator can
 * go through the linked list forwards or backwards.
 */
typedef struct linked_list_iterator linked_list_iterator_t;

/**
 * Creates a new linked list with no elements.
 *
 * @return New linked list
 */
linked_list_t *linked_list_new(void);

/**
 * @brief frees the memory used by the linked list
 *
 * Frees all of the memory used by this linked list. The values of all
 * remaining elements are freed using the "free_value" function. Does
 * nothing if "list" is NULL.
 *
 * @param list linked list to free
 * @param free_value function to use to free remaining values
 */
void linked_list_free(linked_list_t *list, void (*free_value)(void *value));

/**
 * @brief adds an element to the linked list
 *
 * Add a new element to the end of this linked list. Does nothing if
 * "list" is NULL.
 *
 * @param list list to add the element to
 * @param value new value to add to the linked list
 */
void linked_list_add(linked_list_t *list, void *value);

/**
 * @brief inserts a value into the linked list
 *
 * Inserts a value into the linked list at the specified index. Does
 * nothing if "list" is NULL.
 *
 * @param list list to insert the value into
 * @param index index where the value should be inserted at (can be equal to list size)
 * @param value value to insert into the linked list
 */
void linked_list_insert(linked_list_t *list, size_t index, void *value);

/**
 * @brief Get the value in the linked list at the provided index.
 *
 * Return the value vstored in the linked list at the provided index. Does
 * nothing if "list" is NULL.
 *
 * @param list list to get the value from
 * @param index index of the value to return
 * @return value in the list at the provided index
 */
void *linked_list_get(linked_list_t *list, size_t index);

/**
 * @brief Get the first value that is matched by the provided function
 *
 * Return the first value that the function matches. The matches function
 * parameters are value from the linked list and the provided state.
 *
 * @param list list to get the value from
 * @param matches function to test the values with
 * @param usrptr user data to pass to the matches function
 * @return first value that matches otherwise NULL
 */
void *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);

/**
 * @brief Get the last value that is matched by the provided function
 *
 * Return the last value that the function matches. The matches function
 * parameters are value from the linked list and the provided state.
 *
 * @param list list to get the value from
 * @param matches function to test the values with
 * @param usrptr user data to pass to the matches function
 * @return last value that matches otherwise NULL
 */
void *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);

/**
 * @brief Remove the element at the provided index
 *
 * Removes the element of the linked list at the provided index.
 *
 * @param list linked list to remove the element from
 * @param index index of the element to remove
 * @return value of the element that was removed, NULL if list is NULL or
 *         index is invalid
 */
void *linked_list_remove_at(linked_list_t *list, size_t index);

/**
 * @brief Remove the first element with the provided value
 *
 * Removes the first element with a value equal to the provided value.
 * Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the element from
 * @param value value of the element to remove
 * @return value if a matching element was removed
 */
void *linked_list_remove_first(linked_list_t *list, void *value);

/**
 * @brief Remove the last element with the provided value
 *
 * Removes the last element with a value equal to the provided value.
 * Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the element from
 * @param value value of the element to remove
 * @return value if a matching element was removed
 */
void *linked_list_remove_last(linked_list_t *list, void *value);

/**
 * @brief Remove all elements with the provided value
 *
 * Removes all elements with a value equal to the provided value.
 * Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the elements from
 * @param value value of the elements to remove
 * @return value if any matching element(s) where removed
 */
void *linked_list_remove_all(linked_list_t *list, void *value);

/**
 * @brief Remove the first matching element
 *
 * Removes the first matching element from the linked list. The "matches" function
 * is used to test for matching element values. Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the element from
 * @param matches function to use for testing element values for a match
 * @return value if a matching element was removed
 */
void *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value));

/**
 * @brief Remove the last matching element
 *
 * Removes the last matching element from the linked list. The "matches" function
 * is used to test for matching element values.
 *
 * @param list linked list to remove the element from
 * @param matches function to use for testing element value for a match
 * @return value if a matching element was removed
 */
void *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value));

/**
 * @brief Remove all matching elements
 *
 * Removes all matching elements from the linked list. The "matches" function
 * is used to test for matching element values. Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the elements from
 * @param matches function to use for testing element values for a match
 */
void linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value));

/**
 * @brief Replace the value of the element at the provided index
 *
 * Replaces the value of the element at the provided index. The linked list must
 * contain an element at the index.
 *
 * @param list linked list to replace the value in
 * @param index index of the element to replace the value of
 * @param value new value for the selected element
 * @return whether an element was updated
 */
bool linked_list_set_at(linked_list_t *list, size_t index, void *value);

/**
 * @brief Get the size of the linked list
 *
 * Returns the number of elements in the linked list.
 *
 * @param linked list to get the size of
 * @return number of elements in the linked list, 0 if linked list is NULL
 */
size_t linked_list_size(linked_list_t *list);

/**
 * @brief Get an iterator for the linked list
 *
 * Returns a new iterator for the linked list. Can be either a forward or backward
 * iterator.
 *
 * @param list linked list to iterate over
 * @param forward true for a forward iterator, false for backwards
 * @return new iterator for the linked list in the specified direction, NULL if
 *         "list" is NULL
 */
linked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward);

/**
 * @brief Move to the next element in the linked list
 *
 * Moves the iterator to the next element in the linked list. The direction is
 * specified when retrieving a new iterator.
 *
 * @param iterator iterator for the current element
 * @return iterator for the next element, NULL if iterator is NULL or "iterator"
 *         is at the last element
 */
linked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator);

/**
 * @brief Get the value of the element for the iterator
 *
 * Returns the value of the element that the iterator is at.
 *
 * @param iterator iterator for the current element
 * @return value of the element for the iterator
 */
void *linked_list_iterator_value(linked_list_iterator_t *iterator);

/**
 * @brief Remove the element that the iterator is at
 *
 * Removes the element that the iterator is at. The iterator is updated to the
 * next element.
 *
 * @param iterator iterator for the current element
 * @return updated iterator or NULL if the last element was removed
 */
linked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator);

/**
 * @brief Release the memory for the iterator
 *
 * Frees the memory for the provided iterator. Does nothing if "iterator" is NULL.
 *
 * @param iterator iterator to free
 */
void linked_list_iterator_free(linked_list_iterator_t *iterator);

/**
 * @brief Apply the provided function to all values in the linked list
 *
 * Apply the provided function to all values in the linked list. The values are applied
 * in the forward direction. Does nothing if "list" is NULL.
 *
 * @param list linked list to apply the function to
 * @param fn function to apply to all elements
 */
void linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value));

RETRO_END_DECLS

#endif

./include/libretro-common/include/lists/nested_list.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nested_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_NESTED_LIST_H__
#define __LIBRETRO_SDK_NESTED_LIST_H__

#include <retro_common_api.h>

#include <boolean.h>
#include <stdlib.h>
#include <stddef.h>

RETRO_BEGIN_DECLS

/* Prevent direct access to nested_list_* members */
typedef struct nested_list_item nested_list_item_t;
typedef struct nested_list nested_list_t;

/**************************************/
/* Initialisation / De-Initialisation */
/**************************************/

/**
 * nested_list_init:
 *
 * Creates a new empty nested list. Returned pointer
 * must be freed using nested_list_free.
 *
 * Returns: Valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_init(void);

/**
 * nested_list_free:
 *
 * @list : pointer to nested_list_t object
 *
 * Frees specified nested list.
 */
void nested_list_free(nested_list_t *list);

/***********/
/* Setters */
/***********/

/**
 * nested_list_add_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 * @value   : optional value (user data) associated with
 *            new list item. This is added to the last
 *            item specified by @address
 *
 * Appends a new item to the specified nested list.
 * If @delim is NULL, item is added to the top level
 * list (@list itself) with id equal to @address.
 * Otherwise, @address is split by @delim and each
 * id is added as new 'layer'. For example:
 *
 * > @address = "one:two:three", @delim = ":" will
 *   produce:
 *      top_level_list:one
 *                     `- "one" list:two
 *                                   `- "two" list:three
 *   where @value is assigned to the "two" list:three
 *   item.
 *
 * Returns: true if successful, otherwise false. Will
 * always return false if item specified by @address
 * already exists in the nested list.
 */
bool nested_list_add_item(nested_list_t *list,
      const char *address, const char *delim, const void *value);

/***********/
/* Getters */
/***********/

/**
 * nested_list_get_size:
 *
 * @list : pointer to nested_list_t object
 *
 * Fetches the current size (number of items) in
 * the specified list.
 *
 * Returns: list size.
 */
size_t nested_list_get_size(nested_list_t *list);

/**
 * nested_list_get_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 *
 * Searches for (and returns) the list item corresponding
 * to @address. If @delim is NULL, the top level list
 * (@list itself) is searched for an item with an id
 * equal to @address. Otherwise, @address is split by
 * @delim and each id is searched for in a subsequent
 * list level.
 *
 * Returns: valid nested_list_item_t pointer if item
 * is found, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item(nested_list_t *list,
      const char *address, const char *delim);

/**
 * nested_list_get_item_idx:
 *
 * @list : pointer to nested_list_t object
 * @idx  : item index
 *
 * Fetches the item corresponding to index @idx in
 * the top level list (@list itself) of the specified
 * nested list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * exists, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item_idx(nested_list_t *list,
      size_t idx);

/**
 * nested_list_item_get_parent:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the parent item of the specified nested
 * list item. If returned value is NULL, specified
 * nested list item belongs to a top level list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * has a parent, otherwise NULL.
 */
nested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item);

/**
 * nested_list_item_get_parent_list:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of which the
 * specified list item is a direct member.
 *
 * Returns: valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item);

/**
 * nested_list_item_get_children:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of child items
 * belonging to the specified list item.
 *
 * Returns: valid nested_list_t pointer if item has
 * children, otherwise NULL.
 */
nested_list_t *nested_list_item_get_children(nested_list_item_t *list_item);

/**
 * nested_list_item_get_id:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the id string of the specified list item,
 * as set by nested_list_add_item().
 *
 * Returns: item id if successful, otherwise NULL.
 */
const char *nested_list_item_get_id(nested_list_item_t *list_item);

/**
 * nested_list_item_get_address:
 *
 * @list_item : pointer to nested_list_item_t object
 * @delim     : delimiter to use when concatenating
 *              individual item ids into a an @address
 *              string
 * @address   : a delimited list of item identifiers,
 *              corresponding to item 'levels'
 * @len       : length of supplied @address char array
 
 * Fetches a compound @address string corresponding to
 * the specified item's 'position' in the top level
 * nested list of which it is a member. The resultant
 * @address may be used to find the item when calling
 * nested_list_get_item() on the top level nested list.
 *
 * Returns: true if successful, otherwise false.
 */
bool nested_list_item_get_address(nested_list_item_t *list_item,
      const char *delim, char *address, size_t len);

/**
 * nested_list_item_get_value:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the value (user data) associated with the
 * specified list item.
 *
 * Returns: pointer to user data if set, otherwise
 * NULL.
 */
const void *nested_list_item_get_value(nested_list_item_t *list_item);

RETRO_END_DECLS

#endif

./include/libretro-common/include/lists/string_list.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (string_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_STRING_LIST_H
#define __LIBRETRO_SDK_STRING_LIST_H

#include <retro_common_api.h>

#include <boolean.h>
#include <stdlib.h>
#include <stddef.h>

RETRO_BEGIN_DECLS

union string_list_elem_attr
{
   bool  b;
   int   i;
   void *p;
};

struct string_list_elem
{
   char *data;
   void *userdata;
   union string_list_elem_attr attr;
};

struct string_list
{
   struct string_list_elem *elems;
   size_t size;
   size_t cap;
};

/**
 * string_list_find_elem:
 * @list             : pointer to string list
 * @elem             : element to find inside the string list.
 *
 * Searches for an element (@elem) inside the string list.
 *
 * @return Number of elements found, otherwise 0.
 */
int string_list_find_elem(const struct string_list *list, const char *elem);

/**
 * string_list_find_elem_prefix:
 * @list             : pointer to string list
 * @prefix           : prefix to append to @elem
 * @elem             : element to find inside the string list.
 *
 * Searches for an element (@elem) inside the string list. Will
 * also search for the same element prefixed by @prefix.
 *
 * Returns: true (1) if element could be found, otherwise false (0).
 */
bool string_list_find_elem_prefix(const struct string_list *list,
      const char *prefix, const char *elem);

/**
 * string_split:
 * @str              : string to turn into a string list
 * @delim            : delimiter character to use for splitting the string.
 *
 * Creates a new string list based on string @str, delimited by @delim.
 *
 * Returns: new string list if successful, otherwise NULL.
 */
struct string_list *string_split(const char *str, const char *delim);

bool string_split_noalloc(struct string_list *list,
      const char *str, const char *delim);

bool string_list_deinitialize(struct string_list *list);

bool string_list_initialize(struct string_list *list);

/**
 * string_list_new:
 *
 * Creates a new string list. Has to be freed manually.
 *
 * @return New string list if successful, otherwise NULL.
 **/
struct string_list *string_list_new(void);

/**
 * string_list_append:
 * @list             : pointer to string list
 * @elem             : element to add to the string list
 * @attr             : attributes of new element.
 *
 * Appends a new element to the string list.

 * Hidden non-leaf function cost:
 * - Calls string_list_capacity()
 * - Calls strdup
 *
 * @return true if successful, otherwise false.
 **/
bool string_list_append(struct string_list *list, const char *elem,
      union string_list_elem_attr attr);

/**
 * string_list_free
 * @list             : pointer to string list object
 *
 * Frees a string list.
 **/
void string_list_free(struct string_list *list);

/**
 * string_list_join_concat:
 * @s                : buffer that @list will be joined to.
 * @len              : length of @s.
 * @list             : pointer to string list.
 * @delim            : delimiter character for @list.
 *
 * A string list will be joined/concatenated as a
 * string to @s, delimited by @delim.
 *
 * NOTE: @s must be NULL-terminated.
 *
 * Hidden non-leaf function cost:
 * - Calls strlen()
 * - Calls strlcpy x times in a loop
 **/
void string_list_join_concat(char *s, size_t len,
      const struct string_list *list, const char *sep);

/**
 * string_list_join_concat_special:
 * @s                : buffer that @list will be joined to.
 * @len              : length of @s.
 * @list             : pointer to string list.
 * @delim            : delimiter character for @list.
 *
 * Specialized version of string_list_join_concat
 * without the bounds check.
 *
 * A string list will be joined/concatenated as a
 * string to @s, delimited by @delim.
 **/
void string_list_join_concat_special(char *s, size_t len,
      const struct string_list *list, const char *delim);

/**
 * string_list_capacity:
 * @list             : pointer to string list
 * @cap              : new capacity for string list.
 *
 * Change maximum capacity of string list's size.
 *
 * @return true if successful, otherwise false.
 **/
bool string_list_capacity(struct string_list *list, size_t cap);

struct string_list *string_list_clone(const struct string_list *src);

RETRO_END_DECLS

#endif

./include/libretro-common/include/lrc_hash.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (lrc_hash.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_HASH_H
#define __LIBRETRO_SDK_HASH_H

#include <stdint.h>
#include <stddef.h>

#include <compat/msvc.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <retro_inline.h>

#include <retro_common_api.h>

#ifdef __APPLE__
#include <CommonCrypto/CommonDigest.h>
#endif

RETRO_BEGIN_DECLS

/**
 * sha256_hash:
 * @s                 : Output.
 * @in                : Input.
 * @len               : Size of @out.
 *
 * Hashes SHA256 and outputs a human readable string.
 **/
void sha256_hash(char *s, const uint8_t *in, size_t len);

int sha1_calculate(const char *path, char *result);

uint32_t djb2_calculate(const char *str);

#ifdef __APPLE__
typedef CC_MD5_CTX MD5_CTX;
#define MD5_Init CC_MD5_Init
#define MD5_Update CC_MD5_Update
#define MD5_Final CC_MD5_Final
#else

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;

typedef struct {
	MD5_u32plus lo, hi;
	MD5_u32plus a, b, c, d;
	unsigned char buffer[64];
	MD5_u32plus block[16];
} MD5_CTX;

/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * See md5.c for more information.
 */

void MD5_Init(MD5_CTX *ctx);
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
void MD5_Final(unsigned char *result, MD5_CTX *ctx);

#endif

RETRO_END_DECLS

#endif

./include/libretro-common/include/math/complex.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (complex.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_MATH_COMPLEX_H__
#define __LIBRETRO_SDK_MATH_COMPLEX_H__

#include <stdint.h>

#include <retro_inline.h>

typedef struct
{
   float real;
   float imag;
} fft_complex_t;

static INLINE fft_complex_t fft_complex_mul(fft_complex_t a,
      fft_complex_t b)
{
   fft_complex_t out;
   out.real = a.real * b.real - a.imag * b.imag;
   out.imag = a.imag * b.real + a.real * b.imag;

   return out;

}

static INLINE fft_complex_t fft_complex_add(fft_complex_t a,
      fft_complex_t b)
{
   fft_complex_t out;
   out.real = a.real + b.real;
   out.imag = a.imag + b.imag;

   return out;

}

static INLINE fft_complex_t fft_complex_sub(fft_complex_t a,
      fft_complex_t b)
{
   fft_complex_t out;
   out.real = a.real - b.real;
   out.imag = a.imag - b.imag;

   return out;

}

static INLINE fft_complex_t fft_complex_conj(fft_complex_t a)
{
   fft_complex_t out;
   out.real = a.real;
   out.imag = -a.imag;

   return out;
}

#endif

./include/libretro-common/include/math/float_minmax.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_minmax.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__
#define __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__

#include <stdint.h>
#include <math.h>

#include <retro_inline.h>
#include <retro_miscellaneous.h>
#include <retro_environment.h>

#ifdef __SSE2__
#include <emmintrin.h>
#include <mmintrin.h>
#endif

static INLINE float float_min(float a, float b)
{
#ifdef __SSE2__
   _mm_store_ss( &a, _mm_min_ss(_mm_set_ss(a),_mm_set_ss(b)) );
   return a;
#elif !defined(DJGPP) && (defined(__STDC_C99__) || defined(__STDC_C11__))
   return fminf(a, b);
#else
   return MIN(a, b);
#endif
}

static INLINE float float_max(float a, float b)
{
#ifdef __SSE2__
   _mm_store_ss( &a, _mm_max_ss(_mm_set_ss(a),_mm_set_ss(b)) );
   return a;
#elif !defined(DJGPP) && (defined(__STDC_C99__) || defined(__STDC_C11__))
   return fmaxf(a, b);
#else
   return MAX(a, b);
#endif
}

#endif

./include/libretro-common/include/math/fxp.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fxp.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_MATH_FXP_H__
#define __LIBRETRO_SDK_MATH_FXP_H__

#include <stdint.h>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#include <retro_inline.h>

static INLINE int64_t fx32_mul(const int32_t a, const int32_t b)
{
#ifdef _MSC_VER
   return __emul(a, b);
#else
   return ((int64_t)a) * ((int64_t)b);
#endif
}

static INLINE int32_t fx32_shiftdown(const int64_t a)
{
#ifdef _MSC_VER
	return (int32_t)__ll_rshift(a, 12);
#else
	return (int32_t)(a >> 12);
#endif
}

static INLINE int64_t fx32_shiftup(const int32_t a)
{
#ifdef _MSC_VER
	return __ll_lshift(a, 12);
#else
	return ((int64_t)a) << 12;
#endif
}

#endif

./include/libretro-common/include/media/media_detect_cd.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (media_detect_cd.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_MEDIA_DETECT_CD_H
#define __LIBRETRO_SDK_MEDIA_DETECT_CD_H

#include <retro_common_api.h>
#include <boolean.h>

RETRO_BEGIN_DECLS

enum media_detect_cd_system
{
   MEDIA_CD_SYSTEM_MEGA_CD,
   MEDIA_CD_SYSTEM_SATURN,
   MEDIA_CD_SYSTEM_DREAMCAST,
   MEDIA_CD_SYSTEM_PSX,
   MEDIA_CD_SYSTEM_3DO,
   MEDIA_CD_SYSTEM_PC_ENGINE_CD
};

typedef struct
{
   char title[256];
   char system[128];
   char region[128];
   char serial[64];
   char maker[64];
   char version[32];
   char release_date[32];
   enum media_detect_cd_system system_id;
} media_detect_cd_info_t;

/* Fill in "info" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */
bool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info);

/* Fill in "info" with detected CD info. Use this when you have a cue file and want it parsed to find the first data track and any pregap info. */
bool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info);

RETRO_END_DECLS

#endif

./include/libretro-common/include/memalign.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memalign.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_MEMALIGN_H
#define _LIBRETRO_MEMALIGN_H

#include <stddef.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

void *memalign_alloc(size_t boundary, size_t len);

void *memalign_alloc_aligned(size_t len);

void memalign_free(void *ptr);

RETRO_END_DECLS

#endif

./include/libretro-common/include/memmap.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memmap.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_MEMMAP_H
#define _LIBRETRO_MEMMAP_H

#include <stdio.h>
#include <stdint.h>

#if defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX) || defined(__PS3__) || defined(__PSL1GHT__)
/* No mman available */
#elif defined(_WIN32) && !defined(_XBOX)
#include <windows.h>
#include <errno.h>
#include <io.h>
#else
#define HAVE_MMAN
#include <sys/mman.h>
#endif

#if !defined(HAVE_MMAN) || defined(_WIN32)
void* mmap(void *addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off);

int munmap(void *addr, size_t len);

int mprotect(void *addr, size_t len, int prot);
#endif

int memsync(void *start, void *end);

int memprotect(void *addr, size_t len);

#endif

./include/libretro-common/include/net/net_compat.h

/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_compat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_COMPAT_H
#define _LIBRETRO_SDK_NET_COMPAT_H

#include <stdint.h>
#include <boolean.h>
#include <retro_inline.h>

#include <errno.h>

#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#endif

#include <retro_common_api.h>

#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>

#if _MSC_VER && _MSC_VER <= 1600
/* If we are using MSVC2010 or lower, disable WSAPoll support 
 * to ensure Windows XP and earlier backwards compatibility */
#else
#ifndef WIN32_SUPPORTS_POLL
#define WIN32_SUPPORTS_POLL 1
#endif
#endif

#if defined(WIN32_SUPPORTS_POLL) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
#define NETWORK_HAVE_POLL 1
#endif

#elif defined(_XBOX)
#define NOD3D

#include <xtl.h>
#include <io.h>

#ifndef SO_KEEPALIVE
#define SO_KEEPALIVE 0 /* verify if correct */
#endif

#define socklen_t unsigned int

#elif defined(VITA)
#include <psp2/net/net.h>
#include <psp2/net/netctl.h>

#define NETWORK_HAVE_POLL 1

#define AF_UNSPEC 0
#define AF_INET SCE_NET_AF_INET

#define SOCK_STREAM SCE_NET_SOCK_STREAM
#define SOCK_DGRAM SCE_NET_SOCK_DGRAM

#define INADDR_ANY SCE_NET_INADDR_ANY
#define INADDR_NONE 0xFFFFFFFF

#define SOL_SOCKET SCE_NET_SOL_SOCKET
#define SO_REUSEADDR SCE_NET_SO_REUSEADDR
#define SO_KEEPALIVE SCE_NET_SO_KEEPALIVE
#define SO_BROADCAST SCE_NET_SO_BROADCAST
#define SO_SNDBUF SCE_NET_SO_SNDBUF
#define SO_RCVBUF SCE_NET_SO_RCVBUF
#define SO_SNDTIMEO SCE_NET_SO_SNDTIMEO
#define SO_RCVTIMEO SCE_NET_SO_RCVTIMEO
#define SO_ERROR SCE_NET_SO_ERROR
#define SO_NBIO SCE_NET_SO_NBIO

#define IPPROTO_IP SCE_NET_IPPROTO_IP
#define IP_MULTICAST_TTL SCE_NET_IP_MULTICAST_TTL

#define IPPROTO_TCP SCE_NET_IPPROTO_TCP
#define TCP_NODELAY SCE_NET_TCP_NODELAY

#define IPPROTO_UDP SCE_NET_IPPROTO_UDP

#define MSG_DONTWAIT SCE_NET_MSG_DONTWAIT

#define POLLIN   SCE_NET_EPOLLIN
#define POLLOUT  SCE_NET_EPOLLOUT
#define POLLERR  SCE_NET_EPOLLERR
#define POLLHUP  SCE_NET_EPOLLHUP
#define POLLNVAL 0

#define sockaddr SceNetSockaddr
#define sockaddr_in SceNetSockaddrIn
#define in_addr SceNetInAddr
#define socklen_t unsigned int

#define socket(a,b,c) sceNetSocket("unknown",a,b,c)
#define getsockname sceNetGetsockname
#define getsockopt sceNetGetsockopt
#define setsockopt sceNetSetsockopt
#define bind sceNetBind
#define listen sceNetListen
#define accept sceNetAccept
#define connect sceNetConnect
#define send sceNetSend
#define sendto sceNetSendto
#define recv sceNetRecv
#define recvfrom sceNetRecvfrom
#define htonl sceNetHtonl
#define ntohl sceNetNtohl
#define htons sceNetHtons
#define ntohs sceNetNtohs
#define inet_ntop sceNetInetNtop
#define inet_pton sceNetInetPton

#elif defined(GEKKO)
#include <network.h>

#define NETWORK_HAVE_POLL 1

#define pollfd pollsd

#define socket(a,b,c) net_socket(a,b,c)
#define getsockopt(a,b,c,d,e) net_getsockopt(a,b,c,d,e)
#define setsockopt(a,b,c,d,e) net_setsockopt(a,b,c,d,e)
#define bind(a,b,c) net_bind(a,b,c)
#define listen(a,b) net_listen(a,b)
#define accept(a,b,c) net_accept(a,b,c)
#define connect(a,b,c) net_connect(a,b,c)
#define send(a,b,c,d) net_send(a,b,c,d)
#define sendto(a,b,c,d,e,f) net_sendto(a,b,c,d,e,f)
#define recv(a,b,c,d) net_recv(a,b,c,d)
#define recvfrom(a,b,c,d,e,f) net_recvfrom(a,b,c,d,e,f)
#define select(a,b,c,d,e) net_select(a,b,c,d,e)
#define gethostbyname(a) net_gethostbyname(a)

#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>

#include <netinet/in.h>
#ifndef __PSL1GHT__
#include <netinet/tcp.h>
#endif

#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>

#if !defined(__PSL1GHT__) && defined(__PS3__)
#include <netex/libnetctl.h>
#include <netex/errno.h>
#else
#include <signal.h>
#endif

#if defined(__PSL1GHT__)
#include <net/poll.h>

#define NETWORK_HAVE_POLL 1

#elif defined(WIIU)
#define WIIU_RCVBUF 0x40000
#define WIIU_SNDBUF 0x40000

#elif !defined(__PS3__)
#include <poll.h>

#define NETWORK_HAVE_POLL 1

#endif
#endif

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

#if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY) && !defined(_3DS)
#define HAVE_INET6 1
#endif

#ifdef NETWORK_HAVE_POLL
#ifdef GEKKO
#define NET_POLL_FD(sockfd, sockfds)    (sockfds)->socket  = (sockfd)
#else
#define NET_POLL_FD(sockfd, sockfds)    (sockfds)->fd      = (sockfd)
#endif
#define NET_POLL_EVENT(sockev, sockfds) (sockfds)->events |= (sockev)
#define NET_POLL_HAS_EVENT(sockev, sockfds) ((sockfds)->revents & (sockev))
#endif

RETRO_BEGIN_DECLS

/* Compatibility layer for legacy or incomplete BSD socket implementations.
 * Only for IPv4. Mostly useful for the consoles which do not support
 * anything reasonably modern on the socket API side of things. */
#ifdef HAVE_SOCKET_LEGACY
#define sockaddr_storage sockaddr_in

#ifdef AI_PASSIVE
#undef AI_PASSIVE
#endif
#ifdef AI_CANONNAME
#undef AI_CANONNAME
#endif
#ifdef AI_NUMERICHOST
#undef AI_NUMERICHOST
#endif
#ifdef AI_NUMERICSERV
#undef AI_NUMERICSERV
#endif

#ifdef NI_NUMERICHOST
#undef NI_NUMERICHOST
#endif
#ifdef NI_NUMERICSERV
#undef NI_NUMERICSERV
#endif
#ifdef NI_NOFQDN
#undef NI_NOFQDN
#endif
#ifdef NI_NAMEREQD
#undef NI_NAMEREQD
#endif
#ifdef NI_DGRAM
#undef NI_DGRAM
#endif

#define AI_PASSIVE     1
#define AI_CANONNAME   2
#define AI_NUMERICHOST 4
#define AI_NUMERICSERV 8

#define NI_NUMERICHOST 1
#define NI_NUMERICSERV 2
#define NI_NOFQDN      4
#define NI_NAMEREQD    8
#define NI_DGRAM       16

#ifndef __PS3__
struct addrinfo
{
   int ai_flags;
   int ai_family;
   int ai_socktype;
   int ai_protocol;
   socklen_t ai_addrlen;
   struct sockaddr *ai_addr;
   char *ai_canonname;
   struct addrinfo *ai_next;
};
#endif

/* gai_strerror() not used, so we skip that. */

#else
/* Ensure that getaddrinfo and getnameinfo flags are always defined. */
#ifndef AI_PASSIVE
#define AI_PASSIVE 0
#endif
#ifndef AI_CANONNAME
#define AI_CANONNAME 0
#endif
#ifndef AI_NUMERICHOST
#define AI_NUMERICHOST 0
#endif
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV 0
#endif

#ifndef NI_NUMERICHOST
#define NI_NUMERICHOST 0
#endif
#ifndef NI_NUMERICSERV
#define NI_NUMERICSERV 0
#endif
#ifndef NI_NOFQDN
#define NI_NOFQDN 0
#endif
#ifndef NI_NAMEREQD
#define NI_NAMEREQD 0
#endif
#ifndef NI_DGRAM
#define NI_DGRAM 0
#endif

#endif

#if defined(_XBOX)
struct hostent
{
   char *h_name;
   char **h_aliases;
   int  h_addrtype;
   int  h_length;
   char **h_addr_list;
   char *h_addr;
   char *h_end;
};

#elif defined(VITA)
struct pollfd
{
   int fd;
   unsigned events;
   unsigned revents;
   unsigned __pad; /* Align to 64-bits boundary */
};

struct hostent
{
   char *h_name;
   char **h_aliases;
   int  h_addrtype;
   int  h_length;
   char **h_addr_list;
   char *h_addr;
   char *h_end;
};

#endif

static INLINE bool isagain(int val)
{
#if defined(_WIN32)
   return (val == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK);
#elif !defined(__PSL1GHT__) && defined(__PS3__)
   return (sys_net_errno == SYS_NET_EAGAIN) || (sys_net_errno == SYS_NET_EWOULDBLOCK);
#elif defined(VITA)
   return (val == SCE_NET_ERROR_EAGAIN) || (val == SCE_NET_ERROR_EWOULDBLOCK);
#elif defined(WIIU)
   return (val == -1) && (socketlasterr() == SO_SUCCESS || socketlasterr() == SO_EWOULDBLOCK);
#elif defined(GEKKO)
   return (-val == EAGAIN);
#else
   return (val < 0) && (errno == EAGAIN || errno == EWOULDBLOCK);
#endif
}

static INLINE bool isinprogress(int val)
{
#if defined(_WIN32)
   return (val == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK);
#elif !defined(__PSL1GHT__) && defined(__PS3__)
   return (sys_net_errno == SYS_NET_EINPROGRESS);
#elif defined(VITA)
   return (val == SCE_NET_ERROR_EINPROGRESS);
#elif defined(WIIU)
   return (val == -1) && (socketlasterr() == SO_EINPROGRESS);
#elif defined(GEKKO)
   return (-val == EINPROGRESS);
#else
   return (val < 0) && (errno == EINPROGRESS);
#endif
}

#if defined(_WIN32) && !defined(_XBOX)
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
int inet_pton(int af, const char *src, void *dst);
#endif

#elif defined(_XBOX)
struct hostent *gethostbyname(const char *name);

#elif defined(VITA)
char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
uint32_t inet_addr(const char *cp);

struct hostent *gethostbyname(const char *name);

#elif defined(GEKKO)
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
int inet_pton(int af, const char *src, void *dst);

#endif

int getaddrinfo_retro(const char *node, const char *service,
      struct addrinfo *hints, struct addrinfo **res);

void freeaddrinfo_retro(struct addrinfo *res);

int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);

bool addr_6to4(struct sockaddr_storage *addr);

bool ipv4_is_lan_address(const struct sockaddr_in *addr);
bool ipv4_is_cgnat_address(const struct sockaddr_in *addr);

/**
 * network_init:
 *
 * Platform specific socket library initialization.
 *
 * @return true if successful, otherwise false.
 **/
bool network_init(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/net/net_http.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_HTTP_H
#define _LIBRETRO_SDK_NET_HTTP_H

#include <stdint.h>
#include <boolean.h>
#include <string.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

struct http_t;
struct http_connection_t;

struct http_connection_t *net_http_connection_new(const char *url, const char *method, const char *data);

/**
 * net_http_connection_iterate:
 *
 * Leaf function.
 **/
bool net_http_connection_iterate(struct http_connection_t *conn);

bool net_http_connection_done(struct http_connection_t *conn);

void net_http_connection_free(struct http_connection_t *conn);

void net_http_connection_set_user_agent(struct http_connection_t *conn, const char *user_agent);

void net_http_connection_set_headers(struct http_connection_t *conn, const char *headers);

void net_http_connection_set_content(struct http_connection_t *conn, const char *content_type,
      size_t content_length, const void *content);

const char *net_http_connection_url(struct http_connection_t *conn);

const char* net_http_connection_method(struct http_connection_t* conn);

struct http_t *net_http_new(struct http_connection_t *conn);

/**
 * net_http_fd:
 *
 * Leaf function.
 *
 * You can use this to call net_http_update
 * only when something will happen; select() it for reading.
 **/
int net_http_fd(struct http_t *state);

/**
 * net_http_update:
 *
 * @return true if it's done, or if something broke.
 * @total will be 0 if it's not known.
 **/
bool net_http_update(struct http_t *state, size_t* progress, size_t* total);

/**
 * net_http_status:
 *
 * Report HTTP status. 200, 404, or whatever.
 *
 * Leaf function.
 *
 * @return HTTP status code.
 **/
int net_http_status(struct http_t *state);

/**
 * net_http_error:
 *
 * Leaf function
 **/
bool net_http_error(struct http_t *state);

/**
 * net_http_headers:
 *
 * Leaf function.
 *
 * @return the response headers. The returned buffer is owned by the
 * caller of net_http_new; it is not freed by net_http_delete.
 * If the status is not 20x and accept_error is false, it returns NULL.
 **/
struct string_list *net_http_headers(struct http_t *state);

/**
 * net_http_data:
 *
 * Leaf function.
 *
 * @return the downloaded data. The returned buffer is owned by the
 * HTTP handler; it's freed by net_http_delete.
 * If the status is not 20x and accept_error is false, it returns NULL.
 **/
uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_error);

/**
 * net_http_delete:
 *
 * Cleans up all memory.
 **/
void net_http_delete(struct http_t *state);

/**
 * net_http_urlencode:
 *
 * URL Encode a string
 * caller is responsible for deleting the destination buffer
 **/
void net_http_urlencode(char **dest, const char *source);

/**
 * net_http_urlencode_full:
 *
 * Re-encode a full URL
 **/
void net_http_urlencode_full(char *s, const char *source, size_t len);

RETRO_END_DECLS

#endif

./include/libretro-common/include/net/net_http_parse.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_HTTP_PARSE_H
#define _LIBRETRO_SDK_NET_HTTP_PARSE_H

#include <stdint.h>
#include <boolean.h>
#include <string.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/**
 * string_parse_html_anchor:
 * @line               : Buffer where the <a> tag is stored
 * @link               : Buffer to store the link URL in
 * @name               : Buffer to store the link URL in
 * @link_size          : Size of the link buffer including the NUL-terminator
 * @name_size          : Size of the name buffer including the NUL-terminator
 *
 * Parses an HTML anchor link stored in @line in the form of: <a href="/path/to/url">Title</a>
 * The buffer pointed to by @link is filled with the URL path the link points to,
 * and @name is filled with the title portion of the link.
 *
 * @return 0 if URL was parsed completely, otherwise 1.
 **/
int string_parse_html_anchor(const char *line, char *link, char *name,
      size_t link_size, size_t name_size);

RETRO_END_DECLS

#endif

./include/libretro-common/include/net/net_ifinfo.h

/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_ifinfo.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_IFINFO_H
#define _LIBRETRO_SDK_NET_IFINFO_H

#include <stddef.h>

#include <boolean.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

struct net_ifinfo_entry
{
   char name[256];
   char host[256];
};

typedef struct net_ifinfo
{
   struct net_ifinfo_entry *entries;
   size_t size;
} net_ifinfo_t;

bool net_ifinfo_new(net_ifinfo_t *list);

void net_ifinfo_free(net_ifinfo_t *list);

bool net_ifinfo_best(const char *dst, void *src, bool ipv6);

RETRO_END_DECLS

#endif

./include/libretro-common/include/net/net_socket.h

/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_SOCKET_H
#define _LIBRETRO_SDK_NET_SOCKET_H

#include <stddef.h>
#include <stdint.h>
#include <boolean.h>

#include <net/net_compat.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

enum socket_domain
{
   SOCKET_DOMAIN_INET = 0
};

enum socket_type
{
   SOCKET_TYPE_DATAGRAM = 0,
   SOCKET_TYPE_STREAM,
   SOCKET_TYPE_SEQPACKET
};

enum socket_protocol
{
   SOCKET_PROTOCOL_NONE = 0,
   SOCKET_PROTOCOL_TCP,
   SOCKET_PROTOCOL_UDP
};

typedef struct socket_target
{
   unsigned port;
   const char *server;
   enum socket_domain domain;
   enum socket_protocol prot;
} socket_target_t;

int socket_init(void **address, uint16_t port, const char *server,
      enum socket_type type, int family);

int socket_next(void **address);

int socket_close(int fd);

bool socket_set_block(int fd, bool block);

/* TODO: all callers should be converted to socket_set_block() */
bool socket_nonblock(int fd);

int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
      fd_set *errorfds, struct timeval *timeout);

#ifdef NETWORK_HAVE_POLL
int socket_poll(struct pollfd *fds, unsigned nfds, int timeout);
#endif

bool socket_wait(int fd, bool *rd, bool *wr, int timeout);

bool socket_send_all_blocking(int fd, const void *data_, size_t len, bool no_signal);

bool socket_send_all_blocking_with_timeout(int fd,
      const void *data_, size_t len, int timeout, bool no_signal);

ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t len,
      bool no_signal);

bool socket_receive_all_blocking(int fd, void *data_, size_t len);

bool socket_receive_all_blocking_with_timeout(int fd,
      void *data_, size_t len, int timeout);

ssize_t socket_receive_all_nonblocking(int fd, bool *error,
      void *data_, size_t len);

bool socket_bind(int fd, void *data);

int socket_connect(int fd, void *data);

bool socket_connect_with_timeout(int fd, void *data, int timeout);

int socket_create(
      const char *name,
      enum socket_domain domain_type,
      enum socket_type socket_type,
      enum socket_protocol protocol_type);

void socket_set_target(void *data, socket_target_t *in_addr);

RETRO_END_DECLS

#endif

./include/libretro-common/include/net/net_socket_ssl.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_SOCKET_SSL_H
#define _LIBRETRO_SDK_NET_SOCKET_SSL_H

#include <stdlib.h>
#include <boolean.h>
#include <retro_common_api.h>

RETRO_BEGIN_DECLS

void* ssl_socket_init(int fd, const char *domain);

int ssl_socket_connect(void *state_data, void *data, bool timeout_enable, bool nonblock);

int ssl_socket_send_all_blocking(void *state_data, const void *data_, size_t len, bool no_signal);

ssize_t ssl_socket_send_all_nonblocking(void *state_data, const void *data_, size_t len, bool no_signal);

int ssl_socket_receive_all_blocking(void *state_data, void *data_, size_t len);

ssize_t ssl_socket_receive_all_nonblocking(void *state_data, bool *error, void *data_, size_t len);

void ssl_socket_close(void *state_data);

void ssl_socket_free(void *state_data);

RETRO_END_DECLS

#endif

./include/libretro-common/include/playlists/label_sanitization.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (label_sanitization.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <stddef.h>
#include <boolean.h>

/**
 * label_sanitize:
 *
 * NOTE: Does not work with nested blocks.
 **/
void label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*));

void label_remove_parens(char *label);

void label_remove_brackets(char *label);

void label_remove_parens_and_brackets(char *label);

void label_keep_region(char *label);

void label_keep_disc(char *label);

void label_keep_region_and_disc(char *label);

./include/libretro-common/include/queues/fifo_queue.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fifo_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FIFO_BUFFER_H
#define __LIBRETRO_SDK_FIFO_BUFFER_H

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

#include <retro_common_api.h>
#include <retro_inline.h>
#include <boolean.h>

RETRO_BEGIN_DECLS

/**
 * Returns the available data in \c buffer for reading.
 *
 * @param buffer <tt>fifo_buffer_t *</tt>. The FIFO queue to check.
 * @return The number of bytes available for reading from \c buffer.
 */
#define FIFO_READ_AVAIL(buffer) (((buffer)->end + (((buffer)->end < (buffer)->first) ? (buffer)->size : 0)) - (buffer)->first)

/**
 * Returns the available space in \c buffer for writing.
 *
 * @param buffer <tt>fifo_buffer_t *</tt>. The FIFO queue to check.
 * @return The number of bytes that \c buffer can accept.
 */
#define FIFO_WRITE_AVAIL(buffer) (((buffer)->size - 1) - (((buffer)->end + (((buffer)->end < (buffer)->first) ? (buffer)->size : 0)) - (buffer)->first))

/**
 * Returns the available data in \c buffer for reading.
 *
 * @param buffer \c fifo_buffer_t. The FIFO queue to check.
 * @return The number of bytes available for reading from \c buffer.
 */
#define FIFO_READ_AVAIL_NONPTR(buffer) (((buffer).end + (((buffer).end < (buffer).first) ? (buffer).size : 0)) - (buffer).first)

/**
 * Returns the available space in \c buffer for writing.
 *
 * @param buffer \c fifo_buffer_t. The FIFO queue to check.
 * @return The number of bytes that \c buffer can accept.
 */
#define FIFO_WRITE_AVAIL_NONPTR(buffer) (((buffer).size - 1) - (((buffer).end + (((buffer).end < (buffer).first) ? (buffer).size : 0)) - (buffer).first))

/** @copydoc fifo_buffer_t */
struct fifo_buffer
{
   uint8_t *buffer;
   size_t size;
   size_t first;
   size_t end;
};

/**
 * A bounded FIFO byte queue implemented as a ring buffer.
 *
 * Useful for communication between threads,
 * although the caller is responsible for synchronization.
 */
typedef struct fifo_buffer fifo_buffer_t;

/**
 * Creates a new FIFO queue with \c size bytes of memory.
 * Must be freed with \c fifo_free.
 *
 * @param size The size of the FIFO queue, in bytes.
 * @return The new queue if successful, \c NULL otherwise.
 * @see fifo_initialize
 */
fifo_buffer_t *fifo_new(size_t len);

/**
 * Initializes an existing FIFO queue with \c size bytes of memory.
 *
 * Suitable for use with \c fifo_buffer_t instances
 * of static or automatic lifetime.
 * Must be freed with \c fifo_deinitialize.
 *
 * @param buf Pointer to the FIFO queue to initialize.
 * May be static or automatic.
 * @param size The size of the FIFO queue, in bytes.
 * @return \c true if \c buf was initialized with the requested memory,
 * \c false if \c buf is \c NULL or there was an error.
 */
bool fifo_initialize(fifo_buffer_t *buf, size_t len);

/**
 * Resets the bounds of \c buffer,
 * effectively clearing it.
 *
 * No memory will actually be freed,
 * but the contents of \c buffer will be overwritten
 * with the next call to \c fifo_write.
 * @param buffer The FIFO queue to clear.
 * Behavior is undefined if \c NULL.
 */
static INLINE void fifo_clear(fifo_buffer_t *buffer)
{
   buffer->first = 0;
   buffer->end   = 0;
}

/**
 * Writes \c size bytes to the given queue.
 *
 * @param buffer The FIFO queue to write to.
 * @param in_buf The buffer to read bytes from.
 * @param size The length of \c in_buf, in bytes.
 */
void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len);

/**
 * Reads \c size bytes from the given queue.
 *
 * @param buffer The FIFO queue to read from.
 * @param in_buf The buffer to store the read bytes in.
 * @param size The length of \c in_buf, in bytes.
 * @post Upon return, \c buffer will have up to \c size more bytes of space available for writing.
 */
void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t len);

/**
 * Releases \c buffer and its contents.
 *
 * @param buffer The FIFO queue to free.
 * If \c NULL, this function will do nothing.
 * Behavior is undefined if \c buffer was previously freed.
 * @see fifo_deinitialize
 */
void fifo_free(fifo_buffer_t *buffer);

/**
 * Deallocates the contents of \c buffer,
 * but not \c buffer itself.
 *
 * Suitable for use with static or automatic \c fifo_buffer_t instances.
 *
 * @param buffer The buffer to deinitialize.
 * @return \c false if \c buffer is \c NULL, \c true otherwise.
 * @see fifo_free
 */
bool fifo_deinitialize(fifo_buffer_t *buffer);


RETRO_END_DECLS

#endif

./include/libretro-common/include/queues/generic_queue.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (generic_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GENERIC_QUEUE_H
#define __LIBRETRO_SDK_GENERIC_QUEUE_H

#include <retro_common_api.h>

#include <boolean.h>
#include <stddef.h>

RETRO_BEGIN_DECLS

/**
 * Represents a generic queue. Can contain any number of elements. Each element contains
 * a value of type "void *". Can be used as a FIFO or LIFO queue.
 */
typedef struct generic_queue generic_queue_t;

/**
 * Represents an iterator for iterating over a queue.
 */
typedef struct generic_queue_iterator generic_queue_iterator_t;

/**
 * Creates a new queue with no elements.
 *
 * @return New queue
 */
generic_queue_t *generic_queue_new(void);

/**
 * @brief frees the memory used by the queue
 * 
 * Frees all of the memory used by this queue. The values of all
 * remaining elements are freed using the "free_value" function. Does
 * nothing if "queue" is NULL.
 *
 * @param queue queue to free
 * @param free_value function to use to free remaining values
 */
void generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value));

/**
 * @brief Push a new value onto the queue
 *
 * Pushes a new value onto the end of the queue. Does nothing if "queue"
 * is NULL.
 *
 * @param queue queue to the push the value onto
 * @param value value to push onto the queue
 */
void generic_queue_push(generic_queue_t *queue, void *value);

/**
 * @brief Remove the last value from the queue
 *
 * Removes the last element from the queue. Does nothing if the queue is
 * NULL.
 *
 * @param queue queue to get the value from
 * @return value of the last element, NULL if queue is empty or NULL
 */
void *generic_queue_pop(generic_queue_t *queue);

/**
 * @brief Get the last value from the queue
 *
 * Returns the value of the last element in the queue. Returns NULL if the
 * queue is NULL or empty.
 *
 * @param queue queue to get the last value from
 * @return value of the last element or NULL
 */
void *generic_queue_peek(generic_queue_t *queue);

/**
 * @brief Get the first value from the queue
 *
 * Returns the value of the first element in the queue. Returns NULL if the
 * queue is NULL or empty.
 *
 * @param queue queue to get the first value from
 * @return value of the first element or NULL
 */
void *generic_queue_peek_first(generic_queue_t *queue);

/**
 * @brief Push a new value onto the front of the queue
 *
 * Pushes a new value onto the front of the queue. Does nothing if "queue"
 * is NULL.
 *
 * @param queue queue to the push the value onto
 * @param value value to push onto the queue
 */
void generic_queue_shift(generic_queue_t *queue, void *value);

/**
 * @brief Remove the first value from the queue
 *
 * Removes the first element from the queue. Does nothing if the queue is
 * NULL.
 *
 * @param queue queue to get the value from
 * @return value of the last element, NULL if queue is empty or NULL
 */
void *generic_queue_unshift(generic_queue_t *queue);

/**
 * @brief Get the size of the queue
 *
 * Returns the number of elements in the queue.
 *
 * @param queue queue to get the size of
 * @return number of elements in the queue, 0 if queue is NULL
 */
size_t generic_queue_length(generic_queue_t *queue);

/**
 * @brief Remove the first element in the queue with the provided value
 *
 * Removes the first element with a value matching the provided value. Does
 * nothing if queue is NULL.
 *
 * @param queue queue to remove the element from
 * @param value value to look for in the queue
 * @return the value of the element removed, NULL if no element was removed
 */
void *generic_queue_remove(generic_queue_t *queue, void *value);

/**
 * @brief Get an iterator for the queue
 *
 * Returns a new iterator for the queue. Can be either a forward or backward
 * iterator.
 *
 * @param queue queue to iterate over
 * @param forward true for a forward iterator, false for backwards
 * @return new iterator for the queue in the specified direction, NULL if
 *         "queue" is NULL
 */
generic_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward);

/**
 * @brief Move to the next element in the queue
 *
 * Moves the iterator to the next element in the queue. The direction is
 * specified when retrieving a new iterator.
 *
 * @param iterator iterator for the current element
 * @return iterator for the next element, NULL if iterator is NULL or "iterator"
 *         is at the last element
 */
generic_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator);

/**
 * @brief Get the value of the element for the iterator
 *
 * Returns the value of the element that the iterator is at.
 *
 * @param iterator iterator for the current element
 * @return value of the element for the iterator
 */
void *generic_queue_iterator_value(generic_queue_iterator_t *iterator);

/**
 * @brief Remove the element that the iterator is at
 *
 * Removes the element that the iterator is at. The iterator is updated to the
 * next element.
 *
 * @param iterator iterator for the current element
 * @return updated iterator or NULL if the last element was removed
 */
generic_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator);

/**
 * @brief Release the memory for the iterator
 *
 * Frees the memory for the provided iterator. Does nothing if "iterator" is NULL.
 *
 * @param iterator iterator to free
 */
void generic_queue_iterator_free(generic_queue_iterator_t *iterator);

RETRO_END_DECLS

#endif

./include/libretro-common/include/queues/message_queue.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (message_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_MSG_QUEUE_H
#define __LIBRETRO_SDK_MSG_QUEUE_H

#include <stddef.h>

#include <retro_common_api.h>
#include <boolean.h>

RETRO_BEGIN_DECLS

enum message_queue_icon
{
   MESSAGE_QUEUE_ICON_DEFAULT = 0 /* default icon is tied to category */
};

enum message_queue_category
{
   MESSAGE_QUEUE_CATEGORY_INFO = 0,
   MESSAGE_QUEUE_CATEGORY_ERROR,
   MESSAGE_QUEUE_CATEGORY_WARNING,
   MESSAGE_QUEUE_CATEGORY_SUCCESS
};

typedef struct queue_elem
{
   char *msg;
   char *title;
   unsigned duration;
   unsigned prio;
   enum message_queue_icon icon;
   enum message_queue_category category;
} queue_elem_t;

typedef struct msg_queue
{
   char *tmp_msg;
   queue_elem_t **elems;
   size_t ptr;
   size_t size;
} msg_queue_t;

typedef struct
{
   unsigned duration;
   unsigned prio;
   enum message_queue_icon icon;
   enum message_queue_category category;
   char msg[1024];
   char title[1024];
} msg_queue_entry_t;

/**
 * msg_queue_new:
 * @len               : maximum size of message
 *
 * Creates a message queue with maximum size different messages.
 *
 * Returns: NULL if allocation error, pointer to a message queue
 * if successful. Has to be freed manually.
 **/
msg_queue_t *msg_queue_new(size_t len);

bool msg_queue_initialize(msg_queue_t *queue, size_t len);

/**
 * msg_queue_push:
 * @queue             : pointer to queue object
 * @msg               : message to add to the queue
 * @prio              : priority level of the message
 * @duration          : how many times the message can be pulled
 *                      before it vanishes (E.g. show a message for
 *                      3 seconds @ 60fps = 180 duration).
 *
 * Push a new message onto the queue.
 **/
void msg_queue_push(msg_queue_t *queue, const char *msg,
      unsigned prio, unsigned duration,
      char *title,
      enum message_queue_icon icon, enum message_queue_category category);

/**
 * msg_queue_pull:
 * @queue             : pointer to queue object
 *
 * Pulls highest priority message in queue.
 *
 * Returns: NULL if no message in queue, otherwise a string
 * containing the message.
 **/
const char *msg_queue_pull(msg_queue_t *queue);

/**
 * msg_queue_extract:
 * @queue             : pointer to queue object
 * @queue_entry       : pointer to external queue entry struct
 *
 * Removes highest priority message from queue, copying
 * contents into queue_entry struct.
 *
 * Returns: false if no messages in queue, otherwise true
 **/
bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry);

/**
 * msg_queue_size:
 * @queue             : pointer to queue object
 *
 * Fetches number of messages in queue.
 *
 * Returns: Number of messages in queue.
 **/
size_t msg_queue_size(msg_queue_t *queue);

/**
 * msg_queue_clear:
 * @queue             : pointer to queue object
 *
 * Clears out everything in the queue.
 **/
void msg_queue_clear(msg_queue_t *queue);

/**
 * msg_queue_free:
 * @queue             : pointer to queue object
 *
 * Frees message queue..
 **/
void msg_queue_free(msg_queue_t *queue);

bool msg_queue_deinitialize(msg_queue_t *queue);

RETRO_END_DECLS

#endif

./include/libretro-common/include/queues/task_queue.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (task_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_TASK_QUEUE_H__
#define __LIBRETRO_SDK_TASK_QUEUE_H__

#include <stdint.h>
#include <stddef.h>
#include <boolean.h>

#include <retro_common.h>
#include <retro_common_api.h>

#include <libretro.h>

RETRO_BEGIN_DECLS

enum task_type
{
   /** A regular task. The vast majority of tasks will use this type. */
   TASK_TYPE_NONE,

   /**
    * Only one blocking task can exist in the queue at a time.
    * Attempts to add a new one while another is running will fail.
    */
   TASK_TYPE_BLOCKING
};

enum task_style
{
   TASK_STYLE_NONE,
   TASK_STYLE_POSITIVE,
   TASK_STYLE_NEGATIVE
};

typedef struct retro_task retro_task_t;

/** @copydoc retro_task::callback */
typedef void (*retro_task_callback_t)(retro_task_t *task,
      void *task_data,
      void *user_data, const char *error);

/** @copydoc retro_task::handler */
typedef void (*retro_task_handler_t)(retro_task_t *task);

/** @copydoc task_finder_data::func */
typedef bool (*retro_task_finder_t)(retro_task_t *task,
      void *userdata);

/**
 * Displays a message output by a task.
 */
typedef void (*retro_task_queue_msg_t)(retro_task_t *task,
      const char *msg,
      unsigned prio, unsigned duration, bool flush);

/** @copydoc task_retriever_data::func */
typedef bool (*retro_task_retriever_t)(retro_task_t *task, void *data);

/**
 * Called by \c task_queue_wait after each task executes
 * (i.e. once per pass over the queue).
 * @param data Arbitrary data.
 * The function should cast this to a known type.
 * @return \c true if \c task_queue_wait should continue waiting,
 * \c false if it should return early.
 * @see task_queue_wait
 */
typedef bool (*retro_task_condition_fn_t)(void *data);

typedef struct
{
   char *source_file;
} decompress_task_data_t;

enum retro_task_flags
{
   /**
    * If \c true, the frontend should use some alternative means
    * of displaying this task's progress or messages.
    * Not used within cores.
    */
   RETRO_TASK_FLG_ALTERNATIVE_LOOK = (1 << 0),
   /**
    * Set to \c true by \c handler to indicate that this task has finished.
    * At this point the task queue will call \c callback and \c cleanup,
    * then deallocate the task.
    */
   RETRO_TASK_FLG_FINISHED         = (1 << 1),
   /**
    * Set to true by the task queue to signal that this task \em must end.
    * \c handler should check to see if this is set,
    * aborting or completing its work as soon as possible afterward.
    * \c callback and \c cleanup will still be called as normal.
    *
    * @see task_queue_reset
    */
   RETRO_TASK_FLG_CANCELLED        = (1 << 2),
   /**
    * If set, the task queue will not call \c progress_cb
    * and will not display any messages from this task.
    */
   RETRO_TASK_FLG_MUTE             = (1 << 3)
};

/**
 * A unit of work executed by the task system,
 * spread across one or more frames.
 *
 * Some fields are set by the caller,
 * others are set by the task system.
 */
struct retro_task
{
   /**
    * The time (in microseconds) when the task should start running,
    * or 0 if it should start as soon as possible.
    * The exact time this task starts will depend on when the queue is next updated.
    * Set by the caller.
    * @note This is a point in time, not a duration.
    * It is not affected by a frontend's time manipulation (pausing, fast-forward, etc.).
    * @see cpu_features_get_time_usec
    */
   retro_time_t when;

   /**
    * The main body of work for a task.
    * Should be as fast as possible,
    * as it will be called with each task queue update
    * (usually once per frame).
    * Must not be \c NULL.
    *
    * @param task The task that this handler is associated with.
    * Can be used to configure or query the task.
    * Will never be \c NULL.
    * @see task_queue_check
    */
   retro_task_handler_t  handler;

   /**
    * Called when this task finishes;
    * executed during the next task queue update
    * after \c finished is set to \c true.
    * May be \c NULL, in which case this function is skipped.
    *
    * @param task The task that is being cleaned up.
    * Will never be \c NULL.
    * @param task_data \c task's \c task_data field.
    * @param user_data \c task's \c user_data field.
    * @param error \c task's \c error field.
    * @see task_queue_check
    * @see retro_task_callback_t
    */
   retro_task_callback_t callback;

   /**
    * Called when this task finishes immediately after \c callback is run.
    * Used to clean up any resources or state owned by the task.
    * May be \c NULL, in which case this function is skipped.
    *
    * @param task The task that is being cleaned up.
    * Will never be \c NULL.
    */
   retro_task_handler_t cleanup;

   /**
    * Pointer to arbitrary data, intended for "returning" an object from the task
    * (although it can be used for any purpose).
    * If owned by the task, it should be cleaned up within \c cleanup.
    * Not modified or freed by the task queue.
    */
   void *task_data;

   /**
    * Pointer to arbitrary data, intended for passing parameters to the task.
    * If owned by the task, it should be cleaned up within \c cleanup.
    * Not modified or freed by the task queue.
    */
   void *user_data;

   /**
    * Pointer to arbitrary data, intended for state that exists for the task's lifetime.
    * If owned by the task, it should be cleaned up within \c cleanup.
    * Not modified or freed by the task queue.
    */
   void *state;

   /**
    * Human-readable details about an error that occurred while running the task.
    * Should be created and assigned within \c handler if there was an error.
    * Will be cleaned up by the task queue with \c free() upon this task's completion.
    * @see task_set_error
    */
   char *error;

   /**
    * Called to update a task's \c progress,
    * or to update some view layer (e.g. an on-screen display)
    * about the task's progress.
    *
    * Skipped if \c NULL or if \c mute is set.
    *
    * @param task The task whose progress is being updated or reported.
    * @see progress
    */
   void (*progress_cb)(retro_task_t*);

   /**
    * Human-readable description of this task.
    * May be \c NULL,
    * but if not then it will be disposed of by the task system with \c free()
    * upon this task's completion.
    * Can be modified or replaced at any time.
    * @see strdup
    */
   char *title;

   /**
    * Pointer to arbitrary data, intended for use by a frontend
    * (for example, to associate a sticky notification with a task).
    *
    * This should be cleaned up within \c cleanup if necessary.
    * Cores may use this for any purpose.
    */
   void *frontend_userdata;

   /**
    * @private Pointer to the next task in the queue.
    * Do not touch this; it is managed by the task system.
    */
   retro_task_t *next;

   /**
    * Indicates the current progress of the task.
    *
    * -1 means the task is indefinite or not measured,
    * 0-100 is a percentage of the task's completion.
    *
    * Set by the caller.
    *
    * @see progress_cb
    */
   int8_t progress;

   /**
    * A unique identifier assigned to a task when it's created.
    * Set by the task system.
    */
   uint32_t ident;

   /**
    * The type of task this is.
    * Set by the caller.
    */
   enum task_type type;
   enum task_style style;

   uint8_t flags;
};

/**
 * Parameters for \c task_queue_find.
 *
 * @see task_queue_find
 */
typedef struct task_finder_data
{
   /**
    * Predicate to call for each task.
    * Must not be \c NULL.
    *
    * @param task The task to query.
    * @param userdata \c userdata from this struct.
    * @return \c true if this task matches the search criteria,
    * at which point \c task_queue_find will stop searching and return \c true.
    */
   retro_task_finder_t func;

   /**
    * Pointer to arbitrary data.
    * Passed directly to \c func.
    * May be \c NULL.
    */
   void *userdata;
} task_finder_data_t;

/**
 * Contains the result of a call to \c task_retriever_data::func.
 * Implemented as an intrusive singly-linked list.
 */
typedef struct task_retriever_info
{
   /**
    * The next item in the result list,
    * or \c NULL if this is the last one.
    */
   struct task_retriever_info *next;

   /**
    * Arbitrary data returned by \c func.
    * Can be anything, but should be a simple \c struct
    * so that it can be freed by \c task_queue_retriever_info_free.
    */
   void *data;
} task_retriever_info_t;

/**
 * Parameters for \c task_queue_retrieve.
 *
 * @see task_queue_retrieve
 */
typedef struct task_retriever_data
{
   /**
    * Contains the result of each call to \c func that returned \c true.
    * Should be initialized to \c NULL.
    * Will remain \c NULL after \c task_queue_retrieve if no tasks matched.
    * Must be freed by \c task_queue_retriever_info_free.
    * @see task_queue_retriever_info_free
    */
   task_retriever_info_t *list;

   /**
    * The handler to compare against.
    * Only tasks with this handler will be considered for retrieval.
    * Must not be \c NULL.
    */
   retro_task_handler_t handler;

   /**
    * The predicate that determines if the given task will be retrieved.
    * Must not be \c NULL.
    *
    * @param task[in] The task to query.
    * @param data[out] Arbitrary data that the retriever should return.
    * Allocated by the task queue based on \c element_size.
    * @return \c true if \c data should be appended to \c list.
    */
   retro_task_retriever_t func;

   /**
    * The size of the output that \c func may write to.
    * Must not be zero.
    */
   size_t element_size;
} task_retriever_data_t;

/**
 * Returns the next item in the result list.
 * Here's a usage example, assuming that \c results is used to store strings:
 *
 * @code{.c}
 * void print_results(task_retriever_info_t *results)
 * {
 *    char* text = NULL;
 *    task_retriever_info_t *current = results;
 *    while (text = task_queue_retriever_info_next(&current))
 *    {
 *       printf("%s\n", text);
 *    }
 * }
 * @endcode
 *
 * @param link Pointer to the first element in the result list.
 * Must not be \c NULL.
 * @return The next item in the result list.
 */
void *task_queue_retriever_info_next(task_retriever_info_t **link);

/**
 * Frees the result of a call to \c task_queue_retrieve.
 * @param list The result list to free.
 * May be \c NULL, in which case this function does nothing.
 * The list, its nodes, and its elements will all be freed.
 *
 * If the list's elements must be cleaned up with anything besides \c free,
 * then the caller must do that itself before invoking this function.
 */
void task_queue_retriever_info_free(task_retriever_info_t *list);

/**
 * Cancels the provided task.
 * The task should finish its work as soon as possible afterward.
 *
 * @param task The task to cancel.
 * @see task_set_cancelled
 */
void task_queue_cancel_task(void *task);

void task_set_flags(retro_task_t *task, uint8_t flags, bool set);

/**
 * Sets \c task::error to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param error The error message to set.
 * @see retro_task::error
 * @warning This does not free the existing error message.
 * The caller must do that itself.
 */
void task_set_error(retro_task_t *task, char *error);

/**
 * Sets \c task::progress to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param progress The progress value to set.
 * @see retro_task::progress
 */
void task_set_progress(retro_task_t *task, int8_t progress);

/**
 * Sets \c task::title to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param title The title to set.
 * @see retro_task::title
 * @see task_free_title
 * @warning This does not free the existing title.
 * The caller must do that itself.
 */
void task_set_title(retro_task_t *task, char *title);

/**
 * Sets \c task::data to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param data The data to set.
 * @see retro_task::data
 */
void task_set_data(retro_task_t *task, void *data);

/**
 * Frees the \c task's title, if any.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * @see task_set_title
 */
void task_free_title(retro_task_t *task);

/**
 * Returns \c task::error.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::error.
 * @see retro_task::error
 */
char* task_get_error(retro_task_t *task);

/**
 * Returns \c task::progress.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::progress.
 * @see retro_task::progress
 */
int8_t task_get_progress(retro_task_t *task);

/**
 * Returns \c task::title.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::title.
 * @see retro_task::title
 */
char* task_get_title(retro_task_t *task);

/**
 * Returns \c task::data.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::data.
 * @see retro_task::data
 */
void* task_get_data(retro_task_t *task);

/**
 * Returns whether the task queue is running
 * on the same thread that called \c task_queue_init.
 *
 * @return \c true if the caller is running
 * on the same thread that called \c task_queue_init.
 */
bool task_is_on_main_thread(void);

/**
 * Ensures that the task queue is in threaded mode.
 *
 * Next time \c retro_task_queue_check is called,
 * the task queue will be recreated with threading enabled.
 * Existing tasks will continue to run on the new thread.
 */
void task_queue_set_threaded(void);

/**
 * Ensures that the task queue is not in threaded mode.
 *
 * Next time \c retro_task_queue_check is called,
 * the task queue will be recreated with threading disabled.
 * Existing tasks will continue to run on whichever thread updates the queue.
 *
 * @see task_queue_set_threaded
 * @see task_queue_is_threaded
 */
void task_queue_unset_threaded(void);

/**
 * Returns whether the task queue is running in threaded mode.
 *
 * @return \c true if the task queue is running its tasks on a separate thread.
 */
bool task_queue_is_threaded(void);

/**
 * Calls the function given in \c find_data for each task
 * until it returns \c true for one of them,
 * or until all tasks have been searched.
 *
 * @param find_data Parameters for the search.
 * Behavior is undefined if \c NULL.
 * @return \c true if \c find_data::func returned \c true for any task.
 * @see task_finder_data_t
 */
bool task_queue_find(task_finder_data_t *find_data);

/**
 * Retrieves arbitrary data from every task
 * whose handler matches \c data::handler.
 *
 * @param data[in, out] Parameters for retrieving data from the task queue,
 * including the results themselves.
 * Behavior is undefined if \c NULL.
 * @see task_retriever_data_t
 */
void task_queue_retrieve(task_retriever_data_t *data);

 /**
  * Runs each task.
  * If a task is finished or cancelled,
  * its callback and cleanup handler will be called.
  * Afterwards, the task will be deallocated.
  * If used in a core, generally called in \c retro_run
  * and just before \c task_queue_deinit.
  * @warning This must only be called from the main thread.
  */
void task_queue_check(void);

uint8_t task_get_flags(retro_task_t *task);

/**
 * Schedules a task to start running.
 * If \c task::when is 0, it will start as soon as possible.
 *
 * Tasks with the same \c task::when value
 * will be executed in the order they were scheduled.
 *
 * @param task The task to schedule.
 * @return \c true unless \c task's type is \c TASK_TYPE_BLOCKING
 * and there's already a blocking task in the queue.
 */
bool task_queue_push(retro_task_t *task);

/**
 * Block until all active (i.e. current time > \c task::when) tasks have finished,
 * or until the given function returns \c false.
 * If a scheduled task's \c when is passed while within this function,
 * it will start executing.
 *
 * Must only be called from the main thread.
 *
 * @param cond Function to call after all tasks in the queue have executed
 * (i.e. once per pass over the task queue).
 * May be \c NULL, in which case the task queue will wait unconditionally.
 * @param data Pointer to arbitrary data, passed directly into \c cond.
 * May be \c NULL.
 * @see retro_task_condition_fn_t
 * @see task_queue_deinit
 * @see task_queue_reset
 * @warning Passing \c NULL to \c cond is strongly discouraged.
 * If you use tasks that run indefinitely
 * (e.g. for the lifetime of the core),
 * you will need a way to stop these tasks externally;
 * otherwise, you risk the frontend and core freezing.
 */
void task_queue_wait(retro_task_condition_fn_t cond, void* data);

/**
 * Marks all tasks in the queue as cancelled.
 *
 * The tasks won't immediately be terminated;
 * each task may finish its work,
 * but must do so as quickly as possible.
 *
 * Must only be called from the main thread.
 *
 * @see task_queue_wait
 * @see task_queue_deinit
 * @see task_set_finished
 * @see task_get_cancelled
 */
void task_queue_reset(void);

/**
 * Deinitializes the task system.
 *
 * Outstanding tasks will not be cleaned up;
 * if the intent is to finish the core or frontend's work,
 * then all tasks must be finished before calling this function.
 * May be safely called multiple times in a row,
 * but only from the main thread.
 * @see task_queue_wait
 * @see task_queue_reset
 */
void task_queue_deinit(void);

/**
 * Initializes the task system with the provided parameters.
 * Must be called before any other task_queue_* function,
 * and must only be called from the main thread.
 *
 * @param threaded \c true if tasks should run on a separate thread,
 * \c false if they should remain on the calling thread.
 * All tasks run in sequence on a single thread.
 * If you want to scale a task to multiple threads,
 * you must do so within the task itself.
 * @param msg_push The task system will call this function to output messages.
 * If \c NULL, no messages will be output.
 * @note Calling this function while the task system is already initialized
 * will reinitialize it with the new parameters,
 * but it will not reset the task queue;
 * all existing tasks will continue to run
 * when the queue is updated.
 * @see task_queue_deinit
 * @see retro_task_queue_msg_t
 */
void task_queue_init(bool threaded, retro_task_queue_msg_t msg_push);

/**
 * Allocates and initializes a new task.
 * Deallocated by the task queue after it finishes executing.
 *
 * @returns Pointer to a newly allocated task,
 * or \c NULL if allocation fails.
 */
retro_task_t *task_init(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/retro_assert.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_assert.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RETRO_ASSERT_H
#define __RETRO_ASSERT_H

#include <assert.h>

#ifdef RARCH_INTERNAL
#include <stdio.h>
#define retro_assert(cond) ((void)( (cond) || (printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__), abort(), 0) ))
#else
#define retro_assert(cond) assert(cond)
#endif

#endif

./include/libretro-common/include/retro_common_api.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_common_api.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H

/*
This file is designed to normalize the libretro-common compiling environment
for public API headers. This should be leaner than a normal compiling environment,
since it gets #included into other project's sources.
*/

/* ------------------------------------ */

/*
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
headers to enable them to get used by c++ sources.
However, we want to support building this library as C++ as well, so a
special technique is called for.
*/

#define RETRO_BEGIN_DECLS
#define RETRO_END_DECLS

#ifdef __cplusplus

#ifdef CXX_BUILD
/* build wants everything to be built as c++, so no extern "C" */
#else
#undef RETRO_BEGIN_DECLS
#undef RETRO_END_DECLS
#define RETRO_BEGIN_DECLS extern "C" {
#define RETRO_END_DECLS }
#endif

#else

/* header is included by a C source file, so no extern "C" */

#endif

/*
IMO, this non-standard ssize_t should not be used.
However, it's a good example of how to handle something like this.
*/
#ifdef _MSC_VER
#ifndef HAVE_SSIZE_T
#define HAVE_SSIZE_T
#if defined(_WIN64)
typedef __int64 ssize_t;
#elif defined(_WIN32)
typedef int ssize_t;
#endif
#endif
#elif defined(__MACH__)
#include <sys/types.h>
#endif

#ifdef _MSC_VER
#if _MSC_VER >= 1800
#include <inttypes.h>
#else
#ifndef PRId64
#define PRId64 "I64d"
#define PRIu64 "I64u"
#define PRIuPTR "Iu"
#endif
#endif
#else
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
/* https://github.com/libretro/RetroArch/issues/6009 */
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h>
#endif
#ifndef PRId64
#error "inttypes.h is being screwy"
#endif
#define STRING_REP_INT64 "%" PRId64
#define STRING_REP_UINT64 "%" PRIu64
#define STRING_REP_USIZE "%" PRIuPTR

/* Wrap a declaration in RETRO_DEPRECATED() to produce a compiler warning when
it's used. This is intended for developer machines, so it won't work on ancient
or obscure compilers */
#if defined(_MSC_VER)
#if _MSC_VER >= 1400 /* Visual C 2005 or later */
#define RETRO_DEPRECATED(decl) __declspec(deprecated) decl
#endif
#elif defined(__GNUC__)
#if __GNUC__ >= 3 /* GCC 3 or later */
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
#endif
#elif defined(__clang__)
#if __clang_major__ >= 3 /* clang 3 or later */
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
#endif
#endif
#ifndef RETRO_DEPRECATED /* Unsupported compilers */
#define RETRO_DEPRECATED(decl) decl
#endif

/*
I would like to see retro_inline.h moved in here; possibly boolean too.

rationale: these are used in public APIs, and it is easier to find problems
and write code that works the first time portably when they are included uniformly
than to do the analysis from scratch each time you think you need it, for each feature.

Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
then you should pay the price everywhere, so you can see how much grief it will cause.

Of course, another school of thought is that you should do as little damage as possible
in as few places as possible...
*/

/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
#endif

./include/libretro-common/include/retro_common.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_common.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_COMMON_RETRO_COMMON_H
#define _LIBRETRO_COMMON_RETRO_COMMON_H

/*!
 * @internal This file is designed to normalize the libretro-common compiling environment.
 * It is not to be used in public API headers, as they should be designed as leanly as possible.
 * Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable,
 * in a public API, you may need this.
 */

/* conditional compilation is handled inside here */
#include <compat/msvc.h>

#endif

./include/libretro-common/include/retro_dirent.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_dirent.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RETRO_DIRENT_H
#define __RETRO_DIRENT_H

#include <libretro.h>
#include <retro_common_api.h>

#include <boolean.h>

/** @defgroup dirent Directory Entries
 * @{
 */

RETRO_BEGIN_DECLS

/**
 * The minimum VFS version (as defined in \c retro_vfs_interface_info::required_interface_version)
 * required by the \c dirent functions.
 * If no acceptable VFS interface is provided,
 * all dirent functions will fall back to libretro-common's implementations.
 * @see retro_vfs_interface_info
 */
#define DIRENT_REQUIRED_VFS_VERSION 3

/**
 * Installs a frontend-provided VFS interface for the dirent functions to use
 * instead of libretro-common's built-in implementations.
 *
 * @param vfs_info The VFS interface returned by the frontend.
 * The dirent functions will fall back to libretro-common's implementations
 * if \c vfs_info::required_interface_version is too low.
 * @see retro_vfs_interface_info
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info);

/**
 * Opaque handle to a directory entry (aka "dirent").
 * It may name a file, directory, or other filesystem object.
 * @see retro_opendir
 */
typedef struct RDIR RDIR;

/**
 * Opens a directory for reading.
 *
 * @param name Path to a directory to open.
 * @return An \c RDIR representing the given directory if successful.
 * Returns \c NULL if \c name is \c NULL, the empty string, or does not name a directory.
 * @note The returned \c RDIR must be closed with \c retro_closedir.
 * @see retro_opendir_include_hidden
 * @see retro_closedir
 */
struct RDIR *retro_opendir(const char *name);

/**
 * @copybrief retro_opendir
 *
 * @param name Path to the directory to open.
 * @param include_hidden Whether to include hidden files and directories
 * when iterating over this directory with \c retro_readdir.
 * Platforms and filesystems have different notions of "hidden" files.
 * Setting this to \c false will not prevent this function from opening \c name.
 * @return An \c RDIR representing the given directory if successful.
 * Returns \c NULL if \c name is \c NULL, the empty string, or does not name a directory.
 * @note The returned \c RDIR must be closed with \c retro_closedir.
 * @see retro_opendir
 * @see retro_closedir
 */
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden);

/**
 * Reads the next entry in the given directory.
 *
 * Here's a usage example that prints the names of all files in the current directory:
 * @code
 * struct RDIR *rdir = retro_opendir(".");
 * if (rdir)
 * {
 *    while (retro_readdir(rdir))
 *    {
 *       const char *name = retro_dirent_get_name(rdir);
 *       printf("%s\n", name);
 *    }
 *    retro_closedir(rdir);
 *    rdir = NULL;
 * }
 * @endcode
 *
 * @param rdir The directory to iterate over.
 * Behavior is undefined if \c NULL.
 * @return \c true if the next entry was read successfully,
 * \c false if there are no more entries to read or if there was an error.
 * @note This may include "." and ".." on Unix-like platforms.
 * @see retro_dirent_get_name
 * @see retro_dirent_is_dir
 */
int retro_readdir(struct RDIR *rdir);

/**
 * @deprecated Left for compatibility.
 * @param rdir Ignored.
 * @return \c false.
 */
bool retro_dirent_error(struct RDIR *rdir);

/**
 * Gets the name of the dirent's current file or directory.
 *
 * @param rdir The dirent to get the name of.
 * Behavior is undefined if \c NULL.
 * @return The name of the directory entry (file, directory, etc.) that the dirent points to.
 * Will return \c NULL if there was an error,
 * \c retro_readdir has not been called on \c rdir,
 * or if there are no more entries to read.
 * @note This returns only a name, not a full path.
 * @warning The returned string is managed by the VFS implementation
 * and must not be modified or freed by the caller.
 * @warning The returned string is only valid until the next call to \c retro_readdir.
 * @see retro_readdir
 */
const char *retro_dirent_get_name(struct RDIR *rdir);

/**
 * Checks if the given \c RDIR's current dirent names a directory.
 *
 * @param rdir The directory entry to check.
 * Behavior is undefined if \c NULL.
 * @param unused Ignored for compatibility reasons. Pass \c NULL.
 * @return \c true if \c rdir refers to a directory, otherwise \c false.
 * @see retro_readdir
 */
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused);

/**
 * Closes an opened \c RDIR that was returned by \c retro_opendir.
 *
 * @param rdir The directory entry to close.
 * If \c NULL, this function does nothing.
 * @see retro_vfs_closedir_t
 */
void retro_closedir(struct RDIR *rdir);

RETRO_END_DECLS

/** @} */

#endif

./include/libretro-common/include/retro_endianness.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_endianness.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ENDIANNESS_H
#define __LIBRETRO_SDK_ENDIANNESS_H

#include <retro_inline.h>
#include <stdint.h>
#include <stdlib.h>

#if defined(_MSC_VER) && _MSC_VER > 1200
#define SWAP16 _byteswap_ushort
#define SWAP32 _byteswap_ulong
#else
/**
 * Swaps the byte order of a 16-bit unsigned integer.
 * @param x The integer to byteswap.
 * @return \c with its two bytes swapped.
 */
static INLINE uint16_t SWAP16(uint16_t x)
{
  return ((x & 0x00ff) << 8) |
         ((x & 0xff00) >> 8);
}

/**
 * Swaps the byte order of a 32-bit unsigned integer.
 * @param x The integer to byteswap.
 * @return \c with its bytes swapped.
 */
static INLINE uint32_t SWAP32(uint32_t x)
{
  return ((x & 0x000000ff) << 24) |
         ((x & 0x0000ff00) <<  8) |
         ((x & 0x00ff0000) >>  8) |
         ((x & 0xff000000) >> 24);
}

#endif

#if defined(_MSC_VER) && _MSC_VER <= 1200
static INLINE uint64_t SWAP64(uint64_t val)
{
  return
      ((val & 0x00000000000000ff) << 56)
    | ((val & 0x000000000000ff00) << 40)
    | ((val & 0x0000000000ff0000) << 24)
    | ((val & 0x00000000ff000000) << 8)
    | ((val & 0x000000ff00000000) >> 8)
    | ((val & 0x0000ff0000000000) >> 24)
    | ((val & 0x00ff000000000000) >> 40)
    | ((val & 0xff00000000000000) >> 56);
}
#else
/**
 * Swaps the byte order of a 64-bit unsigned integer.
 * @param x The integer to byteswap.
 * @return \c with its bytes swapped.
 */
static INLINE uint64_t SWAP64(uint64_t val)
{
  return   ((val & 0x00000000000000ffULL) << 56)
	 | ((val & 0x000000000000ff00ULL) << 40)
	 | ((val & 0x0000000000ff0000ULL) << 24)
	 | ((val & 0x00000000ff000000ULL) << 8)
	 | ((val & 0x000000ff00000000ULL) >> 8)
	 | ((val & 0x0000ff0000000000ULL) >> 24)
	 | ((val & 0x00ff000000000000ULL) >> 40)
         | ((val & 0xff00000000000000ULL) >> 56);
}
#endif

#ifdef _MSC_VER
/* MSVC pre-defines macros depending on target arch */
#if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_M_ARM64)
#ifndef LSB_FIRST
#define LSB_FIRST 1
#endif
#elif _M_PPC
#ifndef MSB_FIRST
#define MSB_FIRST 1
#endif
#else
/* MSVC can run on _M_ALPHA and _M_IA64 too, but they're both bi-endian; need to find what mode MSVC runs them at */
#error "unknown platform, can't determine endianness"
#endif
#else
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#ifndef MSB_FIRST
#define MSB_FIRST 1
#endif
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#ifndef LSB_FIRST
#define LSB_FIRST 1
#endif
#else
#error "Invalid endianness macros"
#endif
#endif

#if defined(MSB_FIRST) && defined(LSB_FIRST)
#  error "Bug in LSB_FIRST/MSB_FIRST definition"
#endif

#if !defined(MSB_FIRST) && !defined(LSB_FIRST)
#  error "Bug in LSB_FIRST/MSB_FIRST definition"
#endif

#ifdef MSB_FIRST
#  define RETRO_IS_BIG_ENDIAN 1
#  define RETRO_IS_LITTLE_ENDIAN 0
/* For compatibility */
#  define WORDS_BIGENDIAN 1
#else
#  define RETRO_IS_BIG_ENDIAN 0
#  define RETRO_IS_LITTLE_ENDIAN 1
/* For compatibility */
#  undef WORDS_BIGENDIAN
#endif


/**
 * Checks if the current CPU is little-endian.
 *
 * @return \c true on little-endian CPUs,
 * \c false on big-endian CPUs.
 */
#define is_little_endian() RETRO_IS_LITTLE_ENDIAN

/**
 * Byte-swaps an unsigned 64-bit integer on big-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on big-endian CPUs,
 * \c val unchanged on little-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_big64(val) (SWAP64(val))
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big64(val) (val)
#endif

/**
 * Byte-swaps an unsigned 32-bit integer on big-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on big-endian CPUs,
 * \c val unchanged on little-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_big32(val) (SWAP32(val))
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big32(val) (val)
#endif

/**
 * Byte-swaps an unsigned 64-bit integer on little-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on little-endian CPUs,
 * \c val unchanged on big-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_little64(val) (val)
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little64(val) (SWAP64(val))
#endif

/**
 * Byte-swaps an unsigned 32-bit integer on little-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on little-endian CPUs,
 * \c val unchanged on big-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_little32(val) (val)
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little32(val) (SWAP32(val))
#endif

/**
 * Byte-swaps an unsigned 16-bit integer on big-endian systems.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on big-endian systems,
 * \c val unchanged on little-endian systems.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_big16(val) (SWAP16(val))
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big16(val) (val)
#endif

/**
 * Byte-swaps an unsigned 16-bit integer on little-endian systems.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on little-endian systems,
 * \c val unchanged on big-endian systems.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_little16(val) (val)
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little16(val) (SWAP16(val))
#endif

/**
 * Stores a 32-bit integer in at the given address, in big-endian order.
 *
 * @param addr The address to store the value at.
 * Behavior is undefined if \c NULL or not aligned to a 32-bit boundary.
 * @param data The value to store in \c addr.
 * Will be byteswapped if on a little-endian CPU.
 */
static INLINE void store32be(uint32_t *addr, uint32_t data)
{
   *addr = swap_if_little32(data);
}

/**
 * Loads a 32-bit integer order from the given address, in big-endian order.
 *
 * @param addr The address to load the value from.
 * Behavior is undefined if \c NULL or not aligned to a 32-bit boundary.
 * @return The value at \c addr, byteswapped if on a little-endian CPU.
 */
static INLINE uint32_t load32be(const uint32_t *addr)
{
   return swap_if_little32(*addr);
}

/**
 * Converts the given unsigned 16-bit integer to little-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_le16(val) swap_if_big16(val)

/**
 * Converts the given unsigned 32-bit integer to little-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_le32(val) swap_if_big32(val)

/**
 * Converts the given unsigned 64-bit integer to little-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_le64(val) swap_if_big64(val)

/**
 * Converts the given unsigned 16-bit integer to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_le_to_cpu16(val) swap_if_big16(val)

/**
 * Converts the given unsigned 32-bit integer to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_le_to_cpu32(val) swap_if_big32(val)

/**
 * Converts the given unsigned 64-bit integer to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_le_to_cpu64(val) swap_if_big64(val)

/**
 * Converts the given unsigned 16-bit integer to big-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_be16(val) swap_if_little16(val)

/**
 * Converts the given unsigned 32-bit integer to big-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_be32(val) swap_if_little32(val)

/**
 * Converts the given unsigned 64-bit integer to big-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_be64(val) swap_if_little64(val)

/**
 * Converts the given unsigned 16-bit integer from big-endian to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_be_to_cpu16(val) swap_if_little16(val)

/**
 * Converts the given unsigned 32-bit integer from big-endian to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_be_to_cpu32(val) swap_if_little32(val)

/**
 * Converts the given unsigned 64-bit integer from big-endian to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_be_to_cpu64(val) swap_if_little64(val)

#ifdef  __GNUC__
/**
 * This attribute indicates that pointers to this type may alias
 * to pointers of any other type, similar to \c void* or \c char*.
 */
#define MAY_ALIAS  __attribute__((__may_alias__))
#else
#define MAY_ALIAS
#endif

#pragma pack(push, 1)
struct retro_unaligned_uint16_s
{
  uint16_t val;
} MAY_ALIAS;
struct retro_unaligned_uint32_s
{
  uint32_t val;
} MAY_ALIAS;
struct retro_unaligned_uint64_s
{
  uint64_t val;
} MAY_ALIAS;
#pragma pack(pop)

/**
 * A wrapper around a \c uint16_t that allows unaligned access
 * where supported by the compiler.
 */
typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;

/**
 * A wrapper around a \c uint32_t that allows unaligned access
 * where supported by the compiler.
 */
typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;

/**
 * A wrapper around a \c uint64_t that allows unaligned access
 * where supported by the compiler.
 */
typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;

/* L-value references to unaligned pointers.  */
#define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)->val)
#define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)->val)
#define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)->val)

/**
 * Reads a 16-bit unsigned integer from the given address
 * and converts it from big-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @return The first two bytes of \c addr as a 16-bit unsigned integer,
 * byteswapped from big-endian to host-native order if necessary.
 */
static INLINE uint16_t retro_get_unaligned_16be(void *addr)
{
   return retro_be_to_cpu16(retro_unaligned16(addr));
}

/**
 * Reads a 32-bit unsigned integer from the given address
 * and converts it from big-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @return The first four bytes of \c addr as a 32-bit unsigned integer,
 * byteswapped from big-endian to host-native order if necessary.
 */
static INLINE uint32_t retro_get_unaligned_32be(void *addr)
{
   return retro_be_to_cpu32(retro_unaligned32(addr));
}

/**
 * Reads a 64-bit unsigned integer from the given address
 * and converts it from big-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @return The first eight bytes of \c addr as a 64-bit unsigned integer,
 * byteswapped from big-endian to host-native order if necessary.
 */
static INLINE uint64_t retro_get_unaligned_64be(void *addr)
{
   return retro_be_to_cpu64(retro_unaligned64(addr));
}

/**
 * Reads a 16-bit unsigned integer from the given address
 * and converts it from little-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @return The first two bytes of \c addr as a 16-bit unsigned integer,
 * byteswapped from little-endian to host-native order if necessary.
 */
static INLINE uint16_t retro_get_unaligned_16le(void *addr)
{
   return retro_le_to_cpu16(retro_unaligned16(addr));
}

/**
 * Reads a 32-bit unsigned integer from the given address
 * and converts it from little-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @return The first four bytes of \c addr as a 32-bit unsigned integer,
 * byteswapped from little-endian to host-native order if necessary.
 */
static INLINE uint32_t retro_get_unaligned_32le(void *addr)
{
   return retro_le_to_cpu32(retro_unaligned32(addr));
}

/**
 * Reads a 64-bit unsigned integer from the given address
 * and converts it from little-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @return The first eight bytes of \c addr as a 64-bit unsigned integer,
 * byteswapped from little-endian to host-native order if necessary.
 */
static INLINE uint64_t retro_get_unaligned_64le(void *addr)
{
   return retro_le_to_cpu64(retro_unaligned64(addr));
}

/**
 * Writes a 16-bit unsigned integer to the given address
 * (converted to little-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v)
{
   retro_unaligned16(addr) = retro_cpu_to_le16(v);
}

/**
 * Writes a 32-bit unsigned integer to the given address
 * (converted to little-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v)
{
   retro_unaligned32(addr) = retro_cpu_to_le32(v);
}

/**
 * Writes a 64-bit unsigned integer to the given address
 * (converted to little-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v)
{
   retro_unaligned64(addr) = retro_cpu_to_le64(v);
}

/**
 * Writes a 16-bit unsigned integer to the given address
 * (converted to big-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v)
{
   retro_unaligned16(addr) = retro_cpu_to_be16(v);
}

/**
 * Writes a 32-bit unsigned integer to the given address
 * (converted to big-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v)
{
   retro_unaligned32(addr) = retro_cpu_to_be32(v);
}

/**
 * Writes a 64-bit unsigned integer to the given address
 * (converted to big-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v)
{
   retro_unaligned64(addr) = retro_cpu_to_be64(v);
}


#endif

./include/libretro-common/include/retro_environment.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_environment.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ENVIRONMENT_H
#define __LIBRETRO_SDK_ENVIRONMENT_H

/*
This file is designed to create a normalized environment for compiling
libretro-common's private implementations, or any other sources which might
enjoy use of it's environment (RetroArch for instance).
This should be an elaborately crafted environment so that sources don't
need to be full of platform-specific workarounds.
*/

#if defined (__cplusplus)
#if 0
printf("This is C++, version %d.\n", __cplusplus);
#endif
/* The expected values would be
 *   199711L, for ISO/IEC 14882:1998 or 14882:2003
 */

#elif defined(__STDC__)
/* This is standard C. */

#if (__STDC__ == 1)
/* The implementation is ISO-conforming. */
#define __STDC_ISO__
#else
/* The implementation is not ISO-conforming. */
#endif

#if defined(__STDC_VERSION__)
#if (__STDC_VERSION__ >= 201112L)
/* This is C11. */
#define __STDC_C11__
#elif (__STDC_VERSION__ >= 199901L)
/* This is C99. */
#define __STDC_C99__
#elif (__STDC_VERSION__ >= 199409L)
/* This is C89 with amendment 1. */
#define __STDC_C89__
#define __STDC_C89_AMENDMENT_1__
#else
/* This is C89 without amendment 1. */
#define __STDC_C89__
#endif
#else /* !defined(__STDC_VERSION__) */
/* This is C89. __STDC_VERSION__ is not defined. */
#define __STDC_C89__
#endif

#else   /* !defined(__STDC__) */
/* This is not standard C. __STDC__ is not defined. */
#endif

#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
/* Try to find out if we're compiling for WinRT or non-WinRT */
#if defined(_MSC_VER) && defined(__has_include)
#if __has_include(<winapifamily.h>)
#define HAVE_WINAPIFAMILY_H 1
#else
#define HAVE_WINAPIFAMILY_H 0
#endif

/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */
#define HAVE_WINAPIFAMILY_H 1
#else
#define HAVE_WINAPIFAMILY_H 0
#endif

#if HAVE_WINAPIFAMILY_H
#include <winapifamily.h>
#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
#else
#define WINAPI_FAMILY_WINRT 0
#endif /* HAVE_WINAPIFAMILY_H */

#if WINAPI_FAMILY_WINRT
#undef __WINRT__
#define __WINRT__ 1
#endif

/* MSVC obviously has to have some non-standard constants... */
#if _M_IX86_FP == 1
#define __SSE__ 1
#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))
#define __SSE__ 1
#define __SSE2__ 1
#endif

#endif

#endif

./include/libretro-common/include/retro_inline.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_inline.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_INLINE_H
#define __LIBRETRO_SDK_INLINE_H

#ifndef INLINE

/**
 * Cross-platform inline specifier.
 *
 * Expands to something like \c __inline or \c inline,
 * depending on the compiler.
 */
#if defined(_WIN32) || defined(__INTEL_COMPILER)
#define INLINE __inline
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
#define INLINE inline
#elif defined(__GNUC__)
#define INLINE __inline__
#else
#define INLINE
#endif

#endif
#endif

./include/libretro-common/include/retro_math.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_math.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_COMMON_MATH_H
#define _LIBRETRO_COMMON_MATH_H

#include <stdint.h>
#include <stdlib.h>

#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif

#include <limits.h>

#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
#include <retro_inline.h>

#ifndef M_PI
#if !defined(USE_MATH_DEFINES)
#define M_PI 3.14159265358979323846264338327
#endif
#endif

#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

/**
 * next_pow2:
 * @v         : initial value
 *
 * Get next power of 2 value based on  initial value.
 *
 * Returns: next power of 2 value (derived from @v).
 **/
static INLINE uint32_t next_pow2(uint32_t v)
{
   v--;
   v |= v >> 1;
   v |= v >> 2;
   v |= v >> 4;
   v |= v >> 8;
   v |= v >> 16;
   v++;
   return v;
}

/**
 * prev_pow2:
 * @v         : initial value
 *
 * Get previous power of 2 value based on initial value.
 *
 * Returns: previous power of 2 value (derived from @v).
 **/
static INLINE uint32_t prev_pow2(uint32_t v)
{
   v |= v >> 1;
   v |= v >> 2;
   v |= v >> 4;
   v |= v >> 8;
   v |= v >> 16;
   return v - (v >> 1);
}

/**
 * clamp:
 * @v         : initial value
 *
 * Get the clamped value based on initial value.
 *
 * Returns: clamped value (derived from @v).
 **/
static INLINE float clamp_value(float v, float min, float max)
{
   return v <= min ? min : v >= max ? max : v;
}

/**
 * saturate_value:
 * @v         : initial value
 *
 * Get the clamped 0.0-1.0 value based on initial value.
 *
 * Returns: clamped 0.0-1.0 value (derived from @v).
 **/
static INLINE float saturate_value(float v)
{
   return clamp_value(v, 0.0f, 1.0f);
}

/**
 * dot_product:
 * @a         : left hand vector value
 * @b         : right hand vector value
 *
 * Get the dot product of the two passed in vectors.
 *
 * Returns: dot product value (derived from @a and @b).
 **/
static INLINE float dot_product(const float* a, const float* b)
{
   return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
}

/**
 * convert_rgb_to_yxy:
 * @rgb         : in RGB colour space value
 * @Yxy         : out Yxy colour space value
 *
 * Convert from RGB colour space to Yxy colour space.
 *
 * Returns: Yxy colour space value (derived from @rgb).
 **/
static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)
{
   float inv;
   float xyz[3];
   float one[3]        = {1.0, 1.0, 1.0};
   float rgb_xyz[3][3] = {
      {0.4124564, 0.3575761, 0.1804375},
      {0.2126729, 0.7151522, 0.0721750},
      {0.0193339, 0.1191920, 0.9503041}
   };

   xyz[0]              = dot_product(rgb_xyz[0], rgb);
   xyz[1]              = dot_product(rgb_xyz[1], rgb);
   xyz[2]              = dot_product(rgb_xyz[2], rgb);

   inv                 = 1.0f / dot_product(xyz, one);
   Yxy[0]              = xyz[1];
   Yxy[1]              = xyz[0] * inv;
   Yxy[2]              = xyz[1] * inv;
}

/**
 * convert_yxy_to_rgb:
 * @rgb         : in Yxy colour space value
 * @Yxy         : out rgb colour space value
 *
 * Convert from Yxy colour space to rgb colour space.
 *
 * Returns: rgb colour space value (derived from @Yxy).
 **/
static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
{
   float xyz[3];
   float xyz_rgb[3][3] = {
      {3.2404542, -1.5371385, -0.4985314},
      {-0.9692660, 1.8760108,  0.0415560},
      {0.0556434, -0.2040259, 1.0572252}
   };
   xyz[0]              = Yxy[0] * Yxy[1] / Yxy[2];
   xyz[1]              = Yxy[0];
   xyz[2]              = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];

   rgb[0]              = dot_product(xyz_rgb[0], xyz);
   rgb[1]              = dot_product(xyz_rgb[1], xyz);
   rgb[2]              = dot_product(xyz_rgb[2], xyz);
}

/**
 * Picks a random value between a specified range.
 *
 * @param \c min unsigned minimum possible value.
 * @param \c max unsigned maximum possible value.
 *
 * @return unsigned random value between \c min and \c max (inclusive).
 */
static INLINE size_t random_range(unsigned min, unsigned max)
{
   return (min == max) ? min : (size_t)((float)rand() / (float)RAND_MAX * (max + 1 - min) + min);
}

#endif

./include/libretro-common/include/retro_miscellaneous.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_miscellaneous.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RARCH_MISCELLANEOUS_H
#define __RARCH_MISCELLANEOUS_H

#define RARCH_MAX_SUBSYSTEMS 10
#define RARCH_MAX_SUBSYSTEM_ROMS 10

#include <stdint.h>
#include <boolean.h>
#include <retro_inline.h>

#if defined(_WIN32)

#if defined(_XBOX)
#include <Xtl.h>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif

#endif

#include <limits.h>

#ifdef _MSC_VER
#include <compat/msvc.h>
#endif

#ifdef IOS
#include <sys/param.h>
#endif

/**
 * Computes the bitwise OR of two bit arrays.
 *
 * @param a[in,out] The first bit array, and the location of the result.
 * @param b[in] The second bit array.
 * @param count The length of each bit array, in 32-bit words.
 */
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
{
   uint32_t i;
   for (i = 0; i < count;i++)
      a[i] |= b[i];
}

/**
 * Clears every bit in \c a that is set in \c b.
 *
 * @param a[in,out] The bit array to modify.
 * @param b[in] The bit array to use for reference.
 * @param count The length of each bit array, in 32-bit words
 * (\em not bits or bytes).
 */
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
{
   uint32_t i;
   for (i = 0; i < count;i++)
      a[i] &= ~b[i];
}

/**
 * Checks if any bits in \c ptr are set.
 *
 * @param ptr The bit array to check.
 * @param count The length of the buffer pointed to by \c ptr, in 32-bit words
 * (\em not bits or bytes).
 * @return \c true if any bit in \c ptr is set,
 * \c false if all bits are clear (zero).
 */
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
{
   uint32_t i;
   for (i = 0; i < count; i++)
   {
      if (ptr[i] != 0)
         return true;
   }
   return false;
}

/**
 * Checks if any bits in \c a are different from those in \c b.
 *
 * @param a The first bit array to compare.
 * @param b The second bit array to compare.
 * @param count The length of each bit array, in 32-bit words
 * (\em not bits or bytes).
 * @return \c true if \c and \c differ by at least one bit,
 * \c false if they're both identical.
 */
static INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count)
{
   uint32_t i;
   for (i = 0; i < count; i++)
   {
      if (a[i] != b[i])
         return true;
   }
   return false;
}

/**
 * An upper limit for the length of a path (including the filename).
 * If a path is longer than this, it may not work properly.
 * This value may vary by platform.
 */

#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__) || defined(HAVE_EMSCRIPTEN)

#ifndef PATH_MAX_LENGTH
#define PATH_MAX_LENGTH 512
#endif

#ifndef DIR_MAX_LENGTH
#define DIR_MAX_LENGTH 256
#endif

/**
 * An upper limit for the length of a file or directory (excluding parent directories).
 * If a path has a component longer than this, it may not work properly.
 */
#ifndef NAME_MAX_LENGTH
#define NAME_MAX_LENGTH 128
#endif

#else

#ifndef PATH_MAX_LENGTH
#define PATH_MAX_LENGTH 2048
#endif

#ifndef DIR_MAX_LENGTH
#define DIR_MAX_LENGTH 1024
#endif

/**
 * An upper limit for the length of a file or directory (excluding parent directories).
 * If a path has a component longer than this, it may not work properly.
 */
#ifndef NAME_MAX_LENGTH
#define NAME_MAX_LENGTH 256
#endif

#endif


#ifndef MAX
/**
 * @return \c a or \c b, whichever is larger.
 */
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

#ifndef MIN
/**
 * @return \c a or \c b, whichever is smaller.
 */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

/**
 * Gets the number of elements in an array whose size is known at compile time.
 * @param a An array of fixed length.
 * @return The number of elements in \c a.
 */
#define ARRAY_SIZE(a)              (sizeof(a) / sizeof((a)[0]))

/** @defgroup BITS Bit Arrays
 *
 * @{
 */

#define BITS_GET_ELEM(a, i)        ((a).data[i])
#define BITS_GET_ELEM_PTR(a, i)    ((a)->data[i])

/** @defgroup BIT_ Arbitrary-length Bit Arrays
 *
 * @{
 */

/**
 * Sets a particular bit within a bit array to 1.
 *
 * @param a A \c uint8_t array,
 * treated here as a bit vector.
 * @param bit Index of the bit to set, where 0 is the least significant.
 */
#define BIT_SET(a, bit)   ((a)[(bit) >> 3] |=  (1 << ((bit) & 7)))

/**
 * Clears a particular bit within a bit array.
 *
 * @param a A \c uint8_t array,
 * treated here as a bit vector.
 * @param bit Index of the bit to clear, where 0 is the least significant.
 */
#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))

/**
 * Gets the value of a particular bit within a bit array.
 *
 * @param a A \c uint8_t array,
 * treated here as a bit vector.
 * @param bit Index of the bit to get, where 0 is the least significant.
 * @return The value of the bit at the specified index.
 */
#define BIT_GET(a, bit)   (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)

/** @} */

/** @defgroup BIT16 16-bit Bit Arrays
 *
 * @{
 */

/**
 * Sets a particular bit within a 16-bit integer to 1.
 * @param a An unsigned 16-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to set, where 0 is the least significant and 15 is the most.
 */
#define BIT16_SET(a, bit)    ((a) |=  (1 << ((bit) & 15)))

/**
 * Clears a particular bit within a 16-bit integer.
 *
 * @param a An unsigned 16-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to clear, where 0 is the least significant and 15 is the most.
 */
#define BIT16_CLEAR(a, bit)  ((a) &= ~(1 << ((bit) & 15)))

/**
 * Gets the value of a particular bit within a 16-bit integer.
 *
 * @param a An unsigned 16-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to get, where 0 is the least significant and 15 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT16_GET(a, bit)    (((a) >> ((bit) & 15)) & 1)

/**
 * Clears all bits in a 16-bit bitmask.
 */
#define BIT16_CLEAR_ALL(a)   ((a) = 0)

/** @} */

/** @defgroup BIT32 32-bit Bit Arrays
 *
 * @{
 */

/**
 * Sets a particular bit within a 32-bit integer to 1.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to set, where 0 is the least significant and 31 is the most.
 */
#define BIT32_SET(a, bit)    ((a) |=  (UINT32_C(1) << ((bit) & 31)))

/**
 * Clears a particular bit within a 32-bit integer.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to clear, where 0 is the least significant and 31 is the most.
 */
#define BIT32_CLEAR(a, bit)  ((a) &= ~(UINT32_C(1) << ((bit) & 31)))

/**
 * Gets the value of a particular bit within a 32-bit integer.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to get, where 0 is the least significant and 31 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT32_GET(a, bit)    (((a) >> ((bit) & 31)) & 1)

/**
 * Clears all bits in a 32-bit bitmask.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 */
#define BIT32_CLEAR_ALL(a)   ((a) = 0)

/** @} */

/**
 * @defgroup BIT64 64-bit Bit Arrays
 * @{
 */

/**
 * Sets a particular bit within a 64-bit integer to 1.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to set, where 0 is the least significant and 63 is the most.
 */
#define BIT64_SET(a, bit)    ((a) |=  (UINT64_C(1) << ((bit) & 63)))

/**
 * Clears a particular bit within a 64-bit integer.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to clear, where 0 is the least significant and 63 is the most.
 */
#define BIT64_CLEAR(a, bit)  ((a) &= ~(UINT64_C(1) << ((bit) & 63)))

/**
 * Gets the value of a particular bit within a 64-bit integer.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to get, where 0 is the least significant and 63 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT64_GET(a, bit)    (((a) >> ((bit) & 63)) & 1)

/**
 * Clears all bits in a 64-bit bitmask.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 */
#define BIT64_CLEAR_ALL(a)   ((a) = 0)

/** @} */

#define BIT128_SET(a, bit)   ((a).data[(bit) >> 5] |=  (UINT32_C(1) << ((bit) & 31)))
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))
#define BIT128_GET(a, bit)   (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
#define BIT128_CLEAR_ALL(a)  memset(&(a), 0, sizeof(a))

#define BIT128_SET_PTR(a, bit)   BIT128_SET(*a, bit)
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
#define BIT128_GET_PTR(a, bit)   BIT128_GET(*a, bit)
#define BIT128_CLEAR_ALL_PTR(a)  BIT128_CLEAR_ALL(*a)

/**
 * Sets a single bit from a 256-bit \c retro_bits_t to 1.
 *
 * @param a A 256-bit \c retro_bits_t.
 * @param bit Index of the bit to set,
 * where 0 is the least significant and 255 is the most.
 */
#define BIT256_SET(a, bit)       BIT128_SET(a, bit)

/**
 * Clears a single bit from a 256-bit \c retro_bits_t.
 *
 * @param a A 256-bit \c retro_bits_t.
 * @param bit Index of the bit to clear,
 * where 0 is the least significant and 255 is the most.
 */
#define BIT256_CLEAR(a, bit)     BIT128_CLEAR(a, bit)

/**
 * Gets the value of a single bit from a 256-bit \c retro_bits_t.
 *
 * @param a A 256-bit \c retro_bits_t.
 * @param bit Index of the bit to get,
 * where 0 is the least significant and 255 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT256_GET(a, bit)       BIT128_GET(a, bit)

/**
 * Clears all bits in a 256-bit \c retro_bits_t.
 *
 * @param a A 256-bit \c retro_bits_t.
 */
#define BIT256_CLEAR_ALL(a)      BIT128_CLEAR_ALL(a)

/** Variant of BIT256_SET() that takes a pointer to a \c retro_bits_t. */
#define BIT256_SET_PTR(a, bit)   BIT256_SET(*a, bit)

/** Variant of BIT256_CLEAR() that takes a pointer to a \c retro_bits_t. */
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)

/** Variant of BIT256_GET() that takes a pointer to a \c retro_bits_t. */
#define BIT256_GET_PTR(a, bit)   BIT256_GET(*a, bit)

/** Variant of BIT256_CLEAR_ALL() that takes a pointer to a \c retro_bits_t. */
#define BIT256_CLEAR_ALL_PTR(a)  BIT256_CLEAR_ALL(*a)

/**
 * Sets a single bit from a 512-bit \c retro_bits_512_t to 1.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 * @param bit Index of the bit to set,
 * where 0 is the least significant and 511 is the most.
 */
#define BIT512_SET(a, bit)       BIT256_SET(a, bit)

/**
 * Clears a single bit from a 512-bit \c retro_bits_512_t.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 * @param bit Index of the bit to clear,
 * where 0 is the least significant and 511 is the most.
 */
#define BIT512_CLEAR(a, bit)     BIT256_CLEAR(a, bit)

/**
 * Gets the value of a single bit from a 512-bit \c retro_bits_512_t.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 * @param bit Index of the bit to get,
 * where 0 is the least significant and 511 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT512_GET(a, bit)       BIT256_GET(a, bit)

/**
 * Clears all bits in a 512-bit \c retro_bits_512_t.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 */
#define BIT512_CLEAR_ALL(a)      BIT256_CLEAR_ALL(a)

/** Variant of BIT512_SET() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_SET_PTR(a, bit)   BIT512_SET(*a, bit)

/** Variant of BIT512_CLEAR() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)

/** Variant of BIT512_GET() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_GET_PTR(a, bit)   BIT512_GET(*a, bit)

/** Variant of BIT512_CLEAR_ALL() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_CLEAR_ALL_PTR(a)  BIT512_CLEAR_ALL(*a)

#define BITS_COPY16_PTR(a,bits) \
{ \
   BIT128_CLEAR_ALL_PTR(a); \
   BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
}

#define BITS_COPY32_PTR(a,bits) \
{ \
   BIT128_CLEAR_ALL_PTR(a); \
   BITS_GET_ELEM_PTR(a, 0) = (bits); \
}

#define BITS_COPY64_PTR(a,bits) \
{ \
   BIT128_CLEAR_ALL_PTR(a); \
   BITS_GET_ELEM_PTR(a, 0) = (bits); \
   BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \
}

/* Helper macros and struct to keep track of many booleans. */

/** A 256-bit boolean array. */
typedef struct
{
   /** @private 256 bits. Not intended for direct use. */
   uint32_t data[8];
} retro_bits_t;

/** A 512-bit boolean array. */
typedef struct
{
   /** @private 512 bits. Not intended for direct use. */
   uint32_t data[16];
} retro_bits_512_t;

/** @} */

#ifdef _WIN32
#  ifdef _WIN64
#    define PRI_SIZET PRIu64
#  else
#    if _MSC_VER == 1800
#      define PRI_SIZET PRIu32
#    else
#      define PRI_SIZET "u"
#    endif
#  endif
#elif defined(PS2)
#  define PRI_SIZET "u"
#else
#  if (SIZE_MAX == 0xFFFF)
#    define PRI_SIZET "hu"
#  elif (SIZE_MAX == 0xFFFFFFFF)
#    define PRI_SIZET "u"
#  elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
#    define PRI_SIZET "lu"
#  else
#    error PRI_SIZET: unknown SIZE_MAX
#  endif
#endif

#endif

./include/libretro-common/include/retro_stat.h

/* Copyright  (C) 2010-2016 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_stat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RETRO_STAT_H
#define __RETRO_STAT_H

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

#include <boolean.h>

RETRO_BEGIN_DECLS

/**
 * path_is_directory:
 * @path               : path
 *
 * Checks if path is a directory.
 *
 * Returns: true (1) if path is a directory, otherwise false (0).
 */
bool path_is_directory(const char *path);

bool path_is_character_special(const char *path);

bool path_is_valid(const char *path);

int32_t path_get_size(const char *path);

/**
 * path_mkdir_norecurse:
 * @dir                : directory
 *
 * Create directory on filesystem.
 *
 * Returns: true (1) if directory could be created, otherwise false (0).
 **/
bool mkdir_norecurse(const char *dir);

RETRO_END_DECLS

#endif

./include/libretro-common/include/retro_timers.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_timers.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_COMMON_TIMERS_H
#define __LIBRETRO_COMMON_TIMERS_H

#include <stdint.h>

#if defined(XENON)
#include <time/time.h>
#elif !defined(__PSL1GHT__) && defined(__PS3__)
#include <sys/timer.h>
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
#include <unistd.h>
#elif defined(WIIU)
#include <wiiu/os/thread.h>
#elif defined(PSP)
#include <pspthreadman.h>
#elif defined(VITA)
#include <psp2/kernel/threadmgr.h>
#elif defined(_3DS)
#include <3ds.h>
#else
#include <time.h>
#endif

#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif

#include <limits.h>

#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
#include <retro_inline.h>

#ifdef DJGPP
#define timespec timeval
#define tv_nsec tv_usec
#include <unistd.h>

extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
{
   usleep(1000000L * rqtp->tv_sec + rqtp->tv_nsec / 1000);

   if (rmtp)
      rmtp->tv_sec = rmtp->tv_nsec=0;

   return 0;
}

#define nanosleep nanosleepDOS
#endif

/**
 * Briefly suspends the running thread.
 *
 * @param msec The time to sleep for, in milliseconds.
 **/
#if defined(VITA)
#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))
#elif defined(_3DS)
#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
#define retro_sleep(msec) (SleepEx((msec), FALSE))
#elif defined(_WIN32)
#define retro_sleep(msec) (Sleep((msec)))
#elif defined(XENON)
#define retro_sleep(msec) (udelay(1000 * (msec)))
#elif !defined(__PSL1GHT__) && defined(__PS3__)
#define retro_sleep(msec) (sys_timer_usleep(1000 * (msec)))
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
#define retro_sleep(msec) (usleep(1000 * (msec)))
#elif defined(WIIU)
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
#elif defined(__EMSCRIPTEN__)
/* defined in frontend */
#ifdef __cplusplus
extern "C" {
#endif
void retro_sleep(unsigned msec);
#ifdef __cplusplus
}
#endif
#else
static INLINE void retro_sleep(unsigned msec)
{
   struct timespec tv;
   tv.tv_sec          = msec / 1000;
   tv.tv_nsec         = (msec % 1000) * 1000000;
   nanosleep(&tv, NULL);
}
#endif

#endif

./include/libretro-common/include/rthreads/async_job.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (async_job.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ASYNC_JOB_H
#define __LIBRETRO_SDK_ASYNC_JOB_H

typedef struct async_job async_job_t;
typedef void (*async_task_t)(void *payload);

async_job_t *async_job_new(void);

void async_job_free(async_job_t *ajob);

int async_job_add(async_job_t *ajob, async_task_t task, void *payload);

#endif /* __LIBRETRO_SDK_ASYNC_JOB_H */

./include/libretro-common/include/rthreads/rthreads.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rthreads.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_RTHREADS_H__
#define __LIBRETRO_SDK_RTHREADS_H__

#include <retro_common_api.h>

#include <boolean.h>
#include <stdint.h>
#include <retro_inline.h>
#include <retro_miscellaneous.h>

RETRO_BEGIN_DECLS

/** Platform-agnostic handle to a thread. */
typedef struct sthread sthread_t;

/** Platform-agnostic handle to a mutex. */
typedef struct slock slock_t;

/** Platform-agnostic handle to a condition variable. */
typedef struct scond scond_t;

#ifdef HAVE_THREAD_STORAGE
/** Platform-agnostic handle to thread-local storage. */
typedef unsigned sthread_tls_t;
#endif

/**
 * Creates a new thread and starts running it.
 *
 * @param thread_func Function to run in the new thread.
 * Called with the value given in \c userdata as an argument.
 * @param userdata Pointer to anything (even \c NULL), passed directly to \c thread_func.
 * Must be cleaned up by the caller or the thread.
 * @return Pointer to the new thread,
 * or \c NULL if there was an error.
 * @warn Make sure that the thread can respond to cancellation requests,
 * especially if used in a core.
 * If a core-created thread isn't terminated by the time the core is unloaded,
 * it may leak into the frontend and cause undefined behavior
 * (especially if another session with the core is started).
 */
sthread_t *sthread_create(void (*thread_func)(void*), void *userdata);

/**
 * Creates a new thread with a specific priority hint and starts running it.
 *
 * @param thread_func Function to run in the new thread.
 * Called with the value given in \c userdata as an argument.
 * @param userdata Pointer to anything (even \c NULL), passed directly to \c thread_func.
 * Must be cleaned up by the caller or the thread.
 * @param thread_priority Priority hint for the new thread.
 * Threads with a higher number are more likely to be scheduled first.
 * Should be between 1 and 100, inclusive;
 * if not, the operating system will assign a default priority.
 * May be ignored.
 * @return Pointer to the new thread,
 * or \c NULL if there was an error.
 */
sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority);

/**
 * Detaches the given thread.
 *
 * When a detached thread terminates,
 * its resources are automatically released back to the operating system
 * without needing another thread to join with it.
 *
 * @param thread Thread to detach.
 * @return 0 on success, a non-zero error code on failure.
 * @warn Once a thread is detached, it cannot be joined.
 * @see sthread_join
 */
int sthread_detach(sthread_t *thread);

/**
 * Waits for the given thread to terminate.
 *
 * @param thread The thread to wait for.
 * Must be joinable.
 * Returns immediately if it's already terminated
 * or if it's \c NULL.
 */
void sthread_join(sthread_t *thread);

/**
 * Returns whether the given thread is the same as the calling thread.
 *
 * @param thread Thread to check.
 * @return \c true if \c thread is the same as the calling thread,
 * \c false if not or if it's \c NULL.
 * @note libretro does not have a notion of a "main" thread,
 * since the core may not be running on the same thread
 * that called \c main (or local equivalent).
 * @see sthread_get_thread_id
 */
bool sthread_isself(sthread_t *thread);

/**
 * Creates a new mutex (a.k.a. lock) that can be used to synchronize shared data.
 *
 * Must be manually freed with \c slock_free.
 *
 * @return Pointer to the new mutex,
 * or \c NULL if there was an error.
 */
slock_t *slock_new(void);

/**
 * Frees a mutex.
 *
 * Behavior is undefined if \c lock was previously freed.
 *
 * @param lock Pointer to the mutex to free.
 * May be \c NULL, in which this function does nothing.
 */
void slock_free(slock_t *lock);

/**
 * Locks a mutex, preventing other threads from claiming it until it's unlocked.
 *
 * If the mutex is already locked by another thread,
 * the calling thread will block until the mutex is unlocked.
 *
 * @param lock Pointer to the mutex to lock.
 * If \c NULL, will return without further action.
 * @see slock_try_lock
 */
void slock_lock(slock_t *lock);

/**
 * Tries to lock a mutex if it's not already locked by another thread.
 *
 * If the mutex is already in use by another thread,
 * returns immediately without waiting for it.
 *
 * @param lock The mutex to try to lock.
 * @return \c true if the mutex was successfully locked,
 * \c false if it was already locked by another thread or if \c lock is \c NULL.
 * @see slock_lock
 */
bool slock_try_lock(slock_t *lock);

/**
 * Unlocks a mutex, allowing other threads to claim it.
 *
 * @post The mutex is unlocked,
 * and another thread may lock it.
 * @param lock The mutex to unlock.
 * If \c NULL, this function is a no-op.
 */
void slock_unlock(slock_t *lock);

/**
 * Creates and initializes a condition variable.
 *
 * Must be manually freed with \c scond_free.
 *
 * @return Pointer to the new condition variable,
 * or \c NULL if there was an error.
 */
scond_t *scond_new(void);

/**
 * Frees a condition variable.
 *
 * @param cond Pointer to the condition variable to free.
 * If \c NULL, this function is a no-op.
 * Behavior is undefined if \c cond was previously freed.
 */
void scond_free(scond_t *cond);

/**
 * Blocks until the given condition variable is signaled or broadcast.
 *
 * @param cond Condition variable to wait on.
 * This function blocks until another thread
 * calls \c scond_signal or \c scond_broadcast with this condition variable.
 * @param lock Mutex to lock while waiting.
 *
 * @see scond_signal
 * @see scond_broadcast
 * @see scond_wait_timeout
 */
void scond_wait(scond_t *cond, slock_t *lock);

/**
 * Blocks until the given condition variable is signaled or broadcast,
 * or until the specified time has passed.
 *
 * @param cond Condition variable to wait on.
 * This function blocks until another thread
 * calls \c scond_signal or \c scond_broadcast with this condition variable.
 * @param lock Mutex to lock while waiting.
 * @param timeout_us Time to wait for a signal, in microseconds.
 *
 * @return \c false if \c timeout_us elapses
 * before \c cond is signaled or broadcast, otherwise \c true.
 */
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);

/**
 * Unblocks all threads waiting on the specified condition variable.
 *
 * @param cond Condition variable to broadcast.
 * @return 0 on success, non-zero on failure.
 */
int scond_broadcast(scond_t *cond);

/**
 * Unblocks at least one thread waiting on the specified condition variable.
 *
 * @param cond Condition variable to signal.
 */
void scond_signal(scond_t *cond);

#ifdef HAVE_THREAD_STORAGE
/**
 * Creates a thread-local storage key.
 *
 * Thread-local storage keys have a single value associated with them
 * that is unique to the thread that uses them.
 *
 * New thread-local storage keys have a value of \c NULL for all threads,
 * and new threads initialize all existing thread-local storage to \c NULL.
 *
 * @param tls[in,out] Pointer to the thread local storage key that will be initialized.
 * Must be cleaned up with \c sthread_tls_delete.
 * Behavior is undefined if \c NULL.
 * @return \c true if the operation succeeded, \c false otherwise.
 * @see sthread_tls_delete
 */
bool sthread_tls_create(sthread_tls_t *tls);

/**
 * Deletes a thread local storage key.
 *
 * The value must be cleaned up separately \em before calling this function,
 * if necessary.
 *
 * @param tls The thread local storage key to delete.
 * Behavior is undefined if \c NULL.
 * @return \c true if the operation succeeded, \c false otherwise.
 */
bool sthread_tls_delete(sthread_tls_t *tls);

/**
 * Gets the calling thread's local data for the given key.
 *
 * @param tls The thread-local storage key to get the data for.
 * @return The calling thread's local data associated with \c tls,
 * which should previously have been set with \c sthread_tls_set.
 * Will be \c NULL if this thread has not set a value or if there was an error.
 */
void *sthread_tls_get(sthread_tls_t *tls);

/**
 * Sets the calling thread's local data for the given key.
 *
 * @param tls The thread-local storage key to set the data for.
 * @param data Pointer to the data that will be associated with \c tls.
 * May be \c NULL.
 * @return \c true if \c data was successfully assigned to \c tls,
 * \c false if there was an error.
 */
bool sthread_tls_set(sthread_tls_t *tls, const void *data);
#endif

/**
 * Gets a thread's unique ID.
 *
 * @param thread The thread to get the ID of.
 * @return The provided thread's ID,
 * or 0 if it's \c NULL.
 */
uintptr_t sthread_get_thread_id(sthread_t *thread);

/**
 * Get the calling thread's unique ID.
 * @return The calling thread's ID.
 * @see sthread_get_thread_id
 */
uintptr_t sthread_get_current_thread_id(void);

RETRO_END_DECLS

#endif

./include/libretro-common/include/rthreads/tpool.h

/*
 * Copyright (c) 2010-2020 The RetroArch team
 * Copyright (c) 2017 John Schember <john@nachtimwald.com>
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (tpool.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE
 */

#ifndef __LIBRETRO_SDK_TPOOL_H__
#define __LIBRETRO_SDK_TPOOL_H__

#include <retro_common_api.h>

#include <boolean.h>

#include <retro_inline.h>
#include <retro_miscellaneous.h>

RETRO_BEGIN_DECLS

struct tpool;
typedef struct tpool tpool_t;

/**
 * (*thread_func_t):
 * @arg           : Argument.
 *
 * Callback function that the pool will call to do work.
 **/
typedef void (*thread_func_t)(void *arg);

/**
 * tpool_create:
 * @num           : Number of threads the pool should have.
 *                  If 0 defaults to 2.
 *
 * Create a thread pool.
 *
 * Returns: pool.
 */
tpool_t *tpool_create(size_t num);

/**
 * tpool_destroy:
 * @tp            : Thread pool.
 *
 * Destroy a thread pool
 * The pool can be destroyed while there is outstanding work to process. All
 * outstanding unprocessed work will be discarded. There may be a delay before
 * this function returns because it will block for work that is processing to
 * complete.
 **/
void tpool_destroy(tpool_t *tp);

/**
 * tpool_add_work:
 * @tp         : Thread pool.
 * @func       : Function the pool should call.
 * @arg        : Argument to pass to func.
 *
 * Add work to a thread pool.
 *
 * Returns: true if work was added, otherwise false.
 **/
bool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg);

/**
 * tpool_wait:
 * @tp Thread pool.
 *
 * Wait for all work in the pool to be completed.
 */
void tpool_wait(tpool_t *tp);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/chd_stream.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (chd_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILE_CHD_STREAM_H
#define _LIBRETRO_SDK_FILE_CHD_STREAM_H

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

typedef struct chdstream chdstream_t;

/* First data track */
#define CHDSTREAM_TRACK_FIRST_DATA (-1)
/* Last track */
#define CHDSTREAM_TRACK_LAST (-2)
/* Primary (largest) data track, used for CRC identification purposes */
#define CHDSTREAM_TRACK_PRIMARY (-3)

chdstream_t *chdstream_open(const char *path, int32_t track);

void chdstream_close(chdstream_t *stream);

ssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes);

int chdstream_getc(chdstream_t *stream);

char *chdstream_gets(chdstream_t *stream, char *buffer, size_t len);

uint64_t chdstream_tell(chdstream_t *stream);

void chdstream_rewind(chdstream_t *stream);

int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence);

ssize_t chdstream_get_size(chdstream_t *stream);

uint32_t chdstream_get_track_start(chdstream_t* stream);

uint32_t chdstream_get_frame_size(chdstream_t* stream);

uint32_t chdstream_get_first_track_sector(chdstream_t* stream);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/file_stream.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FILE_STREAM_H
#define __LIBRETRO_SDK_FILE_STREAM_H

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>

#include <sys/types.h>

#include <libretro.h>
#include <retro_common_api.h>
#include <retro_inline.h>
#include <boolean.h>

#include <stdarg.h>
#include <vfs/vfs_implementation.h>

/** @defgroup file_stream File Streams
 *
 * All functions in this header will use the VFS interface set in \ref filestream_vfs_init if possible,
 * or else they will fall back to built-in equivalents.
 *
 * @note These functions are modeled after those in the C standard library
 * (and may even use them internally),
 * but identical behavior is not guaranteed.
 *
 * @{
 */

/**
 * The minimum version of the VFS interface required by the \c filestream functions.
 */
#define FILESTREAM_REQUIRED_VFS_VERSION 2

RETRO_BEGIN_DECLS

/**
 * Opaque handle to a file stream.
 * @warning This is not interchangeable with \c FILE* or \c retro_vfs_file_handle.
 */
typedef struct RFILE RFILE;

#define FILESTREAM_REQUIRED_VFS_VERSION 2

/**
 * Initializes the \c filestream functions to use the VFS interface provided by the frontend.
 * Optional; if not called, all \c filestream functions
 * will use libretro-common's built-in implementations.
 *
 * @param vfs_info The VFS interface returned by the frontend.
 * If \c vfs_info::iface (but \em not \c vfs_info itself) is \c NULL,
 * then libretro-common's built-in VFS implementation will be used.
 */
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);

/**
 * Returns the size of the given file, in bytes.
 *
 * @param stream The open file to query.
 * @return The size of \c stream in bytes,
 * or -1 if there was an error.
 * @see retro_vfs_size_t
 */
int64_t filestream_get_size(RFILE *stream);

/**
 * Sets the size of the given file,
 * truncating or extending it as necessary.
 *
 * @param stream The file to resize.
 * @param length The new size of \c stream, in bytes.
 * @return 0 if the resize was successful,
 * or -1 if there was an error.
 * @see retro_vfs_truncate_t
 */
int64_t filestream_truncate(RFILE *stream, int64_t length);

/**
 * Opens a file for reading or writing.
 *
 * @param path Path to the file to open.
 * Should be in the format described in \ref GET_VFS_INTERFACE.
 * @param mode The mode to open the file in.
 * Should be one or more of the flags in \refitem RETRO_VFS_FILE_ACCESS OR'd together,
 * and \c RETRO_VFS_FILE_ACCESS_READ or \c RETRO_VFS_FILE_ACCESS_WRITE
 * (or both) must be included.
 * @param hints Optional hints to pass to the frontend.
 *
 * @return The opened file, or \c NULL if there was an error.
 * Must be cleaned up with \c filestream_close when no longer needed.
 * @see retro_vfs_open_t
 */
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);

/**
 * Sets the current position of the file stream.
 * Use this to read specific sections of a file.
 *
 * @param stream The file to set the stream position of.
 * @param offset The new stream position, in bytes.
 * @param seek_position The position to seek from.
 * Should be one of the values in \refitem RETRO_VFS_SEEK_POSITION.
 * @return The new stream position in bytes relative to the beginning,
 * or -1 if there was an error.
 * @see RETRO_VFS_SEEK_POSITION
 * @see retro_vfs_seek_t
 */
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);

/**
 * Reads data from the given file into a buffer.
 * If the read is successful,
 * the file's stream position will advance by the number of bytes read.
 *
 * @param stream The file to read from.
 * @param data The buffer in which to store the read data.
 * @param len The size of \c data, in bytes.
 * @return The number of bytes read,
 * or -1 if there was an error.
 * May be less than \c len, but never more.
 * @see retro_vfs_read_t
 */
int64_t filestream_read(RFILE *stream, void *data, int64_t len);

/**
 * Writes data from a buffer to the given file.
 * If the write is successful,
 * the file's stream position will advance by the number of bytes written.
 *
 * @param stream The file to write to.
 * @param data The buffer containing the data to write.
 * @param len The size of \c data, in bytes.
 * @return The number of bytes written,
 * or -1 if there was an error.
 * May be less than \c len, but never more.
 * @see retro_vfs_write_t
 */
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);

/**
 * Returns the current position of the given file in bytes.
 *
 * @param stream The file to return the stream position for.
 * @return The current stream position in bytes relative to the beginning,
 * or -1 if there was an error.
 * @see retro_vfs_tell_t
 */
int64_t filestream_tell(RFILE *stream);

/**
 * Rewinds the given file to the beginning.
 * Equivalent to <tt>filestream_seek(stream, 0, RETRO_VFS_SEEK_POSITION_START)</tt>.

 * @param stream The file to rewind.
 * May be \c NULL, in which case this function does nothing.
 */
void filestream_rewind(RFILE *stream);

/**
 * Closes the given file.
 *
 * @param stream The file to close.
 * This should have been created with \c filestream_open.
 * Behavior is undefined if \c NULL.
 * @return 0 if the file was closed successfully,
 * or -1 if there was an error.
 * @post \c stream is no longer valid and should not be used,
 * even if this function fails.
 * @see retro_vfs_close_t
 */
int filestream_close(RFILE *stream);

/**
 * Opens a file, reads its contents into a newly-allocated buffer,
 * then closes it.
 *
 * @param path[in] Path to the file to read.
 * Should be in the format described in \ref GET_VFS_INTERFACE.
 * @param buf[out] A pointer to the address of the newly-allocated buffer.
 * The buffer will contain the entirety of the file at \c path.
 * Will be allocated with \c malloc and must be freed with \c free.
 * @param len[out] Pointer to the size of the buffer in bytes.
 * May be \c NULL, in which case the length is not written.
 * Value is unspecified if this function fails.
 * @return 1 if the file was read successfully,
 * 0 if there was an error.
 * @see filestream_write_file
 */
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);

/**
 * Reads a line of text from the given file,
 * up to a given length.
 *
 * Will read to the next newline or until the buffer is full,
 * whichever comes first.
 *
 * @param stream The file to read from.
 * @param s The buffer to write the retrieved line to.
 * Will contain at most \c len - 1 characters
 * plus a null terminator.
 * The newline character (if any) will not be included.
 * The line delimiter must be Unix-style (\c '\n').
 * Carriage returns (\c '\r') will not be treated specially.
 * @param len The length of the buffer \c s, in bytes.
 * @return \s if successful, \c NULL if there was an error.
 */
char* filestream_gets(RFILE *stream, char *s, size_t len);

/**
 * Reads a single character from the given file.
 *
 * @param stream The file to read from.
 * @return The character read, or -1 upon reaching the end of the file.
 */
int filestream_getc(RFILE *stream);

/**
 * Reads formatted text from the given file,
 * with arguments provided as a standard \c va_list.
 *
 * @param stream The file to read from.
 * @param format The string to write, possibly including scanf-compatible format specifiers.
 * @param args Argument list with zero or more elements
 * whose values will be updated according to the semantics of \c format.
 * @return The number of arguments in \c args that were successfully assigned,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/fscanf
 * @see https://en.cppreference.com/w/c/variadic
 */
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);

/**
 * Reads formatted text from the given file.
 *
 * @param stream The file to read from.
 * @param format The string to write, possibly including scanf-compatible format specifiers.
 * @param ... Zero or more arguments that will be updated according to the semantics of \c format.
 * @return The number of arguments in \c ... that were successfully assigned,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/fscanf
 */
int filestream_scanf(RFILE *stream, const char* format, ...);

/**
 * Determines if there's any more data left to read from this file.
 *
 * @param stream The file to check the position of.
 * @return -1 if this stream has reached the end of the file,
 * 0 if not.
 */
int filestream_eof(RFILE *stream);

/**
 * Writes the entirety of a given buffer to a file at a given path.
 * Any file that already exists will be overwritten.
 *
 * @param path Path to the file that will be written to.
 * @param data The buffer to write to \c path.
 * @param size The size of \c data, in bytes.
 * @return \c true if the file was written successfully,
 * \c false if there was an error.
 */
bool filestream_write_file(const char *path, const void *data, int64_t size);

/**
 * Writes a single character to the given file.
 *
 * @param stream The file to write to.
 * @param c The character to write.
 * @return The character written,
 * or -1 if there was an error.
 * Will return -1 if \c stream is \c NULL.
 */
int filestream_putc(RFILE *stream, int c);

/**
 * Writes formatted text to the given file,
 * with arguments provided as a standard \c va_list.
 *
 * @param stream The file to write to.
 * @param format The string to write, possibly including printf-compatible format specifiers.
 * @param args A list of arguments to be formatted and inserted in the resulting string.
 * @return The number of characters written,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/vfprintf
 * @see https://en.cppreference.com/w/c/variadic
 */
int filestream_vprintf(RFILE *stream, const char* format, va_list args);

/**
 * Writes formatted text to the given file.
 *
 * @param stream The file to write to.
 * @param format The string to write, possibly including printf-compatible format specifiers.
 * @param ... Zero or more arguments to be formatted and inserted into the resulting string.
 * @return The number of characters written,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/printf
 */
int filestream_printf(RFILE *stream, const char* format, ...);

/**
 * Checks if there was an error in using the given file stream.
 *
 * @param stream The file stream to check for errors.
 * @return \c true if there was an error in using this stream,
 * \c false if not or if \c stream is \c NULL.
 */
int filestream_error(RFILE *stream);

/**
 * Flushes pending writes to the operating system's file layer.
 * There is no guarantee that pending writes will be written to disk immediately.
 *
 * @param stream The file to flush.
 * @return 0 if the flush was successful,
 * or -1 if there was an error.
 * @see retro_vfs_flush_t
 */
int filestream_flush(RFILE *stream);

/**
 * Deletes the file at the given path.
 * If the file is open by any process,
 * the behavior is platform-specific.
 *
 * @note This function might or might not delete directories recursively,
 * depending on the platform and the underlying VFS implementation.
 *
 * @param path The file to delete.
 * @return 0 if the file was deleted successfully,
 * or -1 if there was an error.
 * @see retro_vfs_remove_t
 */
int filestream_delete(const char *path);

/**
 * Moves a file to a new location, with a new name.
 *
 * @param old_path Path to the file to rename.
 * @param new_path The target name and location of the file.
 * @return 0 if the file was renamed successfully,
 * or -1 if there was an error.
 * @see retro_vfs_rename_t
 */
int filestream_rename(const char *old_path, const char *new_path);

/**
 * Copies a file to a new location.
 *
 * @param src_path Path to the file to rename.
 * @param dst_path The target name and location of the file.
 * @return 0 if the file was copied successfully,
 * or -1 if there was an error.
 */
int filestream_copy(const char *src_path, const char *dst_path);

/**
 * Compares and verifies files.
 *
 * @param src_path Path to the file.
 * @param dst_path Path to the other file.
 * @return 0 if the files are equal,
 * or -1 if there was an error.
 */
int filestream_cmp(const char *src_path, const char *dst_path);

/**
 * Get the path that was used to open a file.
 *
 * @param stream The file to get the path of.
 * @return The path that was used to open \c stream,
 * or \c NULL if there was an error.
 * The string is owned by \c stream and must not be modified or freed by the caller.
 */
const char* filestream_get_path(RFILE *stream);

/**
 * Determines if a file exists at the given path.
 *
 * @param path The path to check for existence.
 * @return \c true if a file exists at \c path,
 * \c false if not or if \c path is \c NULL or empty.
 */
bool filestream_exists(const char *path);

/**
 * Reads a line from the given file into a newly-allocated buffer.
 *
 * @param stream The file to read from.
 * @return Pointer to the line read from \c stream,
 * or \c NULL if there was an error.
 * Must be freed with \c free when no longer needed.
 */
char* filestream_getline(RFILE *stream);

/**
 * Returns the open file handle
 * that was originally returned by the VFS interface.
 *
 * @param stream File handle returned by \c filestream_open.
 * @return The file handle returned by the underlying VFS implementation.
 */
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);

RETRO_END_DECLS

/** @} */

#endif

./include/libretro-common/include/streams/file_stream_transforms.h

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream_transforms.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H

#include <stdint.h>
#include <string.h>
#include <retro_common_api.h>
#include <streams/file_stream.h>

/**
 * @file file_stream_transforms.h
 *
 * Contains macros that redirect standard C I/O functions
 * to libretro's own file stream API.
 * Useful when porting an existing emulator to a core.
 * To use these functions without overriding the standard I/O functions,
 * define \c SKIP_STDIO_REDEFINES before including this header.
 *
 * @see https://man7.org/linux/man-pages/man3/stdio.3.html
 */

RETRO_BEGIN_DECLS

#ifndef SKIP_STDIO_REDEFINES

/** @see https://en.cppreference.com/w/c/io/FILE */
#define FILE RFILE

#undef fopen
#undef fclose
#undef ftell
#undef fseek
#undef fread
#undef fgets
#undef fgetc
#undef fwrite
#undef fputc
#undef fflush
#undef fprintf
#undef ferror
#undef feof
#undef fscanf

#define fopen rfopen
#define fclose rfclose
#define ftell rftell
#define fseek rfseek
#define fread rfread
#define fgets rfgets
#define fgetc rfgetc
#define fwrite rfwrite
#define fputc rfputc
#define fflush rfflush
#define fprintf rfprintf
#define ferror rferror
#define feof rfeof
#define fscanf rfscanf

#endif

/** @see https://en.cppreference.com/w/c/io/fopen */
RFILE* rfopen(const char *path, const char *mode);

/** @see https://en.cppreference.com/w/c/io/fclose */
int rfclose(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/ftell */
int64_t rftell(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fseek */
int64_t rfseek(RFILE* stream, int64_t offset, int origin);

/** @see https://en.cppreference.com/w/c/io/fread */
int64_t rfread(void* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fgets */
char *rfgets(char *s, int maxCount, RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fgetc */
int rfgetc(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fwrite */
int64_t rfwrite(void const* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fputc */
int rfputc(int character, RFILE * stream);

/** @see https://en.cppreference.com/w/c/io/fflush */
int64_t rfflush(RFILE * stream);

/** @see https://en.cppreference.com/w/c/io/fprintf */
int rfprintf(RFILE * stream, const char * format, ...);

/** @see https://en.cppreference.com/w/c/io/ferror */
int rferror(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/feof */
int rfeof(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fscanf */
int rfscanf(RFILE * stream, const char * format, ...);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/interface_stream.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (interface_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_INTERFACE_STREAM_H
#define _LIBRETRO_SDK_INTERFACE_STREAM_H

#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>

#include <retro_common_api.h>
#include <boolean.h>

RETRO_BEGIN_DECLS

enum intfstream_type
{
   INTFSTREAM_FILE = 0,
   INTFSTREAM_MEMORY,
   INTFSTREAM_CHD,
   INTFSTREAM_RZIP
};

typedef struct intfstream_internal intfstream_internal_t, intfstream_t;

typedef struct intfstream_info
{
   struct
   {
      struct
      {
         uint8_t *data;
         uint64_t size;
      } buf;
      bool writable;
   } memory;
   struct
   {
      void *handle;
      int32_t track;
   } chd;
   enum intfstream_type type;
} intfstream_info_t;

void *intfstream_init(intfstream_info_t *info);

bool intfstream_resize(intfstream_internal_t *intf,
      intfstream_info_t *info);

bool intfstream_open(intfstream_internal_t *intf,
      const char *path, unsigned mode, unsigned hints);

int64_t intfstream_read(intfstream_internal_t *intf,
      void *s, uint64_t len);

int64_t intfstream_write(intfstream_internal_t *intf,
      const void *s, uint64_t len);

int intfstream_printf(intfstream_internal_t *intf,
      const char* format, ...);

int64_t intfstream_get_ptr(intfstream_internal_t *intf);

char *intfstream_gets(intfstream_internal_t *intf,
      char *buffer, uint64_t len);

int intfstream_getc(intfstream_internal_t *intf);

int64_t intfstream_seek(intfstream_internal_t *intf,
      int64_t offset, int whence);

int64_t intfstream_truncate(intfstream_internal_t *intf,
      uint64_t len);

void intfstream_rewind(intfstream_internal_t *intf);

int64_t intfstream_tell(intfstream_internal_t *intf);

int intfstream_eof(intfstream_internal_t *intf);

void intfstream_putc(intfstream_internal_t *intf, int c);

int intfstream_close(intfstream_internal_t *intf);

int64_t intfstream_get_size(intfstream_internal_t *intf);

int intfstream_flush(intfstream_internal_t *intf);

uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf);

uint32_t intfstream_get_frame_size(intfstream_internal_t *intf);

uint32_t intfstream_get_first_sector(intfstream_internal_t* intf);

bool intfstream_is_compressed(intfstream_internal_t *intf);

bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc);

intfstream_t *intfstream_open_file(const char *path,
      unsigned mode, unsigned hints);

intfstream_t *intfstream_open_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size);

/* Deprecated.  Has the same effect as `intfstream_open_memory` with
   a mode including `RETRO_VFS_FILE_ACCESS_WRITE`. */
intfstream_t *intfstream_open_writable_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size);

intfstream_t *intfstream_open_chd_track(const char *path,
      unsigned mode, unsigned hints, int32_t track);

intfstream_t *intfstream_open_rzip_file(const char *path,
      unsigned mode);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/memory_stream.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memory_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILE_MEMORY_STREAM_H
#define _LIBRETRO_SDK_FILE_MEMORY_STREAM_H

#include <stdint.h>
#include <stddef.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

typedef struct memstream memstream_t;

memstream_t *memstream_open(unsigned writing);

void memstream_close(memstream_t *stream);

uint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes);

uint64_t memstream_write(memstream_t *stream, const void *data, uint64_t bytes);

int memstream_getc(memstream_t *stream);

void memstream_putc(memstream_t *stream, int c);

char *memstream_gets(memstream_t *stream, char *s, size_t len);

uint64_t memstream_pos(memstream_t *stream);

void memstream_rewind(memstream_t *stream);

int64_t memstream_seek(memstream_t *stream, int64_t offset, int whence);

void memstream_set_buffer(uint8_t *buffer, uint64_t size);

uint64_t memstream_get_last_size(void);

uint64_t memstream_get_ptr(memstream_t *stream);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/network_stream.h

/* Copyright  (C) 2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (network_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NETWORK_STREAM_H
#define _LIBRETRO_SDK_NETWORK_STREAM_H

#include <stddef.h>
#include <stdint.h>

#include <boolean.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

enum
{
   /**
    * Indicates that \c netstream_seek should seek
    * relative to the beginning of the stream.
    */
   NETSTREAM_SEEK_SET = 0,

   /**
    * Indicates that \c netstream_seek should seek
    * relative to its current position.
    */
   NETSTREAM_SEEK_CUR,

   /**
    * Indicates that \c netstream_seek should seek
    * relative to the end of the stream.
    */
   NETSTREAM_SEEK_END
};

/**
 * A stream that ensures data is read/written in network byte order (big endian).
 *
 * @note Despite what the name may suggests,
 * this object does \em not actually perform any network operations.
 * It is intended to be used as input/output for functions that do.
 */
typedef struct netstream
{
   /** The buffer used by the stream for reading or writing. */
   void   *buf;

   /** The size of \c buf in bytes. */
   size_t size;

   /** The number of bytes that have been written to \c buf. */
   size_t used;

   /**
    * The current position of the stream, in bytes.
    * @see netstream_seek
    */
   size_t pos;
} netstream_t;

/**
 * Opens a network-order stream.
 *
 * @param stream Pointer to the network-order stream to initialize.
 * Behavior is undefined if \c NULL.
 * @param buf Pre-allocated buffer.
 * May be \c NULL, in which case a new buffer will be created with \c malloc.
 * @param size Buffer size in bytes.
 * If \c buf is \c NULL, then this will be the size of the newly-allocated buffer.
 * If not, then this is the size of the existing buffer.
 * If zero, then a buffer will not be allocated.
 * @param used The number of bytes in use.
 * Ignored for non pre-allocated buffers.
 * @return \c true if the stream was opened.
 * For new buffers, \c false if allocation failed.
 * For existing buffers, \c false if \c size is zero
 * or less than \c used.
 * @see netstream_close
 */
bool netstream_open(netstream_t *stream, void *buf, size_t len, size_t used);

/**
 * Closes a network-order stream.
 *
 * @param stream Pointer to the network-order stream to close.
 * The stream itself is not deallocated,
 * but its fields will be reset.
 * Behavior is undefined if \c NULL.
 * @param dealloc Whether to release the underlying buffer with \c free.
 * Set to \c true if the creating \c netstream_open call allocated a buffer,
 * or else its memory will be leaked.
 * @note \c stream itself is not deallocated.
 * This function can be used on static or local variables.
 * @see netstream_open
 */
void netstream_close(netstream_t *stream, bool dealloc);

/**
 * Resets the stream to the beginning and discards any used bytes.
 *
 * @param stream The network-order stream to reset.
 * Behavior is undefined if \c NULL.
 *
 * @note This does not deallocate the underlying buffer,
 * nor does it wipe its memory.
 */
void netstream_reset(netstream_t *stream);

/**
 * Resizes the "used" portion of the stream.
 *
 * @param stream The network-order stream to resize.
 * Behavior is undefined if \c NULL.
 * @param used The number of bytes in the stream that are considered written.
 * @return \c true if the stream's "used" region was resized,
 * \c false if it would've been extended past the buffer's capacity.
 * @note This function does not reallocate or clear the underlying buffer.
 * It only sets the boundaries of the "used" portion of the stream.
 */
bool netstream_truncate(netstream_t *stream, size_t used);

/**
 * Retrieves the network-order stream's data.
 *
 * @param stream Pointer to the network-order stream.
 * Behavior is undefined if \c NULL.
 * @param data[out] Pointer to a variable to store the stream's data.
 * The data itself is not copied,
 * so the pointer will be invalidated
 * if the stream is closed or reallocated.
 * @param len[out] Set to the length of the stream's data in bytes.
 */
void netstream_data(netstream_t *stream, void **data, size_t *len);

/**
 * Checks whether the network-order stream has any more data to read,
 * or any more room to write data.
 *
 * @param stream The network-order stream to check.
 * @return \c true if the stream is at EOF, \c false otherwise.
 */
bool netstream_eof(netstream_t *stream);

/**
 * Gets the network-order stream's current position.
 *
 * @param stream Pointer to a network-order stream.
 * @return The stream's position indicator.
 */
size_t netstream_tell(netstream_t *stream);

/**
 * Sets the network-order stream's current position.
 *
 * @param stream Pointer to a network-order stream.
 * @param offset The new position of the stream, in bytes.
 * @param origin The position used as reference for the offset.
 * Must be one of \c NETSTREAM_SEEK_SET, \c NETSTREAM_SEEK_CUR or \c NETSTREAM_SEEK_END.
 * @return \c true on success, \c false on failure.
 */
bool netstream_seek(netstream_t *stream, long offset, int origin);

/**
 * Reads data from the network-order stream.
 * Does not byte-swap any data;
 * this is useful for reading strings or unspecified binary data.
 *
 * @param stream The network-order stream to read from.
 * @param data The buffer that will receive data from the stream.
 * @param len The number of bytes to read.
 * If 0, will read all remaining bytes.
 * @return \c true on success, \c false on failure.
 */
bool netstream_read(netstream_t *stream, void *data, size_t len);

/**
 * Reads a single byte from the network-order stream.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the byte that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_byte(netstream_t   *stream, uint8_t  *data);

/**
 * Reads an unsigned 16-bit integer from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_word(netstream_t   *stream, uint16_t *data);

/**
 * Reads an unsigned 32-bit integer from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_dword(netstream_t  *stream, uint32_t *data);

/**
 * Reads an unsigned 64-bit integer from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_qword(netstream_t  *stream, uint64_t *data);
#ifdef __STDC_IEC_559__
/**
 * Reads a 32-bit floating-point number from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_float(netstream_t  *stream, float    *data);

/**
 * Reads a 64-bit floating-point number from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_double(netstream_t *stream, double   *data);
#endif

/**
 * Reads a null-terminated string from the network-order stream,
 * up to the given length.
 *
 * @param stream Pointer to a network stream object.
 * @param s[out] The buffer that will receive the string.
 * Will be \c NULL-terminated.
 * @param len The length of \c s, in bytes.
 * @return The length of the read string in bytes,
 * or -1 if there was an error.
 */
int netstream_read_string(netstream_t *stream, char *s, size_t len);

/**
 * Reads a string of fixed length from a network-order stream.
 * Will fail if there isn't enough data to read.
 *
 * @param stream Pointer to a network stream object.
 * @param s The buffer that will receive the string.
 * Will be \c NULL-terminated.
 * @param len The length of \c s in bytes,
 * including the \c NULL terminator.
 *
 * @return \c true if a string of the exact length was read,
 * \c false if there was an error.
 */
bool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len);

/**
 * Writes arbitrary data to a network-order stream.
 * Does not byte-swap any data;
 * this is useful for writing strings or unspecified binary data.
 *
 * @param stream Pointer to a network stream object.
 * @param data The data to write into the network stream.
 * @param len The length of \c data, in bytes.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write(netstream_t *stream, const void *data, size_t len);

/**
 * Writes a single byte to a network-order stream.
 *
 * @param stream Pointer to a network stream object.
 * @param data The byte to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_byte(netstream_t   *stream, uint8_t  data);

/**
 * Writes an unsigned 16-bit integer to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_word(netstream_t   *stream, uint16_t data);

/**
 * Writes an unsigned 32-bit integer to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_dword(netstream_t  *stream, uint32_t data);

/**
 * Writes an unsigned 64-bit integer to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_qword(netstream_t  *stream, uint64_t data);
#ifdef __STDC_IEC_559__

/**
 * Writes a 32-bit floating-point number to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_float(netstream_t  *stream, float    data);

/**
 * Writes a 64-bit floating-point number to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_double(netstream_t *stream, double   data);
#endif

/**
 * Writes a null-terminated string to a network-order stream.
 * Does not byte-swap any data.
 *
 * @param stream Pointer to a network stream object.
 * @param s A \c NULL-terminated string.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_string(netstream_t *stream, const char *s);

/**
 * Writes a string of fixed length to a network-order stream,
 * \c NULL-terminating it if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param s Pointer to a string.
 * Does not need to be \c NULL-terminated,
 * but \c NULL values will not stop processing.
 * Will be \c NULL
 * @param len Length of \c s in bytes,
 * including the \c NULL terminator.
 * Exactly this many bytes will be written to the stream;
 * the last character will be set to \c NULL.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_fixed_string(netstream_t *stream, const char *s,
      size_t len);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/rzip_stream.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rzip_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILE_RZIP_STREAM_H
#define _LIBRETRO_SDK_FILE_RZIP_STREAM_H

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/* Rudimentary interface for streaming data to/from a
 * zlib-compressed chunk-based RZIP archive file.
 * 
 * This is somewhat less efficient than using regular
 * gzip code, but this is by design - the intention here
 * is to create an interface that integrates seamlessly
 * with normal RetroArch functionality, using only
 * standard/existing libretro-common routines.
 * (Actual efficiency is pretty good, regardless:
 * archived file size is almost identical to a solid
 * zip file, and compression/decompression speed is
 * not substantially worse than external archiving tools;
 * it is certainly acceptable for use in real-time
 * frontend applications)
 * 
 * When reading existing files, uncompressed content
 * is handled automatically. File type (compressed/
 * uncompressed) is detected via the RZIP header.
 * 
 * ## RZIP file format:
 * 
 * <file id header>:                8 bytes
 *                                  - [#][R][Z][I][P][v][file format version][#]
 * <uncompressed chunk size>:       4 bytes, little endian order
 *                                  - nominal (maximum) size of each uncompressed
 *                                    chunk, in bytes
 * <total uncompressed data size>:  8 bytes, little endian order
 * <size of next compressed chunk>: 4 bytes, little endian order
 *                                  - size on-disk of next compressed data
 *                                    chunk, in bytes
 * <next compressed chunk>:         n bytes of zlib compressed data
 * ...
 * <size of next compressed chunk> : repeated until end of file
 * <next compressed chunk>         :
 * 
 */

/* Prevent direct access to rzipstream_t members */
typedef struct rzipstream rzipstream_t;

/* File Open */

/* Opens a new or existing RZIP file
 * > Supported 'mode' values are:
 *   - RETRO_VFS_FILE_ACCESS_READ
 *   - RETRO_VFS_FILE_ACCESS_WRITE
 * > When reading, 'path' may reference compressed
 *   or uncompressed data
 * Returns NULL if arguments are invalid, file
 * is invalid or an IO error occurs */
rzipstream_t* rzipstream_open(const char *path, unsigned mode);

/* File Read */

/* Reads (a maximum of) 'len' bytes from an RZIP file.
 * Returns actual number of bytes read, or -1 in
 * the event of an error */
int64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len);

/* Reads next character from an RZIP file.
 * Returns character value, or EOF if no data
 * remains.
 * Note: Always returns EOF if file is open
 * for writing. */
int rzipstream_getc(rzipstream_t *stream);

/* Reads one line from an RZIP file and stores it
 * in the character array pointed to by 's'.
 * It stops reading when either (len-1) characters
 * are read, the newline character is read, or the
 * end-of-file is reached, whichever comes first.
 * On success, returns 's'. In the event of an error,
 * or if end-of-file is reached and no characters
 * have been read, returns NULL. */
char* rzipstream_gets(rzipstream_t *stream, char *s, size_t len);

/* Reads all data from file specified by 'path' and
 * copies it to 'buf'.
 * - 'buf' will be allocated and must be free()'d manually.
 * - Allocated 'buf' size is equal to 'len'.
 * Returns false in the event of an error */
bool rzipstream_read_file(const char *path, void **buf, int64_t *len);

/* File Write */

/* Writes 'len' bytes to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len);

/* Writes a single character to an RZIP file.
 * Returns character written, or EOF in the event
 * of an error */
int rzipstream_putc(rzipstream_t *stream, int c);

/* Writes a variable argument list to an RZIP file.
 * Ugly 'internal' function, required to enable
 * 'printf' support in the higher level 'interface_stream'.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args);

/* Writes formatted output to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_printf(rzipstream_t *stream, const char* format, ...);

/* Writes contents of 'data' buffer to file
 * specified by 'path'.
 * Returns false in the event of an error */
bool rzipstream_write_file(const char *path, const void *data, int64_t len);

/* File Control */

/* Sets file position to the beginning of the
 * specified RZIP file.
 * Note: It is not recommended to rewind a file
 * that is open for writing, since the caller
 * may end up with a file containing junk data
 * at the end (harmless, but a waste of space). */
void rzipstream_rewind(rzipstream_t *stream);

/* File Status */

/* Returns total size (in bytes) of the *uncompressed*
 * data in an RZIP file.
 * (If reading an uncompressed file, this corresponds
 * to the 'physical' file size in bytes)
 * Returns -1 in the event of a error. */
int64_t rzipstream_get_size(rzipstream_t *stream);

/* Returns EOF when no further *uncompressed* data
 * can be read from an RZIP file. */
int rzipstream_eof(rzipstream_t *stream);

/* Returns the offset of the current byte of *uncompressed*
 * data relative to the beginning of an RZIP file.
 * Returns -1 in the event of a error. */
int64_t rzipstream_tell(rzipstream_t *stream);

/* Returns true if specified RZIP file contains
 * compressed content */
bool rzipstream_is_compressed(rzipstream_t *stream);

/* File Close */

/* Closes RZIP file. If file is open for writing,
 * flushes any remaining buffered data to disk.
 * Returns -1 in the event of a error. */
int rzipstream_close(rzipstream_t *stream);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/stdin_stream.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdin_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_STDIN_STREAM_H__
#define LIBRETRO_SDK_STDIN_STREAM_H__

#include <stdint.h>
#include <stddef.h>

#include <retro_miscellaneous.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/**
 * Reads data from \c stdin if supported by the current platform.
 * @param buf[out] The buffer to read data into.
 * @param size The length of \c buf in bytes.
 * @return The number of bytes that were read,
 * or 0 if there was an error
 * (including a lack of platform support).
 * @note \c stdin is commonly used for text,
 * but this function can read binary data as well.
 * @see https://man7.org/linux/man-pages/man3/stdout.3.html
 */
size_t read_stdin(char *s, size_t len);

RETRO_END_DECLS

#endif

./include/libretro-common/include/streams/trans_stream.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_TRANS_STREAM_H__
#define LIBRETRO_SDK_TRANS_STREAM_H__

#include <stdint.h>
#include <stddef.h>
#include <boolean.h>

#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif

#include <retro_miscellaneous.h>

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

enum trans_stream_error
{
    TRANS_STREAM_ERROR_NONE = 0,
    TRANS_STREAM_ERROR_AGAIN, /* more work to do */
    TRANS_STREAM_ERROR_ALLOCATION_FAILURE, /* malloc failure */
    TRANS_STREAM_ERROR_INVALID, /* invalid state */
    TRANS_STREAM_ERROR_BUFFER_FULL, /* output buffer full */
    TRANS_STREAM_ERROR_OTHER
};

struct trans_stream_backend
{
   const char *ident;
   const struct trans_stream_backend *reverse;

   /* Create a stream data structure */
   void *(*stream_new)(void);

   /* Free it */
   void  (*stream_free)(void *);

   /* (Optional) Set extra properties, defined per transcoder */
   bool  (*define)(void *, const char *, uint32_t);

   /* Set our input source */
   void  (*set_in)(void *, const uint8_t *, uint32_t);

   /* Set our output target */
   void  (*set_out)(void *, uint8_t *, uint32_t);

   /* Perform a transcoding, flushing/finalizing if asked to. Writes out how
    * many bytes were read and written. Error target optional. */
   bool  (*trans)(void *, bool, uint32_t *, uint32_t *, enum trans_stream_error *);
};

/**
 * trans_stream_trans_full:
 * @backend                     : transcoding backend
 * @data                        : (optional) existing stream data, or a target
 *                                for the new stream data to be saved
 * @in                          : input data
 * @in_size                     : input size
 * @out                         : output data
 * @out_size                    : output size
 * @error                       : (optional) output for error code
 *
 * Perform a full transcoding from a source to a destination.
 */
bool trans_stream_trans_full(
    struct trans_stream_backend *backend, void **data,
    const uint8_t *in, uint32_t in_size,
    uint8_t *out, uint32_t out_size,
    enum trans_stream_error *error);

const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void);
const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void);
const struct trans_stream_backend* trans_stream_get_pipe_backend(void);

extern const struct trans_stream_backend zlib_deflate_backend;
extern const struct trans_stream_backend zlib_inflate_backend;
extern const struct trans_stream_backend pipe_backend;

RETRO_END_DECLS

#endif

./include/libretro-common/include/string/stdstring.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdstring.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_STDSTRING_H
#define __LIBRETRO_SDK_STDSTRING_H

#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <boolean.h>

#include <retro_common_api.h>
#include <retro_inline.h>
#include <compat/strl.h>

RETRO_BEGIN_DECLS

#define STRLEN_CONST(x)                   ((sizeof((x))-1))

#define string_is_not_equal(a, b)         !string_is_equal((a), (b))

#define TOLOWER(c)   ((c) |  (lr_char_props[(unsigned char)(c)] & 0x20))
#define TOUPPER(c)   ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))

/* C standard says \f \v are space, but this one disagrees */
#define ISSPACE(c)   (lr_char_props[(unsigned char)(c)] & 0x80)

#define ISDIGIT(c)   (lr_char_props[(unsigned char)(c)] & 0x40)
#define ISALPHA(c)   (lr_char_props[(unsigned char)(c)] & 0x20)
#define ISLOWER(c)   (lr_char_props[(unsigned char)(c)] & 0x04)
#define ISUPPER(c)   (lr_char_props[(unsigned char)(c)] & 0x02)
#define ISALNUM(c)   (lr_char_props[(unsigned char)(c)] & 0x60)
#define ISUALPHA(c)  (lr_char_props[(unsigned char)(c)] & 0x28)
#define ISUALNUM(c)  (lr_char_props[(unsigned char)(c)] & 0x68)
#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01)

/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
#define string_is_equal_noncase string_is_equal_case_insensitive

static INLINE bool string_is_empty(const char *data)
{
   return !data || (*data == '\0');
}

static INLINE bool string_is_equal(const char *a, const char *b)
{
   return (a && b) ? !strcmp(a, b) : false;
}

static INLINE bool string_starts_with_size(const char *str, const char *prefix,
      size_t len)
{
   return (str && prefix) ? !strncmp(prefix, str, len) : false;
}

static INLINE bool string_starts_with(const char *str, const char *prefix)
{
   return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
}

static INLINE bool string_ends_with_size(const char *s, const char *suffix,
      size_t len, size_t suffix_len)
{
   return (len < suffix_len) ? false :
         !memcmp(suffix, s + (len - suffix_len), suffix_len);
}

static INLINE bool string_ends_with(const char *s, const char *suffix)
{
   return s && suffix && string_ends_with_size(s, suffix, strlen(s), strlen(suffix));
}

/**
 * strlen_size:
 *
 * Leaf function.
 *
 * @return the length of 'str' (c.f. strlen()), but only
 * checks the first 'size' characters
 * - If 'str' is NULL, returns 0
 * - If 'str' is not NULL and no '\0' character is found
 *   in the first 'size' characters, returns 'size'
 **/
static INLINE size_t strlen_size(const char *str, size_t len)
{
   size_t i = 0;
   if (str)
      while (i < len && str[i]) i++;
   return i;
}


static INLINE bool string_is_equal_case_insensitive(const char *a,
      const char *b)
{
   int result              = 0;
   const unsigned char *p1 = (const unsigned char*)a;
   const unsigned char *p2 = (const unsigned char*)b;

   if (!a || !b)
      return false;
   if (p1 == p2)
      return true;

   while ((result = tolower (*p1) - tolower (*p2++)) == 0)
      if (*p1++ == '\0')
         break;

   return (result == 0);
}

static INLINE bool string_starts_with_case_insensitive(const char *str,
      const char *prefix)
{
   int result              = 0;
   const unsigned char *p1 = (const unsigned char*)str;
   const unsigned char *p2 = (const unsigned char*)prefix;

   if (!str || !prefix)
      return false;
   if (p1 == p2)
      return true;

   while ((result = tolower (*p1++) - tolower (*p2)) == 0)
      if (*p2++ == '\0')
         break;

   return (result == 0 || *p2 == '\0');
}

char *string_to_upper(char *s);

char *string_to_lower(char *s);

char *string_ucwords(char *s);

char *string_replace_substring(
      const char *in,          size_t in_len,
      const char *pattern,     size_t pattern_len,
      const char *replacement, size_t replacement_len);

/**
 * string_trim_whitespace_left:
 *
 * Remove leading whitespaces
 **/
char *string_trim_whitespace_left(char *const s);

/**
 * string_trim_whitespace_right:
 *
 * Remove trailing whitespaces
 **/
char *string_trim_whitespace_right(char *const s);

/**
 * string_trim_whitespace:
 *
 * Remove leading and trailing whitespaces
 **/
char *string_trim_whitespace(char *const s);

/**
 * word_wrap:
 * @dst                : pointer to destination buffer.
 * @dst_size           : size of destination buffer.
 * @src                : pointer to input string.
 * @src_len            : length of @src
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : not used, but is necessary to keep
 *                       compatibility with word_wrap_wideglyph().
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by 'src' to destination buffer
 * specified by 'dst' and 'dst_size'.
 * This function assumes that all glyphs in the string
 * have an on-screen pixel width similar to that of
 * regular Latin characters - i.e. it will not wrap
 * correctly any text containing so-called 'wide' Unicode
 * characters (e.g. CJK languages, emojis, etc.).
 **/
size_t word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,
      int line_width, int wideglyph_width, unsigned max_lines);

/**
 * word_wrap_wideglyph:
 * @dst                : pointer to destination buffer.
 * @dst_size           : size of destination buffer.
 * @src                : pointer to input string.
 * @src_len            : length of @src
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : effective width of 'wide' Unicode glyphs.
 *                       the value here is normalised relative to the
 *                       typical on-screen pixel width of a regular
 *                       Latin character:
 *                       - a regular Latin character is defined to
 *                         have an effective width of 100
 *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
 *                       - e.g. if 'wide' Unicode characters in 'src'
 *                         have an on-screen pixel width twice that of
 *                         regular Latin characters, wideglyph_width
 *                         would be 200
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by @src to destination buffer
 * specified by @dst and @dst_size.
 * This function assumes that all glyphs in the string
 * are:
 * - EITHER 'non-wide' Unicode glyphs, with an on-screen
 *   pixel width similar to that of regular Latin characters
 * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
 *   with an on-screen pixel width defined by @wideglyph_width
 * Note that wrapping may occur in inappropriate locations
 * if @src string contains 'wide' Unicode characters whose
 * on-screen pixel width deviates greatly from the set
 * @wideglyph_width value.
 **/
size_t word_wrap_wideglyph(
      char *dst, size_t dst_size,
      const char *src, size_t src_len,
      int line_width, int wideglyph_width,
      unsigned max_lines);

/**
 * string_tokenize:
 *
 * Splits string into tokens separated by @delim
 * > Returned token string must be free()'d
 * > Returns NULL if token is not found
 * > After each call, @str is set to the position after the
 *   last found token
 * > Tokens *include* empty strings
 * Usage example:
 *    char *str      = "1,2,3,4,5,6,7,,,10,";
 *    char **str_ptr = &str;
 *    char *token    = NULL;
 *    while ((token = string_tokenize(str_ptr, ",")))
 *    {
 *        printf("%s\n", token);
 *        free(token);
 *        token = NULL;
 *    }
 **/
char* string_tokenize(char **str, const char *delim);

/**
 * string_remove_all_chars:
 * @str                : input string (must be non-NULL, otherwise UB)
 *
 * Leaf function.
 *
 * Removes every instance of character @c from @str
 **/
void string_remove_all_chars(char *str, char c);

/**
 * string_replace_all_chars:
 * @str                : input string (must be non-NULL, otherwise UB)
 * @find               : character to find
 * @replace            : character to replace @find with
 *
 * Hidden non-leaf function cost:
 * - Calls strchr (in a loop)
 *
 * Replaces every instance of character @find in @str
 * with character @replace
 **/
void string_replace_all_chars(char *str, char find, char replace);

/**
 * string_to_unsigned:
 * @str                : input string
 *
 * Converts string to unsigned integer.
 *
 * @return 0 if string is invalid, otherwise > 0
 **/
unsigned string_to_unsigned(const char *str);

/**
 * string_hex_to_unsigned:
 * @str                : input string (must be non-NULL, otherwise UB)
 *
 * Converts hexadecimal string to unsigned integer.
 * Handles optional leading '0x'.
 *
 * @return 0 if string is invalid, otherwise > 0
 **/
unsigned string_hex_to_unsigned(const char *str);

/**
 * string_count_occurrences_single_character:
 *
 * Leaf function.
 *
 * Get the total number of occurrences of character @c in @str.
 *
 * @return Total number of occurrences of character @c
 */
int string_count_occurrences_single_character(const char *str, char c);

/**
 * string_replace_whitespace_with_single_character:
 *
 * Leaf function.
 *
 * Replaces all spaces with given character @c.
 **/
void string_replace_whitespace_with_single_character(char *str, char c);

/**
 * string_replace_multi_space_with_single_space:
 *
 * Leaf function.
 *
 * Replaces multiple spaces with a single space in a string.
 **/
void string_replace_multi_space_with_single_space(char *str);

/**
 * string_remove_all_whitespace:
 *
 * Leaf function.
 *
 * Remove all spaces from the given string.
 **/
void string_remove_all_whitespace(char *str_trimmed, const char *str);

/* Retrieve the last occurance of the given character in a string. */
int string_index_last_occurance(const char *str, char c);

/**
 * string_find_index_substring_string:
 * @str                : input string (must be non-NULL, otherwise UB)
 * @substr             : substring to find in @str
 *
 * Hidden non-leaf function cost:
 * - Calls strstr
 *
 * Find the position of substring @substr in string @str.
 **/
int string_find_index_substring_string(const char *str, const char *substr);

/**
 * string_copy_only_ascii:
 *
 * Leaf function.
 *
 * Strips non-ASCII characters from a string.
 **/
void string_copy_only_ascii(char *str_stripped, const char *str);

extern const unsigned char lr_char_props[256];

RETRO_END_DECLS

#endif

./include/libretro-common/include/time/rtime.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtime.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_RTIME_H__
#define __LIBRETRO_SDK_RTIME_H__

#include <retro_common_api.h>

#include <stdint.h>
#include <stddef.h>
#include <time.h>

RETRO_BEGIN_DECLS

/* TODO/FIXME: Move all generic time handling functions
 * to this file */

/**
 * Must be called before using \c rtime_localtime().
 * May be called multiple times without ill effects,
 * but must only be called from the main thread.
 */
void rtime_init(void);

/**
 * Must be called upon program or core termination.
 * May be called multiple times without ill effects,
 * but must only be called from the main thread.
 */
void rtime_deinit(void);

/**
 * Thread-safe wrapper around standard \c localtime(),
 * which by itself is not guaranteed to be thread-safe.
 * @param timep Pointer to a time_t object to convert.
 * @param result Pointer to a tm object to store the result in.
 * @return \c result.
 * @see https://en.cppreference.com/w/c/chrono/localtime
 */
struct tm *rtime_localtime(const time_t *timep, struct tm *result);

RETRO_END_DECLS

#endif

./include/libretro-common/include/utils/md5.h

/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * See md5.c for more information.
 */

#ifdef HAVE_OPENSSL
#include <openssl/md5.h>
#elif !defined(_MD5_H)
#define _MD5_H

#include <retro_common_api.h>

RETRO_BEGIN_DECLS

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;

typedef struct {
	MD5_u32plus lo, hi;
	MD5_u32plus a, b, c, d;
	unsigned char buffer[64];
	MD5_u32plus block[16];
} MD5_CTX;

extern void MD5_Init(MD5_CTX *ctx);
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);

RETRO_END_DECLS

#endif

./include/libretro-common/include/vfs/vfs.h

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef __LIBRETRO_SDK_VFS_H
#define __LIBRETRO_SDK_VFS_H

#include <retro_common_api.h>
#include <boolean.h>

#ifdef RARCH_INTERNAL
#ifndef VFS_FRONTEND
#define VFS_FRONTEND
#endif
#endif

RETRO_BEGIN_DECLS

#ifdef _WIN32
typedef void* HANDLE;
#endif

#ifdef HAVE_CDROM
typedef struct
{
   int64_t byte_pos;
   char *cue_buf;
   size_t cue_len;
   unsigned cur_lba;
   unsigned last_frame_lba;
   unsigned char cur_min;
   unsigned char cur_sec;
   unsigned char cur_frame;
   unsigned char cur_track;
   unsigned char last_frame[2352];
   char drive;
   bool last_frame_valid;
} vfs_cdrom_t;
#endif

enum vfs_scheme
{
   VFS_SCHEME_NONE = 0,
   VFS_SCHEME_CDROM
};

#if !(defined(__WINRT__) && defined(__cplusplus_winrt))
#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else
struct libretro_vfs_implementation_file
#endif
{
#ifdef HAVE_CDROM
   vfs_cdrom_t cdrom; /* int64_t alignment */
#endif
   int64_t size;
   uint64_t mappos;
   uint64_t mapsize;
   FILE *fp;
#ifdef _WIN32
   HANDLE fh;
#endif
   char *buf;
   char* orig_path;
   uint8_t *mapped;
   int fd;
   unsigned hints;
   enum vfs_scheme scheme;
};
#endif

/* Replace the following symbol with something appropriate
 * to signify the file is being compiled for a front end instead of a core.
 * This allows the same code to act as reference implementation
 * for VFS and as fallbacks for when the front end does not provide VFS functionality.
 */

#ifdef VFS_FRONTEND
typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
#else
typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;
#endif

#ifdef VFS_FRONTEND
typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
#else
typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
#endif

RETRO_END_DECLS

#endif

./include/libretro-common/include/vfs/vfs_implementation_cdrom.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vfs_implementation_cdrom.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H

#include <vfs/vfs.h>
#include <cdrom/cdrom.h>

RETRO_BEGIN_DECLS

int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence);

void retro_vfs_file_open_cdrom(
      libretro_vfs_implementation_file *stream,
      const char *path, unsigned mode, unsigned hints);

int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
      void *s, uint64_t len);

int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream);

const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void);

const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream);

RETRO_END_DECLS

#endif

./include/libretro-common/include/vfs/vfs_implementation.h

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H

#include <stdio.h>
#include <stdint.h>
#include <libretro.h>
#include <retro_environment.h>
#include <vfs/vfs.h>

RETRO_BEGIN_DECLS

libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);

int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);

int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);

int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);

int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len);

int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len);

int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream);

int retro_vfs_file_remove_impl(const char *path);

int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);

const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);

int retro_vfs_stat_impl(const char *path, int32_t *size);

int retro_vfs_mkdir_impl(const char *dir);

libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);

bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);

const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);

bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);

int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);

#ifdef __WINRT__

void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);

#endif

RETRO_END_DECLS

#endif

./include/libretro-common/include/vulkan/vulkan_symbol_wrapper.h

/* This header is autogenerated by vulkan_loader_generator.py */
#ifndef VULKAN_SYMBOL_WRAPPER_H
#define VULKAN_SYMBOL_WRAPPER_H
#define VK_NO_PROTOTYPES
#include <vulkan/vulkan.h>

#ifdef __cplusplus
extern "C" {
#endif

extern PFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;
#define vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance
extern PFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;
#define vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion
extern PFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;
#define vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties
extern PFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;
#define vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties
extern PFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;
#define vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance
extern PFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;
#define vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices
extern PFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;
#define vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures
extern PFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;
#define vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties
extern PFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;
#define vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties
extern PFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;
#define vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;
#define vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties
extern PFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;
#define vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties
extern PFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;
#define vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr
extern PFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;
#define vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice
extern PFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;
#define vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice
extern PFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;
#define vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties
extern PFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;
#define vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties
extern PFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;
#define vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue
extern PFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;
#define vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit
extern PFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;
#define vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle
extern PFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;
#define vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle
extern PFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;
#define vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory
extern PFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;
#define vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory
extern PFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;
#define vkMapMemory vulkan_symbol_wrapper_vkMapMemory
extern PFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;
#define vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory
extern PFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;
#define vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges
extern PFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;
#define vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges
extern PFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;
#define vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment
extern PFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;
#define vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory
extern PFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;
#define vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory
extern PFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;
#define vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements
extern PFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;
#define vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements
extern PFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;
#define vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements
extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;
#define vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties
extern PFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;
#define vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse
extern PFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;
#define vkCreateFence vulkan_symbol_wrapper_vkCreateFence
extern PFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;
#define vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence
extern PFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;
#define vkResetFences vulkan_symbol_wrapper_vkResetFences
extern PFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;
#define vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus
extern PFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;
#define vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences
extern PFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;
#define vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore
extern PFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;
#define vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore
extern PFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;
#define vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent
extern PFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;
#define vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent
extern PFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;
#define vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus
extern PFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;
#define vkSetEvent vulkan_symbol_wrapper_vkSetEvent
extern PFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;
#define vkResetEvent vulkan_symbol_wrapper_vkResetEvent
extern PFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;
#define vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool
extern PFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;
#define vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool
extern PFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;
#define vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults
extern PFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;
#define vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer
extern PFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;
#define vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer
extern PFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;
#define vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView
extern PFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;
#define vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView
extern PFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;
#define vkCreateImage vulkan_symbol_wrapper_vkCreateImage
extern PFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;
#define vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage
extern PFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;
#define vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout
extern PFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;
#define vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView
extern PFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;
#define vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView
extern PFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;
#define vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule
extern PFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;
#define vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule
extern PFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;
#define vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache
extern PFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;
#define vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache
extern PFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;
#define vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData
extern PFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;
#define vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches
extern PFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;
#define vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines
extern PFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;
#define vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines
extern PFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;
#define vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline
extern PFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;
#define vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout
extern PFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;
#define vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout
extern PFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;
#define vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler
extern PFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;
#define vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler
extern PFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;
#define vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout
extern PFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;
#define vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout
extern PFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;
#define vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool
extern PFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;
#define vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool
extern PFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;
#define vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool
extern PFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;
#define vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets
extern PFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;
#define vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets
extern PFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;
#define vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets
extern PFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;
#define vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer
extern PFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;
#define vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer
extern PFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;
#define vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass
extern PFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;
#define vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass
extern PFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;
#define vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity
extern PFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;
#define vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool
extern PFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;
#define vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool
extern PFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;
#define vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool
extern PFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;
#define vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers
extern PFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;
#define vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers
extern PFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;
#define vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer
extern PFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;
#define vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer
extern PFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;
#define vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer
extern PFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;
#define vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline
extern PFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;
#define vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport
extern PFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;
#define vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor
extern PFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;
#define vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth
extern PFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;
#define vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias
extern PFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;
#define vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants
extern PFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;
#define vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds
extern PFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;
#define vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask
extern PFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;
#define vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask
extern PFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;
#define vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference
extern PFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;
#define vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets
extern PFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;
#define vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer
extern PFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;
#define vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers
extern PFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;
#define vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw
extern PFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;
#define vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed
extern PFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;
#define vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect
extern PFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;
#define vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect
extern PFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;
#define vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch
extern PFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;
#define vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect
extern PFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;
#define vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer
extern PFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;
#define vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage
extern PFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;
#define vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage
extern PFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;
#define vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage
extern PFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;
#define vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer
extern PFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;
#define vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer
extern PFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;
#define vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer
extern PFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;
#define vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage
extern PFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;
#define vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage
extern PFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;
#define vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments
extern PFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;
#define vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage
extern PFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;
#define vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent
extern PFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;
#define vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent
extern PFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;
#define vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents
extern PFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;
#define vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier
extern PFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;
#define vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery
extern PFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;
#define vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery
extern PFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;
#define vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool
extern PFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;
#define vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp
extern PFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;
#define vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults
extern PFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;
#define vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants
extern PFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;
#define vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass
extern PFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;
#define vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass
extern PFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;
#define vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass
extern PFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;
#define vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands
extern PFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;
#define vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;
#define vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;
#define vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR
extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;
#define vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR
extern PFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;
#define vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR
extern PFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;
#define vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR
extern PFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;
#define vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR
extern PFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;
#define vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR
extern PFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;
#define vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR
extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;
#define vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR
extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
#define vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR
extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;
#define vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR
extern PFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;
#define vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR
extern PFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;
#define vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR
extern PFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;
#define vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR
extern PFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;
#define vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR
extern PFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;
#define vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR

extern PFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;
#define vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT
extern PFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;
#define vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT
extern PFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;
#define vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT

void vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr);
PFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void);
VkBool32 vulkan_symbol_wrapper_load_global_symbols(void);
VkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance);
VkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance);
VkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device);
VkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol);
VkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol);

#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, name, pfn) vulkan_symbol_wrapper_load_instance_symbol(instance, name, (PFN_vkVoidFunction*) &(pfn))
#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, name) vulkan_symbol_wrapper_load_instance_symbol(instance, #name, (PFN_vkVoidFunction*) & name)
#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, name, pfn) vulkan_symbol_wrapper_load_device_symbol(device, name, (PFN_vkVoidFunction*) &(pfn))
#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, name) vulkan_symbol_wrapper_load_device_symbol(device, #name, (PFN_vkVoidFunction*) & name)

#ifdef __cplusplus
}
#endif
#endif

./include/libretro-common/libco/aarch64.c

/*
  libco.aarch64 (2017-06-26)
  author: webgeek1234
  license: public domain
*/

#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#ifndef __APPLE__
#include <malloc.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

static thread_local uint64_t co_active_buffer[64];
static thread_local cothread_t co_active_handle;

asm (
      ".globl co_switch_aarch64\n"
      ".globl _co_switch_aarch64\n"
      "co_switch_aarch64:\n"
      "_co_switch_aarch64:\n"
      "  stp x8,  x9,  [x1]\n"
      "  stp x10, x11, [x1, #16]\n"
      "  stp x12, x13, [x1, #32]\n"
      "  stp x14, x15, [x1, #48]\n"
      "  str x19, [x1, #72]\n"
      "  stp x20, x21, [x1, #80]\n"
      "  stp x22, x23, [x1, #96]\n"
      "  stp x24, x25, [x1, #112]\n"
      "  stp x26, x27, [x1, #128]\n"
      "  stp x28, x29, [x1, #144]\n"
      "  mov x16, sp\n"
      "  stp x16, x30, [x1, #160]\n"

      "  ldp x8,  x9,  [x0]\n"
      "  ldp x10, x11, [x0, #16]\n"
      "  ldp x12, x13, [x0, #32]\n"
      "  ldp x14, x15, [x0, #48]\n"
      "  ldr x19, [x0, #72]\n"
      "  ldp x20, x21, [x0, #80]\n"
      "  ldp x22, x23, [x0, #96]\n"
      "  ldp x24, x25, [x0, #112]\n"
      "  ldp x26, x27, [x0, #128]\n"
      "  ldp x28, x29, [x0, #144]\n"
      "  ldp x16, x17, [x0, #160]\n"
      "  mov sp, x16\n"
      "  br x17\n"
    );

/* ASM */
void co_switch_aarch64(cothread_t handle, cothread_t current);

static void crash(void)
{
   /* Called only if cothread_t entrypoint returns. */
   assert(0);
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
	uint64_t *ptr     = NULL;
   cothread_t handle = 0;
   size              = (size + 1023) & ~1023;
#if HAVE_POSIX_MEMALIGN >= 1
   if (posix_memalign(&handle, 1024, size + 512) < 0)
      return 0;
#else
   handle            = memalign(1024, size + 512);
#endif

   if (!handle)
      return handle;

   ptr     = (uint64_t*)handle;
   /* Non-volatiles.  */
   ptr[0]  = 0; /* x8  */
   ptr[1]  = 0; /* x9  */
   ptr[2]  = 0; /* x10 */
   ptr[3]  = 0; /* x11 */
   ptr[4]  = 0; /* x12 */
   ptr[5]  = 0; /* x13 */
   ptr[6]  = 0; /* x14 */
   ptr[7]  = 0; /* x15 */
   ptr[8]  = 0; /* padding */
   ptr[9]  = 0; /* x19 */
   ptr[10] = 0; /* x20 */
   ptr[11] = 0; /* x21 */
   ptr[12] = 0; /* x22 */
   ptr[13] = 0; /* x23 */
   ptr[14] = 0; /* x24 */
   ptr[15] = 0; /* x25 */
   ptr[16] = 0; /* x26 */
   ptr[17] = 0; /* x27 */
   ptr[18] = 0; /* x28 */
   ptr[20] = (uintptr_t)ptr + size + 512 - 16; /* x30, stack pointer */
   ptr[19] = ptr[20]; /* x29, frame pointer */
   ptr[21] = (uintptr_t)entrypoint; /* PC (link register x31 gets saved here). */
   return handle;
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_active_handle = co_active_buffer;
   return co_active_handle;
}

void co_delete(cothread_t handle)
{
   free(handle);
}

void co_switch(cothread_t handle)
{
   cothread_t co_previous_handle = co_active();
   co_switch_aarch64(co_active_handle = handle, co_previous_handle);
}

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/amd64.c

/*
  libco.amd64 (2009-10-12)
  author: byuu
  license: public domain
*/

#define LIBCO_C
#include <libco.h>
#include <assert.h>
#include <stdlib.h>

#if defined(__GNUC__) && !defined(_WIN32) && !defined(__cplusplus)
#define CO_USE_INLINE_ASM
#endif

#ifdef __cplusplus
extern "C" {
#endif

static thread_local long long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
#ifndef CO_USE_INLINE_ASM
static void (*co_swap)(cothread_t, cothread_t)  = 0;
#endif

#ifdef _WIN32
/* ABI: Win64 */
  /* On windows handle is allocated by malloc and there it's guaranteed to
     have at least 16-byte alignment. Hence we don't need to align
     it in order to use movaps.  */
static unsigned char co_swap_function[] = {
    0x48, 0x89, 0x22,              /* mov [rdx],rsp          */
    0x48, 0x8b, 0x21,              /* mov rsp,[rcx]          */
    0x58,                          /* pop rax                */
    0x48, 0x89, 0x6a, 0x08,        /* mov [rdx+ 8],rbp       */
    0x48, 0x89, 0x72, 0x10,        /* mov [rdx+16],rsi       */
    0x48, 0x89, 0x7a, 0x18,        /* mov [rdx+24],rdi       */
    0x48, 0x89, 0x5a, 0x20,        /* mov [rdx+32],rbx       */
    0x4c, 0x89, 0x62, 0x28,        /* mov [rdx+40],r12       */
    0x4c, 0x89, 0x6a, 0x30,        /* mov [rdx+48],r13       */
    0x4c, 0x89, 0x72, 0x38,        /* mov [rdx+56],r14       */
    0x4c, 0x89, 0x7a, 0x40,        /* mov [rdx+64],r15       */
  #if !defined(LIBCO_NO_SSE)
    0x0f, 0x29, 0x72, 0x50,        /* movaps [rdx+ 80],xmm6  */
    0x0f, 0x29, 0x7a, 0x60,        /* movaps [rdx+ 96],xmm7  */
    0x44, 0x0f, 0x29, 0x42, 0x70,  /* movaps [rdx+112],xmm8  */
    0x48, 0x83, 0xc2, 0x70,        /* add rdx,112            */
    0x44, 0x0f, 0x29, 0x4a, 0x10,  /* movaps [rdx+ 16],xmm9  */
    0x44, 0x0f, 0x29, 0x52, 0x20,  /* movaps [rdx+ 32],xmm10 */
    0x44, 0x0f, 0x29, 0x5a, 0x30,  /* movaps [rdx+ 48],xmm11 */
    0x44, 0x0f, 0x29, 0x62, 0x40,  /* movaps [rdx+ 64],xmm12 */
    0x44, 0x0f, 0x29, 0x6a, 0x50,  /* movaps [rdx+ 80],xmm13 */
    0x44, 0x0f, 0x29, 0x72, 0x60,  /* movaps [rdx+ 96],xmm14 */
    0x44, 0x0f, 0x29, 0x7a, 0x70,  /* movaps [rdx+112],xmm15 */
  #endif
    0x48, 0x8b, 0x69, 0x08,        /* mov rbp,[rcx+ 8]       */
    0x48, 0x8b, 0x71, 0x10,        /* mov rsi,[rcx+16]       */
    0x48, 0x8b, 0x79, 0x18,        /* mov rdi,[rcx+24]       */
    0x48, 0x8b, 0x59, 0x20,        /* mov rbx,[rcx+32]       */
    0x4c, 0x8b, 0x61, 0x28,        /* mov r12,[rcx+40]       */
    0x4c, 0x8b, 0x69, 0x30,        /* mov r13,[rcx+48]       */
    0x4c, 0x8b, 0x71, 0x38,        /* mov r14,[rcx+56]       */
    0x4c, 0x8b, 0x79, 0x40,        /* mov r15,[rcx+64]       */
  #if !defined(LIBCO_NO_SSE)
    0x0f, 0x28, 0x71, 0x50,        /* movaps xmm6, [rcx+ 80] */
    0x0f, 0x28, 0x79, 0x60,        /* movaps xmm7, [rcx+ 96] */
    0x44, 0x0f, 0x28, 0x41, 0x70,  /* movaps xmm8, [rcx+112] */
    0x48, 0x83, 0xc1, 0x70,        /* add rcx,112            */
    0x44, 0x0f, 0x28, 0x49, 0x10,  /* movaps xmm9, [rcx+ 16] */
    0x44, 0x0f, 0x28, 0x51, 0x20,  /* movaps xmm10,[rcx+ 32] */
    0x44, 0x0f, 0x28, 0x59, 0x30,  /* movaps xmm11,[rcx+ 48] */
    0x44, 0x0f, 0x28, 0x61, 0x40,  /* movaps xmm12,[rcx+ 64] */
    0x44, 0x0f, 0x28, 0x69, 0x50,  /* movaps xmm13,[rcx+ 80] */
    0x44, 0x0f, 0x28, 0x71, 0x60,  /* movaps xmm14,[rcx+ 96] */
    0x44, 0x0f, 0x28, 0x79, 0x70,  /* movaps xmm15,[rcx+112] */
  #endif
    0xff, 0xe0,                    /* jmp rax                */
};

#include <windows.h>

static void co_init(void)
{
   DWORD old_privileges;
   VirtualProtect(co_swap_function,
         sizeof(co_swap_function), PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
/* ABI: SystemV */
#ifndef CO_USE_INLINE_ASM
static unsigned char co_swap_function[] = {
  0x48, 0x89, 0x26,                                 /* mov    [rsi],rsp      */
  0x48, 0x8b, 0x27,                                 /* mov    rsp,[rdi]      */
  0x58,                                             /* pop    rax            */
  0x48, 0x89, 0x6e, 0x08,                           /* mov    [rsi+0x08],rbp */
  0x48, 0x89, 0x5e, 0x10,                           /* mov    [rsi+0x10],rbx */
  0x4c, 0x89, 0x66, 0x18,                           /* mov    [rsi+0x18],r12 */
  0x4c, 0x89, 0x6e, 0x20,                           /* mov    [rsi+0x20],r13 */
  0x4c, 0x89, 0x76, 0x28,                           /* mov    [rsi+0x28],r14 */
  0x4c, 0x89, 0x7e, 0x30,                           /* mov    [rsi+0x30],r15 */
  0x48, 0x8b, 0x6f, 0x08,                           /* mov    rbp,[rdi+0x08] */
  0x48, 0x8b, 0x5f, 0x10,                           /* mov    rbx,[rdi+0x10] */
  0x4c, 0x8b, 0x67, 0x18,                           /* mov    r12,[rdi+0x18] */
  0x4c, 0x8b, 0x6f, 0x20,                           /* mov    r13,[rdi+0x20] */
  0x4c, 0x8b, 0x77, 0x28,                           /* mov    r14,[rdi+0x28] */
  0x4c, 0x8b, 0x7f, 0x30,                           /* mov    r15,[rdi+0x30] */
  0xff, 0xe0,                                       /* jmp    rax            */
};

#include <unistd.h>
#include <sys/mman.h>

static void co_init(void)
{
   unsigned long long addr = (unsigned long long)co_swap_function;
   unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
   unsigned long long size = (addr - base) + sizeof(co_swap_function);
   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#else
static void co_init(void) {}
#endif
#endif

static void crash(void)
{
  assert(0); /* called only if cothread_t entrypoint returns */
}

cothread_t co_active(void)
{
  if (!co_active_handle)
     co_active_handle = &co_active_buffer;
  return co_active_handle;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   cothread_t handle;
#ifndef CO_USE_INLINE_ASM
   if (!co_swap)
   {
      co_init();
      co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
   }
#endif

   if (!co_active_handle)
      co_active_handle = &co_active_buffer;
   size += 512; /* allocate additional space for storage */
   size &= ~15; /* align stack to 16-byte boundary */

#ifdef __GENODE__
   if ((handle = (cothread_t)genode_alloc_secondary_stack(size)))
   {
      long long *p        = (long long*)((char*)handle); /* OS returns top of stack */
      *--p                = (long long)crash;            /* crash if entrypoint returns */
      *--p                = (long long)entrypoint;       /* start of function */
      *(long long*)handle = (long long)p;                /* stack pointer */
   }
#else
   if ((handle = (cothread_t)malloc(size)))
   {
      long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
      *--p = (long long)crash;                           /* crash if entrypoint returns */
      *--p = (long long)entrypoint;                      /* start of function */
      *(long long*)handle = (long long)p;                /* stack pointer */
   }
#endif

   return handle;
}

void co_delete(cothread_t handle)
{
#ifdef __GENODE__
   genode_free_secondary_stack(handle);
#else
   free(handle);
#endif
}

#ifndef CO_USE_INLINE_ASM
void co_switch(cothread_t handle)
{
  register cothread_t co_previous_handle = co_active_handle;
  co_swap(co_active_handle = handle, co_previous_handle);
}
#else
#ifdef __APPLE__
#define ASM_PREFIX "_"
#else
#define ASM_PREFIX ""
#endif
__asm__(
".intel_syntax noprefix         \n"
".globl " ASM_PREFIX "co_switch              \n"
ASM_PREFIX "co_switch:                     \n"
"mov rsi, [rip+" ASM_PREFIX "co_active_handle]\n"
"mov [rsi],rsp                  \n"
"mov [rsi+0x08],rbp             \n"
"mov [rsi+0x10],rbx             \n"
"mov [rsi+0x18],r12             \n"
"mov [rsi+0x20],r13             \n"
"mov [rsi+0x28],r14             \n"
"mov [rsi+0x30],r15             \n"
"mov [rip+" ASM_PREFIX "co_active_handle], rdi\n"
"mov rsp,[rdi]                  \n"
"mov rbp,[rdi+0x08]             \n"
"mov rbx,[rdi+0x10]             \n"
"mov r12,[rdi+0x18]             \n"
"mov r13,[rdi+0x20]             \n"
"mov r14,[rdi+0x28]             \n"
"mov r15,[rdi+0x30]             \n"
"ret                            \n"
".att_syntax                    \n"
);
#endif

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/armeabi.c

/*
  libco.armeabi (2013-04-05)
  author: Themaister
  license: public domain
*/

#define LIBCO_C
#include <libco.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#ifndef __APPLE__
#include <malloc.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

static thread_local uint32_t co_active_buffer[64];
static thread_local cothread_t co_active_handle;

__asm__ (
#if defined(__thumb2__)
      ".align 2\n"
      ".globl co_switch_arm\n"
      ".globl _co_switch_arm\n"
      ".thumb\n"
      ".thumb_func\n"
      ".type   co_switch_arm, %function\n"
      ".type   _co_switch_arm, %function\n"
      "co_switch_arm:\n"
      "_co_switch_arm:\n"
      " mov r3, sp\n"
      " stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
      " stmia r1!, {r3, lr}\n"
      " ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
      " ldmfd r0!, { r3 }\n"
      " mov sp, r3\n"
      " ldmfd r0!, { r3 }\n"
      " mov pc, r3\n"
#else
      ".arm\n"
      ".align 4\n"
      ".globl co_switch_arm\n"
      ".globl _co_switch_arm\n"
      "co_switch_arm:\n"
      "_co_switch_arm:\n"
      "  stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\n"
      "  ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\n"
#endif
    );

/* ASM */
void co_switch_arm(cothread_t handle, cothread_t current);

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   uint32_t *ptr     = NULL;
   cothread_t handle = 0;
   size              = (size + 1023) & ~1023;
#if defined(__APPLE__) || HAVE_POSIX_MEMALIGN >= 1
   if (posix_memalign(&handle, 1024, size + 256) < 0)
      return 0;
#else
   handle = memalign(1024, size + 256);
#endif

   if (!handle)
      return handle;

   ptr    = (uint32_t*)handle;
   /* Non-volatiles.  */
   ptr[0] = 0; /* r4  */
   ptr[1] = 0; /* r5  */
   ptr[2] = 0; /* r6  */
   ptr[3] = 0; /* r7  */
   ptr[4] = 0; /* r8  */
   ptr[5] = 0; /* r9  */
   ptr[6] = 0; /* r10 */
   ptr[7] = 0; /* r11 */
   /* Align stack to 64-bit */
   ptr[8] = (uintptr_t)ptr + size + 256 - 8; /* r13, stack pointer */
   ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */
   return handle;
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_active_handle = co_active_buffer;
   return co_active_handle;
}

void co_delete(cothread_t handle)
{
   free(handle);
}

void co_switch(cothread_t handle)
{
   cothread_t co_previous_handle = co_active();
   co_switch_arm(co_active_handle = handle, co_previous_handle);
}

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/fiber.c

/*
  libco.win (2008-01-28)
  authors: Nach, byuu
  license: public domain
*/

#define LIBCO_C
#include <libco.h>
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif

static thread_local cothread_t co_active_ = 0;

static void __stdcall co_thunk(void *coentry)
{
   ((void (*)(void))coentry)();
}

cothread_t co_active(void)
{
   if (!co_active_)
   {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
#else
      ConvertThreadToFiber(0);
#endif
      co_active_ = GetCurrentFiber();
   }
   return co_active_;
}

cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
{
   if (!co_active_)
   {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
#else
      ConvertThreadToFiber(0);
#endif
      co_active_ = GetCurrentFiber();
   }

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
   return (cothread_t)CreateFiberEx(heapsize, heapsize, FIBER_FLAG_FLOAT_SWITCH, co_thunk, (void*)coentry);
#else
   return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
#endif
}

void co_delete(cothread_t cothread)
{
   DeleteFiber(cothread);
}

void co_switch(cothread_t cothread)
{
   co_active_ = cothread;
   SwitchToFiber(cothread);
}

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/genode.cpp

/*
  libco.genode_secondary_stack (2018-09-15)
  author: Emery Hemingway
  license: public domain
*/

/* Genode include */
#include <base/thread.h>

/* Libco include */
#include <libco.h>

extern "C"
void *genode_alloc_secondary_stack(unsigned long stack_size)
{
	try
   {
		return Genode::Thread::myself()->alloc_secondary_stack("libco", stack_size);
   }
	catch (...)
   {
		Genode::error("libco: failed to allocate ", stack_size, " byte secondary stack");
		return nullptr;
	}
}

extern "C"
void genode_free_secondary_stack(void *stack)
{
	Genode::Thread::myself()->free_secondary_stack(stack);
}

./include/libretro-common/libco/libco.c

/*
  libco
  auto-selection module
  license: public domain
*/

#ifdef __GENODE__
void *genode_alloc_secondary_stack(unsigned long stack_size);
void genode_free_secondary_stack(void *stack);
#endif

#if defined _MSC_VER
  #include <Windows.h>
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
    #include "fiber.c"
  #elif defined _M_IX86
    #include "x86.c"
  #elif defined _M_AMD64
    #include "amd64.c"
  #else
    #include "fiber.c"
  #endif
#elif defined __GNUC__
  #if defined __i386__
    #include "x86.c"
  #elif defined __amd64__
    #include "amd64.c"
  #elif defined _ARCH_PPC
    #include "ppc.c"
  #elif defined(__aarch64__)
    #include "aarch64.c"
  #elif defined(PS2)
    #include "ps2.c"
  #elif defined(PSP)
    #include "psp1.c"
  #elif defined VITA
    #include "scefiber.c"
  #elif defined(__ARM_EABI__) || defined(__arm__)
    #include "armeabi.c"
  #else
    #include "sjlj.c"
  #endif
#else
  #error "libco: unsupported processor, compiler or operating system"
#endif

./include/libretro-common/libco/ppc.c

/*
  libco.ppc (2010-10-17)
  author: blargg
  license: public domain
*/

/* PowerPC 32/64 using embedded or external asm, with optional
floating-point and AltiVec save/restore */

#define LIBCO_C
#include <libco.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)

#if LIBCO_MPROTECT
#include <unistd.h>
#include <sys/mman.h>
#endif

/* State format (offsets in 32-bit words)

+0	Pointer to swap code
	Rest of function descriptor for entry function
+8	PC
+10	SP
	Special regs
	GPRs
	FPRs
	VRs
	stack
*/

enum { state_size  = 1024 };
enum { above_stack = 2048 };
enum { stack_align = 256  };

static thread_local cothread_t co_active_handle = 0;

/**** Determine environment ****/

#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)

/* Whether function calls are indirect through a descriptor,
or are directly to function */
#ifndef LIBCO_PPCDESC
	#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
		#define LIBCO_PPCDESC 1
	#endif
#endif

/* Whether the code should be inline asm stored in .text, or the original
array buffer */
#ifndef LIBCO_STATIC_TEXT
   #if defined(WIIU)
      #define LIBCO_STATIC_TEXT 1
   #endif
#endif

#ifdef LIBCO_PPC_ASM

	#ifdef __cplusplus
		extern "C"
	#endif

	/* Swap code is in ppc.S */
	void co_swap_asm(cothread_t, cothread_t);
	#define CO_SWAP_ASM(x, y) co_swap_asm(x, y)

#elif LIBCO_STATIC_TEXT

asm(
	".globl libco_ppc_code\n"
	"libco_ppc_code:\n"
#if LIBCO_PPC64
	"mfcr    %r8\n"
	"std     %r1,40(%r4)\n"
	"mflr    %r9\n"
	"std     %r14,72(%r4)\n"
	"std     %r15,80(%r4)\n"
	"std     %r16,88(%r4)\n"
	"std     %r17,96(%r4)\n"
	"std     %r18,104(%r4)\n"
	"std     %r19,112(%r4)\n"
	"std     %r20,120(%r4)\n"
	"std     %r21,128(%r4)\n"
	"std     %r22,136(%r4)\n"
	"std     %r23,144(%r4)\n"
	"std     %r24,152(%r4)\n"
	"std     %r25,160(%r4)\n"
	"std     %r26,168(%r4)\n"
	"std     %r27,176(%r4)\n"
	"std     %r28,184(%r4)\n"
	"std     %r29,192(%r4)\n"
	"std     %r30,200(%r4)\n"
	"std     %r31,208(%r4)\n"
	"std     %r9,32(%r4)\n"
	"ld      %r7,32(%r3)\n"
	"ld      %r1,40(%r3)\n"
	"bl      1f\n"
	"trap\n"
	"1:stw     %r8,48(%r4)\n"
	"lwz     %r6,48(%r3)\n"
	"mtctr   %r7\n"
	"ld      %r14,72(%r3)\n"
	"ld      %r15,80(%r3)\n"
	"ld      %r16,88(%r3)\n"
	"ld      %r17,96(%r3)\n"
	"ld      %r18,104(%r3)\n"
	"ld      %r19,112(%r3)\n"
	"ld      %r20,120(%r3)\n"
	"ld      %r21,128(%r3)\n"
	"ld      %r22,136(%r3)\n"
	"ld      %r23,144(%r3)\n"
	"ld      %r24,152(%r3)\n"
	"ld      %r25,160(%r3)\n"
	"ld      %r26,168(%r3)\n"
	"ld      %r27,176(%r3)\n"
	"ld      %r28,184(%r3)\n"
	"ld      %r29,192(%r3)\n"
	"ld      %r30,200(%r3)\n"
	"ld      %r31,208(%r3)\n"
	"mtcr    %r6\n"
#else
	"mfcr    %r8\n"
	"stw     %r1,40(%r4)\n"
	"mflr    %r9\n"
	"stw     %r13,60(%r4)\n"
	"stw     %r14,64(%r4)\n"
	"stw     %r15,68(%r4)\n"
	"stw     %r16,72(%r4)\n"
	"stw     %r17,76(%r4)\n"
	"stw     %r18,80(%r4)\n"
	"stw     %r19,84(%r4)\n"
	"stw     %r20,88(%r4)\n"
	"stw     %r21,92(%r4)\n"
	"stw     %r22,96(%r4)\n"
	"stw     %r23,100(%r4)\n"
	"stw     %r24,104(%r4)\n"
	"stw     %r25,108(%r4)\n"
	"stw     %r26,112(%r4)\n"
	"stw     %r27,116(%r4)\n"
	"stw     %r28,120(%r4)\n"
	"stw     %r29,124(%r4)\n"
	"stw     %r30,128(%r4)\n"
	"stw     %r31,132(%r4)\n"
	"stw     %r9,32(%r4)\n"
	"lwz     %r7,32(%r3)\n"
	"lwz     %r1,40(%r3)\n"
	"bl      1f\n"
	"trap\n"
	"1:stw     %r8,48(%r4)\n"
	"lwz     %r6,48(%r3)\n"
	"mtctr   %r7\n"
	"lwz     %r13,60(%r3)\n"
	"lwz     %r14,64(%r3)\n"
	"lwz     %r15,68(%r3)\n"
	"lwz     %r16,72(%r3)\n"
	"lwz     %r17,76(%r3)\n"
	"lwz     %r18,80(%r3)\n"
	"lwz     %r19,84(%r3)\n"
	"lwz     %r20,88(%r3)\n"
	"lwz     %r21,92(%r3)\n"
	"lwz     %r22,96(%r3)\n"
	"lwz     %r23,100(%r3)\n"
	"lwz     %r24,104(%r3)\n"
	"lwz     %r25,108(%r3)\n"
	"lwz     %r26,112(%r3)\n"
	"lwz     %r27,116(%r3)\n"
	"lwz     %r28,120(%r3)\n"
	"lwz     %r29,124(%r3)\n"
	"lwz     %r30,128(%r3)\n"
	"lwz     %r31,132(%r3)\n"
	"mtcr    %r6\n"
#endif

#ifndef LIBCO_PPC_NOFP
	"stfd    %f14,224(%r4)\n"
	"stfd    %f15,232(%r4)\n"
	"stfd    %f16,240(%r4)\n"
	"stfd    %f17,248(%r4)\n"
	"stfd    %f18,256(%r4)\n"
	"stfd    %f19,264(%r4)\n"
	"stfd    %f20,272(%r4)\n"
	"stfd    %f21,280(%r4)\n"
	"stfd    %f22,288(%r4)\n"
	"stfd    %f23,296(%r4)\n"
	"stfd    %f24,304(%r4)\n"
	"stfd    %f25,312(%r4)\n"
	"stfd    %f26,320(%r4)\n"
	"stfd    %f27,328(%r4)\n"
	"stfd    %f28,336(%r4)\n"
	"stfd    %f29,344(%r4)\n"
	"stfd    %f30,352(%r4)\n"
	"stfd    %f31,360(%r4)\n"
	"lfd     %f14,224(%r3)\n"
	"lfd     %f15,232(%r3)\n"
	"lfd     %f16,240(%r3)\n"
	"lfd     %f17,248(%r3)\n"
	"lfd     %f18,256(%r3)\n"
	"lfd     %f19,264(%r3)\n"
	"lfd     %f20,272(%r3)\n"
	"lfd     %f21,280(%r3)\n"
	"lfd     %f22,288(%r3)\n"
	"lfd     %f23,296(%r3)\n"
	"lfd     %f24,304(%r3)\n"
	"lfd     %f25,312(%r3)\n"
	"lfd     %f26,320(%r3)\n"
	"lfd     %f27,328(%r3)\n"
	"lfd     %f28,336(%r3)\n"
	"lfd     %f29,344(%r3)\n"
	"lfd     %f30,352(%r3)\n"
	"lfd     %f31,360(%r3)\n"
#endif

#ifdef __ALTIVEC__
	"mfvrsave %r5\n"
	"addi    %r8,%r4,384\n"
	"addi    %r9,%r4,400\n"
	"andi.   %r0,%r5,4095\n"
	"stw     %r5,52(%r4)\n"
	"beq-    2\n"
	"stvx    %v20,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v21,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v22,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v23,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v24,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v25,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v26,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v27,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v28,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v29,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v30,%r0,%r8\n"
	"stvx    %v31,%r0,%r9\n"
	"2:lwz     %r5,52(%r3)\n"
	"addi    %r8,%r3,384\n"
	"addi    %r9,%r3,400\n"
	"andi.   %r0,%r5,4095\n"
	"mtvrsave %r5\n"
	"beqctr  \n"
	"lvx     %v20,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v21,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v22,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v23,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v24,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v25,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v26,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v27,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v28,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v29,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v30,%r0,%r8\n"
	"lvx     %v31,%r0,%r9\n"
#endif
	"bctr"
);

extern void libco_ppc_code(cothread_t, cothread_t);

#if LIBCO_PPCDESC
/* Function call goes through indirect descriptor */
#define CO_SWAP_ASM(x, y) \
			((void (*)(cothread_t, cothread_t)) (uintptr_t) x)(x, y)
#else
/* Function call goes directly to code */
#define CO_SWAP_ASM(x, y) \
			libco_ppc_code(x, y)
#endif

#else

/* Swap code is here in array. Please leave dieassembly comments,
as they make it easy to see what it does, and reorder instructions
if one wants to see whether that improves performance. */
static const uint32_t libco_ppc_code [] = {
#if LIBCO_PPC64
    0x7d000026, /* mfcr    r8 */
    0xf8240028, /* std     r1,40(r4) */
    0x7d2802a6, /* mflr    r9 */
    0xf9c40048, /* std     r14,72(r4) */
    0xf9e40050, /* std     r15,80(r4) */
    0xfa040058, /* std     r16,88(r4) */
    0xfa240060, /* std     r17,96(r4) */
    0xfa440068, /* std     r18,104(r4) */
    0xfa640070, /* std     r19,112(r4) */
    0xfa840078, /* std     r20,120(r4) */
    0xfaa40080, /* std     r21,128(r4) */
    0xfac40088, /* std     r22,136(r4) */
    0xfae40090, /* std     r23,144(r4) */
    0xfb040098, /* std     r24,152(r4) */
    0xfb2400a0, /* std     r25,160(r4) */
    0xfb4400a8, /* std     r26,168(r4) */
    0xfb6400b0, /* std     r27,176(r4) */
    0xfb8400b8, /* std     r28,184(r4) */
    0xfba400c0, /* std     r29,192(r4) */
    0xfbc400c8, /* std     r30,200(r4) */
    0xfbe400d0, /* std     r31,208(r4) */
    0xf9240020, /* std     r9,32(r4) */
    0xe8e30020, /* ld      r7,32(r3) */
    0xe8230028, /* ld      r1,40(r3) */
    0x48000009, /* bl      1 */
	0x7fe00008, /* trap */
    0x91040030,/*1:stw     r8,48(r4) */
    0x80c30030, /* lwz     r6,48(r3) */
    0x7ce903a6, /* mtctr   r7 */
    0xe9c30048, /* ld      r14,72(r3) */
    0xe9e30050, /* ld      r15,80(r3) */
    0xea030058, /* ld      r16,88(r3) */
    0xea230060, /* ld      r17,96(r3) */
    0xea430068, /* ld      r18,104(r3) */
    0xea630070, /* ld      r19,112(r3) */
    0xea830078, /* ld      r20,120(r3) */
    0xeaa30080, /* ld      r21,128(r3) */
    0xeac30088, /* ld      r22,136(r3) */
    0xeae30090, /* ld      r23,144(r3) */
    0xeb030098, /* ld      r24,152(r3) */
    0xeb2300a0, /* ld      r25,160(r3) */
    0xeb4300a8, /* ld      r26,168(r3) */
    0xeb6300b0, /* ld      r27,176(r3) */
    0xeb8300b8, /* ld      r28,184(r3) */
    0xeba300c0, /* ld      r29,192(r3) */
    0xebc300c8, /* ld      r30,200(r3) */
    0xebe300d0, /* ld      r31,208(r3) */
    0x7ccff120, /* mtcr    r6 */
#else
	0x7d000026, /* mfcr    r8 */
	0x90240028, /* stw     r1,40(r4) */
	0x7d2802a6, /* mflr    r9 */
	0x91a4003c, /* stw     r13,60(r4) */
	0x91c40040, /* stw     r14,64(r4) */
	0x91e40044, /* stw     r15,68(r4) */
	0x92040048, /* stw     r16,72(r4) */
	0x9224004c, /* stw     r17,76(r4) */
	0x92440050, /* stw     r18,80(r4) */
	0x92640054, /* stw     r19,84(r4) */
	0x92840058, /* stw     r20,88(r4) */
	0x92a4005c, /* stw     r21,92(r4) */
	0x92c40060, /* stw     r22,96(r4) */
	0x92e40064, /* stw     r23,100(r4) */
	0x93040068, /* stw     r24,104(r4) */
	0x9324006c, /* stw     r25,108(r4) */
	0x93440070, /* stw     r26,112(r4) */
	0x93640074, /* stw     r27,116(r4) */
	0x93840078, /* stw     r28,120(r4) */
	0x93a4007c, /* stw     r29,124(r4) */
	0x93c40080, /* stw     r30,128(r4) */
	0x93e40084, /* stw     r31,132(r4) */
	0x91240020, /* stw     r9,32(r4) */
	0x80e30020, /* lwz     r7,32(r3) */
	0x80230028, /* lwz     r1,40(r3) */
	0x48000009, /* bl      1 */
	0x7fe00008, /* trap */
	0x91040030,/*1:stw     r8,48(r4) */
	0x80c30030, /* lwz     r6,48(r3) */
	0x7ce903a6, /* mtctr   r7 */
	0x81a3003c, /* lwz     r13,60(r3) */
	0x81c30040, /* lwz     r14,64(r3) */
	0x81e30044, /* lwz     r15,68(r3) */
	0x82030048, /* lwz     r16,72(r3) */
	0x8223004c, /* lwz     r17,76(r3) */
	0x82430050, /* lwz     r18,80(r3) */
	0x82630054, /* lwz     r19,84(r3) */
	0x82830058, /* lwz     r20,88(r3) */
	0x82a3005c, /* lwz     r21,92(r3) */
	0x82c30060, /* lwz     r22,96(r3) */
	0x82e30064, /* lwz     r23,100(r3) */
	0x83030068, /* lwz     r24,104(r3) */
	0x8323006c, /* lwz     r25,108(r3) */
	0x83430070, /* lwz     r26,112(r3) */
	0x83630074, /* lwz     r27,116(r3) */
	0x83830078, /* lwz     r28,120(r3) */
	0x83a3007c, /* lwz     r29,124(r3) */
	0x83c30080, /* lwz     r30,128(r3) */
	0x83e30084, /* lwz     r31,132(r3) */
	0x7ccff120, /* mtcr    r6 */
#endif

#ifndef LIBCO_PPC_NOFP
	0xd9c400e0, /* stfd    f14,224(r4) */
	0xd9e400e8, /* stfd    f15,232(r4) */
	0xda0400f0, /* stfd    f16,240(r4) */
	0xda2400f8, /* stfd    f17,248(r4) */
	0xda440100, /* stfd    f18,256(r4) */
	0xda640108, /* stfd    f19,264(r4) */
	0xda840110, /* stfd    f20,272(r4) */
	0xdaa40118, /* stfd    f21,280(r4) */
	0xdac40120, /* stfd    f22,288(r4) */
	0xdae40128, /* stfd    f23,296(r4) */
	0xdb040130, /* stfd    f24,304(r4) */
	0xdb240138, /* stfd    f25,312(r4) */
	0xdb440140, /* stfd    f26,320(r4) */
	0xdb640148, /* stfd    f27,328(r4) */
	0xdb840150, /* stfd    f28,336(r4) */
	0xdba40158, /* stfd    f29,344(r4) */
	0xdbc40160, /* stfd    f30,352(r4) */
	0xdbe40168, /* stfd    f31,360(r4) */
	0xc9c300e0, /* lfd     f14,224(r3) */
	0xc9e300e8, /* lfd     f15,232(r3) */
	0xca0300f0, /* lfd     f16,240(r3) */
	0xca2300f8, /* lfd     f17,248(r3) */
	0xca430100, /* lfd     f18,256(r3) */
	0xca630108, /* lfd     f19,264(r3) */
	0xca830110, /* lfd     f20,272(r3) */
	0xcaa30118, /* lfd     f21,280(r3) */
	0xcac30120, /* lfd     f22,288(r3) */
	0xcae30128, /* lfd     f23,296(r3) */
	0xcb030130, /* lfd     f24,304(r3) */
	0xcb230138, /* lfd     f25,312(r3) */
	0xcb430140, /* lfd     f26,320(r3) */
	0xcb630148, /* lfd     f27,328(r3) */
	0xcb830150, /* lfd     f28,336(r3) */
	0xcba30158, /* lfd     f29,344(r3) */
	0xcbc30160, /* lfd     f30,352(r3) */
	0xcbe30168, /* lfd     f31,360(r3) */
#endif

#ifdef __ALTIVEC__
	0x7ca042a6, /* mfvrsave r5 */
	0x39040180, /* addi    r8,r4,384 */
	0x39240190, /* addi    r9,r4,400 */
	0x70a00fff, /* andi.   r0,r5,4095 */
	0x90a40034, /* stw     r5,52(r4) */
	0x4182005c, /* beq-    2 */
	0x7e8041ce, /* stvx    v20,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ea049ce, /* stvx    v21,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7ec041ce, /* stvx    v22,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ee049ce, /* stvx    v23,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f0041ce, /* stvx    v24,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f2049ce, /* stvx    v25,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f4041ce, /* stvx    v26,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f6049ce, /* stvx    v27,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f8041ce, /* stvx    v28,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7fa049ce, /* stvx    v29,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7fc041ce, /* stvx    v30,r0,r8 */
	0x7fe049ce, /* stvx    v31,r0,r9 */
	0x80a30034,/*2:lwz     r5,52(r3) */
	0x39030180, /* addi    r8,r3,384 */
	0x39230190, /* addi    r9,r3,400 */
	0x70a00fff, /* andi.   r0,r5,4095 */
	0x7ca043a6, /* mtvrsave r5 */
	0x4d820420, /* beqctr   */
	0x7e8040ce, /* lvx     v20,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ea048ce, /* lvx     v21,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7ec040ce, /* lvx     v22,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ee048ce, /* lvx     v23,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f0040ce, /* lvx     v24,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f2048ce, /* lvx     v25,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f4040ce, /* lvx     v26,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f6048ce, /* lvx     v27,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f8040ce, /* lvx     v28,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7fa048ce, /* lvx     v29,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7fc040ce, /* lvx     v30,r0,r8 */
	0x7fe048ce, /* lvx     v31,r0,r9 */
#endif

	0x4e800420, /* bctr */
};

	#if LIBCO_PPCDESC
		/* Function call goes through indirect descriptor */
		#define CO_SWAP_ASM(x, y) \
			((void (*)(cothread_t, cothread_t)) (uintptr_t) x)(x, y)
	#else
		/* Function call goes directly to code */
		#define CO_SWAP_ASM(x, y) \
			((void (*)(cothread_t, cothread_t)) (uintptr_t) libco_ppc_code)(x, y)
	#endif

#endif

static uint32_t* co_create_( unsigned size, uintptr_t entry)
{
	uint32_t *t = (uint32_t*)malloc(size);

#if LIBCO_PPCDESC
   if (t)
   {
      /* Copy entry's descriptor */
      memcpy(t, (void*)entry, sizeof(void*) * 3);

      /* Set function pointer to swap routine */
#ifdef LIBCO_PPC_ASM
      *(const void**) t = *(void**) &co_swap_asm;
#else
      *(const void**) t = libco_ppc_code;
#endif
   }
	#endif

	return t;
}

cothread_t co_create(unsigned int size, void (*entry_)(void))
{
	uintptr_t entry = (uintptr_t) entry_;
	uint32_t *t     = NULL;

	/* Be sure main thread was successfully allocated */
	if (co_active())
	{
		size += state_size + above_stack + stack_align;
		t     = co_create_(size, entry);
	}

	if (t)
   {
      uintptr_t sp;
#if LIBCO_PPC64
      int shift = 16;
#else
      int shift = 0;
#endif
      /* Save current registers into new thread, so that any special ones will
         have proper values when thread is begun */
      CO_SWAP_ASM(t, t);

#if LIBCO_PPCDESC
      /* Get real address */
      entry     = (uintptr_t) *(void**)entry;
#endif

      /* Put stack near end of block, and align */
      sp        = (uintptr_t) t + size - above_stack;
      sp       -= sp % stack_align;

      /* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
         save and restore them as 64 bits, regardless of the size the ABI
         uses. So, we manually write pointers at the proper size. We always
         save and restore at the same address, and since PPC is big-endian,
         we must put the low byte first on PPC32. */

      /* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts
         and don't have to care how many bits uintptr_t is. */

      /* Set up so entry will be called on next swap */
      t [8]  = (uint32_t) (entry >> shift >> shift);
      t [9]  = (uint32_t) entry;

      t [10] = (uint32_t) (sp    >> shift >> shift);
      t [11] = (uint32_t) sp;
   }

	return t;
}

void co_delete(cothread_t t)
{
   free(t);
}

static void co_init_(void)
{
#if LIBCO_MPROTECT && !LIBCO_STATIC_TEXT
   /* TODO: pre- and post-pad PPC code so that this doesn't make other
      data executable and writable */
   long page_size = sysconf(_SC_PAGESIZE);
   if (page_size > 0)
   {
      uintptr_t align = page_size;
      uintptr_t begin = (uintptr_t) libco_ppc_code;
      uintptr_t end   = begin + sizeof libco_ppc_code;

      /* Align beginning and end */
      end            += align - 1;
      end            -= end   % align;
      begin          -= begin % align;

      mprotect((void*)begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC);
   }
#endif

   co_active_handle = co_create_(state_size, (uintptr_t) &co_switch);
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_init_();

   return co_active_handle;
}

void co_switch(cothread_t t)
{
   cothread_t old   = co_active_handle;
   co_active_handle = t;
   CO_SWAP_ASM(t, old);
}

./include/libretro-common/libco/ps2.c

#define LIBCO_C
#include "libco.h"

#include <stdlib.h>
#include <stdint.h>
#include <kernel.h>

/* Since cothread_t is a void pointer it must contain an address. We can't return a reference to a local variable
 * because it would go out of scope, so we create a static variable instead so we can return a reference to it.
 */
static int32_t active_thread_id = -1;
extern void *_gp;

cothread_t co_active()
{
  active_thread_id = GetThreadId();
  return &active_thread_id;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   /* Similar scenario as with active_thread_id except there will only be one active_thread_id while there could be many
    * new threads each with their own handle, so we create them on the heap instead and delete them manually when they're
    * no longer needed in co_delete().
    */
   ee_thread_t thread;
   int32_t new_thread_id;
   cothread_t handle       = malloc(sizeof(cothread_t));
   void *threadStack       = (void *)malloc(size);

   if (!threadStack)
      return -1;

   thread.stack_size		   = size;
   thread.gp_reg			   = &_gp;
   thread.func				   = (void *)entrypoint;
   thread.stack			   = threadStack;
   thread.option			   = 0;
   thread.initial_priority = 1;

   new_thread_id           = CreateThread(&thread);
   StartThread(new_thread_id, NULL);
   *(uint32_t *)handle     = new_thread_id;
   return handle;
}

void co_delete(cothread_t handle)
{
   TerminateThread(*(uint32_t *)handle);
   DeleteThread(*(uint32_t *)handle);
   free(handle);
}

void co_switch(cothread_t handle)
{
   WakeupThread(*(uint32_t *)handle);
   /* Sleep the currently active thread so the new thread can start */
   SleepThread();
}

./include/libretro-common/libco/ps3.S

.globl .co_swap_asm
.globl co_swap_asm
.type .co_swap_asm, @function
.type co_swap_asm, @function
.co_swap_asm:
co_swap_asm:
      mfcr    8
      std     1,40(4)
      mflr    9
      std     14,72(4)
      std     15,80(4)
      std     16,88(4)
      std     17,96(4)
      std     18,104(4)
      std     19,112(4)
      std     20,120(4)
      std     21,128(4)
      std     22,136(4)
      std     23,144(4)
      std     24,152(4)
      std     25,160(4)
      std     26,168(4)
      std     27,176(4)
      std     28,184(4)
      std     29,192(4)
      std     30,200(4)
      std     31,208(4)
      std     9,32(4)
      ld      7,32(3)
      ld      1,40(3)
      bl      swap
      trap
swap: stw     8,48(4)
      lwz     6,48(3)
      mtctr   7
      ld      14,72(3)
      ld      15,80(3)
      ld      16,88(3)
      ld      17,96(3)
      ld      18,104(3)
      ld      19,112(3)
      ld      20,120(3)
      ld      21,128(3)
      ld      22,136(3)
      ld      23,144(3)
      ld      24,152(3)
      ld      25,160(3)
      ld      26,168(3)
      ld      27,176(3)
      ld      28,184(3)
      ld      29,192(3)
      ld      30,200(3)
      ld      31,208(3)
      mtcr    6
      bctr

./include/libretro-common/libco/psp1.c

#define LIBCO_C
#include "libco.h"

#include <stdlib.h>
#include <pspthreadman.h>

typedef void (*entrypoint_t)(void);

cothread_t co_active(void)
{
  return (void *)sceKernelGetThreadId();
}

static int thread_wrap(unsigned int argc, void *argp)
{
  entrypoint_t entrypoint = *(entrypoint_t *) argp;
  sceKernelSleepThread();
  entrypoint();
  return 0;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
  SceUID new_thread_id = sceKernelCreateThread("cothread", thread_wrap, 0x12, size, 0, NULL);
  sceKernelStartThread(new_thread_id, sizeof (entrypoint), &entrypoint);
  return (void *) new_thread_id;
}

void co_delete(cothread_t handle)
{
  SceUID id = (SceUID) handle;
  sceKernelTerminateDeleteThread(id);
}

void co_switch(cothread_t handle)
{
  SceUID id = (SceUID) handle;
  sceKernelWakeupThread(id);
  /* Sleep the currently active thread so the new thread can start */
  sceKernelSleepThread();
}

./include/libretro-common/libco/psp2.c

/*
libco.arm (2015-06-18)
license: public domain
*/

#define LIBCO_C
#include "libco.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <psp2/kernel/sysmem.h>
#include <stdio.h>
#include <string.h>

#define FOUR_KB_ALIGN(x) align(x, 12)
#define MB_ALIGN(x)      align(x, 20)

#ifdef __cplusplus
extern "C" {
#endif

   static inline int align(int x, int n)
   {
      return (((x >> n) + 1) << n);
   }

   static thread_local unsigned long co_active_buffer[64];
   static thread_local cothread_t co_active_handle = 0;
   static void(*co_swap)(cothread_t, cothread_t) = 0;
   static int block;
   static uint32_t co_swap_function[] = {
      0xe8a16ff0,  /* stmia r1!, {r4-r11,sp,lr} */
      0xe8b0aff0,  /* ldmia r0!, {r4-r11,sp,pc} */
      0xe12fff1e,  /* bx lr                     */
   };

   static void co_init(void)
   {
      int ret;
      void *base;

      block = sceKernelAllocMemBlockForVM("libco",
            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
      if (block < 0)
         return;

      /* Get base address */
      if ((ret = sceKernelGetMemBlockBase(block, &base)) < 0)
         return;

      /* Set domain to be writable by user */
      if ((ret = sceKernelOpenVMDomain()) < 0)
         return;

      memcpy(base, co_swap_function, sizeof co_swap_function);

      /* Set domain back to read-only */
      if ((ret = sceKernelCloseVMDomain()) < 0)
         return;

      /* Flush icache */
      ret = sceKernelSyncVMDomain(block, base,
            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
      if (ret < 0)
         return;

      co_swap = (void(*)(cothread_t, cothread_t))base;
   }

   cothread_t co_active(void)
   {
      if (!co_active_handle)
         co_active_handle = &co_active_buffer;
      return co_active_handle;
   }

   cothread_t co_create(unsigned int size, void(*entrypoint)(void))
   {
      unsigned long* handle = 0;
      if (!co_swap)
         co_init();
      if (!co_active_handle)
         co_active_handle   = &co_active_buffer;
      size                 += 256;
      size                 &= ~15;

      if ((handle = (unsigned long*)malloc(size)))
      {
         unsigned long *p   = (unsigned long*)((unsigned char*)handle + size);
         handle[8]          = (unsigned long)p;
         handle[9]          = (unsigned long)entrypoint;
      }

      return handle;
   }

   void co_delete(cothread_t handle)
   {
      free(handle);
      sceKernelFreeMemBlock(block);
   }

   void co_switch(cothread_t handle)
   {
      cothread_t co_previous_handle = co_active_handle;
      co_swap(co_active_handle = handle, co_previous_handle);
   }

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/scefiber.c

/*
  libco.win (2016-09-06)
  authors: frangarcj
  license: public domain
*/

#define LIBCO_C
#include <libco.h>
#include <stdlib.h>
#include <psp2/sysmodule.h>

#ifdef __cplusplus
extern "C" {
#endif

static thread_local cothread_t co_active_ = 0;

typedef struct SceFiber
{
	char reserved[128];
} SceFiber __attribute__( ( aligned ( 8 ) ) ) ;

/* Forward declarations */
int32_t _sceFiberInitializeImpl(SceFiber *fiber, char *name, void *entry, uint32_t argOnInitialize,
      void* addrContext, int32_t sizeContext, void* params);
int32_t sceFiberFinalize(SceFiber* fiber);
int32_t sceFiberRun(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
int32_t sceFiberSwitch(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
int32_t sceFiberReturnToThread(uint32_t argOnReturn, uint32_t* argOnRun);

static void co_thunk(uint32_t argOnInitialize, uint32_t argOnRun)
{
   ((void (*)(void))argOnInitialize)();
}

cothread_t co_active(void)
{
   if (!co_active_)
   {
      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
      co_active_ = (cothread_t)1;
   }
   return co_active_;
}

cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
{
   int ret;
   SceFiber* tail_fiber   = malloc(sizeof(SceFiber));
   char * m_ctxbuf        = malloc(sizeof(char)*heapsize);
   if (!co_active_)
   {
      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
      co_active_          = (cothread_t)1;
   }

   /* _sceFiberInitializeImpl */
   if ((ret = _sceFiberInitializeImpl(
               tail_fiber, "tailFiber", co_thunk,
               (uint32_t)coentry, (void*)m_ctxbuf, heapsize, NULL)) == 0)
      return (cothread_t)tail_fiber;
   return (cothread_t)ret;
}

void co_delete(cothread_t cothread)
{
   if (cothread != (cothread_t)1)
      sceFiberFinalize((SceFiber*)cothread);
}

void co_switch(cothread_t cothread)
{
   uint32_t argOnReturn  = 0;
   if (cothread == (cothread_t)1)
   {
      co_active_         = cothread;
      sceFiberReturnToThread(0, NULL);
   }
   else
   {
      SceFiber* theFiber = (SceFiber*)cothread;
      co_active_         = cothread;
      if (co_active_ == (cothread_t)1)
         sceFiberRun(theFiber, 0, &argOnReturn);
      else
         sceFiberSwitch(theFiber, 0, &argOnReturn);
   }
}

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/sjlj.c

/*
  libco.sjlj (2008-01-28)
  author: Nach
  license: public domain
*/

/*
 * Note this was designed for UNIX systems. Based on ideas expressed in a paper
 * by Ralf Engelschall.
 * For SJLJ on other systems, one would want to rewrite springboard() and
 * co_create() and hack the jmb_buf stack pointer.
 */

#define LIBCO_C
#include <libco.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
   sigjmp_buf context;
   void (*coentry)(void);
   void *stack;
} cothread_struct;

static thread_local cothread_struct co_primary;
static thread_local cothread_struct *creating, *co_running = 0;

static void springboard(int ignored)
{
   if (sigsetjmp(creating->context, 0))
      co_running->coentry();
}

cothread_t co_active(void)
{
  if (!co_running)
     co_running = &co_primary;
  return (cothread_t)co_running;
}

cothread_t co_create(unsigned int size, void (*coentry)(void))
{
   cothread_struct *thread;
   if (!co_running)
      co_running = &co_primary;

   if ((thread = (cothread_struct*)malloc(sizeof(cothread_struct))))
   {
      stack_t stack;
      stack_t old_stack;

      thread->coentry = thread->stack = 0;

      stack.ss_flags  = 0;
      stack.ss_size   = size;
      thread->stack   = stack.ss_sp = malloc(size);

      if (stack.ss_sp && !sigaltstack(&stack, &old_stack))
      {
         struct sigaction old_handler = {{0}};
         struct sigaction handler     = {{0}};
         handler.sa_handler           = springboard;
         handler.sa_flags             = SA_ONSTACK;
         sigemptyset(&handler.sa_mask);
         creating                     = thread;

         if (!sigaction(SIGUSR1, &handler, &old_handler))
         {
            if (!raise(SIGUSR1))
               thread->coentry        = coentry;
            sigaltstack(&old_stack, 0);
            sigaction(SIGUSR1, &old_handler, 0);
         }
      }

      if (thread->coentry != coentry)
      {
         co_delete(thread);
         thread = 0;
      }
   }

   return (cothread_t)thread;
}

void co_delete(cothread_t cothread)
{
   if (cothread)
   {
      if (((cothread_struct*)cothread)->stack)
         free(((cothread_struct*)cothread)->stack);
      free(cothread);
   }
}

void co_switch(cothread_t cothread)
{
   if (!sigsetjmp(co_running->context, 0))
   {
      co_running = (cothread_struct*)cothread;
      siglongjmp(co_running->context, 1);
   }
}

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/ucontext.c

/*
  libco.ucontext (2008-01-28)
  author: Nach
  license: public domain
*/

/*
 * WARNING: the overhead of POSIX ucontext is very high,
 * assembly versions of libco or libco_sjlj should be much faster
 *
 * This library only exists for two reasons:
 * 1 - as an initial test for the viability of a ucontext implementation
 * 2 - to demonstrate the power and speed of libco over existing implementations,
 *     such as pth (which defaults to wrapping ucontext on unix targets)
 *
 * Use this library only as a *last resort*
 */

#define LIBCO_C
#include <libco.h>
#include <stdlib.h>
#include <ucontext.h>

#ifdef __cplusplus
extern "C" {
#endif

static thread_local ucontext_t co_primary;
static thread_local ucontext_t *co_running = 0;

cothread_t co_active(void)
{
   if (!co_running)
      co_running = &co_primary;
   return (cothread_t)co_running;
}

cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
{
   ucontext_t *thread;
   if (!co_running)
      co_running = &co_primary;

   if ((thread = (ucontext_t*)malloc(sizeof(ucontext_t))))
   {
      if ((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize)))
      {
         thread->uc_link = co_running;
         thread->uc_stack.ss_size = heapsize;
         makecontext(thread, coentry, 0);
      }
      else
      {
         co_delete((cothread_t)thread);
         thread = 0;
      }
   }
   return (cothread_t)thread;
}

void co_delete(cothread_t cothread)
{
   if (!cothread)
      return;

   if (((ucontext_t*)cothread)->uc_stack.ss_sp)
      free(((ucontext_t*)cothread)->uc_stack.ss_sp);
   free(cothread);
}

void co_switch(cothread_t cothread)
{
   ucontext_t *old_thread = co_running;
   co_running             = (ucontext_t*)cothread;
   swapcontext(old_thread, co_running);
}

#ifdef __cplusplus
}
#endif

./include/libretro-common/libco/x86.c

/*
  libco.x86 (2009-10-12)
  author: byuu
  license: public domain
*/

#define LIBCO_C
#include <libco.h>
#include <assert.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

#if defined(_MSC_VER)
  #define fastcall __fastcall
#elif defined(__GNUC__)
  #define fastcall __attribute__((fastcall))
#else
  #error "libco: please define fastcall macro"
#endif

static thread_local long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;

/* ABI: fastcall */
static unsigned char co_swap_function[] = {
  0x89, 0x22,         /* mov [edx],esp      */
  0x8b, 0x21,         /* mov esp,[ecx]      */
  0x58,               /* pop eax            */
  0x89, 0x6a, 0x04,   /* mov [edx+0x04],ebp */
  0x89, 0x72, 0x08,   /* mov [edx+0x08],esi */
  0x89, 0x7a, 0x0c,   /* mov [edx+0x0c],edi */
  0x89, 0x5a, 0x10,   /* mov [edx+0x10],ebx */
  0x8b, 0x69, 0x04,   /* mov ebp,[ecx+0x04] */
  0x8b, 0x71, 0x08,   /* mov esi,[ecx+0x08] */
  0x8b, 0x79, 0x0c,   /* mov edi,[ecx+0x0c] */
  0x8b, 0x59, 0x10,   /* mov ebx,[ecx+0x10] */
  0xff, 0xe0,         /* jmp eax            */
};

#ifdef _WIN32
#include <windows.h>

static void co_init(void)
{
   DWORD old_privileges;
   VirtualProtect(co_swap_function,
         sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
#include <unistd.h>
#include <sys/mman.h>

static void co_init(void)
{
   unsigned long addr = (unsigned long)co_swap_function;
   unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
   unsigned long size = (addr - base) + sizeof co_swap_function;
   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif

static void crash(void)
{
   assert(0); /* called only if cothread_t entrypoint returns */
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_active_handle = &co_active_buffer;
   return co_active_handle;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   cothread_t handle;
   if (!co_swap)
   {
      co_init();
      co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
   }

   if (!co_active_handle)
      co_active_handle = &co_active_buffer;

   size += 256; /* allocate additional space for storage */
   size &= ~15; /* align stack to 16-byte boundary */

   if ((handle = (cothread_t)malloc(size)))
   {
      long *p        = (long*)((char*)handle + size); /* seek to top of stack */
      *--p           = (long)crash;                   /* crash if entrypoint returns */
      *--p           = (long)entrypoint;              /* start of function */
      *(long*)handle = (long)p;                       /* stack pointer */
   }

   return handle;
}

void co_delete(cothread_t handle)
{
   free(handle);
}

void co_switch(cothread_t handle)
{
   register cothread_t co_previous_handle = co_active_handle;
   co_swap(co_active_handle = handle, co_previous_handle);
}

#ifdef __cplusplus
}
#endif

./include/libretro-common/libretro.h

/*!
 * libretro.h is a simple API that allows for the creation of games and emulators.
 *
 * @file libretro.h
 * @version 1
 * @author libretro
 * @copyright Copyright (C) 2010-2024 The RetroArch team
 *
 * @paragraph LICENSE
 * The following license statement only applies to this libretro API header (libretro.h).
 *
 * Copyright (C) 2010-2024 The RetroArch team
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_H__
#define LIBRETRO_H__

#include <stdint.h>
#include <stddef.h>
#include <limits.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef __cplusplus
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode
 * as it isn't C99-compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include <stdbool.h>
#endif
#endif

#ifndef RETRO_CALLCONV
#  if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__)
#    define RETRO_CALLCONV __attribute__((cdecl))
#  elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64)
#    define RETRO_CALLCONV __cdecl
#  else
#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */
#  endif
#endif

#ifndef RETRO_API
#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
#    ifdef RETRO_IMPORT_SYMBOLS
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)
#      endif
#    else
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)
#      endif
#    endif
#  else
#      if defined(__GNUC__) && __GNUC__ >= 4
#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
#      else
#        define RETRO_API RETRO_CALLCONV
#      endif
#  endif
#endif

/**
 * The major version of the libretro API and ABI.
 * Cores may support multiple versions,
 * or they may reject cores with unsupported versions.
 * It is only incremented for incompatible API/ABI changes;
 * this generally implies a function was removed or changed,
 * or that a \c struct had fields removed or changed.
 * @note A design goal of libretro is to avoid having to increase this value at all costs.
 * This is why there are APIs that are "extended" or "V2".
 */
#define RETRO_API_VERSION         1

/**
 * @defgroup RETRO_DEVICE Input Devices
 * @brief Libretro's fundamental device abstractions.
 *
 * Libretro's input system consists of abstractions over standard device types,
 * such as a joypad (with or without analog), mouse, keyboard, light gun, or an abstract pointer.
 * Instead of managing input devices themselves,
 * cores need only to map their own concept of a controller to libretro's abstractions.
 * This makes it possible for frontends to map the abstract types to a real input device
 * without having to worry about the correct use of arbitrary (real) controller layouts.
 * @{
 */

#define RETRO_DEVICE_TYPE_SHIFT         8
#define RETRO_DEVICE_MASK               ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)

/**
 * Defines an ID for a subclass of a known device type.
 *
 * To define a subclass ID, use this macro like so:
 * @code{c}
 * #define RETRO_DEVICE_SUPER_SCOPE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)
 * #define RETRO_DEVICE_JUSTIFIER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)
 * @endcode
 *
 * Correct use of this macro allows a frontend to select a suitable physical device
 * to map to the emulated device.
 *
 * @note Cores must use the base ID when polling for input,
 * and frontends must only accept the base ID for this purpose.
 * Polling for input using subclass IDs is reserved for future definition.
 *
 * @param base One of the \ref RETRO_DEVICE "base device types".
 * @param id A unique ID, with respect to \c base.
 * Must be a non-negative integer.
 * @return A unique subclass ID.
 * @see retro_controller_description
 * @see retro_set_controller_port_device
 */
#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)

/**
 * @defgroup RETRO_DEVICE Input Device Classes
 * @{
 */

/**
 * Indicates no input.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * all other arguments are ignored and zero is returned.
 *
 * @see retro_input_state_t
 */
#define RETRO_DEVICE_NONE         0

/**
 * An abstraction around a game controller, known as a "RetroPad".
 *
 * The RetroPad is modelled after a SNES controller,
 * but with additional L2/R2/L3/R3 buttons
 * (similar to a PlayStation controller).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button (including D-Pad directions) to query.
 * The result of said query will be 1 if the button is down, 0 if not.
 *
 * There is one exception; if \c RETRO_DEVICE_ID_JOYPAD_MASK is queried
 * (and the frontend supports this query),
 * the result will be a bitmask of all pressed buttons.
 *
 * @see retro_input_state_t
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_ID_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 */
#define RETRO_DEVICE_JOYPAD       1

/**
 * An abstraction around a mouse, similar to the SNES Mouse but with more buttons.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button or axis to query.
 * For buttons, the result of said query
 * will be 1 if the button is down or 0 if not.
 * For mouse wheel axes, the result
 * will be 1 if the wheel was rotated in that direction and 0 if not.
 * For the mouse pointer axis, the result will be thee mouse's movement
 * relative to the last poll.
 * The core is responsible for tracking the mouse's position,
 * and the frontend is responsible for preventing interference
 * by the real hardware pointer (if applicable).
 *
 * @note This should only be used for cores that emulate mouse input,
 * such as for home computers
 * or consoles with mouse attachments.
 * Cores that emulate light guns should use \c RETRO_DEVICE_LIGHTGUN,
 * and cores that emulate touch screens should use \c RETRO_DEVICE_POINTER.
 *
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_DEVICE_LIGHTGUN
 */
#define RETRO_DEVICE_MOUSE        2

/**
 * An abstraction around a keyboard.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the key to poll.
 *
 * @note This should only be used for cores that emulate keyboard input,
 * such as for home computers
 * or consoles with keyboard attachments.
 * Cores that emulate gamepads should use \c RETRO_DEVICE_JOYPAD or \c RETRO_DEVICE_ANALOG,
 * and leave keyboard compatibility to the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK
 * @see retro_key
 */
#define RETRO_DEVICE_KEYBOARD     3

/**
 * An abstraction around a light gun, similar to the PlayStation's Guncon.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes one of several possible inputs.
 *
 * The gun's coordinates are reported in screen space (similar to the pointer)
 * in the range of [-0x8000, 0x7fff].
 * Zero is the center of the game's screen
 * and -0x8000 represents out-of-bounds.
 * The trigger and various auxiliary buttons are also reported.
 *
 * @note A forced off-screen shot can be requested for auto-reloading
 * function in some games.
 *
 * @see RETRO_DEVICE_POINTER
 */
#define RETRO_DEVICE_LIGHTGUN     4

/**
 * An extension of the RetroPad that supports analog input.
 *
 * The analog RetroPad provides two virtual analog sticks (similar to DualShock controllers)
 * and allows any button to be treated as analog (similar to Xbox shoulder triggers).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes an analog axis or an analog button.
 *
 * Analog axes are reported in the range of [-0x8000, 0x7fff],
 * with the X axis being positive towards the right
 * and the Y axis being positive towards the bottom.
 *
 * Analog buttons are reported in the range of [0, 0x7fff],
 * where 0 is unpressed and 0x7fff is fully pressed.
 *
 * @note Cores should only use this type if they need analog input.
 * Otherwise, \c RETRO_DEVICE_JOYPAD should be used.
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ANALOG       5

/**
 * Input Device: Pointer.
 *
 * Abstracts the concept of a pointing mechanism, e.g. touch.
 * This allows libretro to query in absolute coordinates where on the
 * screen a mouse (or something similar) is being placed.
 * For a touch centric device, coordinates reported are the coordinates
 * of the press.
 *
 * Coordinates in X and Y are reported as:
 * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
 * and 0x7fff corresponds to the far right/bottom of the screen.
 * The "screen" is here defined as area that is passed to the frontend and
 * later displayed on the monitor. If the pointer is outside this screen,
 * such as in the black surrounding areas when actual display is larger,
 * edge position is reported. An explicit edge detection is also provided,
 * that will return 1 if the pointer is near the screen edge or actually outside it.
 *
 * The frontend is free to scale/resize this screen as it sees fit, however,
 * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
 * game image, etc.
 *
 * To check if the pointer coordinates are valid (e.g. a touch display
 * actually being touched), \c RETRO_DEVICE_ID_POINTER_PRESSED returns 1 or 0.
 *
 * If using a mouse on a desktop, \c RETRO_DEVICE_ID_POINTER_PRESSED will
 * usually correspond to the left mouse button, but this is a frontend decision.
 * \c RETRO_DEVICE_ID_POINTER_PRESSED will only return 1 if the pointer is
 * inside the game screen.
 *
 * For multi-touch, the index variable can be used to successively query
 * more presses.
 * If index = 0 returns true for \c _PRESSED, coordinates can be extracted
 * with \c _X, \c _Y for index = 0. One can then query \c _PRESSED, \c _X, \c _Y with
 * index = 1, and so on.
 * Eventually \c _PRESSED will return false for an index. No further presses
 * are registered at this point.
 *
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_ID_POINTER_X
 * @see RETRO_DEVICE_ID_POINTER_Y
 * @see RETRO_DEVICE_ID_POINTER_PRESSED
 */
#define RETRO_DEVICE_POINTER      6

/** @} */

/** @defgroup RETRO_DEVICE_ID_JOYPAD RetroPad Input
 * @brief Digital buttons for the RetroPad.
 *
 * Button placement is comparable to that of a SNES controller,
 * combined with the shoulder buttons of a PlayStation controller.
 * These values can also be used for the \c id field of \c RETRO_DEVICE_INDEX_ANALOG_BUTTON
 * to represent analog buttons (usually shoulder triggers).
 * @{
 */

/** The equivalent of the SNES controller's south face button. */
#define RETRO_DEVICE_ID_JOYPAD_B        0

/** The equivalent of the SNES controller's west face button. */
#define RETRO_DEVICE_ID_JOYPAD_Y        1

/** The equivalent of the SNES controller's left-center button. */
#define RETRO_DEVICE_ID_JOYPAD_SELECT   2

/** The equivalent of the SNES controller's right-center button. */
#define RETRO_DEVICE_ID_JOYPAD_START    3

/** Up on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_UP       4

/** Down on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_DOWN     5

/** Left on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_LEFT     6

/** Right on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7

/** The equivalent of the SNES controller's east face button. */
#define RETRO_DEVICE_ID_JOYPAD_A        8

/** The equivalent of the SNES controller's north face button. */
#define RETRO_DEVICE_ID_JOYPAD_X        9

/** The equivalent of the SNES controller's left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L       10

/** The equivalent of the SNES controller's right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R       11

/** The equivalent of the PlayStation's rear left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L2      12

/** The equivalent of the PlayStation's rear right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R2      13

/**
 * The equivalent of the PlayStation's left analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_L3      14

/**
 * The equivalent of the PlayStation's right analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_R3      15

/**
 * Represents a bitmask that describes the state of all \c RETRO_DEVICE_ID_JOYPAD button constants,
 * rather than the state of a single button.
 *
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ID_JOYPAD_MASK    256

/** @} */

/** @defgroup RETRO_DEVICE_ID_ANALOG Analog RetroPad Input
 * @{
 */

/* Index / Id values for ANALOG device. */
#define RETRO_DEVICE_INDEX_ANALOG_LEFT       0
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT      1
#define RETRO_DEVICE_INDEX_ANALOG_BUTTON     2
#define RETRO_DEVICE_ID_ANALOG_X             0
#define RETRO_DEVICE_ID_ANALOG_Y             1

/** @} */

/* Id values for MOUSE. */
#define RETRO_DEVICE_ID_MOUSE_X                0
#define RETRO_DEVICE_ID_MOUSE_Y                1
#define RETRO_DEVICE_ID_MOUSE_LEFT             2
#define RETRO_DEVICE_ID_MOUSE_RIGHT            3
#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4
#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5
#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8
#define RETRO_DEVICE_ID_MOUSE_BUTTON_4         9
#define RETRO_DEVICE_ID_MOUSE_BUTTON_5         10

/* Id values for LIGHTGUN. */
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X        13 /*Absolute Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y        14 /*Absolute Position*/
/** Indicates if lightgun points off the screen or near the edge */
#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN    15 /*Status Check*/
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER          2
#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD          16 /*Forced off-screen shot*/
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A            3
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B            4
#define RETRO_DEVICE_ID_LIGHTGUN_START            6
#define RETRO_DEVICE_ID_LIGHTGUN_SELECT           7
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C            8
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP          9
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN       10
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT       11
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT      12
/* deprecated */
#define RETRO_DEVICE_ID_LIGHTGUN_X                0 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_Y                1 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR           3 /*Use Aux:A instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO            4 /*Use Aux:B instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE            5 /*Use Start instead*/

/* Id values for POINTER. */
#define RETRO_DEVICE_ID_POINTER_X             0
#define RETRO_DEVICE_ID_POINTER_Y             1
#define RETRO_DEVICE_ID_POINTER_PRESSED       2
#define RETRO_DEVICE_ID_POINTER_COUNT         3
/** Indicates if pointer is off the screen or near the edge */
#define RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN 15
/** @} */

/* Returned from retro_get_region(). */
#define RETRO_REGION_NTSC  0
#define RETRO_REGION_PAL   1

/**
 * Identifiers for supported languages.
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 */
enum retro_language
{
   RETRO_LANGUAGE_ENGLISH             = 0,
   RETRO_LANGUAGE_JAPANESE            = 1,
   RETRO_LANGUAGE_FRENCH              = 2,
   RETRO_LANGUAGE_SPANISH             = 3,
   RETRO_LANGUAGE_GERMAN              = 4,
   RETRO_LANGUAGE_ITALIAN             = 5,
   RETRO_LANGUAGE_DUTCH               = 6,
   RETRO_LANGUAGE_PORTUGUESE_BRAZIL   = 7,
   RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,
   RETRO_LANGUAGE_RUSSIAN             = 9,
   RETRO_LANGUAGE_KOREAN              = 10,
   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,
   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 12,
   RETRO_LANGUAGE_ESPERANTO           = 13,
   RETRO_LANGUAGE_POLISH              = 14,
   RETRO_LANGUAGE_VIETNAMESE          = 15,
   RETRO_LANGUAGE_ARABIC              = 16,
   RETRO_LANGUAGE_GREEK               = 17,
   RETRO_LANGUAGE_TURKISH             = 18,
   RETRO_LANGUAGE_SLOVAK              = 19,
   RETRO_LANGUAGE_PERSIAN             = 20,
   RETRO_LANGUAGE_HEBREW              = 21,
   RETRO_LANGUAGE_ASTURIAN            = 22,
   RETRO_LANGUAGE_FINNISH             = 23,
   RETRO_LANGUAGE_INDONESIAN          = 24,
   RETRO_LANGUAGE_SWEDISH             = 25,
   RETRO_LANGUAGE_UKRAINIAN           = 26,
   RETRO_LANGUAGE_CZECH               = 27,
   RETRO_LANGUAGE_CATALAN_VALENCIA    = 28,
   RETRO_LANGUAGE_CATALAN             = 29,
   RETRO_LANGUAGE_BRITISH_ENGLISH     = 30,
   RETRO_LANGUAGE_HUNGARIAN           = 31,
   RETRO_LANGUAGE_BELARUSIAN          = 32,
   RETRO_LANGUAGE_GALICIAN            = 33,
   RETRO_LANGUAGE_NORWEGIAN           = 34,
   RETRO_LANGUAGE_IRISH               = 35,
   RETRO_LANGUAGE_LAST,

   /** Defined to ensure that <tt>sizeof(retro_language) == sizeof(int)</tt>. Do not use. */
   RETRO_LANGUAGE_DUMMY          = INT_MAX
};

/** @defgroup RETRO_MEMORY Memory Types
 * @{
 */

/* Passed to retro_get_memory_data/size().
 * If the memory type doesn't apply to the
 * implementation NULL/0 can be returned.
 */
#define RETRO_MEMORY_MASK        0xff

/* Regular save RAM. This RAM is usually found on a game cartridge,
 * backed up by a battery.
 * If save game data is too complex for a single memory buffer,
 * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
 * callback can be used. */
#define RETRO_MEMORY_SAVE_RAM    0

/* Some games have a built-in clock to keep track of time.
 * This memory is usually just a couple of bytes to keep track of time.
 */
#define RETRO_MEMORY_RTC         1

/* System ram lets a frontend peek into a game systems main RAM. */
#define RETRO_MEMORY_SYSTEM_RAM  2

/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
#define RETRO_MEMORY_VIDEO_RAM   3

/** @} */

/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
enum retro_key
{
   RETROK_UNKNOWN        = 0,
   RETROK_FIRST          = 0,
   RETROK_BACKSPACE      = 8,
   RETROK_TAB            = 9,
   RETROK_CLEAR          = 12,
   RETROK_RETURN         = 13,
   RETROK_PAUSE          = 19,
   RETROK_ESCAPE         = 27,
   RETROK_SPACE          = 32,
   RETROK_EXCLAIM        = 33,
   RETROK_QUOTEDBL       = 34,
   RETROK_HASH           = 35,
   RETROK_DOLLAR         = 36,
   RETROK_AMPERSAND      = 38,
   RETROK_QUOTE          = 39,
   RETROK_LEFTPAREN      = 40,
   RETROK_RIGHTPAREN     = 41,
   RETROK_ASTERISK       = 42,
   RETROK_PLUS           = 43,
   RETROK_COMMA          = 44,
   RETROK_MINUS          = 45,
   RETROK_PERIOD         = 46,
   RETROK_SLASH          = 47,
   RETROK_0              = 48,
   RETROK_1              = 49,
   RETROK_2              = 50,
   RETROK_3              = 51,
   RETROK_4              = 52,
   RETROK_5              = 53,
   RETROK_6              = 54,
   RETROK_7              = 55,
   RETROK_8              = 56,
   RETROK_9              = 57,
   RETROK_COLON          = 58,
   RETROK_SEMICOLON      = 59,
   RETROK_LESS           = 60,
   RETROK_EQUALS         = 61,
   RETROK_GREATER        = 62,
   RETROK_QUESTION       = 63,
   RETROK_AT             = 64,
   RETROK_LEFTBRACKET    = 91,
   RETROK_BACKSLASH      = 92,
   RETROK_RIGHTBRACKET   = 93,
   RETROK_CARET          = 94,
   RETROK_UNDERSCORE     = 95,
   RETROK_BACKQUOTE      = 96,
   RETROK_a              = 97,
   RETROK_b              = 98,
   RETROK_c              = 99,
   RETROK_d              = 100,
   RETROK_e              = 101,
   RETROK_f              = 102,
   RETROK_g              = 103,
   RETROK_h              = 104,
   RETROK_i              = 105,
   RETROK_j              = 106,
   RETROK_k              = 107,
   RETROK_l              = 108,
   RETROK_m              = 109,
   RETROK_n              = 110,
   RETROK_o              = 111,
   RETROK_p              = 112,
   RETROK_q              = 113,
   RETROK_r              = 114,
   RETROK_s              = 115,
   RETROK_t              = 116,
   RETROK_u              = 117,
   RETROK_v              = 118,
   RETROK_w              = 119,
   RETROK_x              = 120,
   RETROK_y              = 121,
   RETROK_z              = 122,
   RETROK_LEFTBRACE      = 123,
   RETROK_BAR            = 124,
   RETROK_RIGHTBRACE     = 125,
   RETROK_TILDE          = 126,
   RETROK_DELETE         = 127,

   RETROK_KP0            = 256,
   RETROK_KP1            = 257,
   RETROK_KP2            = 258,
   RETROK_KP3            = 259,
   RETROK_KP4            = 260,
   RETROK_KP5            = 261,
   RETROK_KP6            = 262,
   RETROK_KP7            = 263,
   RETROK_KP8            = 264,
   RETROK_KP9            = 265,
   RETROK_KP_PERIOD      = 266,
   RETROK_KP_DIVIDE      = 267,
   RETROK_KP_MULTIPLY    = 268,
   RETROK_KP_MINUS       = 269,
   RETROK_KP_PLUS        = 270,
   RETROK_KP_ENTER       = 271,
   RETROK_KP_EQUALS      = 272,

   RETROK_UP             = 273,
   RETROK_DOWN           = 274,
   RETROK_RIGHT          = 275,
   RETROK_LEFT           = 276,
   RETROK_INSERT         = 277,
   RETROK_HOME           = 278,
   RETROK_END            = 279,
   RETROK_PAGEUP         = 280,
   RETROK_PAGEDOWN       = 281,

   RETROK_F1             = 282,
   RETROK_F2             = 283,
   RETROK_F3             = 284,
   RETROK_F4             = 285,
   RETROK_F5             = 286,
   RETROK_F6             = 287,
   RETROK_F7             = 288,
   RETROK_F8             = 289,
   RETROK_F9             = 290,
   RETROK_F10            = 291,
   RETROK_F11            = 292,
   RETROK_F12            = 293,
   RETROK_F13            = 294,
   RETROK_F14            = 295,
   RETROK_F15            = 296,

   RETROK_NUMLOCK        = 300,
   RETROK_CAPSLOCK       = 301,
   RETROK_SCROLLOCK      = 302,
   RETROK_RSHIFT         = 303,
   RETROK_LSHIFT         = 304,
   RETROK_RCTRL          = 305,
   RETROK_LCTRL          = 306,
   RETROK_RALT           = 307,
   RETROK_LALT           = 308,
   RETROK_RMETA          = 309,
   RETROK_LMETA          = 310,
   RETROK_LSUPER         = 311,
   RETROK_RSUPER         = 312,
   RETROK_MODE           = 313,
   RETROK_COMPOSE        = 314,

   RETROK_HELP           = 315,
   RETROK_PRINT          = 316,
   RETROK_SYSREQ         = 317,
   RETROK_BREAK          = 318,
   RETROK_MENU           = 319,
   RETROK_POWER          = 320,
   RETROK_EURO           = 321,
   RETROK_UNDO           = 322,
   RETROK_OEM_102        = 323,

   RETROK_BROWSER_BACK      = 324,
   RETROK_BROWSER_FORWARD   = 325,
   RETROK_BROWSER_REFRESH   = 326,
   RETROK_BROWSER_STOP      = 327,
   RETROK_BROWSER_SEARCH    = 328,
   RETROK_BROWSER_FAVORITES = 329,
   RETROK_BROWSER_HOME      = 330,
   RETROK_VOLUME_MUTE       = 331,
   RETROK_VOLUME_DOWN       = 332,
   RETROK_VOLUME_UP         = 333,
   RETROK_MEDIA_NEXT        = 334,
   RETROK_MEDIA_PREV        = 335,
   RETROK_MEDIA_STOP        = 336,
   RETROK_MEDIA_PLAY_PAUSE  = 337,
   RETROK_LAUNCH_MAIL       = 338,
   RETROK_LAUNCH_MEDIA      = 339,
   RETROK_LAUNCH_APP1       = 340,
   RETROK_LAUNCH_APP2       = 341,

   RETROK_LAST,

   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

enum retro_mod
{
   RETROKMOD_NONE       = 0x0000,

   RETROKMOD_SHIFT      = 0x01,
   RETROKMOD_CTRL       = 0x02,
   RETROKMOD_ALT        = 0x04,
   RETROKMOD_META       = 0x08,

   RETROKMOD_NUMLOCK    = 0x10,
   RETROKMOD_CAPSLOCK   = 0x20,
   RETROKMOD_SCROLLOCK  = 0x40,

   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

/**
 * @defgroup RETRO_ENVIRONMENT Environment Callbacks
 * @{
 */

/**
 * This bit indicates that the associated environment call is experimental,
 * and may be changed or removed in the future.
 * Frontends should mask out this bit before handling the environment call.
 */
#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000

/** Frontend-internal environment callbacks should include this bit. */
#define RETRO_ENVIRONMENT_PRIVATE 0x20000

/* Environment commands. */
/**
 * Requests the frontend to set the screen rotation.
 *
 * @param[in] data <tt>const unsigned*</tt>.
 * Valid values are 0, 1, 2, and 3.
 * These numbers respectively set the screen rotation to 0, 90, 180, and 270 degrees counter-clockwise.
 * @returns \c true if the screen rotation was set successfully.
 */
#define RETRO_ENVIRONMENT_SET_ROTATION  1

/**
 * Queries whether the core should use overscan or not.
 *
 * @param[out] data <tt>bool*</tt>.
 * Set to \c true if the core should use overscan,
 * \c false if it should be cropped away.
 * @returns \c true if the environment call is available.
 * Does \em not indicate whether overscan should be used.
 * @deprecated As of 2019 this callback is considered deprecated in favor of
 * using core options to manage overscan in a more nuanced, core-specific way.
 */
#define RETRO_ENVIRONMENT_GET_OVERSCAN  2

/**
 * Queries whether the frontend supports frame duping,
 * in the form of passing \c NULL to the video frame callback.
 *
 * @param[out] data <tt>bool*</tt>.
 * Set to \c true if the frontend supports frame duping.
 * @returns \c true if the environment call is available.
 * @see retro_video_refresh_t
 */
#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3

/*
 * Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
 * and reserved to avoid possible ABI clash.
 */

/**
 * @brief Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * \code{.c}
 * void set_message_example(void)
 * {
 *    struct retro_message msg;
 *    msg.frames = 60 * 5; // 5 seconds
 *    msg.msg = "Hello world!";
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
 * }
 * \endcode
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT for new code,
 * as it offers more features.
 * Only use this environment call for compatibility with older cores or frontends.
 *
 * @param[in] data <tt>const struct retro_message*</tt>.
 * Details about the message to show to the user.
 * Behavior is undefined if <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see retro_message
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 * @note The frontend must make its own copy of the message and the underlying string.
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE   6

/**
 * Requests the frontend to shutdown the core.
 * Should only be used if the core can exit on its own,
 * such as from a menu item in a game
 * or an emulated power-off in an emulator.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_SHUTDOWN      7

/**
 * Gives a hint to the frontend of how demanding this core is on the system.
 * For example, reporting a level of 2 means that
 * this implementation should run decently on frontends
 * of level 2 and above.
 *
 * It can be used by the frontend to potentially warn
 * about too demanding implementations.
 *
 * The levels are "floating".
 *
 * This function can be called on a per-game basis,
 * as a core may have different demands for different games or settings.
 * If called, it should be called in <tt>retro_load_game()</tt>.
 * @param[in] data <tt>const unsigned*</tt>.
*/
#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8

/**
 * Returns the path to the frontend's system directory,
 * which can be used to store system-specific configuration
 * such as BIOS files or cached data.
 *
 * @param[out] data <tt>const char**</tt>.
 * Pointer to the \c char* in which the system directory will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no system directory is defined,
 * in which case the core should find an alternative directory.
 * @return \c true if the environment call is available,
 * even if the value returned in \c data is <tt>NULL</tt>.
 * @note Historically, some cores would use this folder for save data such as memory cards or SRAM.
 * This is now discouraged in favor of \c RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY.
 * @see RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9

/**
 * Sets the internal pixel format used by the frontend for rendering.
 * The default pixel format is \c RETRO_PIXEL_FORMAT_0RGB1555 for compatibility reasons,
 * although it's considered deprecated and shouldn't be used by new code.
 *
 * @param[in] data <tt>const enum retro_pixel_format *</tt>.
 * Pointer to the pixel format to use.
 * @returns \c true if the pixel format was set successfully,
 * \c false if it's not supported or this callback is unavailable.
 * @note This function should be called inside \c retro_load_game()
 * or <tt>retro_get_system_av_info()</tt>.
 * @see retro_pixel_format
 */
#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10

/**
 * Sets an array of input descriptors for the frontend
 * to present to the user for configuring the core's controls.
 *
 * This function can be called at any time,
 * preferably early in the core's life cycle.
 * Ideally, no later than \c retro_load_game().
 *
 * @param[in] data <tt>const struct retro_input_descriptor *</tt>.
 * An array of input descriptors terminated by one whose
 * \c retro_input_descriptor::description field is set to \c NULL.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is recognized.
 * @see retro_input_descriptor
 */
#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11

/**
 * Sets a callback function used to notify the core about keyboard events.
 * This should only be used for cores that specifically need keyboard input,
 * such as for home computer emulators or games with text entry.
 *
 * @param[in] data <tt>const struct retro_keyboard_callback *</tt>.
 * Pointer to the callback function.
 * Behavior is undefined if <tt>NULL</tt>.
 * @return \c true if the environment call is recognized.
 * @see retro_keyboard_callback
 * @see retro_key
 */
#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12

/**
 * Sets an interface that the frontend can use to insert and remove disks
 * from the emulated console's disk drive.
 * Can be used for optical disks, floppy disks, or any other game storage medium
 * that can be swapped at runtime.
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * over this environment call, as it supports additional features.
 * Only use this callback to maintain compatibility
 * with older cores or frontends.
 *
 * @param[in] data <tt>const struct retro_disk_control_callback *</tt>.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_callback
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13

/**
 * Requests that a frontend enable a particular hardware rendering API.
 *
 * If successful, the frontend will create a context (and other related resources)
 * that the core can use for rendering.
 * The framebuffer will be at least as large as
 * the maximum dimensions provided in <tt>retro_get_system_av_info</tt>.
 *
 * @param[in, out] data <tt>struct retro_hw_render_callback *</tt>.
 * Pointer to the hardware render callback struct.
 * Used to define callbacks for the hardware-rendering life cycle,
 * as well as to request a particular rendering API.
 * @return \c true if the environment call is recognized
 * and the requested rendering API is supported.
 * \c false if \c data is \c NULL
 * or the frontend can't provide the requested rendering API.
 * @see retro_hw_render_callback
 * @see retro_video_refresh_t
 * @see RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER
 * @note Should be called in <tt>retro_load_game()</tt>.
 * @note If HW rendering is used, pass only \c RETRO_HW_FRAME_BUFFER_VALID or
 * \c NULL to <tt>retro_video_refresh_t</tt>.
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER 14

/**
 * Retrieves a core option's value from the frontend.
 * \c retro_variable::key should be set to an option key
 * that was previously set in \c RETRO_ENVIRONMENT_SET_VARIABLES
 * (or a similar environment call).
 *
 * @param[in,out] data <tt>struct retro_variable *</tt>.
 * Pointer to a single \c retro_variable struct.
 * See the documentation for \c retro_variable for details
 * on which fields are set by the frontend or core.
 * May be \c NULL.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL or the key it specifies is not found.
 * @note Passing \c NULL in to \c data can be useful to
 * test for support of this environment call without looking up any variables.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE 15

/**
 * Notifies the frontend of the core's available options.
 *
 * The core may check these options later using \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * The frontend may also present these options to the user
 * in its own configuration UI.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment.
 * The core may later call this function again
 * to communicate updated options to the frontend,
 * but the number of core options must not change.
 *
 * Here's an example that sets two options.
 *
 * @code
 * void set_variables_example(void)
 * {
 *    struct retro_variable options[] = {
 *        { "foo_speedhack", "Speed hack; false|true" }, // false by default
 *        { "foo_displayscale", "Display scale factor; 1|2|3|4" }, // 1 by default
 *        { NULL, NULL },
 *    };
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, &options);
 * }
 * @endcode
 *
 * The possible values will generally be displayed and stored as-is by the frontend.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 for new code,
 * as it offers more features such as categories and translation.
 * Only use this environment call to maintain compatibility
 * with older frontends or cores.
 * @note Keep the available options (and their possible values) as low as possible;
 * it should be feasible to cycle through them without a keyboard.
 * @param[in] data <tt>const struct retro_variable *</tt>.
 * Pointer to an array of \c retro_variable structs that define available core options,
 * terminated by a <tt>{ NULL, NULL }</tt> element.
 * The frontend must maintain its own copy of this array.
 *
 * @returns \c true if the environment call is available,
 * even if \c data is <tt>NULL</tt>.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_VARIABLES 16

/**
 * Queries whether at least one core option was updated by the frontend
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * This typically means that the user opened the core options menu and made some changes.
 *
 * Cores usually call this each frame before the core's main emulation logic.
 * Specific options can then be queried with \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 *
 * @param[out] data <tt>bool *</tt>.
 * Set to \c true if at least one core option was updated
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * Behavior is undefined if this pointer is \c NULL.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17

/**
 * Notifies the frontend that this core can run without loading any content,
 * such as when emulating a console that has built-in software.
 * When a core is loaded without content,
 * \c retro_load_game receives an argument of <tt>NULL</tt>.
 * This should be called within \c retro_set_environment() only.
 *
 * @param[in] data <tt>const bool *</tt>.
 * Pointer to a single \c bool that indicates whether this frontend can run without content.
 * Can point to a value of \c false but this isn't necessary,
 * as contentless support is opt-in.
 * The behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see retro_load_game
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18

/**
 * Retrieves the absolute path from which this core was loaded.
 * Useful when loading assets from paths relative to the core,
 * as is sometimes the case when using <tt>RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME</tt>.
 *
 * @param[out] data <tt>const char **</tt>.
 * Pointer to a string in which the core's path will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if the core is statically linked to the frontend
 * or if the core's path otherwise cannot be determined.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19

/* Environment call 20 was an obsolete version of SET_AUDIO_CALLBACK.
 * It was not used by any known core at the time, and was removed from the API.
 * The number 20 is reserved to prevent ABI clashes.
 */

/**
 * Sets a callback that notifies the core of how much time has passed
 * since the last iteration of <tt>retro_run</tt>.
 * If the frontend is not running the core in real time
 * (e.g. it's frame-stepping or running in slow motion),
 * then the reference value will be provided to the callback instead.
 *
 * @param[in] data <tt>const struct retro_frame_time_callback *</tt>.
 * Pointer to a single \c retro_frame_time_callback struct.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @note Frontends may disable this environment call in certain situations.
 * It will return \c false in those cases.
 * @see retro_frame_time_callback
 */
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21

/**
 * Registers a set of functions that the frontend can use
 * to tell the core it's ready for audio output.
 *
 * It is intended for games that feature asynchronous audio.
 * It should not be used for emulators unless their audio is asynchronous.
 *
 *
 * The callback only notifies about writability; the libretro core still
 * has to call the normal audio callbacks
 * to write audio. The audio callbacks must be called from within the
 * notification callback.
 * The amount of audio data to write is up to the core.
 * Generally, the audio callback will be called continuously in a loop.
 *
 * A frontend may disable this callback in certain situations.
 * The core must be able to render audio with the "normal" interface.
 *
 * @param[in] data <tt>const struct retro_audio_callback *</tt>.
 * Pointer to a set of functions that the frontend will call to notify the core
 * when it's ready to receive audio data.
 * May be \c NULL, in which case the frontend will return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @warning The provided callbacks can be invoked from any thread,
 * so their implementations \em must be thread-safe.
 * @note If a core uses this callback,
 * it should also use <tt>RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK</tt>.
 * @see retro_audio_callback
 * @see retro_audio_sample_t
 * @see retro_audio_sample_batch_t
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22

/**
 * Gets an interface that a core can use to access a controller's rumble motors.
 *
 * The interface supports two independently-controlled motors,
 * one strong and one weak.
 *
 * Should be called from either \c retro_init() or \c retro_load_game(),
 * but not from \c retro_set_environment().
 *
 * @param[out] data <tt>struct retro_rumble_interface *</tt>.
 * Pointer to the interface struct.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the current device doesn't support vibration.
 * @see retro_rumble_interface
 * @defgroup GET_RUMBLE_INTERFACE Rumble Interface
 */
#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23

/**
 * Returns the frontend's supported input device types.
 *
 * The supported device types are returned as a bitmask,
 * with each value of \ref RETRO_DEVICE corresponding to a bit.
 *
 * Should only be called in \c retro_run().
 *
 * @code
 * #define REQUIRED_DEVICES ((1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG))
 * void get_input_device_capabilities_example(void)
 * {
 *    uint64_t capabilities;
 *    environ_cb(RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES, &capabilities);
 *    if ((capabilities & REQUIRED_DEVICES) == REQUIRED_DEVICES)
 *      printf("Joypad and analog device types are supported");
 * }
 * @endcode
 *
 * @param[out] data <tt>uint64_t *</tt>.
 * Pointer to a bitmask of supported input device types.
 * If the frontend supports a particular \c RETRO_DEVICE_* type,
 * then the bit <tt>(1 << RETRO_DEVICE_*)</tt> will be set.
 *
 * Each bit represents a \c RETRO_DEVICE constant,
 * e.g. bit 1 represents \c RETRO_DEVICE_JOYPAD,
 * bit 2 represents \c RETRO_DEVICE_MOUSE, and so on.
 *
 * Bits that do not correspond to known device types will be set to zero
 * and are reserved for future use.
 *
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note If the frontend supports multiple input drivers,
 * availability of this environment call (and the reported capabilities)
 * may depend on the active driver.
 * @see RETRO_DEVICE
 */
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24

/**
 * Returns an interface that the core can use to access and configure available sensors,
 * such as an accelerometer or gyroscope.
 *
 * @param[out] data <tt>struct retro_sensor_interface *</tt>.
 * Pointer to the sensor interface that the frontend will populate.
 * Behavior is undefined if is \c NULL.
 * @returns \c true if the environment call is available,
 * even if the device doesn't have any supported sensors.
 * @see retro_sensor_interface
 * @see retro_sensor_action
 * @see RETRO_SENSOR
 * @addtogroup RETRO_SENSOR
 */
#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface to the device's video camera.
 *
 * The frontend delivers new video frames via a user-defined callback
 * that runs in the same thread as \c retro_run().
 * Should be called in \c retro_load_game().
 *
 * @param[in,out] data <tt>struct retro_camera_callback *</tt>.
 * Pointer to the camera driver interface.
 * Some fields in the struct must be filled in by the core,
 * others are provided by the frontend.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available,
 * even if an actual camera isn't.
 * @note This API only supports one video camera at a time.
 * If the device provides multiple cameras (e.g. inner/outer cameras on a phone),
 * the frontend will choose one to use.
 * @see retro_camera_callback
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for cross-platform logging.
 * Certain platforms don't have a console or <tt>stderr</tt>,
 * or they have their own preferred logging methods.
 * The frontend itself may also display log output.
 *
 * @attention This should not be used for information that the player must immediately see,
 * such as major errors or warnings.
 * In most cases, this is best for information that will help you (the developer)
 * identify problems when debugging or providing support.
 * Unless a core or frontend is intended for advanced users,
 * the player might not check (or even know about) their logs.
 *
 * @param[out] data <tt>struct retro_log_callback *</tt>.
 * Pointer to the callback where the function pointer will be saved.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see retro_log_callback
 * @note Cores can fall back to \c stderr if this interface is not available.
 */
#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27

/**
 * Returns an interface that the core can use for profiling code
 * and to access performance-related information.
 *
 * This callback supports performance counters, a high-resolution timer,
 * and listing available CPU features (mostly SIMD instructions).
 *
 * @param[out] data <tt>struct retro_perf_callback *</tt>.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @see retro_perf_callback
 */
#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28

/**
 * Returns an interface that the core can use to retrieve the device's location,
 * including its current latitude and longitude.
 *
 * @param[out] data <tt>struct retro_location_callback *</tt>.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is available,
 * even if there's no location information available.
 * @see retro_location_callback
 */
#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29

/**
 * @deprecated An obsolete alias to \c RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY kept for compatibility.
 * @see RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY
 **/
#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30

/**
 * Returns the frontend's "core assets" directory,
 * which can be used to store assets that the core needs
 * such as art assets or level data.
 *
 * @param[out] data <tt>const char **</tt>.
 * Pointer to a string in which the core assets directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no core assets directory is defined,
 * in which case the core should find an alternative directory.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is <tt>NULL</tt>.
 */
#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30

/**
 * Returns the frontend's save data directory, if available.
 * This directory should be used to store game-specific save data,
 * including memory card images.
 *
 * Although libretro provides an interface for cores to expose SRAM to the frontend,
 * not all cores can support it correctly.
 * In this case, cores should use this environment callback
 * to save their game data to disk manually.
 *
 * Cores that use this environment callback
 * should flush their save data to disk periodically and when unloading.
 *
 * @param[out] data <tt>const char **</tt>.
 * Pointer to the string in which the save data directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May return \c NULL if no save data directory is defined.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is <tt>NULL</tt>.
 * @note Early libretro cores used \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY for save data.
 * This is still supported for backwards compatibility,
 * but new cores should use this environment call instead.
 * \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY should be used for game-agnostic data
 * such as BIOS files or core-specific configuration.
 * @note The returned directory may or may not be the same
 * as the one used for \c retro_get_memory_data.
 *
 * @see retro_get_memory_data
 * @see RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31

/**
 * Sets new video and audio parameters for the core.
 * This can only be called from within <tt>retro_run</tt>.
 *
 * This environment call may entail a full reinitialization of the frontend's audio/video drivers,
 * hence it should \em only be used if the core needs to make drastic changes
 * to audio/video parameters.
 *
 * This environment call should \em not be used when:
 * <ul>
 * <li>Changing the emulated system's internal resolution,
 * within the limits defined by the existing values of \c max_width and \c max_height.
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY instead,
 * and adjust \c retro_get_system_av_info to account for
 * supported scale factors and screen layouts
 * when computing \c max_width and \c max_height.
 * Only use this environment call if \c max_width or \c max_height needs to increase.
 * <li>Adjusting the screen's aspect ratio,
 * e.g. when changing the layout of the screen(s).
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY or \c RETRO_ENVIRONMENT_SET_ROTATION instead.
 * </ul>
 *
 * The frontend will reinitialize its audio and video drivers within this callback;
 * after that happens, audio and video callbacks will target the newly-initialized driver,
 * even within the same \c retro_run call.
 *
 * This callback makes it possible to support configurable resolutions
 * while avoiding the need to compute the "worst case" values of \c max_width and \c max_height.
 *
 * @param[in] data <tt>const struct retro_system_av_info *</tt>.
 * Pointer to the new video and audio parameters that the frontend should adopt.
 * @returns \c true if the environment call is available
 * and the new av_info struct was accepted.
 * \c false if the environment call is unavailable or \c data is <tt>NULL</tt>.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 */
#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32

/**
 * Provides an interface that a frontend can use
 * to get function pointers from the core.
 *
 * This allows cores to define their own extensions to the libretro API,
 * or to expose implementations of a frontend's libretro extensions.
 *
 * @param[in] data <tt>const struct retro_get_proc_address_interface *</tt>.
 * Pointer to the interface that the frontend can use to get function pointers from the core.
 * The frontend must maintain its own copy of this interface.
 * @returns \c true if the environment call is available
 * and the returned interface was accepted.
 * @note The provided interface may be called at any time,
 * even before this environment call returns.
 * @note Extensions should be prefixed with the name of the frontend or core that defines them.
 * For example, a frontend named "foo" that defines a debugging extension
 * should expect the core to define functions prefixed with "foo_debug_".
 * @warning If a core wants to use this environment call,
 * it \em must do so from within \c retro_set_environment().
 * @see retro_get_proc_address_interface
 */
#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33

/**
 * Registers a core's ability to handle "subsystems",
 * which are secondary platforms that augment a core's primary emulated hardware.
 *
 * A core doesn't need to emulate a secondary platform
 * in order to use it as a subsystem;
 * as long as it can load a secondary file for some practical use,
 * then this environment call is most likely suitable.
 *
 * Possible use cases of a subsystem include:
 *
 * \li Installing software onto an emulated console's internal storage,
 * such as the Nintendo DSi.
 * \li Emulating accessories that are used to support another console's games,
 * such as the Super Game Boy or the N64 Transfer Pak.
 * \li Inserting a secondary ROM into a console
 * that features multiple cartridge ports,
 * such as the Nintendo DS's Slot-2.
 * \li Loading a save data file created and used by another core.
 *
 * Cores should \em not use subsystems for:
 *
 * \li Emulators that support multiple "primary" platforms,
 * such as a Game Boy/Game Boy Advance core
 * or a Sega Genesis/Sega CD/32X core.
 * Use \c retro_system_content_info_override, \c retro_system_info,
 * and/or runtime detection instead.
 * \li Selecting different memory card images.
 * Use dynamically-populated core options instead.
 * \li Different variants of a single console,
 * such the Game Boy vs. the Game Boy Color.
 * Use core options or runtime detection instead.
 * \li Games that span multiple disks.
 * Use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * and m3u-formatted playlists instead.
 * \li Console system files (BIOS, firmware, etc.).
 * Use \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 * and a common naming convention instead.
 *
 * When the frontend loads a game via a subsystem,
 * it must call \c retro_load_game_special() instead of \c retro_load_game().
 *
 * @param[in] data <tt>const struct retro_subsystem_info *</tt>.
 * Pointer to an array of subsystem descriptors,
 * terminated by a zeroed-out \c retro_subsystem_info struct.
 * The frontend should maintain its own copy
 * of this array and the strings within it.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @note This environment call \em must be called from within \c retro_set_environment(),
 * as frontends may need the registered information before loading a game.
 * @see retro_subsystem_info
 * @see retro_load_game_special
 */
#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34

/**
 * Declares one or more types of controllers supported by this core.
 * The frontend may then allow the player to select one of these controllers in its menu.
 *
 * Many consoles had controllers that came in different versions,
 * were extensible with peripherals,
 * or could be held in multiple ways;
 * this environment call can be used to represent these differences
 * and adjust the core's behavior to match.
 *
 * Possible use cases include:
 *
 * \li Supporting different classes of a single controller that supported their own sets of games.
 *     For example, the SNES had two different lightguns (the Super Scope and the Justifier)
 *     whose games were incompatible with each other.
 * \li Representing a platform's alternative controllers.
 *     For example, several platforms had music/rhythm games that included controllers
 *     shaped like musical instruments.
 * \li Representing variants of a standard controller with additional inputs.
 *     For example, numerous consoles in the 90's introduced 6-button controllers for fighting games,
 *     steering wheels for racing games,
 *     or analog sticks for 3D platformers.
 * \li Representing add-ons for consoles or standard controllers.
 *     For example, the 3DS had a Circle Pad Pro attachment that added a second analog stick.
 * \li Selecting different configurations for a single controller.
 *     For example, the Wii Remote could be held sideways like a traditional game pad
 *     or in one hand like a wand.
 * \li Providing multiple ways to simulate the experience of using a particular controller.
 *     For example, the Game Boy Advance featured several games
 *     with motion or light sensors in their cartridges;
 *     a core could provide controller configurations
 *     that allow emulating the sensors with either analog axes
 *     or with their host device's sensors.
 *
 * Should be called in retro_load_game.
 * The frontend must maintain its own copy of the provided array,
 * including all strings and subobjects.
 * A core may exclude certain controllers for known incompatible games.
 *
 * When the frontend changes the active device for a particular port,
 * it must call \c retro_set_controller_port_device() with that port's index
 * and one of the IDs defined in its retro_controller_info::types field.
 *
 * Input ports are generally associated with different players
 * (and the frontend's UI may reflect this with "Player 1" labels),
 * but this is not required.
 * Some games use multiple controllers for a single player,
 * or some cores may use port indexes to represent an emulated console's
 * alternative input peripherals.
 *
 * @param[in] data <tt>const struct retro_controller_info *</tt>.
 * Pointer to an array of controller types defined by this core,
 * terminated by a zeroed-out \c retro_controller_info.
 * Each element of this array represents a controller port on the emulated device.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_controller_info
 * @see retro_set_controller_port_device
 * @see RETRO_DEVICE_SUBCLASS
 */
#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35

/**
 * Notifies the frontend of the address spaces used by the core's emulated hardware,
 * and of the memory maps within these spaces.
 * This can be used by the frontend to provide cheats, achievements, or debugging capabilities.
 * Should only be used by emulators, as it makes little sense for game engines.
 *
 * @note Cores should also expose these address spaces
 * through retro_get_memory_data and \c retro_get_memory_size if applicable;
 * this environment call is not intended to replace those two functions,
 * as the emulated hardware may feature memory regions outside of its own address space
 * that are nevertheless useful for the frontend.
 *
 * @param[in] data <tt>const struct retro_memory_map *</tt>.
 * Pointer to a single memory-map listing.
 * The frontend must maintain its own copy of this object and its contents,
 * including strings and nested objects.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_memory_map
 * @see retro_get_memory_data
 * @see retro_memory_descriptor
 */
#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Resizes the viewport without reinitializing the video driver.
 *
 * Similar to \c RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
 * but any changes that would require video reinitialization will not be performed.
 * Can only be called from within \c retro_run().
 *
 * This environment call allows a core to revise the size of the viewport at will,
 * which can be useful for emulated platforms that support dynamic resolution changes
 * or for cores that support multiple screen layouts.
 *
 * A frontend must guarantee that this environment call completes in
 * constant time.
 *
 * @param[in] data <tt>const struct retro_game_geometry *</tt>.
 * Pointer to the new video parameters that the frontend should adopt.
 * \c retro_game_geometry::max_width and \c retro_game_geometry::max_height
 * will be ignored.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @return \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 */
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37

/**
 * Returns the name of the user, if possible.
 * This callback is suitable for cores that offer personalization,
 * such as online facilities or user profiles on the emulated system.
 * @param[out] data <tt>const char **</tt>.
 * Pointer to the user name string.
 * May be \c NULL, in which case the core should use a default name.
 * The returned pointer is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the frontend couldn't provide a name.
 */
#define RETRO_ENVIRONMENT_GET_USERNAME 38

/**
 * Returns the frontend's configured language.
 * It can be used to localize the core's UI,
 * or to customize the emulated firmware if applicable.
 *
 * @param[out] data <tt>retro_language *</tt>.
 * Pointer to the language identifier.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note The returned language may not be the same as the operating system's language.
 * Cores should fall back to the operating system's language (or to English)
 * if the environment call is unavailable or the returned language is unsupported.
 * @see retro_language
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_GET_LANGUAGE 39

/**
 * Returns a frontend-managed framebuffer
 * that the core may render directly into
 *
 * This environment call is provided as an optimization
 * for cores that use software rendering
 * (i.e. that don't use \refitem RETRO_ENVIRONMENT_SET_HW_RENDER "a graphics hardware API");
 * specifically, the intended use case is to allow a core
 * to render directly into frontend-managed video memory,
 * avoiding the bandwidth use that copying a whole framebuffer from core to video memory entails.
 *
 * Must be called every frame if used,
 * as this may return a different framebuffer each frame
 * (e.g. for swap chains).
 * However, a core may render to a different buffer even if this call succeeds.
 *
 * @param[in,out] data <tt>struct retro_framebuffer *</tt>.
 * Pointer to a frontend's frame buffer and accompanying data.
 * Some fields are set by the core, others are set by the frontend.
 * Only guaranteed to be valid for the duration of the current \c retro_run call,
 * and must not be used afterwards.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call was recognized
 * and the framebuffer was successfully returned.
 * @see retro_framebuffer
 */
#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface for accessing the data of specific rendering APIs.
 * Not all hardware rendering APIs support or need this.
 *
 * The details of these interfaces are specific to each rendering API.
 *
 * @note \c retro_hw_render_callback::context_reset must be called by the frontend
 * before this environment call can be used.
 * Additionally, the contents of the returned interface are invalidated
 * after \c retro_hw_render_callback::context_destroyed has been called.
 * @param[out] data <tt>const struct retro_hw_render_interface **</tt>.
 * The render interface for the currently-enabled hardware rendering API, if any.
 * The frontend will store a pointer to the interface at the address provided here.
 * The returned interface is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available,
 * the active graphics API has a libretro rendering interface,
 * and the frontend is able to return said interface.
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see retro_hw_render_interface
 * @note Since not every libretro-supported hardware rendering API
 * has a \c retro_hw_render_interface implementation,
 * a result of \c false is not necessarily an error.
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Explicitly notifies the frontend of whether this core supports achievements.
 * The core must expose its emulated address space via
 * \c retro_get_memory_data or \c RETRO_ENVIRONMENT_GET_MEMORY_MAPS.
 * Must be called before the first call to <tt>retro_run</tt>.
 *
 * If \ref retro_get_memory_data returns a valid address
 * but this environment call is not used,
 * the frontend (at its discretion) may or may not opt in the core to its achievements support.
 * whether this core is opted in to the frontend's achievement support
 * is left to the frontend's discretion.
 * @param[in] data <tt>const bool *</tt>.
 * Pointer to a single \c bool that indicates whether this core supports achievements.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 * @see retro_get_memory_data
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Defines an interface that the frontend can use
 * to ask the core for the parameters it needs for a hardware rendering context.
 * The exact semantics depend on \ref RETRO_ENVIRONMENT_SET_HW_RENDER "the active rendering API".
 * Will be used some time after \c RETRO_ENVIRONMENT_SET_HW_RENDER is called,
 * but before \c retro_hw_render_callback::context_reset is called.
 *
 * @param[in] data <tt>const struct retro_hw_render_context_negotiation_interface *</tt>.
 * Pointer to the context negotiation interface.
 * Will be populated by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported,
 * even if the current graphics API doesn't use
 * a context negotiation interface (in which case the argument is ignored).
 * @see retro_hw_render_context_negotiation_interface
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Notifies the frontend of any quirks associated with serialization.
 *
 * Should be set in either \c retro_init or \c retro_load_game, but not both.
 * @param[in, out] data <tt>uint64_t *</tt>.
 * Pointer to the core's serialization quirks.
 * The frontend will set the flags of the quirks it supports
 * and clear the flags of those it doesn't.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported.
 * @see retro_serialize
 * @see retro_unserialize
 * @see RETRO_SERIALIZATION_QUIRK
 */
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44

/**
 * The frontend will try to use a "shared" context when setting up a hardware context.
 * Mostly applicable to OpenGL.
 *
 * In order for this to have any effect,
 * the core must call \c RETRO_ENVIRONMENT_SET_HW_RENDER at some point
 * if it hasn't already.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available
 * and the frontend supports shared hardware contexts.
 */
#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use to access the file system.
 * Should be called as early as possible.
 *
 * @param[in,out] data <tt>struct retro_vfs_interface_info *</tt>.
 * Information about the desired VFS interface,
 * as well as the interface itself.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available
 * and the frontend can provide a VFS interface of the requested version or newer.
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 */
#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use
 * to set the state of any accessible device LEDs.
 *
 * @param[out] data <tt>struct retro_led_interface *</tt>.
 * Pointer to the LED interface that the frontend will populate.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL
 * or no LEDs are accessible.
 * @see retro_led_interface
 */
#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns hints about certain steps that the core may skip for this frame.
 *
 * A frontend may not need a core to generate audio or video in certain situations;
 * this environment call sets a bitmask that indicates
 * which steps the core may skip for this frame.
 *
 * This can be used to increase performance for some frontend features.
 *
 * @note Emulation accuracy should not be compromised;
 * for example, if a core emulates a platform that supports display capture
 * (i.e. looking at its own VRAM), then it should perform its rendering as normal
 * unless it can prove that the emulated game is not using display capture.
 *
 * @param[out] data <tt>retro_av_enable_flags *</tt>.
 * Pointer to the bitmask of steps that the frontend will skip.
 * Other bits are set to zero and are reserved for future use.
 * If \c NULL, the frontend will only return whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * regardless of the value output to \c data.
 * If \c false, the core should assume that the frontend will not skip any steps.
 * @see retro_av_enable_flags
 */
#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for raw MIDI I/O.
 *
 * @param[out] data <tt>struct retro_midi_interface *</tt>.
 * Pointer to the MIDI interface.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_midi_interface
 */
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend if it's currently in fast-forward mode.
 * @param[out] data <tt>bool *</tt>.
 * Set to \c true if the frontend is currently fast-forwarding its main loop.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @returns \c true if this environment call is available,
 * regardless of the value returned in \c data.
 *
 * @see RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE
 */
#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the refresh rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal refresh rate.
 *
 * @param[out] data <tt>float *</tt>.
 * Pointer to the \c float in which the frontend will store its target refresh rate.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns whether the frontend can return the state of all buttons at once as a bitmask,
 * rather than requiring a series of individual calls to \c retro_input_state_t.
 *
 * If this callback returns \c true,
 * you can get the state of all buttons by passing \c RETRO_DEVICE_ID_JOYPAD_MASK
 * as the \c id parameter to \c retro_input_state_t.
 * Bit #N represents the RETRO_DEVICE_ID_JOYPAD constant of value N,
 * e.g. <tt>(1 << RETRO_DEVICE_ID_JOYPAD_A)</tt> represents the A button.
 *
 * @param data Ignored.
 * @returns \c true if the frontend can report the complete digital joypad state as a bitmask.
 * @see retro_input_state_t
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 */
#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the version of the core options API supported by the frontend.
 *
 * Over the years, libretro has used several interfaces
 * for allowing cores to define customizable options.
 * \ref SET_CORE_OPTIONS_V2 "Version 2 of the interface"
 * is currently preferred due to its extra features,
 * but cores and frontends should strive to support
 * versions \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS "1"
 * and \ref RETRO_ENVIRONMENT_SET_VARIABLES "0" as well.
 * This environment call provides the information that cores need for that purpose.
 *
 * If this environment call returns \c false,
 * then the core should assume version 0 of the core options API.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the integer that will store the frontend's
 * supported core options API version.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_VARIABLES
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52

/**
 * @copybrief RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 *
 * @deprecated This environment call has been superseded
 * by RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
 * which supports categorizing options into groups.
 * This environment call should only be used to maintain compatibility
 * with older cores and frontends.
 *
 * This environment call is intended to replace \c RETRO_ENVIRONMENT_SET_VARIABLES,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 1.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * Example entry:
 * @code
 * {
 *     "foo_option",
 *     "Speed hack coprocessor X",
 *     "Provides increased performance at the expense of reduced accuracy",
 *     {
 *         { "false",    NULL },
 *         { "true",     NULL },
 *         { "unstable", "Turbo (Unstable)" },
 *         { NULL, NULL },
 *     },
 *     "false"
 * }
 * @endcode
 *
 * @param[in] data <tt>const struct retro_core_option_definition *</tt>.
 * Pointer to one or more core option definitions,
 * terminated by a \ref retro_core_option_definition whose values are all zero.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available.
 *
 * @see retro_core_option_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * that supports internationalization.
 *
 * @deprecated This environment call has been superseded
 * by \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
 * which supports categorizing options into groups
 * (plus translating the groups themselves).
 * Only use this environment call to maintain compatibility
 * with older cores and frontends.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_intl for some important details.
 *
 * @param[in] data <tt>const struct retro_core_options_intl *</tt>.
 * Pointer to a core's option values and their translations.
 * @see retro_core_options_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54

/**
 * Notifies the frontend that it should show or hide the named core option.
 *
 * Some core options aren't relevant in all scenarios,
 * such as a submenu for hardware rendering flags
 * when the software renderer is configured.
 * This environment call asks the frontend to stop (or start)
 * showing the named core option to the player.
 * This is only a hint, not a requirement;
 * the frontend may ignore this environment call.
 * By default, all core options are visible.
 *
 * @note This environment call must \em only affect a core option's visibility,
 * not its functionality or availability.
 * \ref RETRO_ENVIRONMENT_GET_VARIABLE "Getting an invisible core option"
 * must behave normally.
 *
 * @param[in] data <tt>const struct retro_core_option_display *</tt>.
 * Pointer to a descriptor for the option that the frontend should show or hide.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL
 * or the specified option doesn't exist.
 * @see retro_core_option_display
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55

/**
 * Returns the frontend's preferred hardware rendering API.
 * Cores should use this information to decide which API to use with \c RETRO_ENVIRONMENT_SET_HW_RENDER.
 * @param[out] data <tt>retro_hw_context_type *</tt>.
 * Pointer to the hardware context type.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * This value will be set even if the environment call returns <tt>false</tt>,
 * unless the frontend doesn't implement it.
 * @returns \c true if the environment call is available
 * and the frontend is able to use a hardware rendering API besides the one returned.
 * If \c false is returned and the core cannot use the preferred rendering API,
 * then it should exit or fall back to software rendering.
 * @note The returned value does not indicate which API is currently in use.
 * For example, the frontend may return \c RETRO_HW_CONTEXT_OPENGL
 * while a Direct3D context from a previous session is active;
 * this would signal that the frontend's current preference is for OpenGL,
 * possibly because the user changed their frontend's video driver while a game is running.
 * @see retro_hw_context_type
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56

/**
 * Returns the minimum version of the disk control interface supported by the frontend.
 *
 * If this environment call returns \c false or \c data is 0 or greater,
 * then cores may use disk control callbacks
 * with \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
 * If the reported version is 1 or greater,
 * then cores should use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE instead.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the unsigned integer that the frontend's supported disk control interface version will be stored in.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57

/**
 * @copybrief RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 * This version of the disk control interface provides
 * more information about disk images.
 * Should be called in \c retro_init.
 *
 * @param[in] data <tt>const struct retro_disk_control_ext_callback *</tt>.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_ext_callback
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58

/**
 * Returns the version of the message interface supported by the frontend.
 *
 * A version of 0 indicates that the frontend
 * only supports the legacy \c RETRO_ENVIRONMENT_SET_MESSAGE interface.
 * A version of 1 indicates that the frontend
 * supports \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT as well.
 * If this environment call returns \c false,
 * the core should behave as if it had returned 0.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 */
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59

/**
 * Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * This environment call supersedes \c RETRO_ENVIRONMENT_SET_MESSAGE,
 * as it provides many more ways to customize
 * how a message is presented to the player.
 * However, a frontend that supports this environment call
 * must still support \c RETRO_ENVIRONMENT_SET_MESSAGE.
 *
 * @param[in] data <tt>const struct retro_message_ext *</tt>.
 * Pointer to the message to display to the player.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_message_ext
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60

/**
 * Returns the number of active input devices currently provided by the frontend.
 *
 * This may change between frames,
 * but will remain constant for the duration of each frame.
 *
 * If this callback returns \c true,
 * a core need not poll any input device
 * with an index greater than or equal to the returned value.
 *
 * If callback returns \c false,
 * the number of active input devices is unknown.
 * In this case, all input devices should be considered active.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61

/**
 * Registers a callback that the frontend can use to notify the core
 * of the audio output buffer's occupancy.
 * Can be used by a core to attempt frame-skipping to avoid buffer under-runs
 * (i.e. "crackling" sounds).
 *
 * @param[in] data <tt>const struct retro_audio_buffer_status_callback *</tt>.
 * Pointer to the the buffer status callback,
 * or \c NULL to unregister any existing callback.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_audio_buffer_status_callback
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62

/**
 * Requests a minimum frontend audio latency in milliseconds.
 *
 * This is a hint; the frontend may assign a different audio latency
 * to accommodate hardware limits,
 * although it should try to honor requests up to 512ms.
 *
 * This callback has no effect if the requested latency
 * is less than the frontend's current audio latency.
 * If value is zero or \c data is \c NULL,
 * the frontend should set its default audio latency.
 *
 * May be used by a core to increase audio latency and
 * reduce the risk of buffer under-runs (crackling)
 * when performing 'intensive' operations.
 *
 * A core using RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 * to implement audio-buffer-based frame skipping can get good results
 * by setting the audio latency to a high (typically 6x or 8x)
 * integer multiple of the expected frame time.
 *
 * This can only be called from within \c retro_run().
 *
 * @warning This environment call may require the frontend to reinitialize its audio system.
 * This environment call should be used sparingly.
 * If the driver is reinitialized,
 * \ref retro_audio_callback_t "all audio callbacks" will be updated
 * to target the newly-initialized driver.
 *
 * @param[in] data <tt>const unsigned *</tt>.
 * Minimum audio latency, in milliseconds.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63

/**
 * Allows the core to tell the frontend when it should enable fast-forwarding,
 * rather than relying solely on the frontend and user interaction.
 *
 * Possible use cases include:
 *
 * \li Temporarily disabling a core's fastforward support
 *     while investigating a related bug.
 * \li Disabling fastforward during netplay sessions,
 *     or when using an emulated console's network features.
 * \li Automatically speeding up the game when in a loading screen
 *     that cannot be shortened with high-level emulation.
 *
 * @param[in] data <tt>const struct retro_fastforwarding_override *</tt>.
 * Pointer to the parameters that decide when and how
 * the frontend is allowed to enable fast-forward mode.
 * May be \c NULL, in which case the frontend will return \c true
 * without updating the fastforward state,
 * which can be used to detect support for this environment call.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_fastforwarding_override
 * @see RETRO_ENVIRONMENT_GET_FASTFORWARDING
 */
#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64

#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65
                                           /* const struct retro_system_content_info_override * --
                                            * Allows an implementation to override 'global' content
                                            * info parameters reported by retro_get_system_info().
                                            * Overrides also affect subsystem content info parameters
                                            * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.
                                            * This function must be called inside retro_set_environment().
                                            * If callback returns false, content info overrides
                                            * are unsupported by the frontend, and will be ignored.
                                            * If callback returns true, extended game info may be
                                            * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
                                            * in retro_load_game() or retro_load_game_special().
                                            *
                                            * 'data' points to an array of retro_system_content_info_override
                                            * structs terminated by a { NULL, false, false } element.
                                            * If 'data' is NULL, no changes will be made to the frontend;
                                            * a core may therefore pass NULL in order to test whether
                                            * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported
                                            * by the frontend.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_system_content_info_override.
                                            *
                                            * Example:
                                            *
                                            * - struct retro_system_info:
                                            * {
                                            *    "My Core",                      // library_name
                                            *    "v1.0",                         // library_version
                                            *    "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
                                            *    true,                           // need_fullpath
                                            *    false                           // block_extract
                                            * }
                                            *
                                            * - Array of struct retro_system_content_info_override:
                                            * {
                                            *    {
                                            *       "md|sms|gg", // extensions
                                            *       false,       // need_fullpath
                                            *       true         // persistent_data
                                            *    },
                                            *    {
                                            *       "sg",        // extensions
                                            *       false,       // need_fullpath
                                            *       false        // persistent_data
                                            *    },
                                            *    { NULL, false, false }
                                            * }
                                            *
                                            * Result:
                                            * - Files of type m3u, cue, iso, chd will not be
                                            *   loaded by the frontend. Frontend will pass a
                                            *   valid path to the core, and core will handle
                                            *   loading internally
                                            * - Files of type md, sms, gg will be loaded by
                                            *   the frontend. A valid memory buffer will be
                                            *   passed to the core. This memory buffer will
                                            *   remain valid until retro_deinit() returns
                                            * - Files of type sg will be loaded by the frontend.
                                            *   A valid memory buffer will be passed to the core.
                                            *   This memory buffer will remain valid until
                                            *   retro_load_game() (or retro_load_game_special())
                                            *   returns
                                            *
                                            * NOTE: If an extension is listed multiple times in
                                            * an array of retro_system_content_info_override
                                            * structs, only the first instance will be registered
                                            */

#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66
                                           /* const struct retro_game_info_ext ** --
                                            * Allows an implementation to fetch extended game
                                            * information, providing additional content path
                                            * and memory buffer status details.
                                            * This function may only be called inside
                                            * retro_load_game() or retro_load_game_special().
                                            * If callback returns false, extended game information
                                            * is unsupported by the frontend. In this case, only
                                            * regular retro_game_info will be available.
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed
                                            * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
                                            * returns true.
                                            *
                                            * 'data' points to an array of retro_game_info_ext structs.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_game_info_ext.
                                            *
                                            * - If function is called inside retro_load_game(),
                                            *   the retro_game_info_ext array is guaranteed to
                                            *   have a size of 1 - i.e. the returned pointer may
                                            *   be used to access directly the members of the
                                            *   first retro_game_info_ext struct, for example:
                                            *
                                            *      struct retro_game_info_ext *game_info_ext;
                                            *      if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext))
                                            *         printf("Content Directory: %s\n", game_info_ext->dir);
                                            *
                                            * - If the function is called inside retro_load_game_special(),
                                            *   the retro_game_info_ext array is guaranteed to have a
                                            *   size equal to the num_info argument passed to
                                            *   retro_load_game_special()
                                            */

/**
 * Defines a set of core options that can be shown and configured by the frontend,
 * so that the player may customize their gameplay experience to their liking.
 *
 * @note This environment call is intended to replace
 * \c RETRO_ENVIRONMENT_SET_VARIABLES and \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 2.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * @param[in] data <tt>const struct retro_core_options_v2 *</tt>.
 * Pointer to a core's options and their associated categories.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available
 * and the frontend supports categories.
 * Note that this environment call is guaranteed to successfully register
 * the provided core options,
 * so the return value does not indicate success or failure.
 *
 * @see retro_core_options_v2
 * @see retro_core_option_v2_category
 * @see retro_core_option_v2_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 67

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * that supports internationalization.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_v2_intl for some important details.
 *
 * @param[in] data <tt>const struct retro_core_options_v2_intl *</tt>.
 * Pointer to a core's option values and categories,
 * plus a translation for each option and category.
 * @see retro_core_options_v2_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL 68

/**
 * Registers a callback that the frontend can use
 * to notify the core that at least one core option
 * should be made hidden or visible.
 * Allows a frontend to signal that a core must update
 * the visibility of any dynamically hidden core options,
 * and enables the frontend to detect visibility changes.
 * Used by the frontend to update the menu display status
 * of core options without requiring a call of retro_run().
 * Must be called in retro_set_environment().
 *
 * @param[in] data <tt>const struct retro_core_options_update_display_callback *</tt>.
 * The callback that the frontend should use.
 * May be \c NULL, in which case the frontend will unset any existing callback.
 * Can be used to query visibility support.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_core_options_update_display_callback
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69

/**
 * Forcibly sets a core option's value.
 *
 * After changing a core option value with this callback,
 * it will be reflected in the frontend
 * and \ref RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE will return \c true.
 * \ref retro_variable::key must match
 * a \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 "previously-set core option",
 * and \ref retro_variable::value must match one of its defined values.
 *
 * Possible use cases include:
 *
 * @li Allowing the player to set certain core options
 *     without entering the frontend's option menu,
 *     using an in-core hotkey.
 * @li Adjusting invalid combinations of settings.
 * @li Migrating settings from older releases of a core.
 *
 * @param[in] data <tt>const struct retro_variable *</tt>.
 * Pointer to a single option that the core is changing.
 * May be \c NULL, in which case the frontend will return \c true
 * to indicate that this environment call is available.
 * @return \c true if this environment call is available
 * and the option named by \c key was successfully
 * set to the given \c value.
 * \c false if the \c key or \c value fields are \c NULL, empty,
 * or don't match a previously set option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_SET_VARIABLE 70

#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
                                           /* struct retro_throttle_state * --
                                            * Allows an implementation to get details on the actual rate
                                            * the frontend is attempting to call retro_run().
                                            */

/**
 * Returns information about how the frontend will use savestates.
 *
 * @param[out] data <tt>retro_savestate_context *</tt>.
 * Pointer to the current savestate context.
 * May be \c NULL, in which case the environment call
 * will return \c true to indicate its availability.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_savestate_context
 */
#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Before calling \c SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, will query which interface is supported.
 *
 * Frontend looks at \c retro_hw_render_interface_type and returns the maximum supported
 * context negotiation interface version. If the \c retro_hw_render_interface_type is not
 * supported or recognized by the frontend, a version of 0 must be returned in
 * \c retro_hw_render_interface's \c interface_version and \c true is returned by frontend.
 *
 * If this environment call returns true with a \c interface_version greater than 0,
 * a core can always use a negotiation interface version larger than what the frontend returns,
 * but only earlier versions of the interface will be used by the frontend.
 *
 * A frontend must not reject a negotiation interface version that is larger than what the
 * frontend supports. Instead, the frontend will use the older entry points that it recognizes.
 * If this is incompatible with a particular core's requirements, it can error out early.
 *
 * @note Regarding backwards compatibility, this environment call was introduced after Vulkan v1
 * context negotiation. If this environment call is not supported by frontend, i.e. the environment
 * call returns \c false , only Vulkan v1 context negotiation is supported (if Vulkan HW rendering
 * is supported at all). If a core uses Vulkan negotiation interface with version > 1, negotiation
 * may fail unexpectedly. All future updates to the context negotiation interface implies that
 * frontend must support this environment call to query support.
 *
 * @param[out] data <tt>struct retro_hw_render_context_negotiation_interface *</tt>.
 * @return \c true if the environment call is available.
 * @see SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see retro_hw_render_interface_type
 * @see retro_hw_render_context_negotiation_interface
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend whether JIT compilation can be used.
 * Primarily used by iOS and tvOS.
 * @param[out] data <tt>bool *</tt>.
 * Set to \c true if the frontend has verified that JIT compilation is possible.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74

/**
 * Returns an interface that the core can use to receive microphone input.
 *
 * @param[out] data <tt>retro_microphone_interface *</tt>.
 * Pointer to the microphone interface.
 * @return \true if microphone support is available,
 * even if no microphones are plugged in.
 * \c false if microphone support is disabled unavailable,
 * or if \c data is \c NULL.
 * @see retro_microphone_interface
 */
#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/* Environment 76 was an obsolete version of RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
* It was not used by any known core at the time, and was removed from the API. */

/**
 * Returns the device's current power state as reported by the frontend.
 *
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
 *
 * @param[out] data <struct retro_device_power *>.
 * Indicates whether the frontend can provide this information, even if the parameter
 * is \c NULL. If the frontend does not support this functionality, then the provided
 * argument will remain unchanged.
 * @return \c true if the environment call is available.
 * @see retro_device_power
 */
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 78
                                           /* const struct retro_netpacket_callback * --
                                            * When set, a core gains control over network packets sent and
                                            * received during a multiplayer session. This can be used to
                                            * emulate multiplayer games that were originally played on two
                                            * or more separate consoles or computers connected together.
                                            *
                                            * The frontend will take care of connecting players together,
                                            * and the core only needs to send the actual data as needed for
                                            * the emulation, while handshake and connection management happen
                                            * in the background.
                                            *
                                            * When two or more players are connected and this interface has
                                            * been set, time manipulation features (such as pausing, slow motion,
                                            * fast forward, rewinding, save state loading, etc.) are disabled to
                                            * avoid interrupting communication.
                                            *
                                            * Should be set in either retro_init or retro_load_game, but not both.
                                            *
                                            * When not set, a frontend may use state serialization-based
                                            * multiplayer, where a deterministic core supporting multiple
                                            * input devices does not need to take any action on its own.
                                            */

/**
 * Returns the device's current power state as reported by the frontend.
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * The return value indicates whether the frontend can provide this information,
 * even if the parameter is \c NULL.
 *
 * If the frontend does not support this functionality,
 * then the provided argument will remain unchanged.
 * @param[out] data <tt>retro_device_power *</tt>.
 * Pointer to the information that the frontend returns about its power state.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_device_power
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
*/
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the "playlist" directory of the frontend.
 *
 * This directory can be used to store core generated playlists, in case
 * this internal functionality is available (e.g. internal core game detection
 * engine).
 *
 * @param[out] data <tt>const char **</tt>.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_PLAYLIST_DIRECTORY 79

/**
 * Returns the "file browser" start directory of the frontend.
 *
 * This directory can serve as a start directory for the core in case it
 * provides an internal way of loading content.
 *
 * @param[out] data <tt>const char **</tt>.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY 80

/**
 * Returns the audio sample rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal sample rate.
 *
 * @param[out] data <tt>unsigned *</tt>.
 * Pointer to the \c unsigned integer in which the frontend will store its target sample rate.
 * Behavior is undefined if \c data is <tt>NULL</tt>.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_SAMPLE_RATE (81 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**@}*/

/**
 * @defgroup GET_VFS_INTERFACE File System Interface
 * @brief File system functionality.
 *
 * @section File Paths
 * File paths passed to all libretro filesystem APIs shall be well formed UNIX-style,
 * using "/" (unquoted forward slash) as the directory separator
 * regardless of the platform's native separator.
 *
 * Paths shall also include at least one forward slash
 * (e.g. use "./game.bin" instead of "game.bin").
 *
 * Other than the directory separator, cores shall not make assumptions about path format.
 * The following paths are all valid:
 * @li \c C:/path/game.bin
 * @li \c http://example.com/game.bin
 * @li \c #game/game.bin
 * @li \c ./game.bin
 *
 * Cores may replace the basename or remove path components from the end, and/or add new components;
 * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request from the front end.
 *
 * The frontend is encouraged to do the best it can when given an ill-formed path,
 * but it is allowed to give up.
 *
 * Frontends are encouraged, but not required, to support native file system paths
 * (including replacing the directory separator, if applicable).
 *
 * Cores are allowed to try using them, but must remain functional if the frontend rejects such requests.
 *
 * Cores are encouraged to use the libretro-common filestream functions for file I/O,
 * as they seamlessly integrate with VFS,
 * deal with directory separator replacement as appropriate
 * and provide platform-specific fallbacks
 * in cases where front ends do not provide their own VFS interface.
 *
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 *
 * @{
 */

/**
 * Opaque file handle.
 * @since VFS API v1
 */
struct retro_vfs_file_handle;

/**
 * Opaque directory handle.
 * @since VFS API v3
 */
struct retro_vfs_dir_handle;

/** @defgroup RETRO_VFS_FILE_ACCESS File Access Flags
 * File access flags.
 * @since VFS API v1
 * @{
 */

/** Opens a file for read-only access. */
#define RETRO_VFS_FILE_ACCESS_READ            (1 << 0)

/**
 * Opens a file for write-only access.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_WRITE           (1 << 1)

/**
 * Opens a file for reading and writing.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_READ_WRITE      (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE)

/**
 * Opens a file without discarding its existing contents.
 * Only meaningful if \c RETRO_VFS_FILE_ACCESS_WRITE is specified.
 */
#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */

/** @} */

/** @defgroup RETRO_VFS_FILE_ACCESS_HINT File Access Hints
 *
 * Hints to the frontend for how a file will be accessed.
 * The VFS implementation may use these to optimize performance,
 * react to external interference (such as concurrent writes),
 * or it may ignore them entirely.
 *
 * Hint flags do not change the behavior of each VFS function
 * unless otherwise noted.
 * @{
 */

/** No particular hints are given. */
#define RETRO_VFS_FILE_ACCESS_HINT_NONE              (0)

/**
 * Indicates that the file will be accessed frequently.
 *
 * The frontend should cache it or map it into memory.
 */
#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS   (1 << 0)

/** @} */

/** @defgroup RETRO_VFS_SEEK_POSITION File Seek Positions
 * File access flags and hints.
 * @{
 */

/**
 * Indicates a seek relative to the start of the file.
 */
#define RETRO_VFS_SEEK_POSITION_START    0

/**
 * Indicates a seek relative to the current stream position.
 */
#define RETRO_VFS_SEEK_POSITION_CURRENT  1

/**
 * Indicates a seek relative to the end of the file.
 * @note The offset passed to \c retro_vfs_seek_t should be negative.
 */
#define RETRO_VFS_SEEK_POSITION_END      2

/** @} */

/** @defgroup RETRO_VFS_STAT File Status Flags
 * File stat flags.
 * @see retro_vfs_stat_t
 * @since VFS API v3
 * @{
 */

/** Indicates that the given path refers to a valid file. */
#define RETRO_VFS_STAT_IS_VALID               (1 << 0)

/** Indicates that the given path refers to a directory. */
#define RETRO_VFS_STAT_IS_DIRECTORY           (1 << 1)

/**
 * Indicates that the given path refers to a character special file,
 * such as \c /dev/null.
 */
#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL   (1 << 2)

/** @} */

/**
 * Returns the path that was used to open this file.
 *
 * @param stream The opened file handle to get the path of.
 * Behavior is undefined if \c NULL or closed.
 * @return The path that was used to open \c stream.
 * The string is owned by \c stream and must not be modified.
 * @since VFS API v1
 * @see filestream_get_path
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);

/**
 * Open a file for reading or writing.
 *
 * @param path The path to open.
 * @param mode A bitwise combination of \c RETRO_VFS_FILE_ACCESS flags.
 * At a minimum, one of \c RETRO_VFS_FILE_ACCESS_READ or \c RETRO_VFS_FILE_ACCESS_WRITE must be specified.
 * @param hints A bitwise combination of \c RETRO_VFS_FILE_ACCESS_HINT flags.
 * @return A handle to the opened file,
 * or \c NULL upon failure.
 * Note that this will return \c NULL if \c path names a directory.
 * The returned file handle must be closed with \c retro_vfs_close_t.
 * @since VFS API v1
 * @see File Paths
 * @see RETRO_VFS_FILE_ACCESS
 * @see RETRO_VFS_FILE_ACCESS_HINT
 * @see retro_vfs_close_t
 * @see filestream_open
 */
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);

/**
 * Close the file and release its resources.
 * All files returned by \c retro_vfs_open_t must be closed with this function.
 *
 * @param stream The file handle to close.
 * Behavior is undefined if already closed.
 * Upon completion of this function, \c stream is no longer valid
 * (even if it returns failure).
 * @return 0 on success, -1 on failure or if \c stream is \c NULL.
 * @see retro_vfs_open_t
 * @see filestream_close
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);

/**
 * Return the size of the file in bytes.
 *
 * @param stream The file to query the size of.
 * @return Size of the file in bytes, or -1 if there was an error.
 * @see filestream_get_size
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);

/**
 * Set the file's length.
 *
 * @param stream The file whose length will be adjusted.
 * @param length The new length of the file, in bytes.
 * If shorter than the original length, the extra bytes will be discarded.
 * If longer, the file's padding is unspecified (and likely platform-dependent).
 * @return 0 on success,
 * -1 on failure.
 * @see filestream_truncate
 * @since VFS API v2
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);

/**
 * Gets the given file's current read/write position.
 * This position is advanced with each call to \c retro_vfs_read_t or \c retro_vfs_write_t.
 *
 * @param stream The file to query the position of.
 * @return The current stream position in bytes
 * or -1 if there was an error.
 * @see filestream_tell
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);

/**
 * Sets the given file handle's current read/write position.
 *
 * @param stream The file to set the position of.
 * @param offset The new position, in bytes.
 * @param seek_position The position to seek from.
 * @return The new position,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see File Seek Positions
 * @see filestream_seek
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);

/**
 * Read data from a file, if it was opened for reading.
 *
 * @param stream The file to read from.
 * @param s The buffer to read into.
 * @param len The number of bytes to read.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes read,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_read
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);

/**
 * Write data to a file, if it was opened for writing.
 *
 * @param stream The file handle to write to.
 * @param s The buffer to write from.
 * @param len The number of bytes to write.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes written,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_write
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);

/**
 * Flush pending writes to the file, if applicable.
 *
 * This does not mean that the changes will be immediately persisted to disk;
 * that may be scheduled for later, depending on the platform.
 *
 * @param stream The file handle to flush.
 * @return 0 on success, -1 on failure.
 * @since VFS API v1
 * @see filestream_flush
 */
typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);

/**
 * Deletes the file at the given path.
 *
 * @param path The path to the file that will be deleted.
 * @return 0 on success, -1 on failure.
 * @see filestream_delete
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);

/**
 * Rename the specified file.
 *
 * @param old_path Path to an existing file.
 * @param new_path The destination path.
 * Must not name an existing file.
 * @return 0 on success, -1 on failure
 * @see filestream_rename
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);

/**
 * Gets information about the given file.
 *
 * @param path The path to the file to query.
 * @param[out] size The reported size of the file in bytes.
 * May be \c NULL, in which case this value is ignored.
 * @return A bitmask of \c RETRO_VFS_STAT flags,
 * or 0 if \c path doesn't refer to a valid file.
 * @see path_stat
 * @see path_get_size
 * @see RETRO_VFS_STAT
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);

/**
 * Creates a directory at the given path.
 *
 * @param dir The desired location of the new directory.
 * @return 0 if the directory was created,
 * -2 if the directory already exists,
 * or -1 if some other error occurred.
 * @see path_mkdir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);

/**
 * Opens a handle to a directory so its contents can be inspected.
 *
 * @param dir The path to the directory to open.
 * Must be an existing directory.
 * @param include_hidden Whether to include hidden files in the directory listing.
 * The exact semantics of this flag will depend on the platform.
 * @return A handle to the opened directory,
 * or \c NULL if there was an error.
 * @see retro_opendir
 * @since VFS API v3
 */
typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);

/**
 * Gets the next dirent ("directory entry")
 * within the given directory.
 *
 * @param[in,out] dirstream The directory to read from.
 * Updated to point to the next file, directory, or other path.
 * @return \c true when the next dirent was retrieved,
 * \c false if there are no more dirents to read.
 * @note This API iterates over all files and directories within \c dirstream.
 * Remember to check what the type of the current dirent is.
 * @note This function does not recurse,
 * i.e. it does not return the contents of subdirectories.
 * @note This may include "." and ".." on Unix-like platforms.
 * @see retro_readdir
 * @see retro_vfs_dirent_is_dir_t
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Gets the filename of the current dirent.
 *
 * The returned string pointer is valid
 * until the next call to \c retro_vfs_readdir_t or \c retro_vfs_closedir_t.
 *
 * @param dirstream The directory to read from.
 * @return The current dirent's name,
 * or \c NULL if there was an error.
 * @note This function only returns the file's \em name,
 * not a complete path to it.
 * @see retro_dirent_get_name
 * @since VFS API v3
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Checks whether the current dirent names a directory.
 *
 * @param dirstream The directory to read from.
 * @return \c true if \c dirstream's current dirent points to a directory,
 * \c false if not or if there was an error.
 * @see retro_dirent_is_dir
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Closes the given directory and release its resources.
 *
 * Must be called on any \c retro_vfs_dir_handle returned by \c retro_vfs_open_t.
 *
 * @param dirstream The directory to close.
 * When this function returns (even failure),
 * \c dirstream will no longer be valid and must not be used.
 * @return 0 on success, -1 on failure.
 * @see retro_closedir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * File system interface exposed by the frontend.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface
{
   /* VFS API v1 */
   /** @copydoc retro_vfs_get_path_t */
	retro_vfs_get_path_t get_path;

   /** @copydoc retro_vfs_open_t */
	retro_vfs_open_t open;

   /** @copydoc retro_vfs_close_t */
	retro_vfs_close_t close;

   /** @copydoc retro_vfs_size_t */
	retro_vfs_size_t size;

   /** @copydoc retro_vfs_tell_t */
	retro_vfs_tell_t tell;

   /** @copydoc retro_vfs_seek_t */
	retro_vfs_seek_t seek;

   /** @copydoc retro_vfs_read_t */
	retro_vfs_read_t read;

   /** @copydoc retro_vfs_write_t */
	retro_vfs_write_t write;

   /** @copydoc retro_vfs_flush_t */
	retro_vfs_flush_t flush;

   /** @copydoc retro_vfs_remove_t */
	retro_vfs_remove_t remove;

   /** @copydoc retro_vfs_rename_t */
	retro_vfs_rename_t rename;
   /* VFS API v2 */

   /** @copydoc retro_vfs_truncate_t */
   retro_vfs_truncate_t truncate;
   /* VFS API v3 */

   /** @copydoc retro_vfs_stat_t */
   retro_vfs_stat_t stat;

   /** @copydoc retro_vfs_mkdir_t */
   retro_vfs_mkdir_t mkdir;

   /** @copydoc retro_vfs_opendir_t */
   retro_vfs_opendir_t opendir;

   /** @copydoc retro_vfs_readdir_t */
   retro_vfs_readdir_t readdir;

   /** @copydoc retro_vfs_dirent_get_name_t */
   retro_vfs_dirent_get_name_t dirent_get_name;

   /** @copydoc retro_vfs_dirent_is_dir_t */
   retro_vfs_dirent_is_dir_t dirent_is_dir;

   /** @copydoc retro_vfs_closedir_t */
   retro_vfs_closedir_t closedir;
};

/**
 * Represents a request by the core for the frontend's file system interface,
 * as well as the interface itself returned by the frontend.
 *
 * You do not need to use these functions directly;
 * you may pass this struct to \c dirent_vfs_init,
 * \c filestream_vfs_init, or \c path_vfs_init
 * so that you can use the wrappers provided by these modules.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface_info
{
   /**
    * The minimum version of the VFS API that the core requires.
    * libretro-common's wrapper API initializers will check this value as well.
    *
    * Set to the core's desired VFS version when requesting an interface,
    * and set by the frontend to indicate its actual API version.
    *
    * If the core asks for a newer VFS API version than the frontend supports,
    * the frontend must return \c false within the \c RETRO_ENVIRONMENT_GET_VFS_INTERFACE call.
    * @since VFS API v1
    */
   uint32_t required_interface_version;

   /**
    * Set by the frontend.
    * The frontend will set this to the VFS interface it provides.
    *
    * The interface is owned by the frontend
    * and must not be modified or freed by the core.
    * @since VFS API v1 */
   struct retro_vfs_interface *iface;
};

/** @} */

/** @defgroup GET_HW_RENDER_INTERFACE Hardware Rendering Interface
 * @{
 */

/**
 * Describes the hardware rendering API supported by
 * a particular subtype of \c retro_hw_render_interface.
 *
 * Not every rendering API supported by libretro has its own interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_interface_type
{
   /**
    * Indicates a \c retro_hw_render_interface for Vulkan.
    * @see retro_hw_render_interface_vulkan
    */
   RETRO_HW_RENDER_INTERFACE_VULKAN     = 0,

   /** Indicates a \c retro_hw_render_interface for Direct3D 9. */
   RETRO_HW_RENDER_INTERFACE_D3D9       = 1,

   /** Indicates a \c retro_hw_render_interface for Direct3D 10. */
   RETRO_HW_RENDER_INTERFACE_D3D10      = 2,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 11.
    * @see retro_hw_render_interface_d3d11
    */
   RETRO_HW_RENDER_INTERFACE_D3D11      = 3,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 12.
    * @see retro_hw_render_interface_d3d12
    */
   RETRO_HW_RENDER_INTERFACE_D3D12      = 4,

   /**
    * Indicates a \c retro_hw_render_interface for
    * the PlayStation's 2 PSKit API.
    * @see retro_hw_render_interface_gskit_ps2
    */
   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2  = 5,

   /** @private Defined to ensure <tt>sizeof(retro_hw_render_interface_type) == sizeof(int)</tt>.
    * Do not use. */
   RETRO_HW_RENDER_INTERFACE_DUMMY      = INT_MAX
};

/**
 * Base render interface type.
 * All \c retro_hw_render_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
struct retro_hw_render_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_interface_type interface_type;

   /**
    * The version of this rendering interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/**
 * @defgroup GET_LED_INTERFACE LED Interface
 * @{
 */

/** @copydoc retro_led_interface::set_led_state */
typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);

/**
 * Interface that the core can use to set the state of available LEDs.
 * @see RETRO_ENVIRONMENT_GET_LED_INTERFACE
 */
struct retro_led_interface
{
   /**
    * Sets the state of an LED.
    *
    * @param led The LED to set the state of.
    * @param state The state to set the LED to.
    * \c true to enable, \c false to disable.
    */
   retro_set_led_state_t set_led_state;
};

/** @} */

/** @defgroup GET_AUDIO_VIDEO_ENABLE Skipped A/V Steps
 * @{
 */

/**
 * Flags that define A/V steps that the core may skip for this frame.
 *
 * @see RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE
 */
enum retro_av_enable_flags
{
   /**
    * If set, the core should render video output with \c retro_video_refresh_t as normal.
    *
    * Otherwise, the frontend will discard any video data received this frame,
    * including frames presented via hardware acceleration.
    * \c retro_video_refresh_t will do nothing.
    *
    * @note After running the frame, the video output of the next frame
    * should be no different than if video was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's graphics pipeline state
    * should not be affected by this flag.
    *
    * @note If emulating a platform that supports display capture
    * (i.e. reading its own VRAM),
    * the core may not be able to completely skip rendering,
    * as the VRAM is part of the graphics pipeline's state.
    */
   RETRO_AV_ENABLE_VIDEO = (1 << 0),

   /**
    * If set, the core should render audio output
    * with \c retro_audio_sample_t or \c retro_audio_sample_batch_t as normal.
    *
    * Otherwise, the frontend will discard any audio data received this frame.
    * The core should skip audio rendering if possible.
    *
    * @note After running the frame, the audio output of the next frame
    * should be no different than if audio was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's audio pipeline state
    * should not be affected by this flag.
    */
   RETRO_AV_ENABLE_AUDIO = (1 << 1),

   /**
    * If set, indicates that any savestates taken this frame
    * are guaranteed to be created by the same binary that will load them,
    * and will not be written to or read from the disk.
    *
    * The core may use these guarantees to:
    *
    * @li Assume that loading state will succeed.
    * @li Update its memory buffers in-place if possible.
    * @li Skip clearing memory.
    * @li Skip resetting the system.
    * @li Skip validation steps.
    *
    * @deprecated Use \c RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT instead,
    * except for compatibility purposes.
    */
   RETRO_AV_ENABLE_FAST_SAVESTATES = (1 << 2),

   /**
    * If set, indicates that the frontend will never need audio from the core.
    * Used by a frontend for implementing runahead via a secondary core instance.
    *
    * The core may stop synthesizing audio if it can do so
    * without compromising emulation accuracy.
    *
    * Audio output for the next frame does not matter,
    * and the frontend will never need an accurate audio state in the future.
    *
    * State will never be saved while this flag is set.
    */
   RETRO_AV_ENABLE_HARD_DISABLE_AUDIO = (1 << 3),

   /**
    * @private Defined to ensure <tt>sizeof(retro_av_enable_flags) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_AV_ENABLE_DUMMY = INT_MAX
};

/** @} */

/**
 * @defgroup GET_MIDI_INTERFACE MIDI Interface
 * @{
 */

/** @copydoc retro_midi_interface::input_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);

/** @copydoc retro_midi_interface::output_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);

/** @copydoc retro_midi_interface::read */
typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);

/** @copydoc retro_midi_interface::write */
typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);

/** @copydoc retro_midi_interface::flush */
typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);

/**
 * Interface that the core can use for raw MIDI I/O.
 */
struct retro_midi_interface
{
   /**
    * Retrieves the current state of MIDI input.
    *
    * @return \c true if MIDI input is enabled.
    */
   retro_midi_input_enabled_t input_enabled;

   /**
    * Retrieves the current state of MIDI output.
    * @return \c true if MIDI output is enabled.
    */
   retro_midi_output_enabled_t output_enabled;

   /**
    * Reads a byte from the MIDI input stream.
    *
    * @param[out] byte The byte received from the input stream.
    * @return \c true if a byte was read,
    * \c false if MIDI input is disabled or \c byte is \c NULL.
    */
   retro_midi_read_t read;

   /**
    * Writes a byte to the output stream.
    *
    * @param byte The byte to write to the output stream.
    * @param delta_time Time since the previous write, in microseconds.
    * @return \c true if c\ byte was written, false otherwise.
    */
   retro_midi_write_t write;

   /**
    * Flushes previously-written data.
    *
    * @return \c true if successful.
    */
   retro_midi_flush_t flush;
};

/** @} */

/** @defgroup SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE Render Context Negotiation
 * @{
 */

/**
 * Describes the hardware rendering API used by
 * a particular subtype of \c retro_hw_render_context_negotiation_interface.
 *
 * Not every rendering API supported by libretro has a context negotiation interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_context_negotiation_interface_type
{
   /**
    * Denotes a context negotiation interface for Vulkan.
    * @see retro_hw_render_context_negotiation_interface_vulkan
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,

   /**
    * @private Defined to ensure <tt>sizeof(retro_hw_render_context_negotiation_interface_type) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX
};

/**
 * Base context negotiation interface type.
 * All \c retro_hw_render_context_negotiation_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 */
struct retro_hw_render_context_negotiation_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_context_negotiation_interface_type interface_type;

   /**
    * The version of this negotiation interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/** @defgroup RETRO_SERIALIZATION_QUIRK Serialization Quirks
 * @{
 */

/**
 * Indicates that serialized state is incomplete in some way.
 *
 * Set if serialization is usable for the common case of saving and loading game state,
 * but should not be relied upon for frame-sensitive frontend features
 * such as netplay or rerecording.
 */
#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0)

/**
 * Indicates that core must spend some time initializing before serialization can be done.
 *
 * \c retro_serialize(), \c retro_unserialize(), and \c retro_serialize_size() will initially fail.
 */
#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1)

/** Set by the core to indicate that serialization size may change within a session. */
#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2)

/** Set by the frontend to acknowledge that it supports variable-sized states. */
#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3)

/** Serialized state can only be loaded during the same session. */
#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4)

/**
 * Serialized state cannot be loaded on an architecture
 * with a different endianness from the one it was saved on.
 */
#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5)

/**
 * Serialized state cannot be loaded on a different platform
 * from the one it was saved on for reasons other than endianness,
 * such as word size dependence.
 */
#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)

/** @} */

/** @defgroup SET_MEMORY_MAPS Memory Descriptors
 * @{
 */

/** @defgroup RETRO_MEMDESC Memory Descriptor Flags
 * Information about how the emulated hardware uses this portion of its address space.
 * @{
 */

/**
 * Indicates that this memory area won't be modified
 * once \c retro_load_game has returned.
 */
#define RETRO_MEMDESC_CONST      (1 << 0)

/**
 * Indicates a memory area with big-endian byte ordering,
 * as opposed to the default of little-endian.
 */
#define RETRO_MEMDESC_BIGENDIAN  (1 << 1)

/**
 * Indicates a memory area that is used for the emulated system's main RAM.
 */
#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2)

/**
 * Indicates a memory area that is used for the emulated system's save RAM,
 * usually found on a game cartridge as battery-backed RAM or flash memory.
 */
#define RETRO_MEMDESC_SAVE_RAM   (1 << 3)

/**
 * Indicates a memory area that is used for the emulated system's video RAM,
 * usually found on a console's GPU (or local equivalent).
 */
#define RETRO_MEMDESC_VIDEO_RAM  (1 << 4)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 2 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_2    (1 << 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 4 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_4    (2 << 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 8 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_8    (3 << 16)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 2 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_2  (1 << 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 4 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_4  (2 << 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 8 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_8  (3 << 24)

/** @} */

/**
 * A mapping from a region of the emulated console's address space
 * to the host's address space.
 *
 * Can be used to map an address in the console's address space
 * to the host's address space, like so:
 *
 * @code
 * void* emu_to_host(void* addr, struct retro_memory_descriptor* descriptor)
 * {
 *     return descriptor->ptr + (addr & ~descriptor->disconnect) - descriptor->start;
 * }
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_descriptor
{
   /**
    * A bitwise \c OR of one or more \ref RETRO_MEMDESC "flags"
    * that describe how the emulated system uses this descriptor's address range.
    *
    * @note If \c ptr is \c NULL,
    * then no flags should be set.
    * @see RETRO_MEMDESC
    */
   uint64_t flags;

   /**
    * Pointer to the start of this memory region's buffer
    * within the \em host's address space.
    * The address listed here must be valid for the duration of the session;
    * it must not be freed or modified by the frontend
    * and it must not be moved by the core.
    *
    * May be \c NULL to indicate a lack of accessible memory
    * at the emulated address given in \c start.
    *
    * @note Overlapping descriptors that include the same byte
    * must have the same \c ptr value.
    */
   void *ptr;

   /**
    * The offset of this memory region,
    * relative to the address given by \c ptr.
    *
    * @note It is recommended to use this field for address calculations
    * instead of performing arithmetic on \c ptr.
    */
   size_t offset;

   /**
    * The starting address of this memory region
    * <em>within the emulated hardware's address space</em>.
    *
    * @note Not represented as a pointer
    * because it's unlikely to be valid on the host device.
    */
   size_t start;

   /**
    * A bitmask that specifies which bits of an address must match
    * the bits of the \ref start address.
    *
    * Combines with \c disconnect to map an address to a memory block.
    *
    * If multiple memory descriptors can claim a particular byte,
    * the first one defined in the \ref retro_memory_descriptor array applies.
    * A bit which is set in \c start must also be set in this.
    *
    * Can be zero, in which case \c start and \c len represent
    * the complete mapping for this region of memory
    * (i.e. each byte is mapped exactly once).
    * In this case, \c len must be a power of two.
    */
   size_t select;

   /**
    * A bitmask of bits that are \em not used for addressing.
    *
    * Any set bits are assumed to be disconnected from
    * the emulated memory chip's address pins,
    * and are therefore ignored when memory-mapping.
    */
   size_t disconnect;

   /**
    * The length of this memory region, in bytes.
    *
    * If applying \ref start and \ref disconnect to an address
    * results in a value higher than this,
    * the highest bit of the address is cleared.
    *
    * If the address is still too high, the next highest bit is cleared.
    * Can be zero, in which case it's assumed to be
    * bounded only by \ref select and \ref disconnect.
    */
   size_t len;

   /**
    * A short name for this address space.
    *
    * Names must meet the following requirements:
    *
    * \li Characters must be in the set <tt>[a-zA-Z0-9_-]</tt>.
    * \li No more than 8 characters, plus a \c NULL terminator.
    * \li Names are case-sensitive, but lowercase characters are discouraged.
    * \li A name must not be the same as another name plus a character in the set \c [A-F0-9]
    *     (i.e. if an address space named "RAM" exists,
    *     then the names "RAM0", "RAM1", ..., "RAMF" are forbidden).
    *     This is to allow addresses to be named by each descriptor unambiguously,
    *     even if the areas overlap.
    * \li May be \c NULL or empty (both are considered equivalent).
    *
    * Here are some examples of pairs of address space names:
    *
    * \li \em blank + \em blank: valid (multiple things may be mapped in the same namespace)
    * \li \c Sp + \c Sp: valid (multiple things may be mapped in the same namespace)
    * \li \c SRAM + \c VRAM: valid (neither is a prefix of the other)
    * \li \c V + \em blank: valid (\c V is not in \c [A-F0-9])
    * \li \c a + \em blank: valid but discouraged (\c a is not in \c [A-F0-9])
    * \li \c a + \c A: valid but discouraged (neither is a prefix of the other)
    * \li \c AR + \em blank: valid (\c R is not in \c [A-F0-9])
    * \li \c ARB + \em blank: valid (there's no \c AR namespace,
    *     so the \c B doesn't cause ambiguity).
    * \li \em blank + \c B: invalid, because it's ambiguous which address space \c B1234 would refer to.
    *
    * The length of the address space's name can't be used to disambugiate,
    * as extra information may be appended to it without a separator.
    */
   const char *addrspace;

   /* TODO: When finalizing this one, add a description field, which should be
    * "WRAM" or something roughly equally long. */

   /* TODO: When finalizing this one, replace 'select' with 'limit', which tells
    * which bits can vary and still refer to the same address (limit = ~select).
    * TODO: limit? range? vary? something else? */

   /* TODO: When finalizing this one, if 'len' is above what 'select' (or
    * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'
    * and 'select' != 0, and the mappings don't tell how the system switches the
    * banks. */

   /* TODO: When finalizing this one, fix the 'len' bit removal order.
    * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.
    * Algorithm: Take bits highest to lowest, but if it goes above len, clear
    * the most recent addition and continue on the next bit.
    * TODO: Can the above be optimized? Is "remove the lowest bit set in both
    * pointer and 'len'" equivalent? */

   /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing
    * the emulated memory in 32-bit chunks, native endian. But that's nothing
    * compared to Darek Mihocka <http://www.emulators.com/docs/nx07_vm101.htm>
    * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE
    * RAM backwards! I'll want to represent both of those, via some flags.
    *
    * I suspect MAME either didn't think of that idea, or don't want the #ifdef.
    * Not sure which, nor do I really care. */

   /* TODO: Some of those flags are unused and/or don't really make sense. Clean
    * them up. */
};

/**
 * A list of regions within the emulated console's address space.
 *
 * The frontend may use the largest value of
 * \ref retro_memory_descriptor::start + \ref retro_memory_descriptor::select
 * in a certain namespace to infer the overall size of the address space.
 * If the address space is larger than that,
 * the last mapping in \ref descriptors should have \ref retro_memory_descriptor::ptr set to \c NULL
 * and \ref retro_memory_descriptor::select should have all bits used in the address space set to 1.
 *
 * Here's an example set of descriptors for the SNES.
 *
 * @code{.c}
 * struct retro_memory_map snes_descriptors = retro_memory_map
 * {
 *    .descriptors = (struct retro_memory_descriptor[])
 *    {
 *       // WRAM; must usually be mapped before the ROM,
 *       // as some SNES ROM mappers try to claim 0x7E0000
 *       { .addrspace="WRAM", .start=0x7E0000, .len=0x20000 },
 *
 *       // SPC700 RAM
 *       { .addrspace="SPC700", .len=0x10000 },
 *
 *       // WRAM mirrors
 *       { .addrspace="WRAM", .start=0x000000, .select=0xC0E000, .len=0x2000 },
 *       { .addrspace="WRAM", .start=0x800000, .select=0xC0E000, .len=0x2000 },
 *
 *       // WRAM mirror, alternate equivalent descriptor
 *       // (Various similar constructions can be created by combining parts of the above two.)
 *       { .addrspace="WRAM", .select=0x40E000, .disconnect=~0x1FFF },
 *
 *       // LoROM (512KB, mirrored a couple of times)
 *       { .addrspace="LoROM", .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="LoROM", .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *
 *       // HiROM (4MB)
 *       { .addrspace="HiROM", .start=0x400000, .select=0x400000, .len=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="HiROM", .start=0x008000, .select=0x408000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // ExHiROM (8MB)
 *       { .addrspace="ExHiROM", .start=0xC00000, .select=0xC00000, .len=4*1024*1024, .offset=0, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x400000, .select=0xC00000, .len=4*1024*1024, .offset=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x808000, .select=0xC08000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x008000, .select=0xC08000, .len=4*1024*1024, .offset=4*1024*1024+0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // Clarifying the full size of the address space
 *       { .select=0xFFFFFF, .ptr=NULL },
 *    },
 *    .num_descriptors = 14,
 * };
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_map
{
   /**
    * Pointer to an array of memory descriptors,
    * each of which describes part of the emulated console's address space.
    */
   const struct retro_memory_descriptor *descriptors;

   /** The number of descriptors in \c descriptors. */
   unsigned num_descriptors;
};

/** @} */

/** @defgroup SET_CONTROLLER_INFO Controller Info
 * @{
 */

/**
 * Details about a controller (or controller configuration)
 * supported by one of a core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_description
{
   /**
    * A human-readable label for the controller or configuration
    * represented by this device type.
    * Most likely the device's original brand name.
    */
   const char *desc;

   /**
    * A unique identifier that will be passed to \c retro_set_controller_port_device()'s \c device parameter.
    * May be the ID of one of \ref RETRO_DEVICE "the generic controller types",
    * or a subclass ID defined with \c RETRO_DEVICE_SUBCLASS.
    *
    * @see RETRO_DEVICE_SUBCLASS
    */
   unsigned id;
};

/**
 * Lists the types of controllers supported by
 * one of core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_info
{

   /**
    * A pointer to an array of device types supported by this controller port.
    *
    * @note Ports that support the same devices
    * may share the same underlying array.
    */
   const struct retro_controller_description *types;

   /** The number of elements in \c types. */
   unsigned num_types;
};

/** @} */

/** @defgroup SET_SUBSYSTEM_INFO Subsystems
 * @{
 */

/**
 * Information about a type of memory associated with a subsystem.
 * Usually used for SRAM (save RAM).
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_get_memory_data
 * @see retro_get_memory_size
 */
struct retro_subsystem_memory_info
{
   /**
    * The file extension the frontend should use
    * to save this memory region to disk, e.g. "srm" or "sav".
    */
   const char *extension;

   /**
    * A constant that identifies this type of memory.
    * Should be at least 0x100 (256) to avoid conflict
    * with the standard libretro memory types,
    * unless a subsystem uses the main platform's memory region.
    * @see RETRO_MEMORY
    */
   unsigned type;
};

/**
 * Information about a type of ROM that a subsystem may use.
 * Subsystems may use one or more ROMs at once,
 * possibly of different types.
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_subsystem_info
 */
struct retro_subsystem_rom_info
{
   /**
    * Human-readable description of what the content represents,
    * e.g. "Game Boy ROM".
    */
   const char *desc;

   /** @copydoc retro_system_info::valid_extensions */
   const char *valid_extensions;

   /** @copydoc retro_system_info::need_fullpath */
   bool need_fullpath;

   /** @copydoc retro_system_info::block_extract */
   bool block_extract;

   /**
    * Indicates whether this particular subsystem ROM is required.
    * If \c true and the user doesn't provide a ROM,
    * the frontend should not load the core.
    * If \c false and the user doesn't provide a ROM,
    * the frontend should pass a zeroed-out \c retro_game_info
    * to the corresponding entry in \c retro_load_game_special().
    */
   bool required;

   /**
    * Pointer to an array of memory descriptors that this subsystem ROM type uses.
    * Useful for secondary cartridges that have their own save data.
    * May be \c NULL, in which case this subsystem ROM's memory is not persisted by the frontend
    * and \c num_memory should be zero.
    */
   const struct retro_subsystem_memory_info *memory;

   /** The number of elements in the array pointed to by \c memory. */
   unsigned num_memory;
};

/**
 * Information about a secondary platform that a core supports.
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 */
struct retro_subsystem_info
{
   /**
    * A human-readable description of the subsystem type,
    * usually the brand name of the original platform
    * (e.g. "Super Game Boy").
    */
   const char *desc;

   /**
    * A short machine-friendly identifier for the subsystem,
    * usually an abbreviation of the platform name.
    * For example, a Super Game Boy subsystem for a SNES core
    * might use an identifier of "sgb".
    * This identifier can be used for command-line interfaces,
    * configuration, or other purposes.
    * Must use lower-case alphabetical characters only (i.e. from a-z).
    */
   const char *ident;

   /**
    * The list of ROM types that this subsystem may use.
    *
    * The first entry is considered to be the "most significant" content,
    * for the purposes of the frontend's categorization.
    * E.g. with Super GameBoy, the first content should be the GameBoy ROM,
    * as it is the most "significant" content to a user.
    *
    * If a frontend creates new files based on the content used (e.g. for savestates),
    * it should derive the filenames from the name of the first ROM in this list.
    *
    * @note \c roms can have a single element,
    * but this is usually a sign that the core should broaden its
    * primary system info instead.
    *
    * @see \c retro_system_info
    */
   const struct retro_subsystem_rom_info *roms;

   /** The length of the array given in \c roms. */
   unsigned num_roms;

   /** A unique identifier passed to retro_load_game_special(). */
   unsigned id;
};

/** @} */

/** @defgroup SET_PROC_ADDRESS_CALLBACK Core Function Pointers
 * @{ */

/**
 * The function pointer type that \c retro_get_proc_address_t returns.
 *
 * Despite the signature shown here, the original function may include any parameters and return type
 * that respects the calling convention and C ABI.
 *
 * The frontend is expected to cast the function pointer to the correct type.
 */
typedef void (RETRO_CALLCONV *retro_proc_address_t)(void);

/**
 * Get a symbol from a libretro core.
 *
 * Cores should only return symbols that serve as libretro extensions.
 * Frontends should not use this to obtain symbols to standard libretro entry points;
 * instead, they should link to the core statically or use \c dlsym (or local equivalent).
 *
 * The symbol name must be equal to the function name.
 * e.g. if <tt>void retro_foo(void);</tt> exists, the symbol in the compiled library must be called \c retro_foo.
 * The returned function pointer must be cast to the corresponding type.
 *
 * @param \c sym The name of the symbol to look up.
 * @return Pointer to the exposed function with the name given in \c sym,
 * or \c NULL if one couldn't be found.
 * @note The frontend is expected to know the returned pointer's type in advance
 * so that it can be cast correctly.
 * @note The core doesn't need to expose every possible function through this interface.
 * It's enough to only expose the ones that it expects the frontend to use.
 * @note The functions exposed through this interface
 * don't need to be publicly exposed in the compiled library
 * (e.g. via \c __declspec(dllexport)).
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);

/**
 * An interface that the frontend can use to get function pointers from the core.
 *
 * @note The returned function pointer will be invalidated once the core is unloaded.
 * How and when that happens is up to the frontend.
 *
 * @see retro_get_proc_address_t
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
struct retro_get_proc_address_interface
{
   /** Set by the core. */
   retro_get_proc_address_t get_proc_address;
};

/** @} */

/** @defgroup GET_LOG_INTERFACE Logging
 * @{
 */

/**
 * The severity of a given message.
 * The frontend may log messages differently depending on the level.
 * It may also ignore log messages of a certain level.
 * @see retro_log_callback
 */
enum retro_log_level
{
   /** The logged message is most likely not interesting to the user. */
   RETRO_LOG_DEBUG = 0,

   /** Information about the core operating normally. */
   RETRO_LOG_INFO,

   /** Indicates a potential problem, possibly one that the core can recover from. */
   RETRO_LOG_WARN,

   /** Indicates a degraded experience, if not failure. */
   RETRO_LOG_ERROR,

   /** Defined to ensure that sizeof(enum retro_log_level) == sizeof(int). Do not use. */
   RETRO_LOG_DUMMY = INT_MAX
};

/**
 * Logs a message to the frontend.
 *
 * @param level The log level of the message.
 * @param fmt The format string to log.
 * Same format as \c printf.
 * Behavior is undefined if this is \c NULL.
 * @param ... Zero or more arguments used by the format string.
 * Behavior is undefined if these don't match the ones expected by \c fmt.
 * @see retro_log_level
 * @see retro_log_callback
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see printf
 */
typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,
      const char *fmt, ...);

/**
 * Details about how to make log messages.
 *
 * @see retro_log_printf_t
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 */
struct retro_log_callback
{
   /**
    * Called when logging a message.
    *
    * @note Set by the frontend.
    */
   retro_log_printf_t log;
};

/** @} */

/** @defgroup GET_PERF_INTERFACE Performance Interface
 * @{
 */

/** @defgroup RETRO_SIMD CPU Features
 * @{
 */

/**
 * Indicates CPU support for the SSE instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE
 */
#define RETRO_SIMD_SSE      (1 << 0)

/**
 * Indicates CPU support for the SSE2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE2
 */
#define RETRO_SIMD_SSE2     (1 << 1)

/** Indicates CPU support for the AltiVec (aka VMX or Velocity Engine) instruction set. */
#define RETRO_SIMD_VMX      (1 << 2)

/** Indicates CPU support for the VMX128 instruction set. Xbox 360 only. */
#define RETRO_SIMD_VMX128   (1 << 3)

/**
 * Indicates CPU support for the AVX instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX
 */
#define RETRO_SIMD_AVX      (1 << 4)

/**
 * Indicates CPU support for the NEON instruction set.
 * @see https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[Neon]
 */
#define RETRO_SIMD_NEON     (1 << 5)

/**
 * Indicates CPU support for the SSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE3
 */
#define RETRO_SIMD_SSE3     (1 << 6)

/**
 * Indicates CPU support for the SSSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSSE3
 */
#define RETRO_SIMD_SSSE3    (1 << 7)

/**
 * Indicates CPU support for the MMX instruction set.
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=MMX
 */
#define RETRO_SIMD_MMX      (1 << 8)

/** Indicates CPU support for the MMXEXT instruction set. */
#define RETRO_SIMD_MMXEXT   (1 << 9)

/**
 * Indicates CPU support for the SSE4 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_1
 */
#define RETRO_SIMD_SSE4     (1 << 10)

/**
 * Indicates CPU support for the SSE4.2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_2
 */
#define RETRO_SIMD_SSE42    (1 << 11)

/**
 * Indicates CPU support for the AVX2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX2
 */
#define RETRO_SIMD_AVX2     (1 << 12)

/** Indicates CPU support for the VFPU instruction set. PS2 and PSP only.
 *
 * @see https://pspdev.github.io/vfpu-docs
 */
#define RETRO_SIMD_VFPU     (1 << 13)

/**
 * Indicates CPU support for Gekko SIMD extensions. GameCube only.
 */
#define RETRO_SIMD_PS       (1 << 14)

/**
 * Indicates CPU support for AES instructions.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#aestechs=AES&othertechs=AES
 */
#define RETRO_SIMD_AES      (1 << 15)

/**
 * Indicates CPU support for the VFPv3 instruction set.
 */
#define RETRO_SIMD_VFPV3    (1 << 16)

/**
 * Indicates CPU support for the VFPv4 instruction set.
 */
#define RETRO_SIMD_VFPV4    (1 << 17)

/** Indicates CPU support for the POPCNT instruction. */
#define RETRO_SIMD_POPCNT   (1 << 18)

/** Indicates CPU support for the MOVBE instruction. */
#define RETRO_SIMD_MOVBE    (1 << 19)

/** Indicates CPU support for the CMOV instruction. */
#define RETRO_SIMD_CMOV     (1 << 20)

/** Indicates CPU support for the ASIMD instruction set. */
#define RETRO_SIMD_ASIMD    (1 << 21)

/** @} */

/**
 * An abstract unit of ticks.
 *
 * Usually nanoseconds or CPU cycles,
 * but it depends on the platform and the frontend.
 */
typedef uint64_t retro_perf_tick_t;

/** Time in microseconds. */
typedef int64_t retro_time_t;

/**
 * A performance counter.
 *
 * Use this to measure the execution time of a region of code.
 * @see retro_perf_callback
 */
struct retro_perf_counter
{
   /**
    * A human-readable identifier for the counter.
    *
    * May be displayed by the frontend.
    * Behavior is undefined if this is \c NULL.
    */
   const char *ident;

   /**
    * The time of the most recent call to \c retro_perf_callback::perf_start
    * on this performance counter.
    *
    * @see retro_perf_start_t
    */
   retro_perf_tick_t start;

   /**
    * The total time spent within this performance counter's measured code,
    * i.e. between calls to \c retro_perf_callback::perf_start and \c retro_perf_callback::perf_stop.
    *
    * Updated after each call to \c retro_perf_callback::perf_stop.
    * @see retro_perf_stop_t
    */
   retro_perf_tick_t total;

   /**
    * The number of times this performance counter has been started.
    *
    * Updated after each call to \c retro_perf_callback::perf_start.
    * @see retro_perf_start_t
    */
   retro_perf_tick_t call_cnt;

   /**
    * \c true if this performance counter has been registered by the frontend.
    * Must be initialized to \c false by the core before registering it.
    * @see retro_perf_register_t
    */
   bool registered;
};

/**
 * @returns The current system time in microseconds.
 * @note Accuracy may vary by platform.
 * The frontend should use the most accurate timer possible.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);

/**
 * @returns The number of ticks since some unspecified epoch.
 * The exact meaning of a "tick" depends on the platform,
 * but it usually refers to nanoseconds or CPU cycles.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);

/**
 * Returns a bitmask of detected CPU features.
 *
 * Use this for runtime dispatching of CPU-specific code.
 *
 * @returns A bitmask of detected CPU features.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see RETRO_SIMD
 */
typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);

/**
 * Asks the frontend to log or display the state of performance counters.
 * How this is done depends on the frontend.
 * Performance counters can be reviewed manually as well.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see retro_perf_counter
 */
typedef void (RETRO_CALLCONV *retro_perf_log_t)(void);

/**
 * Registers a new performance counter.
 *
 * If \c counter has already been registered beforehand,
 * this function does nothing.
 *
 * @param counter The counter to register.
 * \c counter::ident must be set to a unique identifier,
 * and all other values in \c counter must be set to zero or \c false.
 * Behavior is undefined if \c NULL.
 * @post If \c counter is successfully registered,
 * then \c counter::registered will be set to \c true.
 * Otherwise, it will be set to \c false.
 * Registration may fail if the frontend's maximum number of counters (if any) has been reached.
 * @note The counter is owned by the core and must not be freed by the frontend.
 * The frontend must also clean up any references to a core's performance counters
 * before unloading it, otherwise undefined behavior may occur.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);

/**
 * Starts a registered performance counter.
 *
 * Call this just before the code you want to measure.
 *
 * @param counter The counter to start.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);

/**
 * Stops a registered performance counter.
 *
 * Call this just after the code you want to measure.
 *
 * @param counter The counter to stop.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);

/**
 * An interface that the core can use to get performance information.
 *
 * Here's a usage example:
 *
 * @code{.c}
 * #ifdef PROFILING
 * // Wrapper macros to simplify using performance counters.
 * // Optional; tailor these to your project's needs.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
 * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))
 * #else
 * // Exclude the performance counters if profiling is disabled.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_START(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) ((void)0)
 * #endif
 *
 * // Defined somewhere else in the core.
 * extern struct retro_perf_callback perf_cb;
 *
 * void retro_run(void)
 * {
 *    RETRO_PERFORMANCE_INIT(cb, interesting);
 *    RETRO_PERFORMANCE_START(cb, interesting);
 *    interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, interesting);
 *
 *    RETRO_PERFORMANCE_INIT(cb, maybe_slow);
 *    RETRO_PERFORMANCE_START(cb, maybe_slow);
 *    more_interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, maybe_slow);
 * }
 *
 * void retro_deinit(void)
 * {
 *    // Asks the frontend to log the results of all performance counters.
 *    perf_cb.perf_log();
 * }
 * @endcode
 *
 * All functions are set by the frontend.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
struct retro_perf_callback
{
   /** @copydoc retro_perf_get_time_usec_t */
   retro_perf_get_time_usec_t    get_time_usec;

   /** @copydoc retro_perf_get_counter_t */
   retro_get_cpu_features_t      get_cpu_features;

   /** @copydoc retro_perf_get_counter_t */
   retro_perf_get_counter_t      get_perf_counter;

   /** @copydoc retro_perf_register_t */
   retro_perf_register_t         perf_register;

   /** @copydoc retro_perf_start_t */
   retro_perf_start_t            perf_start;

   /** @copydoc retro_perf_stop_t */
   retro_perf_stop_t             perf_stop;

   /** @copydoc retro_perf_log_t */
   retro_perf_log_t              perf_log;
};

/** @} */

/**
 * @defgroup RETRO_SENSOR Sensor Interface
 * @{
 */

/**
 * Defines actions that can be performed on sensors.
 * @note Cores should only enable sensors while they're actively being used;
 * depending on the frontend and platform,
 * enabling these sensors may impact battery life.
 *
 * @see RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE
 * @see retro_sensor_interface
 * @see retro_set_sensor_state_t
 */
enum retro_sensor_action
{
   /** Enables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,

   /** Disables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_DISABLE,

   /** Enables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_ENABLE,

   /** Disables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_DISABLE,

   /** Enables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_ENABLE,

   /** Disables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_DISABLE,

   /** @private Defined to ensure <tt>sizeof(enum retro_sensor_action) == sizeof(int)</tt>. Do not use. */
   RETRO_SENSOR_DUMMY = INT_MAX
};

/** @defgroup RETRO_SENSOR_ID Sensor Value IDs
 * @{
 */
/* Id values for SENSOR types. */

/**
 * Returns the device's acceleration along its local X axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating to the right.
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_X 0

/**
 * Returns the device's acceleration along its local Y axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating upwards,
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Y 1

/**
 * Returns the the device's acceleration along its local Z axis minus the effect of gravity, in m/s^2.
 *
 * Positive values indicate forward acceleration towards the user,
 * assuming the user is looking at the device head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Z 2

/**
 * Returns the angular velocity of the device around its local X axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_X 3

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Y 4

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Z 5

/**
 * Returns the ambient illuminance (light intensity) of the device's environment, in lux.
 *
 * @see https://en.wikipedia.org/wiki/Lux for a table of common lux values.
 */
#define RETRO_SENSOR_ILLUMINANCE 6
/** @} */

/**
 * Adjusts the state of a sensor.
 *
 * @param port The device port of the controller that owns the sensor given in \c action.
 * @param action The action to perform on the sensor.
 * Different devices support different sensors.
 * @param rate The rate at which the underlying sensor should be updated, in Hz.
 * This should be treated as a hint,
 * as some device sensors may not support the requested rate
 * (if it's configurable at all).
 * @returns \c true if the sensor state was successfully adjusted, \c false otherwise.
 * @note If one of the \c RETRO_SENSOR_*_ENABLE actions fails,
 * this likely means that the given sensor is not available
 * on the provided \c port.
 * @see retro_sensor_action
 */
typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
      enum retro_sensor_action action, unsigned rate);

/**
 * Retrieves the current value reported by sensor.
 * @param port The device port of the controller that owns the sensor given in \c id.
 * @param id The sensor value to query.
 * @returns The current sensor value.
 * Exact semantics depend on the value given in \c id,
 * but will return 0 for invalid arguments.
 *
 * @see RETRO_SENSOR_ID
 */
typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);

/**
 * An interface that cores can use to access device sensors.
 *
 * All function pointers are set by the frontend.
 */
struct retro_sensor_interface
{
   /** @copydoc retro_set_sensor_state_t */
   retro_set_sensor_state_t set_sensor_state;

   /** @copydoc retro_sensor_get_input_t */
   retro_sensor_get_input_t get_sensor_input;
};

/** @} */

/** @defgroup GET_CAMERA_INTERFACE Camera Interface
 * @{
 */

/**
 * Denotes the type of buffer in which the camera will store its input.
 *
 * Different camera drivers may support different buffer types.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 * @see retro_camera_callback
 */
enum retro_camera_buffer
{
   /**
    * Indicates that camera frames should be delivered to the core as an OpenGL texture.
    *
    * Requires that the core is using an OpenGL context via \c RETRO_ENVIRONMENT_SET_HW_RENDER.
    *
    * @see retro_camera_frame_opengl_texture_t
    */
   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,

   /**
    * Indicates that camera frames should be delivered to the core as a raw buffer in memory.
    *
    * @see retro_camera_frame_raw_framebuffer_t
    */
   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,

   /**
    * @private Defined to ensure <tt>sizeof(enum retro_camera_buffer) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
};

/**
 * Starts an initialized camera.
 * The camera is disabled by default,
 * and must be enabled with this function before being used.
 *
 * Set by the frontend.
 *
 * @returns \c true if the camera was successfully started, \c false otherwise.
 * Failure may occur if no actual camera is available,
 * or if the frontend doesn't have permission to access it.
 * @note Must be called in \c retro_run().
 * @see retro_camera_callback
 */
typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);

/**
 * Stops the running camera.
 *
 * Set by the frontend.
 *
 * @note Must be called in \c retro_run().
 * @warning The frontend may close the camera on its own when unloading the core,
 * but this behavior is not guaranteed.
 * Cores should clean up the camera before exiting.
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);

/**
 * Called by the frontend to report the state of the camera driver.
 *
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as a raw buffer in memory.
 *
 * Set by the core.
 *
 * @param buffer Pointer to the camera's most recent video frame.
 * Each pixel is in XRGB8888 format.
 * The first pixel represents the top-left corner of the image
 * (i.e. the Y axis goes downward).
 * @param width The width of the frame given in \c buffer, in pixels.
 * @param height The height of the frame given in \c buffer, in pixels.
 * @param pitch The width of the frame given in \c buffer, in bytes.
 * @warning \c buffer may be invalidated when this function returns,
 * so the core should make its own copy of \c buffer if necessary.
 * @see RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
      unsigned width, unsigned height, size_t pitch);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as an OpenGL texture.
 *
 * @param texture_id The ID of the OpenGL texture that represents the camera's most recent frame.
 * Owned by the frontend, and must not be modified by the core.
 * @param texture_target The type of the texture given in \c texture_id.
 * Usually either \c GL_TEXTURE_2D or \c GL_TEXTURE_RECTANGLE,
 * but other types are allowed.
 * @param affine A pointer to a 3x3 column-major affine matrix
 * that can be used to transform pixel coordinates to texture coordinates.
 * After transformation, the bottom-left corner should have coordinates of <tt>(0, 0)</tt>
 * and the top-right corner should have coordinates of <tt>(1, 1)</tt>
 * (or <tt>(width, height)</tt> for \c GL_TEXTURE_RECTANGLE).
 *
 * @note GL-specific typedefs (e.g. \c GLfloat and \c GLuint) are avoided here
 * so that the API doesn't rely on gl.h.
 * @warning \c texture_id and \c affine may be invalidated when this function returns,
 * so the core should make its own copy of them if necessary.
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,
      unsigned texture_target, const float *affine);

/**
 * An interface that the core can use to access a device's camera.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 */
struct retro_camera_callback
{
   /**
    * Requested camera capabilities,
    * given as a bitmask of \c retro_camera_buffer values.
    * Set by the core.
    *
    * Here's a usage example:
    * @code
    * // Requesting support for camera data delivered as both an OpenGL texture and a pixel buffer:
    * struct retro_camera_callback callback;
    * callback.caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);
    * @endcode
    */
   uint64_t caps;

   /**
    * The desired width of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
    * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned width;

   /**
    * The desired height of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
     * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned height;

   /**
    * @copydoc retro_camera_start_t
    * @see retro_camera_callback
    */
   retro_camera_start_t start;

   /**
    * @copydoc retro_camera_stop_t
    * @see retro_camera_callback
    */
   retro_camera_stop_t stop;

   /**
    * @copydoc retro_camera_frame_raw_framebuffer_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;

   /**
    * @copydoc retro_camera_frame_opengl_texture_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_opengl_texture_t frame_opengl_texture;

   /**
    * Core-defined callback invoked by the frontend right after the camera driver is initialized
    * (\em not when calling \c start).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t initialized;

   /**
    * Core-defined callback invoked by the frontend
    * right before the video camera driver is deinitialized
    * (\em not when calling \c stop).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t deinitialized;
};

/** @} */

/** @defgroup GET_LOCATION_INTERFACE Location Interface
 * @{
 */

/** @copydoc retro_location_callback::set_interval */
typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,
      unsigned interval_distance);

/** @copydoc retro_location_callback::start */
typedef bool (RETRO_CALLCONV *retro_location_start_t)(void);

/** @copydoc retro_location_callback::stop */
typedef void (RETRO_CALLCONV *retro_location_stop_t)(void);

/** @copydoc retro_location_callback::get_position */
typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,
      double *horiz_accuracy, double *vert_accuracy);

/** Function type that reports the status of the location service. */
typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);

/**
 * An interface that the core can use to access a device's location.
 *
 * @note It is the frontend's responsibility to request the necessary permissions
 * from the operating system.
 * @see RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE
 */
struct retro_location_callback
{
   /**
    * Starts listening the device's location service.
    *
    * The frontend will report changes to the device's location
    * at the interval defined by \c set_interval.
    * Set by the frontend.
    *
    * @return true if location services were successfully started, false otherwise.
    * Note that this will return \c false if location services are disabled
    * or the frontend doesn't have permission to use them.
    * @note The device's location service may or may not have been enabled
    * before the core calls this function.
    */
   retro_location_start_t         start;

   /**
    * Stop listening to the device's location service.
    *
    * Set by the frontend.
    *
    * @note The location service itself may or may not
    * be turned off by this function,
    * depending on the platform and the frontend.
    * @post The core will stop receiving location service updates.
    */
   retro_location_stop_t          stop;

   /**
    * Returns the device's current coordinates.
    *
    * Set by the frontend.
    *
    * @param[out] lat Pointer to latitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] lon Pointer to longitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] horiz_accuracy Pointer to horizontal accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] vert_accuracy Pointer to vertical accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    */
   retro_location_get_position_t  get_position;

   /**
    * Sets the rate at which the location service should report updates.
    *
    * This is only a hint; the actual rate may differ.
    * Sets the interval of time and/or distance at which to update/poll
    * location-based data.
    *
    * Some platforms may only support one of the two parameters;
    * cores should provide both to ensure compatibility.
    *
    * Set by the frontend.
    *
    * @param interval_ms The desired period of time between location updates, in milliseconds.
    * @param interval_distance The desired distance between location updates, in meters.
    */
   retro_location_set_interval_t  set_interval;

   /** Called when the location service is initialized. Set by the core. Optional. */
   retro_location_lifetime_status_t initialized;

   /** Called when the location service is deinitialized. Set by the core. Optional. */
   retro_location_lifetime_status_t deinitialized;
};

/** @} */

/** @addtogroup GET_RUMBLE_INTERFACE
 * @{ */

/**
 * The type of rumble motor in a controller.
 *
 * Both motors can be controlled independently,
 * and the strong motor does not override the weak motor.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
enum retro_rumble_effect
{
   RETRO_RUMBLE_STRONG = 0,
   RETRO_RUMBLE_WEAK = 1,

   /** @private Defined to ensure <tt>sizeof(enum retro_rumble_effect) == sizeof(int)</tt>. Do not use. */
   RETRO_RUMBLE_DUMMY = INT_MAX
};

/**
 * Requests a rumble state change for a controller.
 * Set by the frontend.
 *
 * @param port The controller port to set the rumble state for.
 * @param effect The rumble motor to set the strength of.
 * @param strength The desired intensity of the rumble motor, ranging from \c 0 to \c 0xffff (inclusive).
 * @return \c true if the requested rumble state was honored.
 * If the controller doesn't support rumble, will return \c false.
 * @note Calling this before the first \c retro_run() may return \c false.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,
      enum retro_rumble_effect effect, uint16_t strength);

/**
 * An interface that the core can use to set the rumble state of a controller.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
struct retro_rumble_interface
{
   /** @copydoc retro_set_rumble_state_t */
   retro_set_rumble_state_t set_rumble_state;
};

/** @} */

/**
 * Called by the frontend to request audio samples.
 * The core should render audio within this function
 * using the callback provided by \c retro_set_audio_sample or \c retro_set_audio_sample_batch.
 *
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_sample_batch_t
 * @see retro_audio_sample_t
 */
typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);

/**
 * Called by the frontend to notify the core that it should pause or resume audio rendering.
 * The initial state of the audio driver after registering this callback is \c false (inactive).
 *
 * @param enabled \c true if the frontend's audio driver is active.
 * If so, the registered audio callback will be called regularly.
 * If not, the audio callback will not be invoked until the next time
 * the frontend calls this function with \c true.
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @note Even if no audio samples are rendered,
 * the core should continue to update its emulated platform's audio engine if necessary.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_callback_t
 */
typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);

/**
 * An interface that the frontend uses to request audio samples from the core.
 * @note To unregister a callback, pass a \c retro_audio_callback_t
 * with both fields set to <tt>NULL</tt>.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 */
struct retro_audio_callback
{
   /** @see retro_audio_callback_t */
   retro_audio_callback_t callback;

   /** @see retro_audio_set_state_callback_t */
   retro_audio_set_state_callback_t set_state;
};

typedef int64_t retro_usec_t;

/**
 * Called right before each iteration of \c retro_run
 * if registered via <tt>RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK</tt>.
 *
 * @param usec Time since the last call to <tt>retro_run</tt>, in microseconds.
 * If the frontend is manipulating the frame time
 * (e.g. via fast-forward or slow motion),
 * this value will be the reference value initially provided to the environment call.
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 * @see retro_frame_time_callback
 */
typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);

/**
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
struct retro_frame_time_callback
{
   /**
    * Called to notify the core of the current frame time.
    * If <tt>NULL</tt>, the frontend will clear its registered callback.
    */
   retro_frame_time_callback_t callback;

   /**
    * The ideal duration of one frame, in microseconds.
    * Compute it as <tt>1000000 / fps</tt>.
    * The frontend will resolve rounding to ensure that framestepping, etc is exact.
    */
   retro_usec_t reference;
};

/** @defgroup SET_AUDIO_BUFFER_STATUS_CALLBACK Audio Buffer Occupancy
 * @{
 */

/**
 * Notifies a libretro core of how full the frontend's audio buffer is.
 * Set by the core, called by the frontend.
 * It will be called right before \c retro_run() every frame.
 *
 * @param active \c true if the frontend's audio buffer is currently in use,
 * \c false if audio is disabled in the frontend.
 * @param occupancy A value between 0 and 100 (inclusive),
 * corresponding to the frontend's audio buffer occupancy percentage.
 * @param underrun_likely \c true if the frontend expects an audio buffer underrun
 * during the next frame, which indicates that a core should attempt frame-skipping.
 */
typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
      bool active, unsigned occupancy, bool underrun_likely);

/**
 * A callback to register with the frontend to receive audio buffer occupancy information.
 */
struct retro_audio_buffer_status_callback
{
   /** @copydoc retro_audio_buffer_status_callback_t */
   retro_audio_buffer_status_callback_t callback;
};

/** @} */

/* Pass this to retro_video_refresh_t if rendering to hardware.
 * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
 * */
#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)

/* Invalidates the current HW context.
 * Any GL state is lost, and must not be deinitialized explicitly.
 * If explicit deinitialization is desired by the libretro core,
 * it should implement context_destroy callback.
 * If called, all GPU resources must be reinitialized.
 * Usually called when frontend reinits video driver.
 * Also called first time video driver is initialized,
 * allowing libretro core to initialize resources.
 */
typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);

/* Gets current framebuffer which is to be rendered to.
 * Could change every frame potentially.
 */
typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);

/* Get a symbol from HW context. */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);

enum retro_hw_context_type
{
   RETRO_HW_CONTEXT_NONE             = 0,
   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
   RETRO_HW_CONTEXT_OPENGL           = 1,
   /* OpenGL ES 2.0. */
   RETRO_HW_CONTEXT_OPENGLES2        = 2,
   /* Modern desktop core GL context. Use version_major/
    * version_minor fields to set GL version. */
   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,
   /* OpenGL ES 3.0 */
   RETRO_HW_CONTEXT_OPENGLES3        = 4,
   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
    * use the corresponding enums directly. */
   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,

   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
   RETRO_HW_CONTEXT_VULKAN           = 6,

   /* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D11            = 7,

   /* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D10            = 8,

   /* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D12            = 9,

   /* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D9             = 10,

   /** Dummy value to ensure sizeof(enum retro_hw_context_type) == sizeof(int). Do not use. */
   RETRO_HW_CONTEXT_DUMMY = INT_MAX
};

struct retro_hw_render_callback
{
   /* Which API to use. Set by libretro core. */
   enum retro_hw_context_type context_type;

   /* Called when a context has been created or when it has been reset.
    * An OpenGL context is only valid after context_reset() has been called.
    *
    * When context_reset is called, OpenGL resources in the libretro
    * implementation are guaranteed to be invalid.
    *
    * It is possible that context_reset is called multiple times during an
    * application lifecycle.
    * If context_reset is called without any notification (context_destroy),
    * the OpenGL context was lost and resources should just be recreated
    * without any attempt to "free" old resources.
    */
   retro_hw_context_reset_t context_reset;

   /* Set by frontend.
    * TODO: This is rather obsolete. The frontend should not
    * be providing preallocated framebuffers. */
   retro_hw_get_current_framebuffer_t get_current_framebuffer;

   /* Set by frontend.
    * Can return all relevant functions, including glClear on Windows. */
   retro_hw_get_proc_address_t get_proc_address;

   /* Set if render buffers should have depth component attached.
    * TODO: Obsolete. */
   bool depth;

   /* Set if stencil buffers should be attached.
    * TODO: Obsolete. */
   bool stencil;

   /* If depth and stencil are true, a packed 24/8 buffer will be added.
    * Only attaching stencil is invalid and will be ignored. */

   /* Use conventional bottom-left origin convention. If false,
    * standard libretro top-left origin semantics are used.
    * TODO: Move to GL specific interface. */
   bool bottom_left_origin;

   /* Major version number for core GL context or GLES 3.1+. */
   unsigned version_major;

   /* Minor version number for core GL context or GLES 3.1+. */
   unsigned version_minor;

   /* If this is true, the frontend will go very far to avoid
    * resetting context in scenarios like toggling fullscreen, etc.
    * TODO: Obsolete? Maybe frontend should just always assume this ...
    */
   bool cache_context;

   /* The reset callback might still be called in extreme situations
    * such as if the context is lost beyond recovery.
    *
    * For optimal stability, set this to false, and allow context to be
    * reset at any time.
    */

   /* A callback to be called before the context is destroyed in a
    * controlled way by the frontend. */
   retro_hw_context_reset_t context_destroy;

   /* OpenGL resources can be deinitialized cleanly at this step.
    * context_destroy can be set to NULL, in which resources will
    * just be destroyed without any notification.
    *
    * Even when context_destroy is non-NULL, it is possible that
    * context_reset is called without any destroy notification.
    * This happens if context is lost by external factors (such as
    * notified by GL_ARB_robustness).
    *
    * In this case, the context is assumed to be already dead,
    * and the libretro implementation must not try to free any OpenGL
    * resources in the subsequent context_reset.
    */

   /* Creates a debug context. */
   bool debug_context;
};

/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
 * Called by the frontend in response to keyboard events.
 * down is set if the key is being pressed, or false if it is being released.
 * keycode is the RETROK value of the char.
 * character is the text character of the pressed key. (UTF-32).
 * key_modifiers is a set of RETROKMOD values or'ed together.
 *
 * The pressed/keycode state can be independent of the character.
 * It is also possible that multiple characters are generated from a
 * single keypress.
 * Keycode events should be treated separately from character events.
 * However, when possible, the frontend should try to synchronize these.
 * If only a character is posted, keycode should be RETROK_UNKNOWN.
 *
 * Similarly if only a keycode event is generated with no corresponding
 * character, character should be 0.
 */
typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,
      uint32_t character, uint16_t key_modifiers);

struct retro_keyboard_callback
{
   retro_keyboard_event_t callback;
};

/** @defgroup SET_DISK_CONTROL_INTERFACE Disk Control
 *
 * Callbacks for inserting and removing disks from the emulated console at runtime.
 * Should be provided by cores that support doing so.
 * Cores should automate this process if possible,
 * but some cases require the player's manual input.
 *
 * The steps for swapping disk images are generally as follows:
 *
 * \li Eject the emulated console's disk drive with \c set_eject_state(true).
 * \li Insert the new disk image with \c set_image_index(index).
 * \li Close the virtual disk tray with \c set_eject_state(false).
 *
 * @{
 */

/**
 * Called by the frontend to open or close the emulated console's virtual disk tray.
 *
 * The frontend may only set the disk image index
 * while the emulated tray is opened.
 *
 * If the emulated console's disk tray is already in the state given by \c ejected,
 * then this function should return \c true without doing anything.
 * The core should return \c false if it couldn't change the disk tray's state;
 * this may happen if the console itself limits when the disk tray can be open or closed
 * (e.g. to wait for the disc to stop spinning).
 *
 * @param ejected \c true if the virtual disk tray should be "ejected",
 * \c false if it should be "closed".
 * @return \c true if the virtual disk tray's state has been set to the given state,
 * false if there was an error.
 * @see retro_get_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);

/**
 * Gets the current ejected state of the disk drive.
 * The initial state is closed, i.e. \c false.
 *
 * @return \c true if the virtual disk tray is "ejected",
 * i.e. it's open and a disk can be inserted.
 * @see retro_set_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);

/**
 * Gets the index of the current disk image,
 * as determined by however the frontend orders disk images
 * (such as m3u-formatted playlists or special directories).
 *
 * @return The index of the current disk image
 * (starting with 0 for the first disk),
 * or a value greater than or equal to \c get_num_images() if no disk is inserted.
 * @see retro_get_num_images_t
 */
typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);

/**
 * Inserts the disk image at the given index into the emulated console's drive.
 * Can only be called while the disk tray is ejected
 * (i.e. \c retro_get_eject_state_t returns \c true).
 *
 * If the emulated disk tray is ejected
 * and already contains the disk image named by \c index,
 * then this function should do nothing and return \c true.
 *
 * @param index The index of the disk image to insert,
 * starting from 0 for the first disk.
 * A value greater than or equal to \c get_num_images()
 * represents the frontend removing the disk without inserting a new one.
 * @return \c true if the disk image was successfully set.
 * \c false if the disk tray isn't ejected or there was another error
 * inserting a new disk image.
 */
typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);

/**
 * @return The number of disk images which are available to use.
 * These are most likely defined in a playlist file.
 */
typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);

struct retro_game_info;

/**
 * Replaces the disk image at the given index with a new disk.
 *
 * Replaces the disk image associated with index.
 * Arguments to pass in info have same requirements as retro_load_game().
 * Virtual disk tray must be ejected when calling this.
 *
 * Passing \c NULL to this function indicates
 * that the frontend has removed this disk image from its internal list.
 * As a result, calls to this function can change the number of available disk indexes.
 *
 * For example, calling <tt>replace_image_index(1, NULL)</tt>
 * will remove the disk image at index 1,
 * and the disk image at index 2 (if any)
 * will be moved to the newly-available index 1.
 *
 * @param index The index of the disk image to replace.
 * @param info Details about the new disk image,
 * or \c NULL if the disk image at the given index should be discarded.
 * The semantics of each field are the same as in \c retro_load_game.
 * @return \c true if the disk image was successfully replaced
 * or removed from the playlist,
 * \c false if the tray is not ejected
 * or if there was an error.
 */
typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
      const struct retro_game_info *info);

/**
 * Adds a new index to the core's internal disk list.
 * This will increment the return value from \c get_num_images() by 1.
 * This image index cannot be used until a disk image has been set
 * with \c replace_image_index.
 *
 * @return \c true if the core has added space for a new disk image
 * and is ready to receive one.
 */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);

/**
 * Sets the disk image that will be inserted into the emulated disk drive
 * before \c retro_load_game is called.
 *
 * \c retro_load_game does not provide a way to ensure
 * that a particular disk image in a playlist is inserted into the console;
 * this function makes up for that.
 * Frontends should call it immediately before \c retro_load_game,
 * and the core should use the arguments
 * to validate the disk image in \c retro_load_game.
 *
 * When content is loaded, the core should verify that the
 * disk specified by \c index can be found at \c path.
 * This is to guard against auto-selecting the wrong image
 * if (for example) the user should modify an existing M3U playlist.
 * We have to let the core handle this because
 * \c set_initial_image() must be called before loading content,
 * i.e. the frontend cannot access image paths in advance
 * and thus cannot perform the error check itself.
 * If \c index is invalid (i.e. <tt>index >= get_num_images()</tt>)
 * or the disk image doesn't match the value given in \c path,
 * the core should ignore the arguments
 * and insert the disk at index 0 into the virtual disk tray.
 *
 * @warning If \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE is called within \c retro_load_game,
 * then this function may not be executed.
 * Set the disk control interface in \c retro_init if possible.
 *
 * @param index The index of the disk image within the playlist to set.
 * @param path The path of the disk image to set as the first.
 * The core should not load this path immediately;
 * instead, it should use it within \c retro_load_game
 * to verify that the correct disk image was loaded.
 * @return \c true if the initial disk index was set,
 * \c false if the arguments are invalid
 * or the core doesn't support this function.
 */
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);

/**
 * Returns the path of the disk image at the given index
 * on the host's file system.
 *
 * @param index The index of the disk image to get the path of.
 * @param s A buffer to store the path in.
 * @param len The size of \c s, in bytes.
 * @return \c true if the disk image's location was successfully
 * queried and copied into \c s,
 * \c false if the index is invalid
 * or the core couldn't locate the disk image.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *s, size_t len);

/**
 * Returns a friendly label for the given disk image.
 *
 * In the simplest case, this may be the disk image's file name
 * with the extension omitted.
 * For cores or games with more complex content requirements,
 * the label can be used to provide information to help the player
 * select a disk image to insert;
 * for example, a core may label different kinds of disks
 * (save data, level disk, installation disk, bonus content, etc.).
 * with names that correspond to in-game prompts,
 * so that the frontend can provide better guidance to the player.
 *
 * @param index The index of the disk image to return a label for.
 * @param s A buffer to store the resulting label in.
 * @param len The length of \c s, in bytes.
 * @return \c true if the disk image at \c index is valid
 * and a label was copied into \c s.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *s, size_t len);

/**
 * An interface that the frontend can use to exchange disks
 * within the emulated console's disk drive.
 *
 * All function pointers are required.
 *
 * @deprecated This struct is superseded by \ref retro_disk_control_ext_callback.
 * Only use this one to maintain compatibility
 * with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * @see retro_disk_control_ext_callback
 */
struct retro_disk_control_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;
};

/**
 * @copybrief retro_disk_control_callback
 *
 * All function pointers are required unless otherwise noted.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
struct retro_disk_control_ext_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;

   /** @copydoc retro_set_initial_image_t
    *
    * Optional; not called if \c NULL.
    *
    * @note The frontend will only try to record/restore the last-used disk index
    * if both \c set_initial_image and \c get_image_path are implemented.
    */
   retro_set_initial_image_t set_initial_image;

   /**
    * @copydoc retro_get_image_path_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_path_t get_image_path;

   /**
    * @copydoc retro_get_image_label_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_label_t get_image_label;
};

/** @} */

/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
 * A core can set it if sending and receiving custom network packets
 * during a multiplayer session is desired.
 */

/* Netpacket flags for retro_netpacket_send_t */
#define RETRO_NETPACKET_UNRELIABLE  0        /* Packet to be sent unreliable, depending on network quality it might not arrive. */
#define RETRO_NETPACKET_RELIABLE    (1 << 0) /* Reliable packets are guaranteed to arrive at the target in the order they were sent. */
#define RETRO_NETPACKET_UNSEQUENCED (1 << 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */
#define RETRO_NETPACKET_FLUSH_HINT  (1 << 2) /* Request the packet and any previously buffered ones to be sent immediately */

/* Broadcast client_id for retro_netpacket_send_t */
#define RETRO_NETPACKET_BROADCAST 0xFFFF

/* Used by the core to send a packet to one or all connected players.
 * A single packet sent via this interface can contain up to 64 KB of data.
 *
 * The client_id RETRO_NETPACKET_BROADCAST sends the packet as a broadcast to
 * all connected players. This is supported from the host as well as clients.
*  Otherwise, the argument indicates the player to send the packet to.
 *
 * A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).
 * Unreliable packets might not be supported by the frontend, but the flags can
 * still be specified. Reliable transmission will be used instead.
 *
 * Calling this with the flag RETRO_NETPACKET_FLUSH_HINT will send off the
 * packet and any previously buffered ones immediately and without blocking.
 * To only flush previously queued packets, buf or len can be passed as NULL/0.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id);

/* Optionally read any incoming packets without waiting for the end of the
 * frame. While polling, retro_netpacket_receive_t and retro_netpacket_stop_t
 * can be called. The core can perform this in a loop to do a blocking read,
 * i.e., wait for incoming data, but needs to handle stop getting called and
 * also give up after a short while to avoid freezing on a connection problem.
 * It is a good idea to manually flush outgoing packets before calling this.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_receive_t)(void);

/* Called by the frontend to signify that a multiplayer session has started.
 * If client_id is 0 the local player is the host of the session and at this
 * point no other player has connected yet.
 *
 * If client_id is > 0 the local player is a client connected to a host and
 * at this point is already fully connected to the host.
 *
 * The core must store the function pointer send_fn and use it whenever it
 * wants to send a packet. Optionally poll_receive_fn can be stored and used
 * when regular receiving between frames is not enough. These function pointers
 * remain valid until the frontend calls retro_netpacket_stop_t.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn, retro_netpacket_poll_receive_t poll_receive_fn);

/* Called by the frontend when a new packet arrives which has been sent from
 * another player with retro_netpacket_send_t. The client_id argument indicates
 * who has sent the packet.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);

/* Called by the frontend when the multiplayer session has ended.
 * Once this gets called the function pointers passed to
 * retro_netpacket_start_t will not be valid anymore.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);

/* Called by the frontend every frame (between calls to retro_run while
 * updating the state of the multiplayer session.
 * This is a good place for the core to call retro_netpacket_send_t from.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);

/* Called by the frontend when a new player connects to the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 * If this function returns false, the newly connected player gets dropped.
 * This can be used for example to limit the number of players.
 */
typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);

/* Called by the frontend when a player leaves or disconnects from the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);

/**
 * A callback interface for giving a core the ability to send and receive custom
 * network packets during a multiplayer session between two or more instances
 * of a libretro frontend.
 *
 * Normally during connection handshake the frontend will compare library_version
 * used by both parties and show a warning if there is a difference. When the core
 * supplies protocol_version, the frontend will check against this instead.
 *
 * @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE
 */
struct retro_netpacket_callback
{
   retro_netpacket_start_t        start;
   retro_netpacket_receive_t      receive;
   retro_netpacket_stop_t         stop;         /* Optional - may be NULL */
   retro_netpacket_poll_t         poll;         /* Optional - may be NULL */
   retro_netpacket_connected_t    connected;    /* Optional - may be NULL */
   retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */
   const char* protocol_version; /* Optional - if not NULL will be used instead of core version to decide if communication is compatible */
};

/**
 * The pixel format used for rendering.
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 */
enum retro_pixel_format
{
   /**
    * 0RGB1555, native endian.
    * Used as the default if \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT is not called.
    * The most significant bit must be set to 0.
    * @deprecated This format remains supported to maintain compatibility.
    * New code should use <tt>RETRO_PIXEL_FORMAT_RGB565</tt> instead.
    * @see RETRO_PIXEL_FORMAT_RGB565
    */
   RETRO_PIXEL_FORMAT_0RGB1555 = 0,

   /**
    * XRGB8888, native endian.
    * The most significant byte (the <tt>X</tt>) is ignored.
    */
   RETRO_PIXEL_FORMAT_XRGB8888 = 1,

   /**
    * RGB565, native endian.
    * This format is recommended if 16-bit pixels are desired,
    * as it is available on a variety of devices and APIs.
    */
   RETRO_PIXEL_FORMAT_RGB565   = 2,

   /** Defined to ensure that <tt>sizeof(retro_pixel_format) == sizeof(int)</tt>. Do not use. */
   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX
};

/** @defgroup GET_SAVESTATE_CONTEXT Savestate Context
 * @{
 */

/**
 * Details about how the frontend will use savestates.
 *
 * @see RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT
 * @see retro_serialize
 */
enum retro_savestate_context
{
   /**
    * Standard savestate written to disk.
    * May be loaded at any time,
    * even in a separate session or on another device.
    *
    * Should not contain any pointers to code or data.
    */
   RETRO_SAVESTATE_CONTEXT_NORMAL                 = 0,

   /**
    * The savestate is guaranteed to be loaded
    * within the same session, address space, and binary.
    * Will not be written to disk or sent over the network;
    * therefore, internal pointers to code or data are acceptable.
    * May still be loaded or saved at any time.
    *
    * @note This context generally implies the use of runahead or rewinding,
    * which may work by taking savestates multiple times per second.
    * Savestate code that runs in this context should be fast.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,

   /**
    * The savestate is guaranteed to be loaded
    * in the same session and by the same binary,
    * but possibly by a different address space
    * (e.g. for "second instance" runahead)
    *
    * Will not be written to disk or sent over the network,
    * but may be loaded in a different address space.
    * Therefore, the savestate <em>must not</em> contain pointers.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY   = 2,

   /**
    * The savestate will not be written to disk,
    * but no other guarantees are made.
    * The savestate will almost certainly be loaded
    * by a separate binary, device, and address space.
    *
    * This context is intended for use with frontends that support rollback netplay.
    * Serialized state should omit any data that would unnecessarily increase bandwidth usage.
    * Must not contain pointers, and integers must be saved in big-endian format.
    * @see retro_endianness.h
    * @see network_stream
    */
   RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY       = 3,

   /**
    * @private Defined to ensure <tt>sizeof(retro_savestate_context) == sizeof(int)</tt>.
    * Do not use.
    */
   RETRO_SAVESTATE_CONTEXT_UNKNOWN                = INT_MAX
};

/** @} */

/** @defgroup SET_MESSAGE User-Visible Messages
 *
 * @{
 */

/**
 * Defines a message that the frontend will display to the user,
 * as determined by <tt>RETRO_ENVIRONMENT_SET_MESSAGE</tt>.
 *
 * @deprecated This struct is superseded by \ref retro_message_ext,
 * which provides more control over how a message is presented.
 * Only use it for compatibility with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see retro_message_ext
 */
struct retro_message
{
   /**
    * Null-terminated message to be displayed.
    * If \c NULL or empty, the message will be ignored.
    */
   const char *msg;

   /** Duration to display \c msg in frames. */
   unsigned    frames;
};

/**
 * The method that the frontend will use to display a message to the player.
 * @see retro_message_ext
 */
enum retro_message_target
{
   /**
    * Indicates that the frontend should display the given message
    * using all other targets defined by \c retro_message_target at once.
    */
   RETRO_MESSAGE_TARGET_ALL = 0,

   /**
    * Indicates that the frontend should display the given message
    * using the frontend's on-screen display, if available.
    *
    * @attention If the frontend allows players to customize or disable notifications,
    * then they may not see messages sent to this target.
    */
   RETRO_MESSAGE_TARGET_OSD,

   /**
    * Indicates that the frontend should log the message
    * via its usual logging mechanism, if available.
    *
    * This is not intended to be a substitute for \c RETRO_ENVIRONMENT_SET_LOG_INTERFACE.
    * It is intended for the common use case of
    * logging a player-facing message.
    *
    * This target should not be used for messages
    * of type \c RETRO_MESSAGE_TYPE_STATUS or \c RETRO_MESSAGE_TYPE_PROGRESS,
    * as it may add unnecessary noise to a log file.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   RETRO_MESSAGE_TARGET_LOG
};

/**
 * A broad category for the type of message that the frontend will display.
 *
 * Each message type has its own use case,
 * therefore the frontend should present each one differently.
 *
 * @note This is a hint that the frontend may ignore.
 * The frontend should fall back to \c RETRO_MESSAGE_TYPE_NOTIFICATION
 * for message types that it doesn't support.
 */
enum retro_message_type
{
   /**
    * A standard on-screen message.
    *
    * Suitable for a variety of use cases,
    * such as messages about errors
    * or other important events.
    *
    * Frontends that display their own messages
    * should display this type of core-generated message the same way.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION = 0,

   /**
    * An on-screen message that should be visually distinct
    * from \c RETRO_MESSAGE_TYPE_NOTIFICATION messages.
    *
    * The exact meaning of "visually distinct" is left to the frontend,
    * but this usually implies that the frontend shows the message
    * in a way that it doesn't typically use for its own notices.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,

   /**
    * Indicates a frequently-updated status display,
    * rather than a standard notification.
    * Status messages are intended to be displayed permanently while a core is running
    * in a way that doesn't suggest user action is required.
    *
    * Here are some possible use cases for status messages:
    *
    * @li An internal framerate counter.
    * @li Debugging information.
    *     Remember to let the player disable it in the core options.
    * @li Core-specific state, such as when a microphone is active.
    *
    * The status message is displayed for the given duration,
    * unless another status message of equal or greater priority is shown.
    */
   RETRO_MESSAGE_TYPE_STATUS,

   /**
    * Denotes a message that reports the progress
    * of a long-running asynchronous task,
    * such as when a core loads large files from disk or the network.
    *
    * The frontend should display messages of this type as a progress bar
    * (or a progress spinner for indefinite tasks),
    * where \c retro_message_ext::msg is the progress bar's title
    * and \c retro_message_ext::progress sets the progress bar's length.
    *
    * This message type shouldn't be used for tasks that are expected to complete quickly.
    */
   RETRO_MESSAGE_TYPE_PROGRESS
};

/**
 * A core-provided message that the frontend will display to the player.
 *
 * @note The frontend is encouraged store these messages in a queue.
 * However, it should not empty the queue of core-submitted messages upon exit;
 * if a core exits with an error, it may want to use this API
 * to show an error message to the player.
 *
 * The frontend should maintain its own copy of the submitted message
 * and all subobjects, including strings.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 */
struct retro_message_ext
{
   /**
    * The \c NULL-terminated text of a message to show to the player.
    * Must not be \c NULL.
    *
    * @note The frontend must honor newlines in this string
    * when rendering text to \c RETRO_MESSAGE_TARGET_OSD.
    */
   const char *msg;

   /**
    * The duration that \c msg will be displayed on-screen, in milliseconds.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned duration;

   /**
    * The relative importance of this message
    * when targeting \c RETRO_MESSAGE_TARGET_OSD.
    * Higher values indicate higher priority.
    *
    * The frontend should use this to prioritize messages
    * when it can't show all active messages at once,
    * or to remove messages from its queue if it's full.
    *
    * The relative display order of messages with the same priority
    * is left to the frontend's discretion,
    * although we suggest breaking ties
    * in favor of the most recently-submitted message.
    *
    * Frontends may handle deprioritized messages at their discretion;
    * such messages may have their \c duration altered,
    * be hidden without being delayed,
    * or even be discarded entirely.
    *
    * @note In the reference frontend (RetroArch),
    * the same priority values are used for frontend-generated notifications,
    * which are typically between 0 and 3 depending upon importance.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned priority;

   /**
    * The severity level of this message.
    *
    * The frontend may use this to filter or customize messages
    * depending on the player's preferences.
    * Here are some ideas:
    *
    * @li Use this to prioritize errors and warnings
    *     over higher-ranking info and debug messages.
    * @li Render warnings or errors with extra visual feedback,
    *     e.g. with brighter colors or accompanying sound effects.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   enum retro_log_level level;

   /**
    * The intended destination of this message.
    *
    * @see retro_message_target
    */
   enum retro_message_target target;

   /**
    * The intended semantics of this message.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    *
    * @see retro_message_type
    */
   enum retro_message_type type;

   /**
    * The progress of an asynchronous task.
    *
    * A value between 0 and 100 (inclusive) indicates the task's percentage,
    * and a value of -1 indicates a task of unknown completion.
    *
    * @note Since message type is a hint, a frontend may ignore progress values.
    * Where relevant, a core should include progress percentage within the message string,
    * such that the message intent remains clear when displayed
    * as a standard frontend-generated notification.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG and for
    * message types other than \c RETRO_MESSAGE_TYPE_PROGRESS.
    */
   int8_t progress;
};

/** @} */

/* Describes how the libretro implementation maps a libretro input bind
 * to its internal input system through a human readable string.
 * This string can be used to better let a user configure input. */
struct retro_input_descriptor
{
   /* Associates given parameters with a description. */
   unsigned port;
   unsigned device;
   unsigned index;
   unsigned id;

   /* Human readable description for parameters.
    * The pointer must remain valid until
    * retro_unload_game() is called. */
   const char *description;
};

/**
 * Contains basic information about the core.
 *
 * @see retro_get_system_info
 * @warning All pointers are owned by the core
 * and must remain valid throughout its lifetime.
 */
struct retro_system_info
{
   /**
    * Descriptive name of the library.
    *
    * @note Should not contain any version numbers, etc.
    */
   const char *library_name;

   /**
    * Descriptive version of the core.
    */
   const char *library_version;

   /**
    * A pipe-delimited string list of file extensions that this core can load, e.g. "bin|rom|iso".
    * Typically used by a frontend for filtering or core selection.
    */
   const char *valid_extensions;

   /* Libretro cores that need to have direct access to their content
    * files, including cores which use the path of the content files to
    * determine the paths of other files, should set need_fullpath to true.
    *
    * Cores should strive for setting need_fullpath to false,
    * as it allows the frontend to perform patching, etc.
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to have a valid path
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * See also:
    *    - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
    *    - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
    */
   bool        need_fullpath;

   /* If true, the frontend is not allowed to extract any archives before
    * loading the real content.
    * Necessary for certain libretro implementations that load games
    * from zipped archives. */
   bool        block_extract;
};

/* Defines overrides which modify frontend handling of
 * specific content file types.
 * An array of retro_system_content_info_override is
 * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_system_content_info_override
{
   /* A list of file extensions for which the override
    * should apply, delimited by a 'pipe' character
    * (e.g. "md|sms|gg")
    * Permitted file extensions are limited to those
    * included in retro_system_info::valid_extensions
    * and/or retro_subsystem_rom_info::valid_extensions */
   const char *extensions;

   /* Overrides the need_fullpath value set in
    * retro_system_info and/or retro_subsystem_rom_info.
    * To reiterate:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * In addition:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info_ext::full_path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info_ext::archive_path may be NULL
    *    - retro_game_info_ext::archive_file may be NULL
    *    - retro_game_info_ext::dir is guaranteed to contain a valid path
    *      to the directory in which the content file exists
    *    - retro_game_info_ext::name is guaranteed to contain the
    *      basename of the content file, without extension
    *    - retro_game_info_ext::ext is guaranteed to contain the
    *      extension of the content file in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - If retro_game_info_ext::file_in_archive is false:
    *       - retro_game_info_ext::full_path is guaranteed to contain
    *         a valid path to an existent file
    *       - retro_game_info_ext::archive_path may be NULL
    *       - retro_game_info_ext::archive_file may be NULL
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the content file exists
    *       - retro_game_info_ext::name is guaranteed to contain the
    *         basename of the content file, without extension
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file in lower case format
    *    - If retro_game_info_ext::file_in_archive is true:
    *       - retro_game_info_ext::full_path may be NULL
    *       - retro_game_info_ext::archive_path is guaranteed to
    *         contain a valid path to an existent compressed file
    *         inside which the content file is located
    *       - retro_game_info_ext::archive_file is guaranteed to
    *         contain a valid path to an existent content file
    *         inside the compressed file referred to by
    *         retro_game_info_ext::archive_path
    *            e.g. for a compressed file '/path/to/foo.zip'
    *            containing 'bar.sfc'
    *             > retro_game_info_ext::archive_path will be '/path/to/foo.zip'
    *             > retro_game_info_ext::archive_file will be 'bar.sfc'
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the compressed file
    *         (containing the content file) exists
    *       - retro_game_info_ext::name is guaranteed to contain
    *         EITHER
    *         1) the basename of the compressed file (containing
    *            the content file), without extension
    *         OR
    *         2) the basename of the content file inside the
    *            compressed file, without extension
    *         In either case, a core should consider 'name' to
    *         be the canonical name/ID of the the content file
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file inside the compressed file,
    *         in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size are
    *      guaranteed to be valid */
   bool need_fullpath;

   /* If need_fullpath is false, specifies whether the content
    * data buffer available in retro_load_game() is 'persistent'
    *
    * If persistent_data is false and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid only until retro_load_game() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid only until retro_load_game() returns
    *
    * If persistent_data is true and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid until retro_deinit() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid until retro_deinit() returns */
   bool persistent_data;
};

/* Similar to retro_game_info, but provides extended
 * information about the source content file and
 * game memory buffer status.
 * And array of retro_game_info_ext is returned by
 * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_game_info_ext
{
   /* - If file_in_archive is false, contains a valid
    *   path to an existent content file (UTF-8 encoded)
    * - If file_in_archive is true, may be NULL */
   const char *full_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contains a valid path
    *   to an existent compressed file inside which the
    *   content file is located (UTF-8 encoded) */
   const char *archive_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contain a valid path
    *   to an existent content file inside the compressed
    *   file referred to by archive_path (UTF-8 encoded)
    *      e.g. for a compressed file '/path/to/foo.zip'
    *      containing 'bar.sfc'
    *      > archive_path will be '/path/to/foo.zip'
    *      > archive_file will be 'bar.sfc' */
   const char *archive_file;

   /* - If file_in_archive is false, contains a valid path
    *   to the directory in which the content file exists
    *   (UTF-8 encoded)
    * - If file_in_archive is true, contains a valid path
    *   to the directory in which the compressed file
    *   (containing the content file) exists (UTF-8 encoded) */
   const char *dir;

   /* Contains the canonical name/ID of the content file
    * (UTF-8 encoded). Intended for use when identifying
    * 'complementary' content named after the loaded file -
    * i.e. companion data of a different format (a CD image
    * required by a ROM), texture packs, internally handled
    * save files, etc.
    * - If file_in_archive is false, contains the basename
    *   of the content file, without extension
    * - If file_in_archive is true, then string is
    *   implementation specific. A frontend may choose to
    *   set a name value of:
    *   EITHER
    *   1) the basename of the compressed file (containing
    *      the content file), without extension
    *   OR
    *   2) the basename of the content file inside the
    *      compressed file, without extension
    *   RetroArch sets the 'name' value according to (1).
    *   A frontend that supports routine loading of
    *   content from archives containing multiple unrelated
    *   content files may set the 'name' value according
    *   to (2). */
   const char *name;

   /* - If file_in_archive is false, contains the extension
    *   of the content file in lower case format
    * - If file_in_archive is true, contains the extension
    *   of the content file inside the compressed file,
    *   in lower case format */
   const char *ext;

   /* String of implementation specific meta-data. */
   const char *meta;

   /* Memory buffer of loaded game content. Will be NULL:
    * IF
    * - retro_system_info::need_fullpath is true and
    *   retro_system_content_info_override::need_fullpath
    *   is unset
    * OR
    * - retro_system_content_info_override::need_fullpath
    *   is true */
   const void *data;

   /* Size of game content memory buffer, in bytes */
   size_t size;

   /* True if loaded content file is inside a compressed
    * archive */
   bool file_in_archive;

   /* - If data is NULL, value is unset/ignored
    * - If data is non-NULL:
    *   - If persistent_data is false, data and size are
    *     valid only until retro_load_game() returns
    *   - If persistent_data is true, data and size are
    *     are valid until retro_deinit() returns */
   bool persistent_data;
};

/**
 * Parameters describing the size and shape of the video frame.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 * @see retro_get_system_av_info
 */
struct retro_game_geometry
{
   /**
    * Nominal video width of game, in pixels.
    * This will typically be the emulated platform's native video width
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_width;

   /**
    * Nominal video height of game, in pixels.
    * This will typically be the emulated platform's native video height
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_height;

   /**
    * Maximum possible width of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video width.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's widest possible screen layout (e.g. side-by-side).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_width;

   /**
    * Maximum possible height of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video height.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's tallest possible screen layout (e.g. vertical).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_height;    /* Maximum possible height of game. */

   /**
    * Nominal aspect ratio of game.
    * If zero or less,
    * an aspect ratio of <tt>base_width / base_height</tt> is assumed.
    *
    * @note A frontend may ignore this setting.
    */
   float    aspect_ratio;
};

/**
 * Parameters describing the timing of the video and audio.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_timing
{
   /** Video output refresh rate, in frames per second. */
   double fps;

   /** The audio output sample rate, in Hz. */
   double sample_rate;
};

/**
 * Configures how the core's audio and video should be updated.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_av_info
{
   /** Parameters describing the size and shape of the video frame. */
   struct retro_game_geometry geometry;

   /** Parameters describing the timing of the video and audio. */
   struct retro_system_timing timing;
};

/** @defgroup SET_CORE_OPTIONS Core Options
 *  @{
 */

/**
 * Represents \ref RETRO_ENVIRONMENT_GET_VARIABLE "a core option query".
 *
 * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
 * (which is a deprecated API),
 * this \c struct serves as an option definition.
 *
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 */
struct retro_variable
{
   /**
    * A unique key identifying this option.
    *
    * Should be a key for an option that was previously defined
    * with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 or similar.
    *
    * Should be prefixed with the core's name
    * to minimize the risk of collisions with another core's options,
    * as frontends are not required to use a namespacing scheme for storing options.
    * For example, a core named "foo" might define an option named "foo_option".
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is used to define an option
    * named by this key.
    */
   const char *key;

   /**
    * Value to be obtained.
    *
    * Set by the frontend to \c NULL if
    * the option named by \ref key does not exist.
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is set by the core to define the possible values
    * for an option named by \ref key.
    * When used this way, it must be formatted as follows:
    * @li The text before the first ';' is the option's human-readable title.
    * @li A single space follows the ';'.
    * @li The rest of the string is a '|'-delimited list of possible values,
    * with the first one being the default.
    */
   const char *value;
};

/**
 * An argument that's used to show or hide a core option in the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 */
struct retro_core_option_display
{
   /**
    * The key for a core option that was defined with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
    * \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
    * or their legacy equivalents.
    */
   const char *key;

   /**
    * Whether the option named by \c key
    * should be displayed to the player in the frontend's core options menu.
    *
    * @note This value is a hint, \em not a requirement;
    * the frontend is free to ignore this field.
    */
   bool visible;
};

/**
 * The maximum number of choices that can be defined for a given core option.
 *
 * This limit was chosen as a compromise between
 * a core's flexibility and a streamlined user experience.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 *
 * If you need more than 128 choices for a core option,
 * consider simplifying your option structure.
 * Here are some ideas:
 *
 * \li If a core option represents a numeric value,
 *     consider reducing the option's granularity
 *     (e.g. define time limits in increments of 5 seconds instead of 1 second).
 *     Providing a fixed set of values based on experimentation
 *     is also a good idea.
 * \li If a core option represents a dynamically-built list of files,
 *     consider leaving out files that won't be useful.
 *     For example, if a core allows the player to choose a specific BIOS file,
 *     it can omit files of the wrong length or without a valid header.
 *
 * @see retro_core_option_definition
 * @see retro_core_option_v2_definition
 */
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128

/**
 * A descriptor for a particular choice within a core option.
 *
 * @note All option values are represented as strings.
 * If you need to represent any other type,
 * parse the string in \ref value.
 *
 * @see retro_core_option_v2_category
 */
struct retro_core_option_value
{
   /**
    * The option value that the frontend will serialize.
    *
    * Must not be \c NULL or empty.
    * No other hard limits are placed on this value's contents,
    * but here are some suggestions:
    *
    * \li If the value represents a number,
    *     don't include any non-digit characters (units, separators, etc.).
    *     Instead, include that information in \c label.
    *     This will simplify parsing.
    * \li If the value represents a file path,
    *     store it as a relative path with respect to one of the common libretro directories
    *     (e.g. \ref RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY "the system directory"
    *     or \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "the save directory"),
    *     and use forward slashes (\c "/") as directory separators.
    *     This will simplify cloud storage if supported by the frontend,
    *     as the same file may be used on multiple devices.
    */
   const char *value;

   /**
    * Human-readable name for \c value that the frontend should show to players.
    *
    * May be \c NULL, in which case the frontend
    * should display \c value itself.
    *
    * Here are some guidelines for writing a good label:
    *
    * \li Make the option labels obvious
    *     so that they don't need to be explained in the description.
    * \li Keep labels short, and don't use unnecessary words.
    *     For example, "OpenGL" is a better label than "OpenGL Mode".
    * \li If the option represents a number,
    *     consider adding units, separators, or other punctuation
    *     into the label itself.
    *     For example, "5 seconds" is a better label than "5".
    * \li If the option represents a number, use intuitive units
    *     that don't take a lot of digits to express.
    *     For example, prefer "1 minute" over "60 seconds" or "60,000 milliseconds".
    */
   const char *label;
};

/**
 * @copybrief retro_core_option_v2_definition
 *
 * @deprecated Use \ref retro_core_option_v2_definition instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
struct retro_core_option_definition
{
   /** @copydoc retro_core_option_v2_definition::key */
   const char *key;

   /** @copydoc retro_core_option_v2_definition::desc */
   const char *desc;

   /** @copydoc retro_core_option_v2_definition::info */
   const char *info;

   /** @copydoc retro_core_option_v2_definition::values */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /** @copydoc retro_core_option_v2_definition::default_value */
   const char *default_value;
};

#ifdef __PS3__
#undef local
#endif

/**
 * A variant of \ref retro_core_options that supports internationalization.
 *
 * @deprecated Use \ref retro_core_options_v2_intl instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see retro_core_options
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_intl
{
   /** @copydoc retro_core_options_v2_intl::us */
   struct retro_core_option_definition *us;

   /** @copydoc retro_core_options_v2_intl::local */
   struct retro_core_option_definition *local;
};

/**
 * A descriptor for a group of related core options.
 *
 * Here's an example category:
 *
 * @code
 * {
 *     "cpu",
 *     "CPU Emulation",
 *     "Settings for CPU quirks."
 * }
 * @endcode
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_category
{
   /**
    * A string that uniquely identifies this category within the core's options.
    * Any \c retro_core_option_v2_definition whose \c category_key matches this
    * is considered to be within this category.
    * Different cores may use the same category keys,
    * so namespacing them is not necessary.
    * Valid characters are <tt>[a-zA-Z0-9_-]</tt>.
    *
    * Frontends should use this category to organize core options,
    * but may customize this category's presentation in other ways.
    * For example, a frontend may use common keys like "audio" or "gfx"
    * to select an appropriate icon in its UI.
    *
    * Required; must not be \c NULL.
    */
   const char *key;

   /**
    * A brief human-readable name for this category,
    * intended for the frontend to display to the player.
    * This should be a name that's concise and descriptive, such as "Audio" or "Video".
    *
    * Required; must not be \c NULL.
    */
   const char *desc;

   /**
    * A human-readable description for this category,
    * intended for the frontend to display to the player
    * as secondary help text (e.g. a sublabel or a tooltip).
    * Optional; may be \c NULL or an empty string.
    */
   const char *info;
};

/**
 * A descriptor for a particular core option and the values it may take.
 *
 * Supports categorizing options into groups,
 * so as not to overwhelm the player.
 *
 * @see retro_core_option_v2_category
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_definition
{
   /**
    * A unique identifier for this option that cores may use
    * \ref RETRO_ENVIRONMENT_GET_VARIABLE "to query its value from the frontend".
    * Must be unique within this core.
    *
    * Should be unique globally;
    * the recommended method for doing so
    * is to prefix each option with the core's name.
    * For example, an option that controls the resolution for a core named "foo"
    * should be named \c "foo_resolution".
    *
    * Valid key characters are in the set <tt>[a-zA-Z0-9_-]</tt>.
    */
   const char *key;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * Required; must not be \c NULL or empty.
    */
   const char *desc;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version may be slightly more concise than \ref desc,
    * as it can rely on the structure of the options menu.
    * For example, "Interface" is a good \c desc_categorized,
    * as it can be displayed as a sublabel for a "Network" category.
    * For \c desc, "Network Interface" would be more suitable.
    *
    * Optional; if this field or \c category_key is empty or \c NULL,
    * \c desc will be used instead.
    */
   const char *desc_categorized;

   /**
    * A human-readable description of this option and its effects,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * @details Intended to be displayed as secondary help text,
    * such as a tooltip or a sublabel.
    *
    * Here are some suggestions for writing a good description:
    *
    * \li Avoid technical jargon unless this option is meant for advanced users.
    *     If unavoidable, suggest one of the default options for those unsure.
    * \li Don't repeat the option name in the description;
    *     instead, describe what the option name means.
    * \li If an option requires a core restart or game reset to take effect,
    *     be sure to say so.
    * \li Try to make the option labels obvious
    *     so that they don't need to be explained in the description.
    *
    * Optional; may be \c NULL.
    */
   const char *info;

   /**
    * @brief A human-readable description of this option and its effects,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version is provided to accommodate descriptions
    * that reference other options by name,
    * as options may have different user-facing names
    * depending on whether the frontend supports categorization.
    *
    * @copydetails info
    *
    * If empty or \c NULL, \c info will be used instead.
    * Will be ignored if \c category_key is empty or \c NULL.
    */
   const char *info_categorized;

   /**
    * The key of the category that this option belongs to.
    *
    * Optional; if equal to \ref retro_core_option_v2_category::key "a defined category",
    * then this option shall be displayed by the frontend
    * next to other options in this same category,
    * assuming it supports doing so.
    * Option categories are intended to be displayed in a submenu,
    * but this isn't a hard requirement.
    *
    * If \c NULL, empty, or not equal to a defined category,
    * then this option is considered uncategorized
    * and the frontend shall display it outside of any category
    * (most likely at a top-level menu).
    *
    * @see retro_core_option_v2_category
    */
   const char *category_key;

   /**
    * One or more possible values for this option,
    * up to the limit of \ref RETRO_NUM_CORE_OPTION_VALUES_MAX.
    *
    * Terminated by a \c { NULL, NULL } element,
    * although frontends should work even if all elements are used.
    */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /**
    * The default value for this core option.
    * Used if it hasn't been set, e.g. for new cores.
    * Must equal one of the \ref value members in the \c values array,
    * or else this option will be ignored.
    */
   const char *default_value;
};

/**
 * A set of core option descriptors and the categories that group them,
 * suitable for enabling a core to be customized.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
struct retro_core_options_v2
{
   /**
    * An array of \ref retro_core_option_v2_category "option categories",
    * terminated by a zeroed-out category \c struct.
    *
    * Will be ignored if the frontend doesn't support core option categories.
    *
    * If \c NULL or ignored, all options will be treated as uncategorized.
    * This most likely means that a frontend will display them at a top-level menu
    * without any kind of hierarchy or grouping.
    */
   struct retro_core_option_v2_category *categories;

   /**
    * An array of \ref retro_core_option_v2_definition "core option descriptors",
    * terminated by a zeroed-out definition \c struct.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_option_v2_definition *definitions;
};

/**
 * A variant of \ref retro_core_options_v2 that supports internationalization.
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_v2_intl
{
   /**
    * Pointer to a core options set
    * whose text is written in American English.
    *
    * This may be passed to \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 as-is
    * if not using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_options_v2 *us;

   /**
    * Pointer to a core options set
    * whose text is written in one of libretro's \ref retro_language "supported languages",
    * most likely the one returned by \ref RETRO_ENVIRONMENT_GET_LANGUAGE.
    *
    * Structure is the same, but usage is slightly different:
    *
    * \li All text (except for keys and option values)
    *     should be written in whichever language
    *     is returned by \c RETRO_ENVIRONMENT_GET_LANGUAGE.
    * \li All fields besides keys and option values may be \c NULL,
    *     in which case the corresponding string in \c us
    *     is used instead.
    * \li All \ref retro_core_option_v2_definition::default_value "default option values"
    *     are taken from \c us.
    *     The defaults in this field are ignored.
    *
    * May be \c NULL, in which case \c us is used instead.
    */
   struct retro_core_options_v2 *local;
};

/**
 * Called by the frontend to determine if any core option's visibility has changed.
 *
 * Each time a frontend sets a core option,
 * it should call this function to see if
 * any core option should be made visible or invisible.
 *
 * May also be called after \ref retro_load_game "loading a game",
 * to determine what the initial visibility of each option should be.
 *
 * Within this function, the core must update the visibility
 * of any dynamically-hidden options
 * using \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.
 *
 * @note All core options are visible by default,
 * even during this function's first call.
 *
 * @return \c true if any core option's visibility was adjusted
 * since the last call to this function.
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
typedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void);

/**
 * Callback registered by the core for the frontend to use
 * when setting the visibility of each core option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
struct retro_core_options_update_display_callback
{
   /**
    * @copydoc retro_core_options_update_display_callback_t
    *
    * Set by the core.
    */
   retro_core_options_update_display_callback_t callback;
};

/** @} */

struct retro_game_info
{
   const char *path;       /* Path to game, UTF-8 encoded.
                            * Sometimes used as a reference for building other paths.
                            * May be NULL if game was loaded from stdin or similar,
                            * but in this case some cores will be unable to load `data`.
                            * So, it is preferable to fabricate something here instead
                            * of passing NULL, which will help more cores to succeed.
                            * retro_system_info::need_fullpath requires
                            * that this path is valid. */
   const void *data;       /* Memory buffer of loaded game. Will be NULL
                            * if need_fullpath was set. */
   size_t      size;       /* Size of memory buffer. */
   const char *meta;       /* String of implementation specific meta-data. */
};

/** @defgroup GET_CURRENT_SOFTWARE_FRAMEBUFFER Frontend-Owned Framebuffers
 * @{
 */

/** @defgroup RETRO_MEMORY_ACCESS Framebuffer Memory Access Types
 * @{
 */

/** Indicates that core will write to the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_WRITE (1 << 0)

/** Indicates that the core will read from the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_READ (1 << 1)

/** @} */

/** @defgroup RETRO_MEMORY_TYPE Framebuffer Memory Types
 * @{
 */

/**
 * Indicates that the returned framebuffer's memory is cached.
 * If not set, random access to the buffer may be very slow.
 */
#define RETRO_MEMORY_TYPE_CACHED (1 << 0)

/** @} */

/**
 * A frame buffer owned by the frontend that a core may use for rendering.
 *
 * @see GET_CURRENT_SOFTWARE_FRAMEBUFFER
 * @see retro_video_refresh_t
 */
struct retro_framebuffer
{
   /**
    * Pointer to the beginning of the framebuffer provided by the frontend.
    * The initial contents of this buffer are unspecified,
    * as is the means used to map the memory;
    * this may be defined in software,
    * or it may be GPU memory mapped to RAM.
    *
    * If the framebuffer is used,
    * this pointer must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to pass an offset to this pointer.
    *
    * @warning This pointer is only guaranteed to be valid
    * for the duration of the same \c retro_run iteration
    * \ref GET_CURRENT_SOFTWARE_FRAMEBUFFER "that requested the framebuffer".
    * Reuse of this pointer is undefined.
    */
   void *data;

   /**
    * The width of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other width.
    */
   unsigned width;

   /**
    * The height of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other height.
    */
   unsigned height;

   /**
    * The distance between the start of one scanline and the beginning of the next, in bytes.
    * In practice this is usually equal to \c width times the pixel size,
    * but that's not guaranteed.
    * Sometimes called the "stride".
    *
    * @setby{frontend}
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined to try to render \c data with any other pitch.
    */
   size_t pitch;

   /**
    * The pixel format of the returned framebuffer.
    * May be different than the format specified by the core in \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT,
    * e.g. due to conversions.
    * Set by the frontend.
    *
    * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
    */
   enum retro_pixel_format format;

   /**
    * One or more \ref RETRO_MEMORY_ACCESS "memory access flags"
    * that specify how the core will access the memory in \c data.
    *
    * @setby{core}
    */
   unsigned access_flags;

   /**
    * Zero or more \ref RETRO_MEMORY_TYPE "memory type flags"
    * that describe how the framebuffer's memory has been mapped.
    *
    * @setby{frontend}
    */
   unsigned memory_flags;
};

/** @} */

/** @defgroup SET_FASTFORWARDING_OVERRIDE Fast-Forward Override
 * @{
 */

/**
 * Parameters that govern when and how the core takes control
 * of fast-forwarding mode.
 */
struct retro_fastforwarding_override
{
   /**
    * The factor by which the core will be sped up
    * when \c fastforward is \c true.
    * This value is used as follows:
    *
    * @li A value greater than 1.0 will run the core at
    *     the specified multiple of normal speed.
    *     For example, a value of 5.0
    *     combined with a normal target rate of 60 FPS
    *     will result in a target rate of 300 FPS.
    *     The actual rate may be lower if the host's hardware can't keep up.
    * @li A value of 1.0 will run the core at normal speed.
    * @li A value between 0.0 (inclusive) and 1.0 (exclusive)
    *     will run the core as fast as the host system can manage.
    * @li A negative value will let the frontend choose a factor.
    * @li An infinite value or \c NaN results in undefined behavior.
    *
    * @attention Setting this value to less than 1.0 will \em not
    * slow down the core.
    */
   float ratio;

   /**
    * If \c true, the frontend should activate fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool fastforward;

   /**
    * If \c true, the frontend should display an on-screen notification or icon
    * while \c fastforward is \c true (where supported).
    * Otherwise, the frontend should not display any such notification.
    */
   bool notification;

   /**
    * If \c true, the core has exclusive control
    * over enabling and disabling fast-forwarding
    * via the \c fastforward field.
    * The frontend will not be able to start or stop fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool inhibit_toggle;
};

/** @} */

/**
 * During normal operation.
 *
 * @note Rate will be equal to the core's internal FPS.
 */
#define RETRO_THROTTLE_NONE              0

/**
 * While paused or stepping single frames.
 *
 * @note Rate will be 0.
 */
#define RETRO_THROTTLE_FRAME_STEPPING    1

/**
 * During fast forwarding.
 *
 * @note Rate will be 0 if not specifically limited to a maximum speed.
 */
#define RETRO_THROTTLE_FAST_FORWARD      2

/**
 * During slow motion.
 *
 * @note Rate will be less than the core's internal FPS.
 */
#define RETRO_THROTTLE_SLOW_MOTION       3

/**
 * While rewinding recorded save states.
 *
 * @note Rate can vary depending on the rewind speed or be 0 if the frontend
 * is not aiming for a specific rate.
 */
#define RETRO_THROTTLE_REWINDING         4

/**
 * While vsync is active in the video driver, and the target refresh rate is lower than the core's internal FPS.
 *
 * @note Rate is the target refresh rate.
 */
#define RETRO_THROTTLE_VSYNC             5

/**
 * When the frontend does not throttle in any way.
 *
 * @note Rate will be 0. An example could be if no vsync or audio output is active.
 */
#define RETRO_THROTTLE_UNBLOCKED         6

/**
 * Details about the actual rate an implementation is calling \c retro_run() at.
 *
 * @see RETRO_ENVIRONMENT_GET_THROTTLE_STATE
 */
struct retro_throttle_state
{
   /**
    * The current throttling mode.
    *
    * @note Should be one of the \c RETRO_THROTTLE_* values.
    * @see RETRO_THROTTLE_NONE
    * @see RETRO_THROTTLE_FRAME_STEPPING
    * @see RETRO_THROTTLE_FAST_FORWARD
    * @see RETRO_THROTTLE_SLOW_MOTION
    * @see RETRO_THROTTLE_REWINDING
    * @see RETRO_THROTTLE_VSYNC
    * @see RETRO_THROTTLE_UNBLOCKED
    */
   unsigned mode;

   /**
    * How many times per second the frontend aims to call retro_run.
    *
    * @note Depending on the mode, it can be 0 if there is no known fixed rate.
    * This won't be accurate if the total processing time of the core and
    * the frontend is longer than what is available for one frame.
    */
   float rate;
};

/** @defgroup GET_MICROPHONE_INTERFACE Microphone Interface
 * @{
 */

/**
 * Opaque handle to a microphone that's been opened for use.
 * The underlying object is accessed or created with \c retro_microphone_interface_t.
 */
typedef struct retro_microphone retro_microphone_t;

/**
 * Parameters for configuring a microphone.
 * Some of these might not be honored,
 * depending on the available hardware and driver configuration.
 */
typedef struct retro_microphone_params
{
   /**
    * The desired sample rate of the microphone's input, in Hz.
    * The microphone's input will be resampled,
    * so cores can ask for whichever frequency they need.
    *
    * If zero, some reasonable default will be provided by the frontend
    * (usually from its config file).
    *
    * @see retro_get_mic_rate_t
    */
   unsigned rate;
} retro_microphone_params_t;

/**
 * @copydoc retro_microphone_interface::open_mic
 */
typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::close_mic
 */
typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::get_params
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::set_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);

/**
 * @copydoc retro_microphone_interface::get_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::read_mic
 */
typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);

/**
 * The current version of the microphone interface.
 * Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t
 * receive new fields.
 *
 * Frontends using cores built against older mic interface versions
 * should not access fields introduced in newer versions.
 */
#define RETRO_MICROPHONE_INTERFACE_VERSION 1

/**
 * An interface for querying the microphone and accessing data read from it.
 *
 * @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE
 */
struct retro_microphone_interface
{
   /**
    * The version of this microphone interface.
    * Set by the core to request a particular version,
    * and set by the frontend to indicate the returned version.
    * 0 indicates that the interface is invalid or uninitialized.
    */
   unsigned interface_version;

   /**
    * Initializes a new microphone.
    * Assuming that microphone support is enabled and provided by the frontend,
    * cores may call this function whenever necessary.
    * A microphone could be opened throughout a core's lifetime,
    * or it could wait until a microphone is plugged in to the emulated device.
    *
    * The returned handle will be valid until it's freed,
    * even if the audio driver is reinitialized.
    *
    * This function is not guaranteed to be thread-safe.
    *
    * @param[in] args Parameters used to create the microphone.
    * May be \c NULL, in which case the default value of each parameter will be used.
    *
    * @returns Pointer to the newly-opened microphone,
    * or \c NULL if one couldn't be opened.
    * This likely means that no microphone is plugged in and recognized,
    * or the maximum number of supported microphones has been reached.
    *
    * @note Microphones are \em inactive by default;
    * to begin capturing audio, call \c set_mic_state.
    * @see retro_microphone_params_t
    */
   retro_open_mic_t open_mic;

   /**
    * Closes a microphone that was initialized with \c open_mic.
    * Calling this function will stop all microphone activity
    * and free up the resources that it allocated.
    * Afterwards, the handle is invalid and must not be used.
    *
    * A frontend may close opened microphones when unloading content,
    * but this behavior is not guaranteed.
    * Cores should close their microphones when exiting, just to be safe.
    *
    * @param microphone Pointer to the microphone that was allocated by \c open_mic.
    * If \c NULL, this function does nothing.
    *
    * @note The handle might be reused if another microphone is opened later.
    */
   retro_close_mic_t close_mic;

   /**
    * Returns the configured parameters of this microphone.
    * These may differ from what was requested depending on
    * the driver and device configuration.
    *
    * Cores should check these values before they start fetching samples.
    *
    * Will not change after the mic was opened.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose parameters will be retrieved.
    * @param[out] params The parameters object that the
    * microphone's parameters will be copied to.
    *
    * @return \c true if the parameters were retrieved,
    * \c false if there was an error.
    */
   retro_get_mic_params_t get_params;

   /**
    * Enables or disables the given microphone.
    * Microphones are disabled by default
    * and must be explicitly enabled before they can be used.
    * Disabled microphones will not process incoming audio samples,
    * and will therefore have minimal impact on overall performance.
    * Cores may enable microphones throughout their lifetime,
    * or only for periods where they're needed.
    *
    * Cores that accept microphone input should be able to operate without it;
    * we suggest substituting silence in this case.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be adjusted.
    * This will have been provided by \c open_mic.
    * @param state \c true if the microphone should receive audio input,
    * \c false if it should be idle.
    * @returns \c true if the microphone's state was successfully set,
    * \c false if \c microphone is invalid
    * or if there was an error.
    */
   retro_set_mic_state_t set_mic_state;

   /**
    * Queries the active state of a microphone at the given index.
    * Will return whether the microphone is enabled,
    * even if the driver is paused.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be queried.
    * @return \c true if the provided \c microphone is valid and active,
    * \c false if not or if there was an error.
    */
   retro_get_mic_state_t get_mic_state;

   /**
    * Retrieves the input processed by the microphone since the last call.
    * \em Must be called every frame unless \c microphone is disabled,
    * similar to how \c retro_audio_sample_batch_t works.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose recent input will be retrieved.
    * @param[out] samples The buffer that will be used to store the microphone's data.
    * Microphone input is in mono (i.e. one number per sample).
    * Should be large enough to accommodate the expected number of samples per frame;
    * for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.
    * @param[in] num_samples The size of the data buffer in samples (\em not bytes).
    * Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here.
    *
    * @return The number of samples that were copied into \c samples.
    * If \c microphone is pending driver initialization,
    * this function will copy silence of the requested length into \c samples.
    *
    * Will return -1 if the microphone is disabled,
    * the audio driver is paused,
    * or there was an error.
    */
   retro_read_mic_t read_mic;
};

/** @} */

/** @defgroup GET_DEVICE_POWER Device Power
 * @{
 */

/**
 * Describes how a device is being powered.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
enum retro_power_state
{
   /**
    * Indicates that the frontend cannot report its power state at this time,
    * most likely due to a lack of support.
    *
    * \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value;
    * instead, the environment callback will return \c false.
    */
   RETRO_POWERSTATE_UNKNOWN = 0,

   /**
    * Indicates that the device is running on its battery.
    * Usually applies to portable devices such as handhelds, laptops, and smartphones.
    */
   RETRO_POWERSTATE_DISCHARGING,

   /**
    * Indicates that the device's battery is currently charging.
    */
   RETRO_POWERSTATE_CHARGING,

   /**
    * Indicates that the device is connected to a power source
    * and that its battery has finished charging.
    */
   RETRO_POWERSTATE_CHARGED,

   /**
    * Indicates that the device is connected to a power source
    * and that it does not have a battery.
    * This usually suggests a desktop computer or a non-portable game console.
    */
   RETRO_POWERSTATE_PLUGGED_IN
};

/**
 * Indicates that an estimate is not available for the battery level or time remaining,
 * even if the actual power state is known.
 */
#define RETRO_POWERSTATE_NO_ESTIMATE (-1)

/**
 * Describes the power state of the device running the frontend.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
struct retro_device_power
{
   /**
    * The current state of the frontend's power usage.
    */
   enum retro_power_state state;

   /**
    * A rough estimate of the amount of time remaining (in seconds)
    * before the device powers off.
    * This value depends on a variety of factors,
    * so it is not guaranteed to be accurate.
    *
    * Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING.
    * May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate.
    */
   int seconds;

   /**
    * The approximate percentage of battery charge,
    * ranging from 0 to 100 (inclusive).
    * The device may power off before this reaches 0.
    *
    * The user might have configured their device
    * to stop charging before the battery is full,
    * so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state.
    */
   int8_t percent;
};

/** @} */

/**
 * @defgroup Callbacks
 * @{
 */

/**
 * Environment callback to give implementations a way of performing uncommon tasks.
 *
 * @note Extensible.
 *
 * @param cmd The command to run.
 * @param data A pointer to the data associated with the command.
 *
 * @return Varies by callback,
 * but will always return \c false if the command is not recognized.
 *
 * @see RETRO_ENVIRONMENT_SET_ROTATION
 * @see retro_set_environment()
 */
typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);

/**
 * Render a frame.
 *
 * @note For performance reasons, it is highly recommended to have a frame
 * that is packed in memory, i.e. pitch == width * byte_per_pixel.
 * Certain graphic APIs, such as OpenGL ES, do not like textures
 * that are not packed in memory.
 *
 * @param data A pointer to the frame buffer data with a pixel format of 15-bit \c 0RGB1555 native endian, unless changed with \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT.
 * @param width The width of the frame buffer, in pixels.
 * @param height The height frame buffer, in pixels.
 * @param pitch The width of the frame buffer, in bytes.
 *
 * @see retro_set_video_refresh()
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 * @see retro_pixel_format
 */
typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,
      unsigned height, size_t pitch);

/**
 * Renders a single audio frame. Should only be used if implementation generates a single sample at a time.
 *
 * @param left The left audio sample represented as a signed 16-bit native endian.
 * @param right The right audio sample represented as a signed 16-bit native endian.
 *
 * @see retro_set_audio_sample()
 * @see retro_set_audio_sample_batch()
 */
typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);

/**
 * Renders multiple audio frames in one go.
 *
 * @note Only one of the audio callbacks must ever be used.
 *
 * @param data A pointer to the audio sample data pairs to render.
 * @param frames The number of frames that are represented in the data. One frame
 *     is defined as a sample of left and right channels, interleaved.
 *     For example: <tt>int16_t buf[4] = { l, r, l, r };</tt> would be 2 frames.
 *
 * @return The number of frames that were processed.
 *
 * @see retro_set_audio_sample_batch()
 * @see retro_set_audio_sample()
 */
typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,
      size_t frames);

/**
 * Polls input.
 *
 * @see retro_set_input_poll()
 */
typedef void (RETRO_CALLCONV *retro_input_poll_t)(void);

/**
 * Queries for input for player 'port'.
 *
 * @param port Which player 'port' to query.
 * @param device Which device to query for. Will be masked with \c RETRO_DEVICE_MASK.
 * @param index The input index to retrieve.
 * The exact semantics depend on the device type given in \c device.
 * @param id The ID of which value to query, like \c RETRO_DEVICE_ID_JOYPAD_B.
 * @returns Depends on the provided arguments,
 * but will return 0 if their values are unsupported
 * by the frontend or the backing physical device.
 * @note Specialization of devices such as \c RETRO_DEVICE_JOYPAD_MULTITAP that
 * have been set with \c retro_set_controller_port_device() will still use the
 * higher level \c RETRO_DEVICE_JOYPAD to request input.
 *
 * @see retro_set_input_state()
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 */
typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,
      unsigned index, unsigned id);

/**
 * Sets the environment callback.
 *
 * @param cb The function which is used when making environment calls.
 *
 * @note Guaranteed to be called before \c retro_init().
 *
 * @see RETRO_ENVIRONMENT
 */
RETRO_API void retro_set_environment(retro_environment_t cb);

/**
 * Sets the video refresh callback.
 *
 * @param cb The function which is used when rendering a frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_video_refresh(retro_video_refresh_t cb);

/**
 * Sets the audio sample callback.
 *
 * @param cb The function which is used when rendering a single audio frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample(retro_audio_sample_t cb);

/**
 * Sets the audio sample batch callback.
 *
 * @param cb The function which is used when rendering multiple audio frames in one go.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);

/**
 * Sets the input poll callback.
 *
 * @param cb The function which is used to poll the active input.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_poll(retro_input_poll_t cb);

/**
 * Sets the input state callback.
 *
 * @param cb The function which is used to query the input state.
 *
 *@note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_state(retro_input_state_t cb);

/**
 * @}
 */

/**
 * Called by the frontend when initializing a libretro core.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * <ul>
 * <li>Do not assume that the core was loaded by the operating system
 * for the first time within this call.
 * It may have been statically linked or retained from a previous session.
 * Consequently, cores must not rely on global variables being initialized
 * to their default values before this function is called;
 * this also goes for object constructors in C++.
 * <li>Although C++ requires that constructors be called for global variables,
 * it does not require that their destructors be called
 * if stored within a dynamic library's global scope.
 * <li>If the core is statically linked to the frontend,
 * global variables may be initialized when the frontend itself is initially executed.
 * </ul>
 * @see retro_deinit
 */
RETRO_API void retro_init(void);

/**
 * Called by the frontend when deinitializing a libretro core.
 * The core must release all of its allocated resources before this function returns.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * <ul>
 * <li>Do not assume that the operating system will unload the core after this function returns,
 * as the core may be linked statically or retained in memory.
 * Cores should use this function to clean up all allocated resources
 * and reset all global variables to their default states.
 * <li>Do not assume that this core won't be loaded again after this function returns.
 * It may be kept in memory by the frontend for later use,
 * or it may be statically linked.
 * Therefore, all global variables should be reset to their default states within this function.
 * <li>C++ does not require that destructors be called
 * for variables within a dynamic library's global scope.
 * Therefore, global objects that own dynamically-managed resources
 * (such as \c std::string or <tt>std::vector</tt>)
 * should be kept behind pointers that are explicitly deallocated within this function.
 * </ul>
 * @see retro_init
 */
RETRO_API void retro_deinit(void);

/**
 * Retrieves which version of the libretro API is being used.
 *
 * @note This is used to validate ABI compatibility when the API is revised.
 *
 * @return Must return \c RETRO_API_VERSION.
 *
 * @see RETRO_API_VERSION
 */
RETRO_API unsigned retro_api_version(void);

/**
 * Gets statically known system info.
 *
 * @note Can be called at any time, even before retro_init().
 *
 * @param info A pointer to a \c retro_system_info where the info is to be loaded into. This must be statically allocated.
 */
RETRO_API void retro_get_system_info(struct retro_system_info *info);

/**
 * Gets information about system audio/video timings and geometry.
 *
 * @note Can be called only after \c retro_load_game() has successfully completed.
 *
 * @note The implementation of this function might not initialize every variable
 * if needed. For example, \c geom.aspect_ratio might not be initialized if
 * the core doesn't desire a particular aspect ratio.
 *
 * @param info A pointer to a \c retro_system_av_info where the audio/video information should be loaded into.
 *
 * @see retro_system_av_info
 */
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);

/**
 * Sets device to be used for player 'port'.
 *
 * By default, \c RETRO_DEVICE_JOYPAD is assumed to be plugged into all
 * available ports.
 *
 * @note Setting a particular device type is not a guarantee that libretro cores
 * will only poll input based on that particular device type. It is only a
 * hint to the libretro core when a core cannot automatically detect the
 * appropriate input device type on its own. It is also relevant when a
 * core can change its behavior depending on device type.
 *
 * @note As part of the core's implementation of retro_set_controller_port_device,
 * the core should call \c RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
 * frontend if the descriptions for any controls have changed as a
 * result of changing the device type.
 *
 * @param port Which port to set the device for, usually indicates the player number.
 * @param device Which device the given port is using. By default, \c RETRO_DEVICE_JOYPAD is assumed for all ports.
 *
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);

/**
 * Resets the currently-loaded game.
 * Cores should treat this as a soft reset (i.e. an emulated reset button) if possible,
 * but hard resets are acceptable.
 */
RETRO_API void retro_reset(void);

/**
 * Runs the game for one video frame.
 *
 * During \c retro_run(), the \c retro_input_poll_t callback must be called at least once.
 *
 * @note If a frame is not rendered for reasons where a game "dropped" a frame,
 * this still counts as a frame, and \c retro_run() should explicitly dupe
 * a frame if \c RETRO_ENVIRONMENT_GET_CAN_DUPE returns true. In this case,
 * the video callback can take a NULL argument for data.
 *
 * @see retro_input_poll_t
 */
RETRO_API void retro_run(void);

/**
 * Returns the amount of data the implementation requires to serialize internal state (save states).
 *
 * @note Between calls to \c retro_load_game() and \c retro_unload_game(), the
 * returned size is never allowed to be larger than a previous returned
 * value, to ensure that the frontend can allocate a save state buffer once.
 *
 * @return The amount of data the implementation requires to serialize the internal state.
 *
 * @see retro_serialize()
 */
RETRO_API size_t retro_serialize_size(void);

/**
 * Serializes the internal state.
 *
 * @param data A pointer to where the serialized data should be saved to.
 * @param size The size of the memory.
 *
 * @return If failed, or size is lower than \c retro_serialize_size(), it
 * should return false. On success, it will return true.
 *
 * @see retro_serialize_size()
 * @see retro_unserialize()
 */
RETRO_API bool retro_serialize(void *data, size_t len);

/**
 * Unserialize the given state data, and load it into the internal state.
 *
 * @return Returns true if loading the state was successful, false otherwise.
 *
 * @see retro_serialize()
 */
RETRO_API bool retro_unserialize(const void *data, size_t len);

/**
 * Reset all the active cheats to their default disabled state.
 *
 * @see retro_cheat_set()
 */
RETRO_API void retro_cheat_reset(void);

/**
 * Enable or disable a cheat.
 *
 * @param index The index of the cheat to act upon.
 * @param enabled Whether to enable or disable the cheat.
 * @param code A string of the code used for the cheat.
 *
 * @see retro_cheat_reset()
 */
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);

/**
 * Loads a game.
 *
 * @param game A pointer to a \c retro_game_info detailing information about the game to load.
 * May be \c NULL if the core is loaded without content.
 *
 * @return Will return true when the game was loaded successfully, or false otherwise.
 *
 * @see retro_game_info
 * @see RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME
 */
RETRO_API bool retro_load_game(const struct retro_game_info *game);

/**
 * Called when the frontend has loaded one or more "special" content files,
 * typically through subsystems.
 *
 * @note Only necessary for cores that support subsystems.
 * Others may return \c false or delegate to <tt>retro_load_game</tt>.
 *
 * @param game_type The type of game to load,
 * as determined by \c retro_subsystem_info.
 * @param info A pointer to an array of \c retro_game_info objects
 * providing information about the loaded content.
 * @param num_info The number of \c retro_game_info objects passed into the info parameter.
 * @return \c true if loading is successful, false otherwise.
 * If the core returns \c false,
 * the frontend should abort the core
 * and return to its main menu (if applicable).
 *
 * @see RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_load_game()
 * @see retro_subsystem_info
 */
RETRO_API bool retro_load_game_special(
  unsigned game_type,
  const struct retro_game_info *info, size_t num_info
);

/**
 * Unloads the currently loaded game.
 *
 * @note This is called before \c retro_deinit(void).
 *
 * @see retro_load_game()
 * @see retro_deinit()
 */
RETRO_API void retro_unload_game(void);

/**
 * Gets the region of the actively loaded content as either \c RETRO_REGION_NTSC or \c RETRO_REGION_PAL.
 * @note This refers to the region of the content's intended television standard,
 * not necessarily the region of the content's origin.
 * For emulated consoles that don't use either standard
 * (e.g. handhelds or post-HD platforms),
 * the core should return \c RETRO_REGION_NTSC.
 * @return The region of the actively loaded content.
 *
 * @see RETRO_REGION_NTSC
 * @see RETRO_REGION_PAL
 */
RETRO_API unsigned retro_get_region(void);

/**
 * Get a region of memory.
 *
 * @param id The ID for the memory block that's desired to retrieve. Can be \c RETRO_MEMORY_SAVE_RAM, \c RETRO_MEMORY_RTC, \c RETRO_MEMORY_SYSTEM_RAM, or \c RETRO_MEMORY_VIDEO_RAM.
 *
 * @return A pointer to the desired region of memory, or NULL when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API void *retro_get_memory_data(unsigned id);

/**
 * Gets the size of the given region of memory.
 *
 * @param id The ID for the memory block to check the size of. Can be RETRO_MEMORY_SAVE_RAM, RETRO_MEMORY_RTC, RETRO_MEMORY_SYSTEM_RAM, or RETRO_MEMORY_VIDEO_RAM.
 *
 * @return The size of the region in memory, or 0 when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API size_t retro_get_memory_size(unsigned id);

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/lists/dir_list.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dir_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>

#if defined(_WIN32) && defined(_XBOX)
#include <xtl.h>
#elif defined(_WIN32)
#include <windows.h>
#endif

#include <lists/dir_list.h>
#include <lists/string_list.h>
#include <file/file_path.h>

#include <compat/strl.h>
#include <retro_dirent.h>

#include <string/stdstring.h>
#include <retro_miscellaneous.h>

static int qstrcmp_plain(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;

   return strcasecmp(a->data, b->data);
}

static int qstrcmp_plain_noext(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;

   const char *ext_a = path_get_extension(a->data);
   size_t l_a = string_is_empty(ext_a) ? strlen(a->data) : (size_t)(ext_a - a->data - 1);
   const char *ext_b = path_get_extension(b->data);
   size_t l_b = string_is_empty(ext_b) ? strlen(b->data) : (size_t)(ext_b - b->data - 1);

   int rv = strncasecmp(a->data, b->data, MIN(l_a, l_b));
   if (rv == 0 && l_a != l_b)
       return (int)(l_a - l_b);
   return rv;
}

static int qstrcmp_dir(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;
   int a_type = a->attr.i;
   int b_type = b->attr.i;

   /* Sort directories before files. */
   if (a_type != b_type)
      return b_type - a_type;
   return strcasecmp(a->data, b->data);
}

static int qstrcmp_dir_noext(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;
   int a_type = a->attr.i;
   int b_type = b->attr.i;

   /* Sort directories before files. */
   if (a_type != b_type)
      return b_type - a_type;
   return qstrcmp_plain_noext(a, b);
}

/**
 * dir_list_sort:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing.
 **/
void dir_list_sort(struct string_list *list, bool dir_first)
{
   if (list)
      qsort(list->elems, list->size, sizeof(struct string_list_elem),
            dir_first ? qstrcmp_dir : qstrcmp_plain);
}

/**
 * dir_list_sort_ignore_ext:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing. File extensions are ignored.
 **/
void dir_list_sort_ignore_ext(struct string_list *list, bool dir_first)
{
   if (list)
      qsort(list->elems, list->size, sizeof(struct string_list_elem),
            dir_first ? qstrcmp_dir_noext : qstrcmp_plain_noext);
}

/**
 * dir_list_free:
 * @list : pointer to the directory listing
 *
 * Frees a directory listing.
 **/
void dir_list_free(struct string_list *list)
{
   string_list_free(list);
}

bool dir_list_deinitialize(struct string_list *list)
{
   if (!list)
      return false;
   return string_list_deinitialize(list);
}

/**
 * dir_list_read:
 * @dir                : directory path.
 * @list               : the string list to add files to
 * @ext_list           : the string list of extensions to include
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Add files within a directory to an existing string list
 *
 * @return -1 on error, 0 on success.
 **/
static int dir_list_read(const char *dir,
      struct string_list *list, struct string_list *ext_list,
      bool include_dirs, bool include_hidden,
      bool include_compressed, bool recursive)
{
   struct RDIR *entry = retro_opendir_include_hidden(dir, include_hidden);

   if (!entry)
      return -1;
   if (retro_dirent_error(entry))
   {
      retro_closedir(entry);
      return -1;
   }

   while (retro_readdir(entry))
   {
      union string_list_elem_attr attr;
      char file_path[PATH_MAX_LENGTH];
      const char *name                = retro_dirent_get_name(entry);

      if (name[0] == '.' || name[0] == '$')
      {
         /* Do not include hidden files and directories */
         if (!include_hidden)
            continue;

         /* char-wise comparisons to avoid string comparison */

         /* Do not include current dir */
         if (name[1] == '\0')
            continue;
         /* Do not include parent dir */
         if (name[1] == '.' && name[2] == '\0')
            continue;
      }

      fill_pathname_join_special(file_path, dir, name, sizeof(file_path));

      if (retro_dirent_is_dir(entry, NULL))
      {
         /* Exclude this frequent hidden dir on platforms which can not handle hidden attribute */
         if (!include_hidden && strcmp(name, "System Volume Information") == 0)
            continue;

#if defined(IOS) || defined(OSX)
         if (string_ends_with(name, ".framework"))
         {
            attr.i = RARCH_PLAIN_FILE;
            if (!string_list_append(list, file_path, attr))
            {
               retro_closedir(entry);
               return -1;
            }
            continue;
         }
#endif
         if (recursive)
            dir_list_read(file_path, list, ext_list, include_dirs,
                  include_hidden, include_compressed, recursive);

         if (!include_dirs)
            continue;
         attr.i = RARCH_DIRECTORY;
      }
      else
      {
         const char *file_ext    = path_get_extension(name);

         attr.i                  = RARCH_FILETYPE_UNSET;

         /*
          * If the file format is explicitly supported by the libretro-core, we
          * need to immediately load it and not designate it as a compressed file.
          *
          * Example: .zip could be supported as a image by the core and as a
          * compressed_file. In that case, we have to interpret it as a image.
          *
          * */
         if (string_list_find_elem_prefix(ext_list, ".", file_ext))
            attr.i            = RARCH_PLAIN_FILE;
         else
         {
            bool is_compressed_file;
            if ((is_compressed_file = path_is_compressed_file(file_path)))
               attr.i               = RARCH_COMPRESSED_ARCHIVE;

            if (ext_list &&
                  (!is_compressed_file || !include_compressed))
               continue;
         }
      }

      if (!string_list_append(list, file_path, attr))
      {
         retro_closedir(entry);
         return -1;
      }
   }

   retro_closedir(entry);

   return 0;
}

/**
 * dir_list_append:
 * @list               : existing list to append to.
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing, appending to an existing list
 *
 * @return Returns true on success, otherwise false.
 **/
bool dir_list_append(struct string_list *list,
      const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive)
{
   bool ret                         = false;
   struct string_list ext_list      = {0};
   struct string_list *ext_list_ptr = NULL;

   if (ext)
   {
      string_list_initialize(&ext_list);
      string_split_noalloc(&ext_list, ext, "|");
      ext_list_ptr                  = &ext_list;
   }
   ret                            = dir_list_read(dir, list, ext_list_ptr,
         include_dirs, include_hidden, include_compressed, recursive) != -1;
   string_list_deinitialize(&ext_list);
   return ret;
}

/**
 * dir_list_new:
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing.
 *
 * @return pointer to a directory listing of type 'struct string_list *' on success,
 * NULL in case of error. Has to be freed manually.
 **/
struct string_list *dir_list_new(const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive)
{
   struct string_list *list       = string_list_new();

   if (!list)
      return NULL;

   if (!dir_list_append(list, dir, ext, include_dirs,
            include_hidden, include_compressed, recursive))
   {
      string_list_free(list);
      return NULL;
   }

   return list;
}

/**
 * dir_list_initialize:
 *
 * NOTE: @list must zero initialised before
 * calling this function, otherwise UB.
 **/
bool dir_list_initialize(struct string_list *list,
      const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive)
{
   if (list && string_list_initialize(list))
      return dir_list_append(list, dir, ext, include_dirs,
            include_hidden, include_compressed, recursive);
   return false;
}

./include/libretro-common/lists/file_list.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <retro_common.h>
#include <lists/file_list.h>
#include <string/stdstring.h>
#include <compat/strcasestr.h>

static bool file_list_deinitialize_internal(file_list_t *list)
{
   size_t i;
   for (i = 0; i < list->size; i++)
   {
      file_list_free_userdata(list, i);
      file_list_free_actiondata(list, i);

      if (list->list[i].path)
         free(list->list[i].path);
      list->list[i].path = NULL;

      if (list->list[i].label)
         free(list->list[i].label);
      list->list[i].label = NULL;

      if (list->list[i].alt)
         free(list->list[i].alt);
      list->list[i].alt = NULL;
   }
   if (list->list)
      free(list->list);
   list->list = NULL;
   return true;
}

bool file_list_reserve(file_list_t *list, size_t nitems)
{
   const size_t item_size = sizeof(struct item_file);
   struct item_file *new_data;

   if (nitems < list->capacity || nitems > (size_t)-1/item_size)
      return false;

   if (!(new_data = (struct item_file*)realloc(list->list, nitems * item_size)))
      return false;

   memset(&new_data[list->capacity], 0, item_size * (nitems - list->capacity));

   list->list     = new_data;
   list->capacity = nitems;

   return true;
}

/* Helper function to initialize item_file structure */
static INLINE void init_item_file(struct item_file *item,
    const char *path, const char *label, unsigned type,
    size_t directory_ptr, size_t entry_idx)
{
    item->path          = strdup(path);
    item->label         = strdup(label);
    item->alt           = NULL;
    item->type          = type;
    item->directory_ptr = directory_ptr;
    item->entry_idx     = entry_idx;
    item->userdata      = NULL;
    item->actiondata    = NULL;
}

bool file_list_insert(file_list_t *list,
      const char *path, const char *label,
      unsigned type, size_t directory_ptr,
      size_t entry_idx,
      size_t idx)
{
   /* Expand file list if needed */
   if (list->size >= list->capacity)
   {
      size_t new_capacity = list->capacity > 0 ? list->capacity * 2 : 1;
      if (!file_list_reserve(list, new_capacity))
         return false;
   }

   /* Shift elements to the right using memmove */
   if (idx < list->size)
      memmove(&list->list[idx + 1], &list->list[idx],
            (list->size - idx) * sizeof(struct item_file));

   init_item_file(&list->list[idx], path, label, type, directory_ptr, entry_idx);
   list->size++;

   return true;
}

bool file_list_append(file_list_t *list,
      const char *path, const char *label,
      unsigned type, size_t directory_ptr,
      size_t entry_idx)
{
   unsigned idx = (unsigned)list->size;
   /* Expand file list if needed */
   if (idx >= list->capacity)
      if (!file_list_reserve(list, list->capacity * 2 + 1))
         return false;

   list->list[idx].path          = NULL;
   list->list[idx].label         = NULL;
   list->list[idx].alt           = NULL;
   list->list[idx].type          = type;
   list->list[idx].directory_ptr = directory_ptr;
   list->list[idx].entry_idx     = entry_idx;
   list->list[idx].userdata      = NULL;
   list->list[idx].actiondata    = NULL;

   if (label)
      list->list[idx].label      = strdup(label);
   if (path)
      list->list[idx].path       = strdup(path);

   list->size++;

   return true;
}

void file_list_pop(file_list_t *list, size_t *directory_ptr)
{
   if (!list)
      return;

   if (list->size != 0)
   {
      --list->size;
      if (list->list[list->size].path)
         free(list->list[list->size].path);
      list->list[list->size].path = NULL;

      if (list->list[list->size].label)
         free(list->list[list->size].label);
      list->list[list->size].label = NULL;
   }

   if (directory_ptr)
      *directory_ptr = list->list[list->size].directory_ptr;
}

void file_list_free(file_list_t *list)
{
   if (!list)
      return;
   file_list_deinitialize_internal(list);
   free(list);
}

bool file_list_deinitialize(file_list_t *list)
{
   if (!list)
      return false;
   if (!file_list_deinitialize_internal(list))
      return false;
   list->capacity = 0;
   list->size     = 0;
   return true;
}

void file_list_clear(file_list_t *list)
{
   size_t i;

   if (!list)
      return;

   for (i = 0; i < list->size; i++)
   {
      if (list->list[i].path)
         free(list->list[i].path);
      list->list[i].path = NULL;

      if (list->list[i].label)
         free(list->list[i].label);
      list->list[i].label = NULL;

      if (list->list[i].alt)
         free(list->list[i].alt);
      list->list[i].alt = NULL;
   }

   list->size = 0;
}

static void file_list_get_label_at_offset(const file_list_t *list, size_t idx,
      const char **label)
{
   if (!label || !list)
      return;

   *label = list->list[idx].path;
   if (list->list[idx].label)
      *label = list->list[idx].label;
}

void file_list_set_alt_at_offset(file_list_t *list, size_t idx,
      const char *alt)
{
   if (!list || !alt)
      return;
   if (list->list[idx].alt)
      free(list->list[idx].alt);
   list->list[idx].alt   = strdup(alt);
}

static int file_list_alt_cmp(const void *a_, const void *b_)
{
   const struct item_file *a = (const struct item_file*)a_;
   const struct item_file *b = (const struct item_file*)b_;
   const char *cmp_a         = a->alt ? a->alt : a->path;
   const char *cmp_b         = b->alt ? b->alt : b->path;
   return strcasecmp(cmp_a, cmp_b);
}

static int file_list_type_cmp(const void *a_, const void *b_)
{
   const struct item_file *a = (const struct item_file*)a_;
   const struct item_file *b = (const struct item_file*)b_;
   if (a->type < b->type)
      return -1;
   if (a->type == b->type)
      return 0;

   return 1;
}

void file_list_sort_on_alt(file_list_t *list)
{
   qsort(list->list, list->size, sizeof(list->list[0]), file_list_alt_cmp);
}

void file_list_sort_on_type(file_list_t *list)
{
   qsort(list->list, list->size, sizeof(list->list[0]), file_list_type_cmp);
}

void *file_list_get_userdata_at_offset(const file_list_t *list, size_t idx)
{
   if (!list)
      return NULL;
   return list->list[idx].userdata;
}

void *file_list_get_actiondata_at_offset(const file_list_t *list, size_t idx)
{
   if (!list)
      return NULL;
   return list->list[idx].actiondata;
}

void file_list_free_actiondata(const file_list_t *list, size_t idx)
{
   if (!list)
      return;
   if (list->list[idx].actiondata)
       free(list->list[idx].actiondata);
   list->list[idx].actiondata = NULL;
}

void file_list_free_userdata(const file_list_t *list, size_t idx)
{
   if (!list)
      return;
   if (list->list[idx].userdata)
       free(list->list[idx].userdata);
   list->list[idx].userdata = NULL;
}

bool file_list_search(const file_list_t *list, const char *needle, size_t *idx)
{
   size_t i;
   bool ret        = false;

   if (!list)
      return false;

   for (i = 0; i < list->size; i++)
   {
      const char *str = NULL;
      const char *alt = list->list[i].alt
            ? list->list[i].alt
            : list->list[i].path;

      if (!alt)
      {
         file_list_get_label_at_offset(list, i, &alt);
         if (!alt)
            continue;
      }

      if ((str = (const char *)strcasestr(alt, needle)) == alt)
      {
         /* Found match with first chars, best possible match. */
         *idx = i;
         ret  = true;
         break;
      }
      else if (str && !ret)
      {
         /* Found mid-string match, but try to find a match with
          * first characters before we settle. */
         *idx = i;
         ret  = true;
      }
   }

   return ret;
}

./include/libretro-common/lists/linked_list.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (linked_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <boolean.h>
#include <stddef.h>
#include <stdlib.h>

#include <lists/linked_list.h>

struct linked_list_item_t
{
   void *value;
   struct linked_list_item_t *previous;
   struct linked_list_item_t *next;
};

struct linked_list
{
   struct linked_list_item_t *first_item;
   struct linked_list_item_t *last_item;
   size_t length;
};

struct linked_list_iterator
{
   linked_list_t *list;
   struct linked_list_item_t *item;
   bool forward;
};

linked_list_t *linked_list_new(void)
{
   linked_list_t *list;

   list = (linked_list_t *)calloc(1, sizeof(linked_list_t));
   return list;
}

void linked_list_free(linked_list_t *list, void (*free_value)(void *value))
{
   if (!list)
   {
      return;
   }

   while (list->first_item)
   {
      struct linked_list_item_t *next;

      next = list->first_item->next;
      if (free_value)
         free_value(list->first_item->value);
      free(list->first_item);

      list->first_item = next;
   }

   free (list);
}

void linked_list_add(linked_list_t *list, void *value)
{
   struct linked_list_item_t *new_item;

   if (!list)
      return;

   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));
   new_item->value = value;
   new_item->previous = list->last_item;
   new_item->next = NULL;

   if (list->length == 0)
      list->first_item = new_item;
   else
      list->last_item->next = new_item;

   list->last_item = new_item;
   list->length++;
}

void linked_list_insert(linked_list_t *list, size_t index, void *value)
{
   size_t i;
   struct linked_list_item_t *previous_item;
   struct linked_list_item_t *next_item;
   struct linked_list_item_t *new_item;

   if (!list || index > list->length)
      return;

   previous_item = NULL;
   next_item = list->first_item;
   for (i = 1; i <= index; i++)
   {
      previous_item = next_item;
      next_item = next_item->next;
   }

   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));
   new_item->value = value;

   if (previous_item)
      previous_item->next = new_item;
   else
      list->first_item = new_item;
   new_item->previous = previous_item;

   if (next_item)
      next_item->previous = new_item;
   else
      list->last_item = new_item;
   new_item->next = next_item;

   list->length++;
}

void *linked_list_get(linked_list_t *list, size_t index)
{
   size_t i;
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   if (index >= list->length)
      return NULL;

   item = list->first_item;
   for (i = 1; i <= index; i++)
      item = item->next;

   return item->value;
}

void *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)
{
   struct linked_list_item_t *item;

   if (!list || !matches)
      return NULL;

   for (item = list->first_item; item; item = item->next)
   {
      if (matches(item->value, usrptr))
         return item->value;
   }

   return NULL;
}

void *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)
{
   struct linked_list_item_t *item;

   if (!list || !matches)
      return NULL;

   for (item = list->last_item; item; item = item->previous)
   {
      if (matches(item->value, usrptr))
         return item->value;
   }

   return NULL;
}

static void _linked_list_remove_item(linked_list_t *list, struct linked_list_item_t *item)
{
   struct linked_list_item_t *previous_item;
   struct linked_list_item_t *next_item;

   previous_item = item->previous;
   next_item = item->next;
   free(item);
   list->length--;

   if (previous_item)
      previous_item->next = next_item;
   else
      list->first_item = next_item;

   if (next_item)
      next_item->previous = previous_item;
   else
      list->last_item = previous_item;
}

void *linked_list_remove_at(linked_list_t *list, size_t index)
{
   size_t i = 0;
   struct linked_list_item_t *item;
   void *value;

   if (!list || list->length == 0 || index >= list->length)
      return NULL;

   item = list->first_item;
   for (i = 1; i <= index; i++)
      item = item->next;

   value = item->value;
   _linked_list_remove_item(list, item);
   return value;
}

void *linked_list_remove_first(linked_list_t *list, void *value)
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list->first_item; item; item = item->next)
   {
      if (item->value == value)
         break;
   }

   if (item)
   {
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void *linked_list_remove_last(linked_list_t *list, void *value)
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list->last_item; item; item = item->previous)
   {
      if (item->value == value)
         break;
   }

   if (item)
   {
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void *linked_list_remove_all(linked_list_t *list, void *value)
{
   struct linked_list_item_t *item;
   bool found = false;

   if (!list)
      return NULL;

   for (item = list->first_item; item;)
   {
      if (item->value == value)
      {
         struct linked_list_item_t *next_item;

         next_item = item->next;
         _linked_list_remove_item(list, item);
         found = true;
         item = next_item;
      } else
      {
         item = item->next;
      }
   }

   return found ? value : NULL;
}

void *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value))
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list->first_item; item; item = item->next)
   {
      if (matches(item->value))
         break;
   }

   if (item)
   {
      void *value;

      value = item->value;
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value))
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list->last_item; item; item = item->previous)
   {
      if (matches(item->value))
         break;
   }

   if (item)
   {
      void *value;

      value = item->value;
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value))
{
   struct linked_list_item_t *item;

   if (!list)
      return;

   for (item = list->first_item; item;)
   {
      if (matches(item->value))
      {
         struct linked_list_item_t *next_item;

         next_item = item->next;
         _linked_list_remove_item(list, item);
         item = next_item;
      } else
      {
         item = item->next;
      }
   }
}

bool linked_list_set_at(linked_list_t *list, size_t index, void *value)
{
   struct linked_list_item_t *item;
   size_t i;

   if (!list || list->length == 0 || index >= list->length)
      return false;

   item = list->first_item;
   for (i = 1; i <= index; i++)
      item = item->next;

   if (item)
   {
      item->value = value;
      return true;
   }

   return false;
}

size_t linked_list_size(linked_list_t *list)
{
   if (list)
      return list->length;

   return 0;
}

linked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward)
{
   linked_list_iterator_t *iterator;

   if (!list || !list->first_item)
      return NULL;

   iterator = (linked_list_iterator_t *)malloc(sizeof(linked_list_iterator_t));
   iterator->list = list;
   iterator->item = forward ? list->first_item : list->last_item;
   iterator->forward = forward;

   return iterator;
}

linked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator)
{
   struct linked_list_item_t *item;

   if (!iterator)
      return NULL;

   item = iterator->forward ? iterator->item->next : iterator->item->previous;
   if (item)
   {
      iterator->item = item;
      return iterator;
   } else
   {
      free(iterator);
      return NULL;
   }
}

void *linked_list_iterator_value(linked_list_iterator_t *iterator)
{
   if (iterator)
      return iterator->item->value;

   return NULL;
}

linked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator)
{
   struct linked_list_item_t *next_item;

   if (!iterator)
      return NULL;

   next_item = iterator->forward ? iterator->item->next : iterator->item->previous;
   _linked_list_remove_item(iterator->list, iterator->item);

   if (next_item)
   {
      iterator->item = next_item;
      return iterator;
   } else
   {
      free(iterator);
      return NULL;
   }
}

void linked_list_iterator_free(linked_list_iterator_t *iterator)
{
   if (iterator)
      free(iterator);
}

void linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value))
{
   size_t i;
   struct linked_list_item_t *item;

   if (!list || !fn)
      return;

   i = 0;
   for (item = list->first_item; item; item = item->next)
      fn(i++, item->value);
}

./include/libretro-common/lists/nested_list.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nested_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string/stdstring.h>
#include <lists/string_list.h>
#include <array/rbuf.h>
#include <array/rhmap.h>

#include <lists/nested_list.h>

struct nested_list_item
{
   nested_list_item_t *parent_item;
   nested_list_t *parent_list;
   nested_list_t *children;
   char *id;
   const void *value;
};

struct nested_list
{
   nested_list_item_t **items;
   nested_list_item_t **item_map;
};

/**************************************/
/* Initialisation / De-Initialisation */
/**************************************/

/* Forward declaration - required since
 * nested_list_free_list() is recursive */
static void nested_list_free_list(nested_list_t *list);

/* Frees contents of a nested list item */
static void nested_list_free_item(nested_list_item_t *item)
{
   if (!item)
      return;

   item->parent_item = NULL;
   item->parent_list = NULL;

   if (item->children)
   {
      nested_list_free_list(item->children);
      item->children = NULL;
   }

   if (item->id)
   {
      free(item->id);
      item->id = NULL;
   }

   item->value = NULL;
   free(item);
}

/* Frees contents of a nested list */
static void nested_list_free_list(nested_list_t *list)
{
   size_t i;

   if (!list)
      return;

   for (i = 0; i < RBUF_LEN(list->items); i++)
      nested_list_free_item(list->items[i]);

   RBUF_FREE(list->items);
   RHMAP_FREE(list->item_map);
   free(list);
}

/**
 * nested_list_init:
 *
 * Creates a new empty nested list. Returned pointer
 * must be freed using nested_list_free.
 *
 * Returns: Valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_init(void)
{
   /* Create nested list */
   nested_list_t *list = (nested_list_t*)malloc(sizeof(*list));

   if (!list)
      return NULL;

   /* Initialise members */
   list->items    = NULL;
   list->item_map = NULL;

   return list;
}

/**
 * nested_list_free:
 * @list : pointer to nested_list_t object
 *
 * Frees specified nested list.
 */
void nested_list_free(nested_list_t *list)
{
   nested_list_free_list(list);
}

/***********/
/* Setters */
/***********/

/* Creates and adds a new item to the specified
 * nested list. Returns NULL if item matching 'id'
 * already exists */
static nested_list_item_t *nested_list_add_item_to_list(nested_list_t *list,
      nested_list_item_t *parent_item, const char *id, const void *value)
{
   size_t num_items             = 0;
   nested_list_item_t *new_item = NULL;
   nested_list_t *child_list    = NULL;

   if (!list || string_is_empty(id))
      goto end;

   num_items = RBUF_LEN(list->items);

   /* Ensure that item does not already exist */
   if (RHMAP_HAS_STR(list->item_map, id))
      goto end;

   /* Attempt to allocate a buffer slot for the
    * new item */
   if (!RBUF_TRYFIT(list->items, num_items + 1))
      goto end;

   /* Create new empty child list */
   child_list = nested_list_init();
   if (!child_list)
      goto end;

   /* Create new list item */
   new_item = (nested_list_item_t*)malloc(sizeof(*new_item));
   if (!new_item)
   {
      nested_list_free(child_list);
      goto end;
   }

   /* Assign members */
   new_item->parent_item = parent_item;
   new_item->parent_list = list;
   new_item->children    = child_list;
   new_item->id          = strdup(id);
   new_item->value       = value;

   /* Increment item buffer size */
   RBUF_RESIZE(list->items, num_items + 1);

   /* Add new item to buffer */
   list->items[num_items] = new_item;

   /* Update map */
   RHMAP_SET_STR(list->item_map, id, new_item);
end:
   return new_item;
}

/**
 * nested_list_add_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 * @value   : optional value (user data) associated with
 *            new list item. This is added to the last
 *            item specified by @address
 *
 * Appends a new item to the specified nested list.
 * If @delim is NULL, item is added to the top level
 * list (@list itself) with id equal to @address.
 * Otherwise, @address is split by @delim and each
 * id is added as new 'layer'. For example:
 *
 * > @address = "one:two:three", @delim = ":" will
 *   produce:
 *      top_level_list:one
 *                     `- "one" list:two
 *                                   `- "two" list:three
 *   where @value is assigned to the "two" list:three
 *   item.
 *
 * Returns: true if successful, otherwise false. Will
 * always return false if item specified by @address
 * already exists in the nested list.
 */
bool nested_list_add_item(nested_list_t *list,
      const char *address, const char *delim, const void *value)
{
   struct string_list id_list = {0};
   const char *top_id         = NULL;
   bool success               = false;

   if (!list || string_is_empty(address))
      return false;

   /* If delim is NULL or address contains a single
    * token, then we are adding an item to the top
    * level list */
   if (string_is_empty(delim))
      top_id = address;
   else
   {
      string_list_initialize(&id_list);
      if (  !string_split_noalloc(&id_list, address, delim)
          || (id_list.size < 1))
         goto end;

      if (id_list.size == 1)
         top_id = id_list.elems[0].data;
   }

   if (!string_is_empty(top_id))
   {
      if (nested_list_add_item_to_list(list, NULL, top_id, value))
         success = true;
   }
   else
   {
      size_t i;
      nested_list_t *current_list     = list;
      nested_list_item_t *parent_item = NULL;
      nested_list_item_t *next_item   = NULL;

      /* Loop over list item ids */
      for (i = 0; i < id_list.size; i++)
      {
         const char *id = id_list.elems[i].data;

         if (string_is_empty(id))
            goto end;

         /* If this is the last entry in the id list,
          * then we are adding the item itself */
         if (i == (id_list.size - 1))
         {
            if (nested_list_add_item_to_list(current_list,
                  parent_item, id, value))
               success = true;

            break;
         }
         /* Otherwise, id corresponds to a 'category' */
         else
         {
            /* Check whether category item already exists */
            next_item = RHMAP_GET_STR(current_list->item_map, id);

            /* Create it, if required */
            if (!next_item)
               next_item = nested_list_add_item_to_list(current_list,
                     parent_item, id, NULL);

            if (!next_item)
               break;

            /* Update pointers */
            parent_item  = next_item;
            current_list = next_item->children;
         }
      }
   }

end:
   string_list_deinitialize(&id_list);
   return success;
}

/***********/
/* Getters */
/***********/

/**
 * nested_list_get_size:
 *
 * @list : pointer to nested_list_t object
 *
 * Fetches the current size (number of items) in
 * the specified list.
 *
 * Returns: list size.
 */
size_t nested_list_get_size(nested_list_t *list)
{
   if (!list)
      return 0;

   return RBUF_LEN(list->items);
}

/**
 * nested_list_get_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 *
 * Searches for (and returns) the list item corresponding
 * to @address. If @delim is NULL, the top level list
 * (@list itself) is searched for an item with an id
 * equal to @address. Otherwise, @address is split by
 * @delim and each id is searched for in a subsequent
 * list level.
 *
 * Returns: valid nested_list_item_t pointer if item
 * is found, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item(nested_list_t *list,
      const char *address, const char *delim)
{
   nested_list_item_t *search_item = NULL;
   struct string_list id_list      = {0};
   const char *top_id              = NULL;

   if (!list || string_is_empty(address))
      goto end;

   /* If delim is NULL or address contains a single
    * token, then we are fetching an item from the
    * top level list */
   if (string_is_empty(delim))
      top_id = address;
   else
   {
      string_list_initialize(&id_list);
      if (  !string_split_noalloc(&id_list, address, delim)
          || (id_list.size < 1))
         goto end;

      if (id_list.size == 1)
         top_id = id_list.elems[0].data;
   }

   if (!string_is_empty(top_id))
      search_item = RHMAP_GET_STR(list->item_map, top_id);
   else
   {
      /* Otherwise, search 'category' levels */
      nested_list_t *current_list   = list;
      nested_list_item_t *next_item = NULL;
      size_t i;

      /* Loop over list item ids */
      for (i = 0; i < id_list.size; i++)
      {
         const char *id = id_list.elems[i].data;

         if (string_is_empty(id))
            goto end;

         /* If this is the last entry in the id list,
          * then we are searching for the item itself */
         if (i == (id_list.size - 1))
         {
            search_item = RHMAP_GET_STR(current_list->item_map, id);
            break;
         }
         /* Otherwise, id corresponds to a 'category' */
         else
         {
            next_item = RHMAP_GET_STR(current_list->item_map, id);

            if (!next_item)
               break;

            /* Update pointer */
            current_list = next_item->children;
         }
      }
   }

end:
   string_list_deinitialize(&id_list);
   return search_item;
}

/**
 * nested_list_get_item_idx:
 *
 * @list : pointer to nested_list_t object
 * @idx  : item index
 *
 * Fetches the item corresponding to index @idx in
 * the top level list (@list itself) of the specified
 * nested list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * exists, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item_idx(nested_list_t *list,
      size_t idx)
{
   if (!list || (idx >= RBUF_LEN(list->items)))
      return NULL;

   return list->items[idx];
}

/**
 * nested_list_item_get_parent:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the parent item of the specified nested
 * list item. If returned value is NULL, specified
 * nested list item belongs to a top level list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * has a parent, otherwise NULL.
 */
nested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;

   return list_item->parent_item;
}

/**
 * nested_list_item_get_parent_list:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of which the
 * specified list item is a direct member.
 *
 * Returns: valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;

   return list_item->parent_list;
}

/**
 * nested_list_item_get_children:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of child items
 * belonging to the specified list item.
 *
 * Returns: valid nested_list_t pointer if item has
 * children, otherwise NULL.
 */
nested_list_t *nested_list_item_get_children(nested_list_item_t *list_item)
{
   if (   !list_item
       || !list_item->children
       || (RBUF_LEN(list_item->children->items) < 1))
      return NULL;

   return list_item->children;
}

/**
 * nested_list_item_get_id:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the id string of the specified list item,
 * as set by nested_list_add_item().
 *
 * Returns: item id if successful, otherwise NULL.
 */
const char *nested_list_item_get_id(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;
   return list_item->id;
}

/**
 * nested_list_item_get_address:
 *
 * @list_item : pointer to nested_list_item_t object
 * @delim     : delimiter to use when concatenating
 *              individual item ids into a an @address
 *              string
 * @s         : a delimited list of item identifiers,
 *              corresponding to item 'levels'
 * @len       : length of supplied @address char array

 * Fetches a compound @address string corresponding to
 * the specified item's 'position' in the top level
 * nested list of which it is a member. The resultant
 * @address may be used to find the item when calling
 * nested_list_get_item() on the top level nested list.
 *
 * Returns: true if successful, otherwise false.
 */
bool nested_list_item_get_address(nested_list_item_t *list_item,
      const char *delim, char *s, size_t len)
{
   if (  !list_item
       || string_is_empty(delim)
       || !s
       || (len < 1))
      return false;

   s[0] = '\0';

   /* We have to combine the IDs
    * of the item and all of its 'ancestors' */
   if (list_item->parent_item)
   {
      size_t i;
      union string_list_elem_attr attr;
      struct string_list id_list       = {0};
      nested_list_item_t *current_item = list_item;

      string_list_initialize(&id_list);
      attr.i     = 0;

      /* Fetch all ids */
      do
      {
         const char *id = current_item->id;
         if (    string_is_empty(id)
             || !string_list_append(&id_list, id, attr))
         {
            string_list_deinitialize(&id_list);
            return false;
         }

         current_item = current_item->parent_item;
      } while (current_item);

      /* Build address string */
      for (i = id_list.size; i > 0; i--)
      {
         size_t _len;
         const char *id = id_list.elems[i - 1].data;

         if (string_is_empty(id))
         {
            string_list_deinitialize(&id_list);
            return false;
         }

         _len = strlcat(s, id, len);
         if (i > 1)
            strlcpy(s + _len, delim, len - _len);
      }
      string_list_deinitialize(&id_list);
   }
   /* If this is an item of the top level
    * list, just copy the item ID directly */
   else
      strlcpy(s, list_item->id, len);

   return true;
}

/**
 * nested_list_item_get_value:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the value (user data) associated with the
 * specified list item.
 *
 * Returns: pointer to user data if set, otherwise
 * NULL.
 */
const void *nested_list_item_get_value(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;

   return list_item->value;
}

./include/libretro-common/lists/string_list.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (string_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <lists/string_list.h>
#include <compat/strl.h>
#include <compat/posix_string.h>
#include <string/stdstring.h>

static bool string_list_deinitialize_internal(struct string_list *list)
{
   if (!list)
      return false;

   if (list->elems)
   {
      unsigned i;
      for (i = 0; i < (unsigned)list->size; i++)
      {
         if (list->elems[i].data)
            free(list->elems[i].data);
         if (list->elems[i].userdata)
            free(list->elems[i].userdata);
         list->elems[i].data     = NULL;
         list->elems[i].userdata = NULL;
      }

      free(list->elems);
   }

   list->elems = NULL;

   return true;
}

bool string_list_capacity(struct string_list *list, size_t cap)
{
   struct string_list_elem *new_data = (struct string_list_elem*)
      realloc(list->elems, cap * sizeof(*new_data));

   if (!new_data)
      return false;

   if (cap > list->cap)
      memset(&new_data[list->cap], 0, sizeof(*new_data) * (cap - list->cap));

   list->elems = new_data;
   list->cap   = cap;
   return true;
}

void string_list_free(struct string_list *list)
{
   if (!list)
      return;

   string_list_deinitialize_internal(list);

   free(list);
}

bool string_list_deinitialize(struct string_list *list)
{
   if (!list)
      return false;
   if (!string_list_deinitialize_internal(list))
      return false;
   list->elems              = NULL;
   list->size               = 0;
   list->cap                = 0;
   return true;
}

struct string_list *string_list_new(void)
{
   struct string_list_elem *
      elems                 = NULL;
   struct string_list *list = (struct string_list*)
      malloc(sizeof(*list));
   if (!list)
      return NULL;

   list->cap                = 0;
   list->size               = 0;
   list->elems              = NULL;

   if (!(elems = (struct string_list_elem*)
      calloc(32, sizeof(*elems))))
   {
      string_list_free(list);
      return NULL;
   }

   list->elems              = elems;
   list->cap                = 32;

   return list;
}

bool string_list_initialize(struct string_list *list)
{
   struct string_list_elem *
      elems                 = NULL;
   if (!list)
      return false;
   if (!(elems = (struct string_list_elem*)
      calloc(32, sizeof(*elems))))
   {
      string_list_deinitialize(list);
      return false;
   }
   list->elems              = elems;
   list->size               = 0;
   list->cap                = 32;
   return true;
}

bool string_list_append(struct string_list *list, const char *elem,
      union string_list_elem_attr attr)
{
   char *data_dup = NULL;

   /* Note: If 'list' is incorrectly initialised
    * (i.e. if struct is zero initialised and
    * string_list_initialize() is not called on
    * it) capacity will be zero. This will cause
    * a segfault. Handle this case by forcing the new
    * capacity to a fixed size of 32 */
   if (      list->size >= list->cap
         && !string_list_capacity(list,
               (list->cap > 0) ? (list->cap * 2) : 32))
      return false;

   if (!(data_dup = strdup(elem)))
      return false;

   list->elems[list->size].data = data_dup;
   list->elems[list->size].attr = attr;

   list->size++;
   return true;
}

void string_list_join_concat(char *s, size_t len,
      const struct string_list *list, const char *delim)
{
   size_t _len = strlen(s);

   /* If @s is already 'full', nothing
    * further can be added
    * > This condition will also be triggered
    *   if @s is not NULL-terminated,
    *   in which case any attempt to increment
    *   @s or decrement @len would lead to
    *   undefined behaviour */
   if (_len < len)
   {
      size_t i;
      for (i = 0; i < list->size; i++)
      {
         _len += strlcpy(s + _len, list->elems[i].data, len - _len);
         if ((i + 1) < list->size)
            _len += strlcpy(s + _len, delim, len - _len);
      }
   }
}

void string_list_join_concat_special(char *s, size_t len,
      const struct string_list *list, const char *delim)
{
   size_t i;
   size_t _len = strlen(s);
   for (i = 0; i < list->size; i++)
   {
      _len += strlcpy(s + _len, list->elems[i].data, len - _len);
      if ((i + 1) < list->size)
         _len += strlcpy(s + _len, delim, len - _len);
   }
}

struct string_list *string_split(const char *str, const char *delim)
{
   char *save      = NULL;
   char *copy      = NULL;
   const char *tmp = NULL;
   struct string_list *list = string_list_new();

   if (!list)
      return NULL;

   if (!(copy = strdup(str)))
      goto error;

   tmp = strtok_r(copy, delim, &save);
   while (tmp)
   {
      union string_list_elem_attr attr;

      attr.i = 0;

      if (!string_list_append(list, tmp, attr))
         goto error;

      tmp = strtok_r(NULL, delim, &save);
   }

   free(copy);
   return list;

error:
   string_list_free(list);
   free(copy);
   return NULL;
}

bool string_split_noalloc(struct string_list *list,
      const char *str, const char *delim)
{
   char *save      = NULL;
   char *copy      = NULL;
   const char *tmp = NULL;

   if (!list)
      return false;

   if (!(copy = strdup(str)))
      return false;

   tmp             = strtok_r(copy, delim, &save);
   while (tmp)
   {
      union string_list_elem_attr attr;

      attr.i = 0;

      if (!string_list_append(list, tmp, attr))
      {
         free(copy);
         return false;
      }

      tmp = strtok_r(NULL, delim, &save);
   }

   free(copy);
   return true;
}

int string_list_find_elem(const struct string_list *list, const char *elem)
{
   if (list)
   {
      size_t i;
      for (i = 0; i < list->size; i++)
      {
         if (string_is_equal_noncase(list->elems[i].data, elem))
            return (int)(i + 1);
      }
   }
   return 0;
}

bool string_list_find_elem_prefix(const struct string_list *list,
      const char *prefix, const char *elem)
{
   if (list)
   {
      size_t i;
      char prefixed[255];
      size_t _len  = strlcpy(prefixed, prefix, sizeof(prefixed));
      strlcpy(prefixed + _len, elem, sizeof(prefixed) - _len);
      for (i = 0; i < list->size; i++)
      {
         if (     string_is_equal_noncase(list->elems[i].data, elem)
               || string_is_equal_noncase(list->elems[i].data, prefixed))
            return true;
      }
   }
   return false;
}

struct string_list *string_list_clone(const struct string_list *src)
{
   size_t i;
   struct string_list_elem *elems = NULL;
   struct string_list *dest       = (struct string_list*)
      malloc(sizeof(struct string_list));

   if (!dest)
      return NULL;

   dest->elems               = NULL;
   dest->size                = src->size;
   if (src->cap < dest->size)
      dest->cap              = dest->size;
   else
      dest->cap              = src->cap;

   if (!(elems = (struct string_list_elem*)
      calloc(dest->cap, sizeof(struct string_list_elem))))
   {
      free(dest);
      return NULL;
   }

   dest->elems               = elems;

   for (i = 0; i < src->size; i++)
   {
      const char *_src    = src->elems[i].data;
      size_t      len     = _src ? strlen(_src) : 0;

      dest->elems[i].data = NULL;
      dest->elems[i].attr = src->elems[i].attr;

      if (len != 0)
      {
         char *ret        = (char*)malloc(len + 1);
         if (ret)
         {
            strcpy(ret, _src);
            dest->elems[i].data = ret;
         }
      }
   }

   return dest;
}

./include/libretro-common/lists/vector_list.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <boolean.h>
#include <stdlib.h>
#include <stddef.h>

/* default type is void*, override by defining VECTOR_LIST_TYPE before inclusion */
#ifndef VECTOR_LIST_TYPE
#define VECTOR_LIST_TYPE void*
#define VECTOR_LIST_TYPE_DEFINED
#endif

/* default name is void, override by defining VECTOR_LIST_NAME before inclusion */
#ifndef VECTOR_LIST_NAME
#define VECTOR_LIST_NAME void
#define VECTOR_LIST_NAME_DEFINED
#endif

#define CAT_I(a,b) a##b
#define CAT(a,b) CAT_I(a, b)
#define MAKE_TYPE_NAME() CAT(VECTOR_LIST_NAME, _vector_list)
#define TYPE_NAME() MAKE_TYPE_NAME()

struct TYPE_NAME()
{
   /* VECTOR_LIST_TYPE for pointers will expand to a pointer-to-pointer */
   VECTOR_LIST_TYPE *data;
   unsigned size;
   unsigned count;
};

static struct TYPE_NAME()* CAT(TYPE_NAME(), _new(void))
{
   struct TYPE_NAME() *list = (struct TYPE_NAME()*)calloc(1, sizeof(*list));

   list->size = 8;
   list->data = (VECTOR_LIST_TYPE*)calloc(list->size, sizeof(*list->data));

   return list;
}

static bool CAT(TYPE_NAME(), _append(struct TYPE_NAME() *list, VECTOR_LIST_TYPE elem))
{
   if (list->size == list->count)
   {
      list->size *= 2;
      list->data = (VECTOR_LIST_TYPE*)realloc(list->data, list->size * sizeof(*list->data));

      if (!list->data)
         return false;
   }

   list->data[list->count] = elem;
   list->count++;

   return true;
}

static void CAT(TYPE_NAME(), _free(struct TYPE_NAME() *list))
{
   if (list)
   {
      if (list->data)
         free(list->data);
      free(list);
   }
}

#ifdef VECTOR_LIST_TYPE_DEFINED
#undef VECTOR_LIST_TYPE
#endif

#ifdef VECTOR_LIST_NAME_DEFINED
#undef VECTOR_LIST_NAME
#endif

./include/libretro-common/Makefile.test

OBJDIR = ../obj-unix

TEST_UNIT_CFLAGS = $(CFLAGS) -Iinclude $(LDFLAGS) -lcheck $(LIBCHECK_CFLAGS) -Werror -Wdeclaration-after-statement -fsanitize=address -fsanitize=undefined -ftest-coverage -fprofile-arcs -ggdb

TEST_GENERIC_QUEUE = test/queues/test_generic_queue
TEST_GENERIC_QUEUE_SRC = test/queues/test_generic_queue.c queues/generic_queue.c

TEST_LINKED_LIST = test/lists/test_linked_list
TEST_LINKED_LIST_SRC = test/lists/test_linked_list.c lists/linked_list.c

TEST_STDSTRING = test/string/test_stdstring
TEST_STDSTRING_SRC = test/string/test_stdstring.c string/stdstring.c encodings/encoding_utf.c \
		     compat/compat_strl.c

TEST_UTILS = test/utils/test_utils
TEST_UTILS_SRC = test/utils/test_utils.c utils/md5.c encodings/encoding_crc32.c \
		streams/file_stream.c vfs/vfs_implementation.c file/file_path.c \
		compat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c

TEST_HASH = test/hash/test_hash
TEST_HASH_SRC = test/hash/test_hash.c hash/lrc_hash.c \
		streams/file_stream.c vfs/vfs_implementation.c file/file_path.c \
		compat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c

all:
	# Build and execute tests in order, to avoid coverage file collision
	# string
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_STDSTRING_SRC) -o $(TEST_STDSTRING)
	$(TEST_STDSTRING)
	lcov -c -d . -o `dirname $(TEST_STDSTRING)`/coverage.info
	# utils
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_UTILS_SRC) -o $(TEST_UTILS)
	$(TEST_UTILS)
	lcov -c -d . -o `dirname $(TEST_UTILS)`/coverage.info
	# utils
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_HASH_SRC) -o $(TEST_HASH)
	$(TEST_HASH)
	lcov -c -d . -o `dirname $(TEST_HASH)`/coverage.info
	# list
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_LINKED_LIST_SRC) -o $(TEST_LINKED_LIST)
	$(TEST_LINKED_LIST)
	lcov -c -d . -o `dirname $(TEST_LINKED_LIST)`/coverage.info
	# queue
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_GENERIC_QUEUE_SRC) -o $(TEST_GENERIC_QUEUE)
	$(TEST_GENERIC_QUEUE)
	lcov -c -d . -o `dirname $(TEST_GENERIC_QUEUE)`/coverage.info
	
	lcov -o test/coverage.info \
	     -a test/utils/coverage.info \
	     -a test/string/coverage.info \
	     -a test/lists/coverage.info \
	     -a test/queues/coverage.info
	genhtml -o test/coverage/ test/coverage.info

clean:
	rm -f *.gcda *.gcno

./include/libretro-common/media/media_detect_cd.c

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (media_detect_cd.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <media/media_detect_cd.h>
#include <streams/file_stream.h>
#include <string/stdstring.h>
#include <file/file_path.h>
#include <retro_miscellaneous.h>

/*#define MEDIA_CUE_PARSE_DEBUG*/

static void media_zero_trailing_spaces(char *s, size_t len)
{
   int i;
   for (i = len - 1; i >= 0; i--)
   {
      if (s[i] == ' ')
         s[i] = '\0';
      else if (s[i] != '\0')
         break;
   }
}

static bool media_skip_spaces(const char **s, size_t len)
{
   if (s && *s && **s)
   {
      size_t i;
      for (i = 0; i < len; i++)
      {
         if ((*s)[i] == ' ' || (*s)[i] == '\t')
            continue;
         *s += i;
         return true;
      }
   }
   return false;
}

/* Fill in "info" with detected CD info. Use this when you have a cue file and want it parsed to find the first data track and any pregap info. */
bool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info)
{
   RFILE *file                          = NULL;
   char *line                           = NULL;
   char track_path[PATH_MAX_LENGTH]     = {0};
   char track_abs_path[PATH_MAX_LENGTH] = {0};
   char track_mode[11]                  = {0};
   bool found_file                      = false;
   bool found_track                     = false;
   unsigned first_data_track            = 0;
   uint64_t data_track_pregap_bytes     = 0;

   if (string_is_empty(path) || !info)
      return false;

   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))
   {
#ifdef MEDIA_CUE_PARSE_DEBUG
      printf("[MEDIA] Could not open cue path for reading: %s\n", path);
      fflush(stdout);
#endif
      return false;
   }

   while (!filestream_eof(file) && (line = filestream_getline(file)))
   {
      size_t _len = 0;
      const char *command = NULL;

      if (string_is_empty(line))
      {
         free(line);
         continue;
      }

      _len    = strlen(line);
      command = line;

      media_skip_spaces(&command, _len);

      if (!found_file && !strncasecmp(command, "FILE", 4))
      {
         const char *file = command + 4;
         media_skip_spaces(&file, _len - 4);

         if (!string_is_empty(file))
         {
            const char *file_end = NULL;
            size_t file_len      = 0;
            bool quoted          = false;

            if (file[0] == '"')
            {
               quoted = true;
               file++;
            }

            if (quoted)
               file_end = strchr(file, '\"');
            else
               file_end = strchr(file, ' ');

            if (file_end)
            {
               file_len = file_end - file;
               memcpy(track_path, file, file_len);
               found_file = true;
#ifdef MEDIA_CUE_PARSE_DEBUG
               printf("Found file: %s\n", track_path);
               fflush(stdout);
#endif
            }
         }
      }
      else if (found_file && !found_track && !strncasecmp(command, "TRACK", 5))
      {
         const char *track = command + 5;
         media_skip_spaces(&track, _len - 5);

         if (!string_is_empty(track))
         {
            char *ptr             = NULL;
            unsigned track_number = (unsigned)strtol(track, &ptr, 10);
#ifdef MEDIA_CUE_PARSE_DEBUG
            printf("Found track: %d\n", track_number);
            fflush(stdout);
#endif
            track++;

            if (track[0] && track[0] != ' ' && track[0] != '\t')
               track++;

            if (!string_is_empty(track))
            {
               media_skip_spaces(&track, strlen(track));
#ifdef MEDIA_CUE_PARSE_DEBUG
               printf("Found track type: %s\n", track);
               fflush(stdout);
#endif
               if (!strncasecmp(track, "MODE", 4))
               {
                  first_data_track = track_number;
                  found_track = true;
                  strlcpy(track_mode, track, sizeof(track_mode));
               }
               else
                  found_file = false;
            }
         }
      }
      else if (found_file && found_track && first_data_track && !strncasecmp(command, "INDEX", 5))
      {
         const char *index = command + 5;
         media_skip_spaces(&index, _len - 5);

         if (!string_is_empty(index))
         {
            char *ptr             = NULL;
            unsigned index_number = (unsigned)strtol(index, &ptr, 10);

            if (index_number == 1)
            {
               const char *pregap = index + 1;

               if (pregap[0] && pregap[0] != ' ' && pregap[0] != '\t')
                  pregap++;

               if (!string_is_empty(pregap))
               {
                  media_skip_spaces(&pregap, strlen(pregap));
                  found_file  = false;
                  found_track = false;

                  if (first_data_track && !string_is_empty(track_mode))
                  {
                     unsigned track_sector_size = 0;
                     unsigned track_mode_number = 0;

                     if (strlen(track_mode) == 10)
                     {
                        sscanf(track_mode, "MODE%d/%d", (int*)&track_mode_number, (int*)&track_sector_size);
#ifdef MEDIA_CUE_PARSE_DEBUG
                        printf("Found track mode %d with sector size %d\n", track_mode_number, track_sector_size);
                        fflush(stdout);
#endif
                        if ((track_mode_number == 1 || track_mode_number == 2) && track_sector_size)
                        {
                           unsigned min = 0;
                           unsigned sec = 0;
                           unsigned frame = 0;
                           sscanf(pregap, "%02d:%02d:%02d", (int*)&min, (int*)&sec, (int*)&frame);

                           if (min || sec || frame || strstr(pregap, "00:00:00"))
                           {
                              data_track_pregap_bytes = ((min * 60 + sec) * 75 + frame) * track_sector_size;
#ifdef MEDIA_CUE_PARSE_DEBUG
                              printf("Found pregap of %02d:%02d:%02d (bytes: %" PRIu64 ")\n", min, sec, frame, data_track_pregap_bytes);
                              fflush(stdout);
#endif
                              break;
                           }
                        }
                     }
                  }
               }
            }
         }
      }

      free(line);
   }

   filestream_close(file);

   if (!string_is_empty(track_path))
   {
      size_t _len;
      if (strstr(track_path, "/") || strstr(track_path, "\\"))
      {
#ifdef MEDIA_CUE_PARSE_DEBUG
         printf("using path %s\n", track_path);
         fflush(stdout);
#endif
         return media_detect_cd_info(track_path, data_track_pregap_bytes, info);
      }

      _len = fill_pathname_basedir(track_abs_path, path, sizeof(track_abs_path));
      strlcpy(track_abs_path + _len, track_path, sizeof(track_abs_path) - _len);
#ifdef MEDIA_CUE_PARSE_DEBUG
      printf("using abs path %s\n", track_abs_path);
      fflush(stdout);
#endif
      return media_detect_cd_info(track_abs_path, data_track_pregap_bytes, info);
   }

   return true;
}

/* Fill in "info" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */
bool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info)
{
   RFILE *file;

   if (string_is_empty(path) || !info)
      return false;

   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))
   {
#ifdef MEDIA_CUE_PARSE_DEBUG
      printf("[MEDIA] Could not open path for reading: %s\n", path);
      fflush(stdout);
#endif
      return false;
   }

   {
      unsigned offset      = 0;
      unsigned sector_size = 0;
      unsigned buf_size    = 17 * 2352;
      char *buf            = (char*)calloc(1, buf_size);
      int64_t read_bytes   = 0;

      if (!buf)
         return false;

      if (pregap_bytes)
         filestream_seek(file, pregap_bytes, RETRO_VFS_SEEK_POSITION_START);

      read_bytes = filestream_read(file, buf, buf_size);

      if (read_bytes != buf_size)
      {
#ifdef MEDIA_CUE_PARSE_DEBUG
         printf("[MEDIA] Could not read from media: got %" PRId64 " bytes instead of %d.\n", read_bytes, buf_size);
         fflush(stdout);
#endif
         filestream_close(file);
         free(buf);
         return false;
      }

      /* 12-byte sync field at the start of every sector, common to both mode1 and mode2 data tracks
       * (when at least sync data is requested). This is a CD-ROM standard feature and not specific to any game devices,
       * and as such should not be part of any system-specific detection or "magic" bytes.
       * Depending on what parts of a sector were requested from the disc, the user data might start at
       * byte offset 0, 4, 8, 12, 16 or 24. Cue sheets only specify the total number of bytes requested from the sectors
       * of a track (like 2048 or 2352) and it is then assumed based on the size/mode as to what fields are present. */
      if (!memcmp(buf, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12))
      {
         /* Assume track data contains all fields. */
         sector_size = 2352;

         /* Assume Mode 2 formed (formless is rarely used) */
         if (buf[15] == 2)
            offset   = 24;
         else /* Assume Mode 1 */
            offset   = 16;
      }
      else /* Assume sectors only contain user data instead. */
         sector_size = 2048;

      if (!memcmp(buf + offset, "SEGADISCSYSTEM",
               STRLEN_CONST("SEGADISCSYSTEM")))
      {
         const char *title_pos  = NULL;
         const char *serial_pos = NULL;

         /* All discs currently in Redump for MCD start with SEGADISCSYSTEM. There are other strings mentioned elsewhere online,
          * but I have not seen any real examples of them. */
         info->system_id = MEDIA_CD_SYSTEM_MEGA_CD;

         strlcpy(info->system, "Sega CD / Mega CD", sizeof(info->system));

         title_pos = buf + offset + 0x150;

         if (media_skip_spaces(&title_pos, 48))
         {
            memcpy(info->title, title_pos, 48 - (title_pos - (buf + offset + 0x150)));
            media_zero_trailing_spaces(info->title, sizeof(info->title));
         }
         else
            strlcpy(info->title, "N/A", sizeof(info->title));

         serial_pos = buf + offset + 0x183;

         if (media_skip_spaces(&serial_pos, 8))
         {
            memcpy(info->serial, serial_pos, 8 - (serial_pos - (buf + offset + 0x183)));
            media_zero_trailing_spaces(info->serial, sizeof(info->serial));
         }
         else
         {
            info->serial[0] = 'N';
            info->serial[1] = '/';
            info->serial[2] = 'A';
            info->serial[3] = '\0';
         }
      }
      else if (!memcmp(buf + offset, "SEGA SEGASATURN",
               STRLEN_CONST("SEGA SEGASATURN")))
      {
         const char *title_pos        = NULL;
         const char *serial_pos       = NULL;
         const char *version_pos      = NULL;
         const char *release_date_pos = NULL;

         info->system_id = MEDIA_CD_SYSTEM_SATURN;

         strlcpy(info->system, "Sega Saturn", sizeof(info->system));

         title_pos = buf + offset + 0x60;

         if (media_skip_spaces(&title_pos, 112))
         {
            memcpy(info->title, title_pos, 112 - (title_pos - (buf + offset + 0x60)));
            media_zero_trailing_spaces(info->title, sizeof(info->title));
         }
         else
            strlcpy(info->title, "N/A", sizeof(info->title));

         serial_pos = buf + offset + 0x20;

         if (media_skip_spaces(&serial_pos, 10))
         {
            memcpy(info->serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x20)));
            media_zero_trailing_spaces(info->serial, sizeof(info->serial));
         }
         else
         {
            info->serial[0] = 'N';
            info->serial[1] = '/';
            info->serial[2] = 'A';
            info->serial[3] = '\0';
         }

         version_pos = buf + offset + 0x2a;

         if (media_skip_spaces(&version_pos, 6))
         {
            memcpy(info->version, version_pos, 6 - (version_pos - (buf + offset + 0x2a)));
            media_zero_trailing_spaces(info->version, sizeof(info->version));
         }
         else
         {
            info->version[0] = 'N';
            info->version[1] = '/';
            info->version[2] = 'A';
            info->version[3] = '\0';
         }

         release_date_pos = buf + offset + 0x30;

         if (media_skip_spaces(&release_date_pos, 8))
         {
            memcpy(info->release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x30)));
            media_zero_trailing_spaces(info->release_date, sizeof(info->release_date));
         }
         else
         {
            info->release_date[0] = 'N';
            info->release_date[1] = '/';
            info->release_date[2] = 'A';
            info->release_date[3] = '\0';
         }
      }
      else if (!memcmp(buf + offset, "SEGA SEGAKATANA", STRLEN_CONST("SEGA SEGAKATANA")))
      {
         const char *title_pos        = NULL;
         const char *serial_pos       = NULL;
         const char *version_pos      = NULL;
         const char *release_date_pos = NULL;

         info->system_id = MEDIA_CD_SYSTEM_DREAMCAST;

         strlcpy(info->system, "Sega Dreamcast", sizeof(info->system));

         title_pos = buf + offset + 0x80;

         if (media_skip_spaces(&title_pos, 96))
         {
            memcpy(info->title, title_pos, 96 - (title_pos - (buf + offset + 0x80)));
            media_zero_trailing_spaces(info->title, sizeof(info->title));
         }
         else
            strlcpy(info->title, "N/A", sizeof(info->title));

         serial_pos = buf + offset + 0x40;

         if (media_skip_spaces(&serial_pos, 10))
         {
            memcpy(info->serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x40)));
            media_zero_trailing_spaces(info->serial, sizeof(info->serial));
         }
         else
         {
            info->serial      [0] = 'N';
            info->serial      [1] = '/';
            info->serial      [2] = 'A';
            info->serial      [3] = '\0';
         }

         version_pos = buf + offset + 0x4a;

         if (media_skip_spaces(&version_pos, 6))
         {
            memcpy(info->version, version_pos, 6 - (version_pos - (buf + offset + 0x4a)));
            media_zero_trailing_spaces(info->version, sizeof(info->version));
         }
         else
         {
            info->version     [0] = 'N';
            info->version     [1] = '/';
            info->version     [2] = 'A';
            info->version     [3] = '\0';
         }

         release_date_pos = buf + offset + 0x50;

         if (media_skip_spaces(&release_date_pos, 8))
         {
            memcpy(info->release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x50)));
            media_zero_trailing_spaces(info->release_date, sizeof(info->release_date));
         }
         else
         {
            info->release_date[0] = 'N';
            info->release_date[1] = '/';
            info->release_date[2] = 'A';
            info->release_date[3] = '\0';
         }
      }
      /* Primary Volume Descriptor fields of ISO9660 */
      else if (!memcmp(buf + offset + (16 * sector_size), "\1CD001\1\0PLAYSTATION", 19))
      {
         const char *title_pos = NULL;

         info->system_id = MEDIA_CD_SYSTEM_PSX;

         strlcpy(info->system, "Sony PlayStation", sizeof(info->system));

         title_pos = buf + offset + (16 * sector_size) + 40;

         if (media_skip_spaces(&title_pos, 32))
         {
            memcpy(info->title, title_pos, 32 - (title_pos - (buf + offset + (16 * sector_size) + 40)));
            media_zero_trailing_spaces(info->title, sizeof(info->title));
         }
         else
            strlcpy(info->title, "N/A", sizeof(info->title));
      }
      else if (!memcmp(buf + offset, "\x01\x5a\x5a\x5a\x5a\x5a\x01\x00\x00\x00\x00\x00", 12))
      {
         info->system_id = MEDIA_CD_SYSTEM_3DO;
         strlcpy(info->system, "3DO", sizeof(info->system));
      }
      else if (!memcmp(buf + offset + 0x950, "PC Engine CD-ROM SYSTEM", 23))
      {
         info->system_id = MEDIA_CD_SYSTEM_PC_ENGINE_CD;
         strlcpy(info->system, "TurboGrafx-CD / PC-Engine CD", sizeof(info->system));
      }

      free(buf);
   }

   filestream_close(file);

   return true;
}

./include/libretro-common/memmap/memalign.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memalign.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <stdlib.h>

#include <memalign.h>

void *memalign_alloc(size_t boundary, size_t len)
{
   void **place   = NULL;
   uintptr_t addr = 0;
   void *ptr      = (void*)malloc(boundary + len + sizeof(uintptr_t));
   if (!ptr)
      return NULL;
   addr           = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary)
      & ~(boundary - 1);
   place          = (void**)addr;
   place[-1]      = ptr;
   return (void*)addr;
}

void memalign_free(void *ptr)
{
   void **p = NULL;
   if (!ptr)
      return;

   p = (void**)ptr;
   free(p[-1]);
}

void *memalign_alloc_aligned(size_t len)
{
#if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_M_X64) || defined(_WIN64)
   return memalign_alloc(64, len);
#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(GEKKO) || defined(_M_IX86)
   return memalign_alloc(32, len);
#else
   return memalign_alloc(32, len);
#endif
}

./include/libretro-common/memmap/memmap.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memmap.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <stdlib.h>
#include <memmap.h>

#ifndef PROT_READ
#define PROT_READ         0x1  /* Page can be read */
#endif

#ifndef PROT_WRITE
#define PROT_WRITE        0x2  /* Page can be written. */
#endif

#ifndef PROT_READWRITE
#define PROT_READWRITE    0x3  /* Page can be written to and read from. */
#endif

#ifndef PROT_EXEC
#define PROT_EXEC         0x4  /* Page can be executed. */
#endif

#ifndef PROT_NONE
#define PROT_NONE         0x0  /* Page can not be accessed. */
#endif

#ifndef MAP_FAILED
#define MAP_FAILED        ((void *) -1)
#endif

#ifdef _WIN32
void* mmap(void *addr, size_t len, int prot, int flags,
      int fildes, size_t offset)
{
   void     *map = (void*)NULL;
   HANDLE handle = INVALID_HANDLE_VALUE;

   switch (prot)
   {
      case PROT_READ:
      default:
         handle = CreateFileMapping((HANDLE)
               _get_osfhandle(fildes), 0, PAGE_READONLY, 0,
               len, 0);
         if (!handle)
            break;
         map = (void*)MapViewOfFile(handle, FILE_MAP_READ, 0, 0, len);
         CloseHandle(handle);
         break;
      case PROT_WRITE:
         handle = CreateFileMapping((HANDLE)
               _get_osfhandle(fildes),0,PAGE_READWRITE,0,
               len, 0);
         if (!handle)
            break;
         map = (void*)MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, len);
         CloseHandle(handle);
         break;
      case PROT_READWRITE:
         handle = CreateFileMapping((HANDLE)
               _get_osfhandle(fildes),0,PAGE_READWRITE,0,
               len, 0);
         if (!handle)
            break;
         map = (void*)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, len);
         CloseHandle(handle);
         break;
   }

   if (map == (void*)NULL)
      return((void*)MAP_FAILED);
   return((void*) ((int8_t*)map + offset));
}

int munmap(void *addr, size_t len)
{
   return (UnmapViewOfFile(addr)) ? 0 : -1;
}

int mprotect(void *addr, size_t len, int prot)
{
   /* Incomplete, just assumes PAGE_EXECUTE_READWRITE right now
    * instead of correctly handling prot */
   prot = 0;
   if (prot & (PROT_READ | PROT_WRITE | PROT_EXEC))
      prot = PAGE_EXECUTE_READWRITE;
   return VirtualProtect(addr, len, prot, 0);
}

#elif !defined(HAVE_MMAN)
void* mmap(void *addr, size_t len, int prot, int flags,
      int fildes, size_t offset)
{
   return malloc(len);
}

int munmap(void *addr, size_t len)
{
   free(addr);
   return 0;
}

int mprotect(void *addr, size_t len, int prot)
{
   /* stub - not really needed at this point
    * since this codepath has no dynarecs. */
   return 0;
}

#endif

#if defined(__MACH__) && defined(__arm__)
#include <libkern/OSCacheControl.h>
#endif

int memsync(void *start, void *end)
{
#if defined(__MACH__) && defined(__arm__)
   size_t _len = (char*)end - (char*)start;
   sys_dcache_flush(start, _len);
   sys_icache_invalidate(start, _len);
   return 0;
#elif defined(__arm__) && !defined(__QNX__)
   __clear_cache(start, end);
   return 0;
#elif defined(HAVE_MMAN)
   size_t _len = (char*)end - (char*)start;
   return msync(start, _len, MS_SYNC | MS_INVALIDATE
#ifdef __QNX__
         MS_CACHE_ONLY
#endif
         );
#else
   return 0;
#endif
}

int memprotect(void *addr, size_t len)
{
   return mprotect(addr, len, PROT_READ | PROT_WRITE | PROT_EXEC);
}

./include/libretro-common/net/net_compat.c

/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_compat.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <stdio.h>

#include <compat/strl.h>
#include <retro_miscellaneous.h>
#include <retro_timers.h>

#include <net/net_compat.h>

#if defined(_WIN32) && !defined(_XBOX)
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
   struct sockaddr_storage addr;

   switch (af)
   {
      case AF_INET:
         memcpy(&((struct sockaddr_in*)&addr)->sin_addr, src,
            sizeof(struct in_addr));
         break;
#ifdef HAVE_INET6
      case AF_INET6:
         memcpy(&((struct sockaddr_in6*)&addr)->sin6_addr, src,
            sizeof(struct in6_addr));
         break;
#endif
      default:
         return NULL;
   }

   addr.ss_family = af;
   if (getnameinfo((struct sockaddr*)&addr, sizeof(addr), dst, size, NULL, 0,
         NI_NUMERICHOST))
      return NULL;

   return dst;
}

int inet_pton(int af, const char *src, void *dst)
{
   struct addrinfo *addr = NULL;
   struct addrinfo hints = {0};

   switch (af)
   {
      case AF_INET:
#ifdef HAVE_INET6
      case AF_INET6:
#endif
         break;
      default:
         return -1;
   }

   hints.ai_family = af;
   hints.ai_flags  = AI_NUMERICHOST;
   switch (getaddrinfo(src, NULL, &hints, &addr))
   {
      case 0:
         break;
      case EAI_NONAME:
         return 0;
      default:
         return -1;
   }

   if (!addr)
      return -1;

   switch (af)
   {
      case AF_INET:
         memcpy(dst, &((struct sockaddr_in*)addr->ai_addr)->sin_addr,
            sizeof(struct in_addr));
         break;
#ifdef HAVE_INET6
      case AF_INET6:
         memcpy(dst, &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr,
            sizeof(struct in6_addr));
         break;
#endif
      default:
         break;
   }

   freeaddrinfo(addr);

   return 1;
}
#endif

#elif defined(_XBOX)
struct hostent *gethostbyname(const char *name)
{
   static struct in_addr addr = {0};
   static struct hostent he   = {0};
   WSAEVENT event;
   XNDNS          *dns = NULL;
   struct hostent *ret = NULL;

   if (!name)
      return NULL;

   event = WSACreateEvent();

   XNetDnsLookup(name, event, &dns);
   if (!dns)
   {
      WSACloseEvent(event);
      return NULL;
   }

   WaitForSingleObject((HANDLE)event, INFINITE);

   if (!dns->iStatus)
   {
      memcpy(&addr, dns->aina, sizeof(addr));

      he.h_name      = NULL;
      he.h_aliases   = NULL;
      he.h_addrtype  = AF_INET;
      he.h_length    = sizeof(addr);
      he.h_addr_list = &he.h_addr;
      he.h_addr      = (char*)&addr;

      ret = &he;
   }

   WSACloseEvent(event);
   XNetDnsRelease(dns);

   return ret;
}

#elif defined(VITA)
#define COMPAT_NET_INIT_SIZE 0x80000

char *inet_ntoa(struct in_addr in)
{
   static char ip_addr[16];

   sceNetInetNtop(AF_INET, &in, ip_addr, sizeof(ip_addr));

   return ip_addr;
}

int inet_aton(const char *cp, struct in_addr *inp)
{
   return sceNetInetPton(AF_INET, cp, inp);
}

uint32_t inet_addr(const char *cp)
{
   struct in_addr in;

   return (sceNetInetPton(AF_INET, cp, &in) == 1) ? in.s_addr : INADDR_NONE;
}

struct hostent *gethostbyname(const char *name)
{
   static struct SceNetInAddr addr = {0};
   static struct hostent      he   = {0};
   int rid;
   struct hostent *ret = NULL;

   if (!name)
      return NULL;

   rid = sceNetResolverCreate("resolver", NULL, 0);
   if (rid < 0)
      return NULL;

   if (sceNetResolverStartNtoa(rid, name, &addr, 0, 0, 0) < 0)
      goto done;

   he.h_name      = NULL;
   he.h_aliases   = NULL;
   he.h_addrtype  = AF_INET;
   he.h_length    = sizeof(addr);
   he.h_addr_list = &he.h_addr;
   he.h_addr      = (char*)&addr;

   ret = &he;

done:
   sceNetResolverDestroy(rid);

   return ret;
}

#elif defined(GEKKO)
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
   const char *addr_str = inet_ntoa(*(struct in_addr*)src);

   if (addr_str)
   {
      strlcpy(dst, addr_str, size);

      return dst;
   }

   return NULL;
}

int inet_pton(int af, const char *src, void *dst)
{
   if (inet_aton(src, (struct in_addr*)dst))
      return 1;

   return 0;
}

#elif defined(WIIU)
#include <malloc.h>

static int _net_compat_thread_entry(int argc, const char **argv)
{
   void *buf = memalign(128, WIIU_RCVBUF + WIIU_SNDBUF);

   if (!buf)
      return -1;

   somemopt(1, buf, WIIU_RCVBUF + WIIU_SNDBUF, 0);

   free(buf);

   return 0;
}

static void _net_compat_thread_cleanup(OSThread *thread, void *stack)
{
   free(stack);
}

#elif defined(_3DS)
#include <malloc.h>
#include <3ds/types.h>
#include <3ds/services/soc.h>

#define SOC_ALIGN      0x1000
#define SOC_BUFFERSIZE 0x100000
#endif

int getaddrinfo_retro(const char *node, const char *service,
      struct addrinfo *hints, struct addrinfo **res)
{
#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
   struct addrinfo default_hints = {0};

   if (!hints)
      hints            = &default_hints;
   if (!hints->ai_family)
      hints->ai_family = AF_INET;

   if (!node)
      node = (hints->ai_flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
#endif

#ifdef HAVE_SOCKET_LEGACY
   {
      struct addrinfo    *info = (struct addrinfo*)calloc(1, sizeof(*info));
      struct sockaddr_in *addr = (struct sockaddr_in*)malloc(sizeof(*addr));

      if (!info || !addr)
         goto failure;

      info->ai_family   = AF_INET;
      info->ai_socktype = hints->ai_socktype;
      info->ai_protocol = hints->ai_protocol;
      info->ai_addrlen  = sizeof(*addr);
      info->ai_addr     = (struct sockaddr*)addr;
      /* We ignore AI_CANONNAME; ai_canonname is always NULL. */

      addr->sin_family = AF_INET;

      if (service)
      {
         /* We can only handle numeric ports; ignore AI_NUMERICSERV. */
         char *service_end = NULL;
         uint16_t port     = (uint16_t)strtoul(service, &service_end, 10);

         if (service_end == service || *service_end)
            goto failure;

         addr->sin_port = htons(port);
      }

      if (hints->ai_flags & AI_NUMERICHOST)
      {
         if (!inet_aton(node, &addr->sin_addr))
            goto failure;
      }
      else
      {
         struct hostent *host = gethostbyname(node);

         if (!host || !host->h_addr)
            goto failure;

         memcpy(&addr->sin_addr, host->h_addr, sizeof(addr->sin_addr));
      }

      *res = info;

      return 0;

failure:
      free(addr);
      free(info);

      return -1;
   }
#else
   return getaddrinfo(node, service, hints, res);
#endif
}

void freeaddrinfo_retro(struct addrinfo *res)
{
#ifdef HAVE_SOCKET_LEGACY
   if (res)
   {
      free(res->ai_addr);
      free(res);
   }
#else
   freeaddrinfo(res);
#endif
}

int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
{
#ifdef HAVE_SOCKET_LEGACY
   const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;

   /* We cannot perform reverse DNS lookups here; ignore the following flags:
      NI_NAMEREQD
      NI_NOFQDN
      NI_NUMERICHOST (always enforced)
    */
   if (host && hostlen)
   {
      const char *_host = inet_ntoa(addr4->sin_addr);

      if (!_host)
         return -1;

      strlcpy(host, _host, hostlen);
   }

   /* We cannot get service names here; ignore the following flags:
      NI_DGRAM
      NI_NUMERICSERV (always enforced)
    */
   if (serv && servlen)
      snprintf(serv, servlen, "%hu", (unsigned short)ntohs(addr4->sin_port));

   return 0;
#else
   return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
#endif
}

bool addr_6to4(struct sockaddr_storage *addr)
{
#ifdef HAVE_INET6
   /* ::ffff:a.b.c.d */
   static const uint16_t prefix[] = {0,0,0,0,0,0xffff};
   uint32_t address;
   uint16_t port;
   struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)addr;
   struct sockaddr_in  *addr4 = (struct sockaddr_in*)addr;

   switch (addr->ss_family)
   {
      case AF_INET:
         /* No need to convert. */
         return true;
      case AF_INET6:
         /* Is the address provided an IPv4? */
         if (!memcmp(&addr6->sin6_addr, prefix, sizeof(prefix)))
            break;
      default:
         /* We don't know how to handle this. */
         return false;
   }

   memcpy(&address, ((uint8_t*)&addr6->sin6_addr) + sizeof(prefix),
      sizeof(address));
   port = addr6->sin6_port;

   memset(addr, 0, sizeof(*addr));

   addr4->sin_family = AF_INET;
   addr4->sin_port   = port;
   memcpy(&addr4->sin_addr, &address, sizeof(addr4->sin_addr));
#endif

   return true;
}

bool ipv4_is_lan_address(const struct sockaddr_in *addr)
{
   static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000};
   static const uint32_t masks[]   = {0xFF000000, 0xFFF00000, 0xFFFF0000};
   size_t i;
   uint32_t uaddr;

   memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
   uaddr = ntohl(uaddr);

   for (i = 0; i < ARRAY_SIZE(subnets); i++)
      if ((uaddr & masks[i]) == subnets[i])
         return true;

   return false;
}

bool ipv4_is_cgnat_address(const struct sockaddr_in *addr)
{
   static const uint32_t subnet = 0x64400000;
   static const uint32_t mask   = 0xFFC00000;
   uint32_t uaddr;

   memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
   uaddr = ntohl(uaddr);

   return (uaddr & mask) == subnet;
}

/**
 * network_init:
 *
 * Platform specific socket library initialization.
 *
 * @return true if successful, otherwise false.
 **/
bool network_init(void)
{
#if defined(_WIN32)
   static bool initialized = false;

   if (!initialized)
   {
      WSADATA wsaData;

      if (WSAStartup(MAKEWORD(2, 2), &wsaData))
      {
         WSACleanup();

         return false;
      }

      initialized = true;
   }

   return true;
#elif defined(__PSL1GHT__) || defined(__PS3__)
   static bool initialized = false;

   if (!initialized)
   {
      int tries;

      sysModuleLoad(SYSMODULE_NET);

      netInitialize();
      if (netCtlInit() < 0)
         goto failure;

      for (tries = 10;;)
      {
         int state;

         if (netCtlGetState(&state) < 0)
            goto failure;
         if (state == NET_CTL_STATE_IPObtained)
            break;

         if (!(--tries))
            goto failure;

         retro_sleep(500);
      }

      initialized = true;
   }

   return true;

failure:
   netCtlTerm();
   netFinalizeNetwork();

   sysModuleUnload(SYSMODULE_NET);

   return false;
#elif defined(VITA)
   if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
   {
      SceNetInitParam param;
      void *net_compat_memory = malloc(COMPAT_NET_INIT_SIZE);

      if (!net_compat_memory)
         return false;

      param.memory = net_compat_memory;
      param.size   = COMPAT_NET_INIT_SIZE;
      param.flags  = 0;

      if (sceNetInit(&param) < 0)
         goto failure;
      if (sceNetCtlInit() < 0)
         goto failure;

      return true;

failure:
      sceNetCtlTerm();
      sceNetTerm();

      free(net_compat_memory);

      return false;
   }

   return true;
#elif defined(GEKKO)
   static bool initialized = false;

   if (!initialized)
   {
      char localip[16] = {0};
      char netmask[16] = {0};
      char gateway[16] = {0};

      if (if_config(localip, netmask, gateway, true, 10) < 0)
      {
         net_deinit();

         return false;
      }

      initialized = true;
   }

   return true;
#elif defined(WIIU)
   static OSThread net_compat_thread;
   static bool initialized = false;

   if (!initialized)
   {
      void *stack = malloc(0x1000);

      if (!stack)
         return false;

      socket_lib_init();

      if (!OSCreateThread(&net_compat_thread, _net_compat_thread_entry,
            0, NULL, (void*)((size_t)stack + 0x1000), 0x1000, 3,
            OS_THREAD_ATTRIB_AFFINITY_ANY))
      {
         free(stack);

         return false;
      }

      OSSetThreadName(&net_compat_thread, "Network compat thread");
      OSSetThreadDeallocator(&net_compat_thread, _net_compat_thread_cleanup);
      OSResumeThread(&net_compat_thread);

      initialized = true;
   }

   return true;
#elif defined(_3DS)
   static bool initialized = false;

   if (!initialized)
   {
      u32 *net_compat_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);

      if (!net_compat_memory)
         return false;

      /* WIFI init */
      if (socInit(net_compat_memory, SOC_BUFFERSIZE))
      {
         socExit();

         free(net_compat_memory);

         return false;
      }

      initialized = true;
   }

   return true;
#else
   static bool initialized = false;

   if (!initialized)
   {
      /* Do not like SIGPIPE killing our app. */
      signal(SIGPIPE, SIG_IGN);

      initialized = true;
   }

   return true;
#endif
}

./include/libretro-common/net/net_http.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include <net/net_http.h>
#include <net/net_compat.h>
#include <net/net_socket.h>
#ifdef HAVE_SSL
#include <net/net_socket_ssl.h>
#endif
#include <compat/strl.h>
#include <features/features_cpu.h>
#include <file/file_path.h>
#include <string/stdstring.h>
#include <string.h>
#include <lists/string_list.h>
#include <retro_common_api.h>
#include <retro_miscellaneous.h>
#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#endif

enum response_part
{
   P_HEADER_TOP = 0,
   P_HEADER,
   P_BODY,
   P_BODY_CHUNKLEN,
   P_DONE
};

enum bodytype
{
   T_FULL = 0,
   T_LEN,
   T_CHUNK
};

struct conn_pool_entry
{
   char *domain;
   int port;
   int fd;
   void *ssl_ctx;
   bool ssl;
   bool connected;
   bool in_use;
   struct conn_pool_entry *next;
};

static struct conn_pool_entry *conn_pool = NULL;
#ifdef HAVE_THREADS
static slock_t *conn_pool_lock = NULL;
#define LOCK_POOL() slock_lock(conn_pool_lock)
#define UNLOCK_POOL() slock_unlock(conn_pool_lock)
#else
#define LOCK_POOL()
#define UNLOCK_POOL()
#endif

typedef struct response
{
   char *data;
   struct string_list *headers;
   size_t pos;
   size_t len;
   size_t buflen;
   int status;
   enum response_part part;
   enum bodytype bodytype;
} response_t;

typedef struct request
{
   char *domain;
   char *path;
   char *method;
   char *contenttype;
   void *postdata;
   char *useragent;
   char *headers;
   size_t contentlength;
   int port;
} request_t;

struct http_t
{
   bool err;

   struct conn_pool_entry *conn;
   bool ssl;
   bool request_sent;

   request_t request;
   response_t response;
};

struct http_connection_t
{
   char *domain;
   char *path;
   char *url;
   char *scan;
   char *method;
   char *contenttype;
   void *postdata;
   char *useragent;
   char *headers;
   size_t contentlength; /* ptr alignment */
   int port;
   bool ssl;
};

struct dns_cache_entry
{
   char *domain;
   int port;
   struct addrinfo *addr;
   retro_time_t timestamp;
   bool valid;
   struct dns_cache_entry *next;
};

static struct dns_cache_entry *dns_cache = NULL;
/* 5 min timeout, in usec */
static const retro_time_t dns_cache_timeout = 1000 /* usec/ms */ * 1000 /* ms/s */ * 60 /* s/min */ * 5 /* min */;
/* only cache failures for 30 seconds */
static const retro_time_t dns_cache_fail_timeout = 1000 /* usec/ms */ * 1000 /* ms/s */ * 30 /* s */;
#ifdef HAVE_THREADS
static slock_t *dns_cache_lock = NULL;
#define LOCK_DNS_CACHE() slock_lock(dns_cache_lock)
#define UNLOCK_DNS_CACHE() slock_unlock(dns_cache_lock)
#else
#define LOCK_DNS_CACHE()
#define UNLOCK_DNS_CACHE()
#endif

/**
 * net_http_urlencode:
 *
 * URL Encode a string
 * caller is responsible for deleting the destination buffer
 **/
void net_http_urlencode(char **dest, const char *source)
{
   static const char urlencode_lut[] =
   {
      0,       /* 0   */
      0,       /* 1   */
      0,       /* 2   */
      0,       /* 3   */
      0,       /* 4   */
      0,       /* 5   */
      0,       /* 6   */
      0,       /* 7   */
      0,       /* 8   */
      0,       /* 9   */
      0,       /* 10  */
      0,       /* 11  */
      0,       /* 12  */
      0,       /* 13  */
      0,       /* 14  */
      0,       /* 15  */
      0,       /* 16  */
      0,       /* 17  */
      0,       /* 18  */
      0,       /* 19  */
      0,       /* 20  */
      0,       /* 21  */
      0,       /* 22  */
      0,       /* 23  */
      0,       /* 24  */
      0,       /* 25  */
      0,       /* 26  */
      0,       /* 27  */
      0,       /* 28  */
      0,       /* 29  */
      0,       /* 30  */
      0,       /* 31  */
      0,       /* 32  */
      0,       /* 33  */
      0,       /* 34  */
      0,       /* 35  */
      0,       /* 36  */
      0,       /* 37  */
      0,       /* 38  */
      0,       /* 39  */
      0,       /* 40  */
      0,       /* 41  */
      '*',     /* 42  */
      0,       /* 43  */
      0,       /* 44  */
      '-',     /* 45  */
      '.',     /* 46  */
      '/',     /* 47  */
      '0',     /* 48  */
      '1',     /* 49  */
      '2',     /* 50  */
      '3',     /* 51  */
      '4',     /* 52  */
      '5',     /* 53  */
      '6',     /* 54  */
      '7',     /* 55  */
      '8',     /* 56  */
      '9',     /* 57  */
      0,       /* 58  */
      0,       /* 59  */
      0,       /* 60  */
      0,       /* 61  */
      0,       /* 62  */
      0,       /* 63  */
      0,       /* 64  */
      'A',     /* 65  */
      'B',     /* 66  */
      'C',     /* 67  */
      'D',     /* 68  */
      'E',     /* 69  */
      'F',     /* 70  */
      'G',     /* 71  */
      'H',     /* 72  */
      'I',     /* 73  */
      'J',     /* 74  */
      'K',     /* 75  */
      'L',     /* 76  */
      'M',     /* 77  */
      'N',     /* 78  */
      'O',     /* 79  */
      'P',     /* 80  */
      'Q',     /* 81  */
      'R',     /* 82  */
      'S',     /* 83  */
      'T',     /* 84  */
      'U',     /* 85  */
      'V',     /* 86  */
      'W',     /* 87  */
      'X',     /* 88  */
      'Y',     /* 89  */
      'Z',     /* 90  */
      0,       /* 91  */
      0,       /* 92  */
      0,       /* 93  */
      0,       /* 94  */
      '_',     /* 95  */
      0,       /* 96  */
      'a',     /* 97  */
      'b',     /* 98  */
      'c',     /* 99  */
      'd',     /* 100 */
      'e',     /* 101 */
      'f',     /* 102 */
      'g',     /* 103 */
      'h',     /* 104 */
      'i',     /* 105 */
      'j',     /* 106 */
      'k',     /* 107 */
      'l',     /* 108 */
      'm',     /* 109 */
      'n',     /* 110 */
      'o',     /* 111 */
      'p',     /* 112 */
      'q',     /* 113 */
      'r',     /* 114 */
      's',     /* 115 */
      't',     /* 116 */
      'u',     /* 117 */
      'v',     /* 118 */
      'w',     /* 119 */
      'x',     /* 120 */
      'y',     /* 121 */
      'z'      /* 122 */
   };

   /* Assume every character will be encoded, so we need 3 times the space. */
   size_t _len                      = strlen(source) * 3 + 1;
   size_t count                     = _len;
   char *enc                        = (char*)calloc(1, _len);
   *dest                            = enc;

   for (; *source; source++)
   {
      int written = 0;

      /* any non-ASCII character will just be encoded without question */
      if ((unsigned)*source < sizeof(urlencode_lut) && urlencode_lut[(unsigned)*source])
         written = snprintf(enc, count, "%c", urlencode_lut[(unsigned)*source]);
      else
         written = snprintf(enc, count, "%%%02X", *source & 0xFF);

      if (written > 0)
         count -= written;

      while (*++enc);
   }

   (*dest)[_len - 1] = '\0';
}

/**
 * net_http_urlencode_full:
 *
 * Re-encode a full URL
 **/
void net_http_urlencode_full(char *s, const char *source, size_t len)
{
   size_t buf_pos;
   size_t tmp_len;
   char url_domain[256];
   char url_path[PATH_MAX_LENGTH];
   int count      = 0;
   char *tmp      = url_path;

   strlcpy(url_path, source, sizeof(url_path));

   while (count < 3 && tmp[0] != '\0')
   {
      tmp = strchr(tmp, '/');
      if (!tmp)
         break;
      count++;
      tmp++;
   }

   tmp_len        = strlen(tmp);
   buf_pos        = ((strlcpy(url_domain, source, tmp - url_path)) - tmp_len) - 1;
   strlcpy(url_path,
         source  + buf_pos + 1,
         tmp_len           + 1
         );

   tmp             = NULL;
   net_http_urlencode(&tmp, url_path);
   buf_pos         = strlcpy(s, url_domain, len);
   s[  buf_pos] = '/';
   s[++buf_pos] = '\0';
   strlcpy(s + buf_pos, tmp, len - buf_pos);
   free(tmp);
}

struct http_connection_t *net_http_connection_new(const char *url,
      const char *method, const char *data)
{
   struct http_connection_t *conn = NULL;

   if (!url)
      return NULL;
   if (!(conn = (struct http_connection_t*)calloc(1, sizeof(*conn))))
      return NULL;

   if (method)
      conn->method         = strdup(method);

   if (data)
   {
      conn->postdata       = strdup(data);
      conn->contentlength  = strlen(data);
   }

   if ((conn->url = strdup(url)))
   {
      if (!strncmp(url, "http://", STRLEN_CONST("http://")))
      {
         conn->scan   = conn->url + STRLEN_CONST("http://");

         if (!string_is_empty(conn->scan))
         {
            conn->domain = conn->scan;
            return conn;
         }
      }
      else if (!strncmp(url, "https://", STRLEN_CONST("https://")))
      {
         conn->scan   = conn->url + STRLEN_CONST("https://");
         conn->ssl    = true;

         if (!string_is_empty(conn->scan))
         {
            conn->domain = conn->scan;
            return conn;
         }
      }
   }

   if (conn->url)
      free(conn->url);
   if (conn->method)
      free(conn->method);
   if (conn->postdata)
      free(conn->postdata);
   free(conn);
   return NULL;
}

/**
 * net_http_connection_iterate:
 *
 * Leaf function.
 **/
bool net_http_connection_iterate(struct http_connection_t *conn)
{
   if (!conn)
      return false;

   while (*conn->scan != '/' && *conn->scan != ':' && *conn->scan != '\0')
      conn->scan++;

   return true;
}

bool net_http_connection_done(struct http_connection_t *conn)
{
   int has_port = 0;

   if (!conn || !conn->domain || !*conn->domain)
      return false;

   if (*conn->scan == ':')
   {
      /* domain followed by port, split off the port */
      *conn->scan++ = '\0';

      if (!isdigit((int)(*conn->scan)))
         return false;

      conn->port = (int)strtoul(conn->scan, &conn->scan, 10);
      has_port   = 1;
   }
   else if (conn->port == 0)
   {
      /* port not specified, default to standard HTTP or HTTPS port */
      if (conn->ssl)
         conn->port = 443;
      else
         conn->port = 80;
   }

   if (*conn->scan == '/')
   {
      /* domain followed by path - split off the path */
      /*   site.com/path.html   or   site.com:80/path.html   */
      *conn->scan    = '\0';
      conn->path = conn->scan + 1;
      return true;
   }
   else if (!*conn->scan)
   {
      /* domain with no path - point path at empty string */
      /*   site.com   or   site.com:80   */
      conn->path = conn->scan;
      return true;
   }
   else if (*conn->scan == '?')
   {
      /* domain with no path, but still has query parms - point path at the query parms */
      /*   site.com?param=3   or  site.com:80?param=3   */
      if (!has_port)
      {
         /* if there wasn't a port, we have to expand the urlcopy so we can separate the two parts */
         size_t domain_len   = strlen(conn->domain);
         size_t path_len     = strlen(conn->scan);
         char* urlcopy       = (char*)malloc(domain_len + path_len + 2);
         memcpy(urlcopy, conn->domain, domain_len);
         urlcopy[domain_len] = '\0';
         memcpy(urlcopy + domain_len + 1, conn->scan, path_len + 1);

         free(conn->url);
         conn->domain        = conn->url     = urlcopy;
         conn->path          = conn->scan    = urlcopy + domain_len + 1;
      }
      else /* There was a port, so overwriting the : will terminate the domain and we can just point at the ? */
         conn->path          = conn->scan;

      return true;
   }

   /* invalid character after domain/port */
   return false;
}

void net_http_connection_free(struct http_connection_t *conn)
{
   if (!conn)
      return;

   if (conn->url)
      free(conn->url);

   if (conn->method)
      free(conn->method);

   if (conn->contenttype)
      free(conn->contenttype);

   if (conn->postdata)
      free(conn->postdata);

   if (conn->useragent)
      free(conn->useragent);

   if (conn->headers)
      free(conn->headers);

   free(conn);
}

void net_http_connection_set_user_agent(
      struct http_connection_t *conn, const char *user_agent)
{
   if (conn->useragent)
      free(conn->useragent);

   conn->useragent = user_agent ? strdup(user_agent) : NULL;
}

void net_http_connection_set_headers(
      struct http_connection_t *conn, const char *headers)
{
   if (conn->headers)
      free(conn->headers);

   conn->headers = headers ? strdup(headers) : NULL;
}

void net_http_connection_set_content(
      struct http_connection_t *conn, const char *content_type,
      size_t content_length, const void *content)

{
   if (conn->contenttype)
      free(conn->contenttype);
   if (conn->postdata)
      free(conn->postdata);

   conn->contenttype   = content_type ? strdup(content_type) : NULL;
   conn->contentlength = content_length;
   if (content_length)
   {
      conn->postdata = malloc(content_length);
      memcpy(conn->postdata, content, content_length);
   }
}

const char *net_http_connection_url(struct http_connection_t *conn)
{
   return conn->url;
}

const char* net_http_connection_method(struct http_connection_t* conn)
{
   return conn->method;
}

static void net_http_dns_cache_remove_expired(void)
{
   struct dns_cache_entry *entry = dns_cache;
   struct dns_cache_entry *prev = NULL;
   while (entry)
   {
      if (     (entry->addr && (entry->timestamp + dns_cache_timeout < cpu_features_get_time_usec()))
            || (!entry->addr && (entry->timestamp + dns_cache_fail_timeout < cpu_features_get_time_usec())))
      {
         if (prev)
            prev->next = entry->next;
         else
            dns_cache = entry->next;
         if (entry->addr)
            freeaddrinfo_retro(entry->addr);
         free(entry->domain);
         free(entry);
         entry = prev ? prev->next : dns_cache;
      }
      else
      {
         prev = entry;
         entry = entry->next;
      }
   }
}

static struct dns_cache_entry *net_http_dns_cache_find(const char *domain, int port)
{
   struct dns_cache_entry *entry;

   net_http_dns_cache_remove_expired();

   entry = dns_cache;
   while (entry)
   {
      if (port == entry->port && string_is_equal(entry->domain, domain))
      {
         /* don't bump timeestamp for failures */
         if (entry->addr)
            entry->timestamp = cpu_features_get_time_usec();
         return entry;
      }
      entry = entry->next;
   }
   return NULL;
}

static struct dns_cache_entry *net_http_dns_cache_add(const char *domain, int port, struct addrinfo *addr)
{
   struct dns_cache_entry *entry = (struct dns_cache_entry*)calloc(1, sizeof(*entry));
   if (!entry)
      return NULL;
   entry->domain = strdup(domain);
   entry->port = port;
   entry->addr = addr;
   entry->timestamp = cpu_features_get_time_usec();
   entry->valid = (addr != NULL);
   entry->next = dns_cache;
   dns_cache = entry;
   return entry;
}

static void net_http_conn_pool_free(struct conn_pool_entry *entry)
{
#ifdef HAVE_SSL
   if (entry->ssl && entry->ssl_ctx)
   {
      ssl_socket_close(entry->ssl_ctx);
      ssl_socket_free(entry->ssl_ctx);
   }
#endif
   if (entry->fd >= 0)
      socket_close(entry->fd);
   free(entry->domain);
   free(entry);
}

static void net_http_conn_pool_remove(struct conn_pool_entry *entry)
{
   struct conn_pool_entry *prev = NULL;
   struct conn_pool_entry *current;
   if (!entry)
      return;

   LOCK_POOL();
   current = conn_pool;
   while (current)
   {
      if (current == entry)
      {
         if (prev)
            prev->next = current->next;
         else
            conn_pool = current->next;
         net_http_conn_pool_free(current);
         UNLOCK_POOL();
         return;
      }
      prev = current;
      current = current->next;
   }
   UNLOCK_POOL();
}

/* *NOT* thread safe, caller must lock */
static void net_http_conn_pool_remove_expired(void)
{
   fd_set fds;
   struct conn_pool_entry *entry = NULL;
   struct conn_pool_entry *prev  = NULL;
   struct timeval tv             = { 0 };
   int max                       = 0;
   FD_ZERO(&fds);
   entry = conn_pool;
   while (entry)
   {
      if (!entry->in_use)
      {
         FD_SET(entry->fd, &fds);
         if (entry->fd >= max)
            max = entry->fd + 1;
      }
      entry = entry->next;
   }
   if (select(max, &fds, NULL, NULL, &tv) <= 0)
      return;
   entry = conn_pool;
   while (entry)
   {
      if (!entry->in_use && FD_ISSET(entry->fd, &fds))
      {
         char buf[4096];
         bool err = false;
#ifdef HAVE_SSL
         if (entry->ssl && entry->ssl_ctx)
            ssl_socket_receive_all_nonblocking(entry->ssl_ctx, &err, buf, sizeof(buf));
         else
#endif
            socket_receive_all_nonblocking(entry->fd, &err, buf, sizeof(buf));

         if (!err)
            continue;

         if (prev)
            prev->next = entry->next;
         else
            conn_pool = entry->next;
         /* if it's not in use and it's reaadable we assume that means it's closed without checking recv */
         net_http_conn_pool_free(entry);
         entry = prev ? prev->next : conn_pool;
      }
      else
      {
         prev = entry;
         entry = entry->next;
      }
   }
}

/* if it's not already in the pool, will add to end.
   *NOT* thread safe, caller must lock */
static void net_http_conn_pool_move_to_end(struct conn_pool_entry *entry)
{
   struct conn_pool_entry *prev    = NULL;
   struct conn_pool_entry *current = conn_pool;
   /* 0 items in pool */
   if (!conn_pool)
   {
      conn_pool   = entry;
      entry->next = NULL;
      return;
   }
   /* already only item in pool */
   if (conn_pool == entry && !conn_pool->next)
      return;
   while (current)
   {
      if (current != entry)
         prev = current;
      else
      {
         /* need to remove current */
         if (prev)
            prev->next = current->next;
         else
            conn_pool = current->next;
      }
      current = current->next;
   }

   if (prev)
      prev->next  = entry;
   if (entry)
      entry->next = NULL;
}

static struct conn_pool_entry *net_http_conn_pool_find(const char *domain, int port)
{
   struct conn_pool_entry *entry;

   LOCK_POOL();

   net_http_conn_pool_remove_expired();

   entry = conn_pool;
   while (entry)
   {
      if (!entry->in_use && port == entry->port && string_is_equal(entry->domain, domain))
      {
         entry->in_use = true;
         net_http_conn_pool_move_to_end(entry);
         UNLOCK_POOL();
         return entry;
      }
      entry = entry->next;
   }
   UNLOCK_POOL();
   return NULL;
}

static struct conn_pool_entry *net_http_conn_pool_add(const char *domain, int port, int fd, bool ssl)
{
   struct conn_pool_entry *entry = (struct conn_pool_entry*)calloc(1, sizeof(*entry));
   if (!entry)
      return NULL;
   entry->domain = strdup(domain);
   entry->port = port;
   entry->fd = fd;
   entry->in_use = true;
   entry->ssl = ssl;
   entry->connected = false;
   LOCK_POOL();
   net_http_conn_pool_move_to_end(entry);
   UNLOCK_POOL();
   return entry;
}

struct http_t *net_http_new(struct http_connection_t *conn)
{
   struct http_t *state;

   if (!conn)
      return NULL;

   state = (struct http_t*)calloc(1, sizeof(struct http_t));
   if (!state)
      return NULL;

   state->ssl  = conn->ssl;
   state->conn = NULL;

   state->request.domain        = strdup(conn->domain);
   state->request.path          = strdup(conn->path);
   state->request.method        = strdup(conn->method);
   state->request.contenttype   = conn->contenttype ? strdup(conn->contenttype) : NULL;
   state->request.contentlength = conn->contentlength;
   if (conn->postdata && conn->contentlength)
   {
      state->request.postdata   = malloc(conn->contentlength);
      memcpy(state->request.postdata, conn->postdata, conn->contentlength);
   }
   state->request.useragent     = conn->useragent ? strdup(conn->useragent) : NULL;
   state->request.headers       = conn->headers ? strdup(conn->headers) : NULL;
   state->request.port          = conn->port;

   state->response.status  = -1;
   state->response.buflen  = 64 * 1024;  /* Start with larger buffer to reduce reallocations */
   state->response.data    = (char*)malloc(state->response.buflen);
   state->response.headers = string_list_new();

   return state;
}

static void net_http_resolve(void *data)
{
   struct dns_cache_entry *entry = (struct dns_cache_entry*)data;
   struct addrinfo hints         = {0};
   struct addrinfo *addr         = NULL;
   char *domain;
   int port;
   char port_buf[6];
#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
   int family                    = AF_INET;
#else
   int family                    = AF_UNSPEC;
#endif

   hints.ai_family = family;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags |= AI_NUMERICSERV;

   LOCK_DNS_CACHE();
   domain = strdup(entry->domain);
   port = entry->port;
   UNLOCK_DNS_CACHE();

   if (!network_init())
   {
      LOCK_DNS_CACHE();
      entry->valid = true;
      entry->addr = NULL;
      UNLOCK_DNS_CACHE();
      free(domain);
      return;
   }

   snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);

   getaddrinfo_retro(domain, port_buf, &hints, &addr);
   free(domain);

   LOCK_DNS_CACHE();
   entry->valid = true;
   entry->addr = addr;
   UNLOCK_DNS_CACHE();
}

static bool net_http_new_socket(struct http_t *state)
{
   struct addrinfo *addr = NULL;
   struct dns_cache_entry *entry;

#ifdef HAVE_THREADS
   sthread_t *thread;

   if (!dns_cache_lock)
      dns_cache_lock = slock_new();
   LOCK_DNS_CACHE();

   /* need some place to create this, I guess */
   if (!conn_pool_lock)
      conn_pool_lock = slock_new();
#endif

   entry = net_http_dns_cache_find(state->request.domain, state->request.port);
   if (entry)
   {
      if (entry->valid)
      {
         int fd;
         if (!entry->addr)
         {
            UNLOCK_DNS_CACHE();
            return false;
         }
         addr = entry->addr;
         fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
         if (fd >= 0)
            state->conn = net_http_conn_pool_add(state->request.domain, state->request.port, fd, state->ssl);
         /* still waiting on thread */
         UNLOCK_DNS_CACHE();
         return (fd >= 0);
      }
      else
      {
         /* still waiting on thread */
         UNLOCK_DNS_CACHE();
         return true;
      }
   }
   else
   {
      entry = net_http_dns_cache_add(state->request.domain, state->request.port, NULL);
#ifdef HAVE_THREADS
      /* create the entry for it as an indicator that the request is underway */
      thread = sthread_create(net_http_resolve, entry);
      sthread_detach(thread);
#else
      net_http_resolve(entry);
#endif
   }

   UNLOCK_DNS_CACHE();

   return true;
}

static bool net_http_connect(struct http_t *state)
{
   struct addrinfo *addr = NULL, *next_addr = NULL;
   struct conn_pool_entry *conn = state->conn;
   struct dns_cache_entry *dns_entry = net_http_dns_cache_find(state->request.domain, state->request.port);
   /* we just used/added this in _new_socket above, if it's not there it's a big bug */
   addr = dns_entry->addr;

#ifndef HAVE_SSL
   if (state->ssl)
      return false;
#else
   if (state->ssl)
   {
      if (!conn)
         return false;

      for (next_addr = addr; conn->fd >= 0; conn->fd = socket_next((void**)&next_addr))
      {
         if (!(conn->ssl_ctx = ssl_socket_init(conn->fd, state->request.domain)))
         {
            socket_close(conn->fd);
            break;
         }

         /* TODO: Properly figure out what's going wrong when the newer
          timeout/poll code interacts with mbed and winsock
          https://github.com/libretro/RetroArch/issues/14742 */

         /* Temp fix, don't use new timeout/poll code for cheevos http requests */
         bool timeout = true;
#ifdef __WIN32
         if (!strcmp(state->request.domain, "retroachievements.org"))
            timeout = false;
#endif

         if (ssl_socket_connect(conn->ssl_ctx, next_addr, timeout, true) < 0)
         {
            ssl_socket_close(conn->ssl_ctx);
            ssl_socket_free(conn->ssl_ctx);
            conn->ssl_ctx = NULL;
         }
         else
         {
            conn->connected = true;
            return true;
         }
      }
      conn->fd    = -1; /* already closed */
      net_http_conn_pool_remove(conn);
      state->conn = NULL;
      state->err  = true;
      return false;
   }
   else
#endif
   {
      for (next_addr = addr; conn->fd >= 0; conn->fd = socket_next((void**)&next_addr))
      {
         if (socket_connect_with_timeout(conn->fd, next_addr, 5000))
         {
            conn->connected = true;
            return true;
         }

         socket_close(conn->fd);
      }
      conn->fd    = -1; /* already closed */
      net_http_conn_pool_remove(conn);
      state->conn = NULL;
      state->err  = true;
      return false;
   }
}

static void net_http_send_str(
      struct http_t *state, const char *text, size_t text_size)
{
   if (state->err)
      return;
#ifdef HAVE_SSL
   if (state->ssl)
   {
      if (!ssl_socket_send_all_blocking(
                  state->conn->ssl_ctx, text, text_size, true))
         state->err = true;
   }
   else
#endif
   {
      if (!socket_send_all_blocking(
                  state->conn->fd, text, text_size, true))
         state->err = true;
   }
}

static bool net_http_send_request(struct http_t *state)
{
   struct request *request = (struct request*)&state->request;

   /* This is a bit lazy, but it works. */
   if (request->method)
   {
      net_http_send_str(state, request->method, strlen(request->method));
      net_http_send_str(state, " /", STRLEN_CONST(" /"));
   }
   else
      net_http_send_str(state, "GET /", STRLEN_CONST("GET /"));

   net_http_send_str(state, request->path, strlen(request->path));
   net_http_send_str(state, " HTTP/1.1\r\n", STRLEN_CONST(" HTTP/1.1\r\n"));

   net_http_send_str(state, "Host: ", STRLEN_CONST("Host: "));
   net_http_send_str(state, request->domain, strlen(request->domain));

   if (request->port && request->port != 80 && request->port != 443)
   {
      char portstr[16];
      size_t _len     = 0;
      portstr[  _len] = ':';
      portstr[++_len] = '\0';
      _len           += snprintf(portstr + _len, sizeof(portstr) - _len,
            "%i", request->port);
      net_http_send_str(state, portstr, _len);
   }

   net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

   /* Pre-formatted headers */
   if (request->headers)
      net_http_send_str(state, request->headers, strlen(request->headers));
   if (request->contenttype)
   {
      net_http_send_str(state, "Content-Type: ", STRLEN_CONST("Content-Type: "));
      net_http_send_str(state, request->contenttype, strlen(request->contenttype));
      net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));
   }

   if (request->method && (string_is_equal(request->method, "POST") || string_is_equal(request->method, "PUT")))
   {
      size_t _len, len;
      char *len_str = NULL;

      if (!request->postdata && !string_is_equal(request->method, "PUT"))
      {
         state->err = true;
         return true;
      }

      if (!request->headers && !request->contenttype)
         net_http_send_str(state,
               "Content-Type: application/x-www-form-urlencoded\r\n",
               STRLEN_CONST("Content-Type: application/x-www-form-urlencoded\r\n"));

      net_http_send_str(state, "Content-Length: ", STRLEN_CONST("Content-Length: "));

      _len = request->contentlength;
#ifdef _WIN32
      len     = snprintf(NULL, 0, "%" PRIuPTR, _len);
      len_str = (char*)malloc(len + 1);
      snprintf(len_str, len + 1, "%" PRIuPTR, _len);
#else
      len     = snprintf(NULL, 0, "%llu", (long long unsigned)_len);
      len_str = (char*)malloc(len + 1);
      snprintf(len_str, len + 1, "%llu", (long long unsigned)_len);
#endif

      len_str[len] = '\0';

      net_http_send_str(state, len_str, strlen(len_str));
      net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

      free(len_str);
   }

   net_http_send_str(state, "User-Agent: ", STRLEN_CONST("User-Agent: "));
   if (request->useragent)
      net_http_send_str(state, request->useragent, strlen(request->useragent));
   else
      net_http_send_str(state, "libretro", STRLEN_CONST("libretro"));
   net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

   net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

   if (request->postdata && request->contentlength)
      net_http_send_str(state, (const char*)request->postdata,
            request->contentlength);

   state->request_sent = true;
   return state->err;
}

/**
 * net_http_fd:
 *
 * Leaf function.
 *
 * You can use this to call net_http_update
 * only when something will happen; select() it for reading.
 **/
int net_http_fd(struct http_t *state)
{
   if (!state || !state->conn)
      return -1;
   return state->conn->fd;
}

static ssize_t net_http_receive_header(struct http_t *state, ssize_t len)
{
   struct response *response = (struct response*)&state->response;

   response->pos += len;

   while (response->part < P_BODY)
   {
      char *dataend  = response->data + response->pos;
      char *lineend  = (char*)memchr(response->data, '\n', response->pos);

      if (!lineend)
         break;

      *lineend       = '\0';

      if (lineend != response->data && lineend[-1]=='\r')
         lineend[-1] = '\0';

      if (response->part == P_HEADER_TOP)
      {
         if (strncmp(response->data, "HTTP/1.", STRLEN_CONST("HTTP/1."))!=0)
         {
            response->part = P_DONE;
            state->err     = true;
            return -1;
         }
         response->status = (int)strtoul(response->data
               + STRLEN_CONST("HTTP/1.1 "), NULL, 10);
         response->part   = P_HEADER;
      }
      else
      {
         if (string_starts_with_case_insensitive(response->data, "Content-Length:"))
         {
            char* ptr = response->data + STRLEN_CONST("Content-Length:");
            while (ISSPACE(*ptr))
               ++ptr;

            response->bodytype = T_LEN;
            response->len      = strtol(ptr, NULL, 10);
         }
         else if (string_is_equal_case_insensitive(response->data, "Transfer-Encoding: chunked"))
            response->bodytype = T_CHUNK;

         if (response->data[0]=='\0')
         {
            if (response->status == 100)
            {
               response->part = P_HEADER_TOP;
            }
            else
            {
               response->part = P_BODY;
               if (response->bodytype == T_CHUNK)
                  response->part = P_BODY_CHUNKLEN;
            }
         }
         else
         {
            union string_list_elem_attr attr;
            attr.i = 0;
            string_list_append(response->headers, response->data, attr);
         }
      }

      memmove(response->data, lineend + 1, dataend-(lineend+1));
      response->pos = (dataend-(lineend + 1));
   }

   if (response->part >= P_BODY)
   {
      len           = response->pos;
      response->pos = 0;
      if (response->bodytype == T_LEN)
      {
         response->buflen = response->len;
         response->data   = (char*)realloc(response->data, response->buflen);
      }
   }
   else
   {
      if (response->pos >= response->buflen - 64)
      {
         response->buflen *= 2;
         response->data    = (char*)realloc(response->data, response->buflen);
      }
   }
   return len;
}

static bool net_http_receive_body(struct http_t *state, ssize_t newlen)
{
   struct response *response = (struct response*)&state->response;

   if (newlen < 0 || state->err)
   {
      if (response->bodytype != T_FULL)
         return false;
      response->part      = P_DONE;
      if (response->buflen != response->len)
         response->data      = (char*)realloc(response->data, response->len);
      return true;
   }

parse_again:
   if (response->bodytype == T_CHUNK)
   {
      if (response->part == P_BODY_CHUNKLEN)
      {
         response->pos      += newlen;

         if (response->pos - response->len >= 2)
         {
            /*
             * len=start of chunk including \r\n
             * pos=end of data
             */

            char *fullend = response->data + response->pos;
            char *end     = (char*)memchr(response->data + response->len + 2, '\n',
                  response->pos - response->len - 2);

            if (end)
            {
               size_t chunklen = strtoul(response->data + response->len, NULL, 16);
               response->pos   = response->len;
               end++;

               memmove(response->data + response->len, end, fullend-end);

               response->len   = chunklen;
               newlen          = (fullend - end);

               /*
                 len=num bytes
                 newlen=unparsed bytes after \n
                 pos=start of chunk including \r\n
               */

               response->part = P_BODY;
               if (response->len == 0)
               {
                  response->part = P_DONE;
                  response->len  = response->pos;
                  response->data = (char*)realloc(response->data, response->len);
                  return true;
               }
               goto parse_again;
            }
         }
      }
      else if (response->part == P_BODY)
      {
         if ((size_t)newlen >= response->len)
         {
            response->pos += response->len;
            newlen        -= response->len;
            response->len  = response->pos;
            response->part = P_BODY_CHUNKLEN;
            goto parse_again;
         }
         response->pos += newlen;
         response->len -= newlen;
      }
   }
   else
   {
      response->pos += newlen;

      if (response->pos > response->len)
         return false;
      else if (response->pos == response->len)
      {
         response->part = P_DONE;
         if (response->buflen != response->len)
            response->data = (char*)realloc(response->data, response->len);
         return true;
      }
   }

   if (response->pos >= response->buflen)
   {
      response->buflen *= 2;
      response->data    = (char*)realloc(response->data, response->buflen);
   }
   return true;
}

static bool net_http_redirect(struct http_t *state, const char *location)
{
   /* this reinitializes state based on the new location */

   /* url may be absolute or relative to the current url */
   bool absolute = (strstr(location, "://") != NULL);

   if (absolute)
   {
      /* this block is a little wasteful, memory-wise */
      struct http_connection_t *new_url = net_http_connection_new(location, NULL, NULL);
      net_http_connection_iterate(new_url);
      if (!net_http_connection_done(new_url))
      {
         net_http_connection_free(new_url);
         return true;
      }
      state->ssl = new_url->ssl;
      if (state->request.domain)
         free(state->request.domain);
      state->request.domain = strdup(new_url->domain);
      state->request.port = new_url->port;
      if (state->request.path)
         free(state->request.path);
      state->request.path = strdup(new_url->path);
      net_http_connection_free(new_url);
   }
   else
   {
      if (*location == '/')
      {
         if (state->request.path)
            free(state->request.path);
         state->request.path = strdup(location);
      }
      else
      {
         char *path = (char*)malloc(PATH_MAX_LENGTH);
         fill_pathname_resolve_relative(path, state->request.path, location, PATH_MAX_LENGTH);
         free(state->request.path);
         state->request.path = path;
      }
   }
   state->request_sent       = false;
   state->response.part      = P_HEADER_TOP;
   state->response.status    = -1;
   state->response.buflen    = 64 * 1024;  /* Start with larger buffer to reduce reallocations */
   state->response.data      = (char*)realloc(state->response.data, state->response.buflen);
   state->response.pos       = 0;
   state->response.len       = 0;
   state->response.bodytype  = T_FULL;
   /* after this, assume location is invalid */
   string_list_deinitialize(state->response.headers);
   string_list_initialize(state->response.headers);
   /* keep going */
   return false;
}

/**
 * net_http_update:
 *
 * @return true if it's done, or if something broke.
 * @total will be 0 if it's not known.
 **/
bool net_http_update(struct http_t *state, size_t* progress, size_t* total)
{
   struct response *response;
   ssize_t _len = 0;

   if (!state || state->err)
      return true;

   if (!state->conn)
   {
      state->conn = net_http_conn_pool_find(state->request.domain, state->request.port);
      if (!state->conn)
      {
         if (!net_http_new_socket(state))
            state->err = true;
         return state->err;
      }
   }

   if (!state->conn->connected)
   {
      if (!net_http_connect(state))
         state->err = true;
      return state->err;
   }

   if (!state->request_sent)
      return net_http_send_request(state);

   response = (struct response*)&state->response;

#ifdef HAVE_SSL
   if (state->ssl && state->conn->ssl_ctx)
      _len = ssl_socket_receive_all_nonblocking(state->conn->ssl_ctx, &state->err,
            (uint8_t*)response->data + response->pos,
            response->buflen - response->pos);
   else
#endif
      _len = socket_receive_all_nonblocking(state->conn->fd, &state->err,
            (uint8_t*)response->data + response->pos,
            response->buflen - response->pos);

   if (response->part < P_BODY)
   {
      if (_len < 0 || state->err)
      {
         net_http_conn_pool_remove(state->conn);
         state->err       = true;
         response->part   = P_DONE;
         response->status = -1;
         return true;
      }
      _len = net_http_receive_header(state, _len);
   }

   if (response->part >= P_BODY && response->part < P_DONE)
   {
      if (!net_http_receive_body(state, _len))
      {
         net_http_conn_pool_remove(state->conn);
         state->err       = true;
         response->part   = P_DONE;
         response->status = -1;
         return true;
      }
   }

   if (progress)
      *progress = response->pos;

   if (total)
   {
      if (response->bodytype == T_LEN)
         *total = response->len;
      else
         *total = 0;
   }

   if (response->part != P_DONE)
      return false;

   for (_len = 0; (size_t)_len < response->headers->size; _len++)
   {
      if (string_is_equal_case_insensitive(response->headers->elems[_len].data, "connection: close"))
      {
         net_http_conn_pool_remove(state->conn);
         state->conn = NULL;
         break;
      }
   }

   if (state->conn)
      state->conn->in_use = false;
   state->conn = NULL;

   if (response->status >= 300 && response->status < 400)
   {
      for (_len = 0; (size_t)_len < response->headers->size; _len++)
      {
         if (string_starts_with_case_insensitive(response->headers->elems[_len].data, "Location: "))
            return net_http_redirect(state, response->headers->elems[_len].data + STRLEN_CONST("Location: "));
      }
   }

   return true;
}

/**
 * net_http_status:
 *
 * Report HTTP status. 200, 404, or whatever.
 *
 * Leaf function.
 *
 * @return HTTP status code.
 **/
int net_http_status(struct http_t *state)
{
   if (!state)
      return -1;
   return state->response.status;
}

/**
 * net_http_headers:
 *
 * Leaf function.
 *
 * @return the response headers. The returned buffer is owned by the
 * caller of net_http_new; it is not freed by net_http_delete().
 * If the status is not 20x and accept_err is false, it returns NULL.
 **/
struct string_list *net_http_headers(struct http_t *state)
{
   if (!state || !state->err)
      return NULL;
   return state->response.headers;
}

/**
 * net_http_data:
 *
 * Leaf function.
 *
 * @return the downloaded data. The returned buffer is owned by the
 * HTTP handler; it's freed by net_http_delete().
 * If the status is not 20x and accept_err is false, it returns NULL.
 **/
uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_err)
{
   if (!state)
      return NULL;

   if (!accept_err && (state->err || state->response.status < 200 || state->response.status > 299))
   {
      if (len)
         *len = 0;
      return NULL;
   }

   if (len)
      *len    = state->response.len;

   return (uint8_t*)state->response.data;
}

/**
 * net_http_delete:
 *
 * Cleans up all memory.
 **/
void net_http_delete(struct http_t *state)
{
   if (!state)
      return;

   if (state->conn)
      net_http_conn_pool_remove(state->conn);
   if (state->request.domain)
      free(state->request.domain);
   if (state->request.path)
      free(state->request.path);
   if (state->request.method)
      free(state->request.method);
   if (state->request.contenttype)
      free(state->request.contenttype);
   if (state->request.postdata)
      free(state->request.postdata);
   if (state->request.useragent)
      free(state->request.useragent);
   if (state->request.headers)
      free(state->request.headers);
   free(state);
}

/**
 * net_http_error:
 *
 * Leaf function
 **/
bool net_http_error(struct http_t *state)
{
   return (state->err || state->response.status < 200 || state->response.status > 299);
}

./include/libretro-common/net/net_http_parse.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http_parse.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <compat/strcasestr.h>

/**
 * string_parse_html_anchor:
 * @line               : Buffer where the <a> tag is stored
 * @link               : Buffer to store the link URL in
 * @name               : Buffer to store the link URL in
 * @link_size          : Size of the link buffer including the NUL-terminator
 * @name_size          : Size of the name buffer including the NUL-terminator
 *
 * Parses an HTML anchor link stored in @line in the form of: <a href="/path/to/url">Title</a>
 * The buffer pointed to by @link is filled with the URL path the link points to,
 * and @name is filled with the title portion of the link.
 *
 * @return 0 if URL was parsed completely, otherwise 1.
 **/
int string_parse_html_anchor(const char *line, char *link, char *name,
      size_t link_size, size_t name_size)
{
   if (!line || !link || !name)
      return 1;

   memset(link, 0, link_size);
   memset(name, 0, name_size);

   line = strcasestr(line, "<a href=\"");

   if (!line)
      return 1;

   line += 9;

   if (line && *line)
   {
      if (!*link)
      {
         const char *end = strstr(line, "\"");

         if (!end)
            return 1;

         memcpy(link, line, end - line);

         *(link + (end - line)) = '\0';
         line += end - line;
      }

      if (!*name)
      {
         const char *start = strstr(line, "\">");
         const char *end   = start ? strstr(start, "</a>") : NULL;

         if (!start || !end)
            return 1;

         memcpy(name, start + 2, end - start - 2);

         *(name + (end - start - 2)) = '\0';
      }
   }

   return 0;
}

./include/libretro-common/net/net_ifinfo.c

/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_ifinfo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <stdio.h>

#include <string/stdstring.h>
#include <net/net_compat.h>

#if defined(_WIN32) && !defined(_XBOX)
#ifdef _MSC_VER
#pragma comment(lib, "Iphlpapi")
#endif

#include <iphlpapi.h>

#elif !defined(VITA) && !defined(GEKKO)
#if defined(WANT_IFADDRS)
#include <compat/ifaddrs.h>
#elif !defined(HAVE_LIBNX) && !defined(_3DS)
#include <ifaddrs.h>
#ifndef WIIU
#include <net/if.h>
#endif
#endif
#endif

#include <net/net_ifinfo.h>

bool net_ifinfo_new(net_ifinfo_t *list)
{
#if defined(_WIN32) && !defined(_XBOX)
   /* Microsoft docs recommend doing it this way. */
   char buf[512];
   ULONG ret;
   PIP_ADAPTER_ADDRESSES addr;
   struct net_ifinfo_entry *entry;
   size_t                interfaces = 0;
   ULONG                 flags      = GAA_FLAG_SKIP_ANYCAST
                                    | GAA_FLAG_SKIP_MULTICAST
                                    | GAA_FLAG_SKIP_DNS_SERVER;
   ULONG                 len        = 15 * 1024;
   PIP_ADAPTER_ADDRESSES addresses  = (PIP_ADAPTER_ADDRESSES)calloc(1, len);

   list->entries                    = NULL;

   if (!addresses)
      goto failure;

   ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addresses, &len);
   if (ret == ERROR_BUFFER_OVERFLOW)
   {
      PIP_ADAPTER_ADDRESSES new_addresses =
         (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);

      if (new_addresses)
      {
         memset(new_addresses, 0, len);

         addresses = new_addresses;
         ret       = GetAdaptersAddresses(AF_UNSPEC, flags, NULL,
            addresses, &len);
      }
   }
   if (ret != ERROR_SUCCESS)
      goto failure;

   /* Count the number of valid interfaces first. */
   addr = addresses;

   do
   {
      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;

      if (!unicast_addr)
         continue;
      if (addr->OperStatus != IfOperStatusUp)
         continue;

      do
      {
         interfaces++;
      } while ((unicast_addr = unicast_addr->Next));
   } while ((addr = addr->Next));

   if (!interfaces)
      goto failure;

   if (!(list->entries =
      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries))))
      goto failure;

   list->size    = 0;
   /* Now create the entries. */
   addr          = addresses;
   entry         = list->entries;

   do
   {
      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;

      if (!unicast_addr)
         continue;
      if (addr->OperStatus != IfOperStatusUp)
         continue;

      buf[0] = '\0';
      if (addr->FriendlyName)
      {
         if (!WideCharToMultiByte(CP_UTF8, 0, addr->FriendlyName, -1,
               buf, sizeof(buf), NULL, NULL))
            buf[0] = '\0'; /* Empty name on conversion failure. */
      }

      do
      {
         if (getnameinfo_retro(unicast_addr->Address.lpSockaddr,
               unicast_addr->Address.iSockaddrLength,
               entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))
            continue;

         strlcpy(entry->name, buf, sizeof(entry->name));

         if (++list->size >= interfaces)
            break;

         entry++;
      } while ((unicast_addr = unicast_addr->Next));

      if (list->size >= interfaces)
         break;
   } while ((addr = addr->Next));

   free(addresses);

   return true;

failure:
   free(addresses);
   net_ifinfo_free(list);

   return false;
#elif defined(VITA)
   SceNetCtlInfo info;
   if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))
   {
      list->size = 0;
      return false;
   }

   strlcpy(list->entries[0].name, "lo",        sizeof(list->entries[0].name));
   strlcpy(list->entries[0].host, "127.0.0.1", sizeof(list->entries[0].host));
   list->size = 1;

   if (!sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &info))
   {
      strlcpy(list->entries[1].name, "wlan", sizeof(list->entries[1].name));
      strlcpy(list->entries[1].host, info.ip_address,
         sizeof(list->entries[1].host));
      list->size++;
   }

   return true;
#elif defined(HAVE_LIBNX) || defined(_3DS) || defined(GEKKO)
   uint32_t addr = 0;
   if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))
   {
      list->size = 0;
      return false;
   }

   strlcpy(list->entries[0].name, "lo", sizeof(list->entries[0].name));
   strlcpy(list->entries[0].host, "127.0.0.1", sizeof(list->entries[0].host));
   list->size = 1;

#if defined(HAVE_LIBNX)
   {
      Result rc = nifmGetCurrentIpAddress(&addr);

      if (!R_SUCCEEDED(rc))
         return true;
   }
#elif defined(_3DS)
   addr = gethostid();
#else
   addr = net_gethostip();
#endif
   if (addr)
   {
      uint8_t *addr8 = (uint8_t*)&addr;
      strlcpy(list->entries[1].name,
#if defined(HAVE_LIBNX)
         "switch"
#elif defined(_3DS)
         "wlan"
#else
         "gekko"
#endif
      , sizeof(list->entries[1].name));
      snprintf(list->entries[1].host, sizeof(list->entries[1].host),
         "%d.%d.%d.%d",
         (int)addr8[0], (int)addr8[1], (int)addr8[2], (int)addr8[3]);
      list->size++;
   }

   return true;
#else
   struct ifaddrs *addr;
   struct net_ifinfo_entry *entry;
   size_t         interfaces = 0;
   struct ifaddrs *addresses = NULL;

   list->entries             = NULL;

   if (getifaddrs(&addresses) || !addresses)
      goto failure;

   /* Count the number of valid interfaces first. */
   addr                      = addresses;

   do
   {
      if (!addr->ifa_addr)
         continue;
#ifndef WIIU
      if (!(addr->ifa_flags & IFF_UP))
         continue;
#endif

      switch (addr->ifa_addr->sa_family)
      {
         case AF_INET:
#ifdef HAVE_INET6
         case AF_INET6:
#endif
            interfaces++;
            break;
         default:
            break;
      }
   } while ((addr = addr->ifa_next));

   if (!interfaces)
      goto failure;

   list->entries =
      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries));
   if (!list->entries)
      goto failure;
   list->size    = 0;

   /* Now create the entries. */
   addr  = addresses;
   entry = list->entries;

   do
   {
      socklen_t addrlen;

      if (!addr->ifa_addr)
         continue;
#ifndef WIIU
      if (!(addr->ifa_flags & IFF_UP))
         continue;
#endif

      switch (addr->ifa_addr->sa_family)
      {
         case AF_INET:
            addrlen = sizeof(struct sockaddr_in);
            break;
#ifdef HAVE_INET6
         case AF_INET6:
            addrlen = sizeof(struct sockaddr_in6);
            break;
#endif
         default:
            continue;
      }

      if (getnameinfo_retro(addr->ifa_addr, addrlen,
            entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))
         continue;

      if (addr->ifa_name)
         strlcpy(entry->name, addr->ifa_name, sizeof(entry->name));

      if (++list->size >= interfaces)
         break;

      entry++;
   } while ((addr = addr->ifa_next));

   freeifaddrs(addresses);

   return true;

failure:
   freeifaddrs(addresses);
   net_ifinfo_free(list);

   return false;
#endif
}

void net_ifinfo_free(net_ifinfo_t *list)
{
   free(list->entries);

   list->entries = NULL;
   list->size    = 0;
}

bool net_ifinfo_best(const char *dst, void *src, bool ipv6)
{
/* TODO/FIXME: Implement for other platforms, if necessary. */
#if defined(_WIN32) && !defined(_XBOX)
   if (!ipv6)
   {
      /* Courtesy of MiniUPnP: https://github.com/miniupnp/miniupnp */
      DWORD index;
#ifdef __WINRT__
      struct sockaddr_in dst_addr = {0};
#endif
      ULONG dst_ip               = (ULONG)inet_addr(dst);

      if (!src)
         return false;
      if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY)
         return false;

#ifdef __WINRT__
      dst_addr.sin_family      = AF_INET;
      dst_addr.sin_addr.s_addr = dst_ip;
      if (GetBestInterfaceEx((struct sockaddr*)&dst_addr, &index) == NO_ERROR)
#else
      if (GetBestInterface(dst_ip, &index) == NO_ERROR)
#endif
      {
         /* Microsoft docs recommend doing it this way. */
         ULONG                 len       = 15 * 1024;
         PIP_ADAPTER_ADDRESSES addresses =
            (PIP_ADAPTER_ADDRESSES)calloc(1, len);

         if (addresses)
         {
            ULONG flags  = GAA_FLAG_SKIP_ANYCAST    | GAA_FLAG_SKIP_MULTICAST
                         | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
            ULONG ret    = GetAdaptersAddresses(AF_INET, flags, NULL,
               addresses, &len);

            if (ret == ERROR_BUFFER_OVERFLOW)
            {
               PIP_ADAPTER_ADDRESSES new_addresses =
                  (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);

               if (new_addresses)
               {
                  memset(new_addresses, 0, len);

                  addresses = new_addresses;
                  ret       = GetAdaptersAddresses(AF_INET, flags, NULL,
                     addresses, &len);
               }
            }

            if (ret == NO_ERROR)
            {
               bool found = false;
               PIP_ADAPTER_ADDRESSES addr = addresses;

               do
               {
                  if (addr->IfIndex == index)
                  {
                     if (addr->FirstUnicastAddress)
                     {
                        struct sockaddr_in *addr_unicast =
                           (struct sockaddr_in*)
                              addr->FirstUnicastAddress->Address.lpSockaddr;

                        memcpy(src, &addr_unicast->sin_addr,
                           sizeof(addr_unicast->sin_addr));

                        found = true;
                     }

                     break;
                  }
               } while ((addr = addr->Next));
               return found;
            }

            free(addresses);
         }
      }
   }
#endif
   return false;
}

./include/libretro-common/net/net_socket.c

/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef _MSC_VER
#include <compat/msvc.h>
#endif

#include <features/features_cpu.h>

#include <net/net_socket.h>

int socket_init(void **address, uint16_t port, const char *server,
      enum socket_type type, int family)
{
   char port_buf[6];
   struct addrinfo hints      = {0};
   struct addrinfo **addrinfo = (struct addrinfo**)address;
   struct addrinfo *addr      = NULL;

   if (!family)
#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
      family = AF_INET;
#else
      family = AF_UNSPEC;
#endif

   hints.ai_family = family;

   switch (type)
   {
      case SOCKET_TYPE_DATAGRAM:
         hints.ai_socktype = SOCK_DGRAM;
         break;
      case SOCKET_TYPE_STREAM:
         hints.ai_socktype = SOCK_STREAM;
         break;
      default:
         return -1;
   }

   if (!server)
      hints.ai_flags = AI_PASSIVE;

   if (!network_init())
      return -1;

   snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
   hints.ai_flags |= AI_NUMERICSERV;

   if (getaddrinfo_retro(server, port_buf, &hints, addrinfo))
      return -1;

   addr = *addrinfo;
   if (!addr)
      return -1;

   return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
}

int socket_next(void **address)
{
   struct addrinfo **addrinfo = (struct addrinfo**)address;
   struct addrinfo *addr      = *addrinfo;

   if ((*addrinfo = addr = addr->ai_next))
      return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);

   return -1;
}

ssize_t socket_receive_all_nonblocking(int fd, bool *err,
      void *data_, size_t len)
{
   ssize_t ret = recv(fd, (char*)data_, len, 0);
   if (ret > 0)
      return ret;
   if (ret < 0 && isagain((int)ret))
      return 0;
   *err = true;
   return -1;
}

bool socket_receive_all_blocking(int fd, void *data_, size_t len)
{
   const uint8_t *data = (const uint8_t*)data_;

   while (len)
   {
      ssize_t ret = recv(fd, (char*)data, len, 0);

      if (!ret)
         return false;

      if (ret < 0)
      {
         if (!isagain((int)ret))
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

bool socket_receive_all_blocking_with_timeout(int fd,
      void *data_, size_t len, int timeout)
{
   const uint8_t *data    = (const uint8_t*)data_;
   retro_time_t  deadline = cpu_features_get_time_usec();

   if (timeout > 0)
      deadline += (retro_time_t)timeout * 1000;
   else
      deadline += 5000000;

   while (len)
   {
      ssize_t ret = recv(fd, (char*)data, len, 0);

      if (!ret)
         return false;

      if (ret < 0)
      {
         int _timeout;
         bool ready = true;

         if (!isagain((int)ret))
            return false;

         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);
         if (_timeout <= 0)
            return false;

         if (!socket_wait(fd, &ready, NULL, _timeout) || !ready)
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

bool socket_set_block(int fd, bool block)
{
#if defined(_WIN32)
   u_long i = !block;

   return !ioctlsocket(fd, FIONBIO, &i);
#elif defined(__PS3__) || defined(VITA) || defined(WIIU)
   int i = !block;

   return !setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(i));
#elif defined(GEKKO)
   u32 i = !block;

   return !net_ioctl(fd, FIONBIO, &i);
#else
   int flags = fcntl(fd, F_GETFL);

   if (block)
      flags &= ~O_NONBLOCK;
   else
      flags |= O_NONBLOCK;

   return !fcntl(fd, F_SETFL, flags);
#endif
}

bool socket_nonblock(int fd)
{
   return socket_set_block(fd, false);
}

int socket_close(int fd)
{
#if defined(_WIN32) && !defined(_XBOX360)
   /* WinSock has headers from the stone age. */
   return closesocket(fd);
#elif defined(__PS3__) || defined(WIIU)
   return socketclose(fd);
#elif defined(VITA)
   return sceNetSocketClose(fd);
#else
   return close(fd);
#endif
}

int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
      fd_set *err_fds, struct timeval *timeout)
{
#if defined(__PS3__)
   return socketselect(nfds, readfds, writefds, err_fds, timeout);
#elif defined(VITA)
   int i, j;
   fd_set rfds, wfds, efds;
   int epoll_fd;
   SceNetEpollEvent *events     = NULL;
   int              event_count = 0;
   int              timeout_us  = -1;
   int              ret         = -1;

   if (nfds < 0 || nfds > 1024)
      return SCE_NET_ERROR_EINVAL;
   if (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))
      return SCE_NET_ERROR_EINVAL;

   epoll_fd = sceNetEpollCreate("socket_select", 0);
   if (epoll_fd < 0)
      return SCE_NET_ERROR_ENOMEM;

   FD_ZERO(&rfds);
   FD_ZERO(&wfds);
   FD_ZERO(&efds);

   for (i = 0; i < nfds; i++)
   {
      if (readfds && FD_ISSET(i, readfds))
         event_count++;
      else if (writefds && FD_ISSET(i, writefds))
         event_count++;
      else if (err_fds && FD_ISSET(i, err_fds))
         event_count++;
   }

#define ALLOC_EVENTS(count) \
   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
   if (!events) \
   { \
      ret = SCE_NET_ERROR_ENOMEM; \
      goto done; \
   }

   if (event_count)
   {
      ALLOC_EVENTS(event_count)

      for (i = 0, j = 0; i < nfds && j < event_count; i++)
      {
         SceNetEpollEvent *event = &events[j];

         if (readfds && FD_ISSET(i, readfds))
            event->events |= SCE_NET_EPOLLIN;
         if (writefds && FD_ISSET(i, writefds))
            event->events |= SCE_NET_EPOLLOUT;

         if (event->events || (err_fds && FD_ISSET(i, err_fds)))
         {
            event->data.fd = i;

            ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
               i, event);
            if (ret < 0)
            {
               switch (ret)
               {
                  case SCE_NET_ERROR_EBADF:
                  case SCE_NET_ERROR_ENOMEM:
                     break;
                  default:
                     ret = SCE_NET_ERROR_EBADF;
                     break;
               }
               goto done;
            }

            j++;
         }
      }

      memset(events, 0, event_count * sizeof(*events));

      /* Keep a copy of the original sets for lookup later. */
      if (readfds)
         memcpy(&rfds, readfds, sizeof(rfds));
      if (writefds)
         memcpy(&wfds, writefds, sizeof(wfds));
      if (err_fds)
         memcpy(&efds, err_fds, sizeof(efds));
   }
   else
   {
      /* Necessary to work with epoll wait. */
      event_count = 1;
      ALLOC_EVENTS(1)
   }

#undef ALLOC_EVENTS

   if (readfds)
      FD_ZERO(readfds);
   if (writefds)
      FD_ZERO(writefds);
   if (err_fds)
      FD_ZERO(err_fds);

   /* Vita's epoll takes a microsecond timeout parameter. */
   if (timeout)
      timeout_us = (int)(timeout->tv_usec + (timeout->tv_sec * 1000000));

   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout_us);
   if (ret <= 0)
      goto done;

#define EPOLL_FD_SET(op, in_set, out_set) \
   if ((event->events & (op)) && FD_ISSET(event->data.fd, (in_set))) \
   { \
      FD_SET(event->data.fd, (out_set)); \
      j++; \
   }

   for (i = 0, j = 0; i < ret; i++)
   {
      SceNetEpollEvent *event = &events[i];

      /* Sanity check */
      if (event->data.fd < 0 || event->data.fd >= nfds)
         continue;

      EPOLL_FD_SET(SCE_NET_EPOLLIN,  &rfds, readfds)
      EPOLL_FD_SET(SCE_NET_EPOLLOUT, &wfds, writefds)
      EPOLL_FD_SET(SCE_NET_EPOLLERR, &efds, err_fds)
   }

   ret = j;

#undef EPOLL_FD_SET

done:
   free(events);
   sceNetEpollDestroy(epoll_fd);

   return ret;
#else
   return select(nfds, readfds, writefds, err_fds, timeout);
#endif
}

#ifdef NETWORK_HAVE_POLL
int socket_poll(struct pollfd *fds, unsigned nfds, int timeout)
{
#if defined(_WIN32)
   return WSAPoll(fds, nfds, timeout);
#elif defined(VITA)
   int i, j;
   int epoll_fd;
   SceNetEpollEvent *events     = NULL;
   int              event_count = (int)nfds;
   int              ret         = -1;

   if (event_count < 0)
      return SCE_NET_ERROR_EINVAL;

   epoll_fd = sceNetEpollCreate("socket_poll", 0);
   if (epoll_fd < 0)
      return SCE_NET_ERROR_ENOMEM;

#define ALLOC_EVENTS(count) \
   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
   if (!events) \
   { \
      ret = SCE_NET_ERROR_ENOMEM; \
      goto done; \
   }

   if (event_count)
   {
      ALLOC_EVENTS(event_count)

      for (i = 0; i < event_count; i++)
      {
         struct pollfd    *fd    = &fds[i];
         SceNetEpollEvent *event = &events[i];

         fd->revents = 0;

         if (fd->fd < 0)
            continue;

         event->events  = fd->events;
         event->data.fd = fd->fd;

         ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
            fd->fd, event);
         if (ret < 0)
            goto done;
      }

      memset(events, 0, event_count * sizeof(*events));
   }
   else
   {
      /* Necessary to work with epoll wait. */
      event_count = 1;
      ALLOC_EVENTS(1)
   }

#undef ALLOC_EVENTS

   /* Vita's epoll takes a microsecond timeout parameter. */
   if (timeout > 0)
      timeout *= 1000;

   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout);
   if (ret <= 0)
      goto done;

   for (i = 0, j = 0; i < ret; i++)
   {
      unsigned k;
      SceNetEpollEvent *event = &events[i];

      /* Sanity check */
      if (event->data.fd < 0)
         continue;

      for (k = 0; k < nfds; k++)
      {
         struct pollfd *fd = &fds[k];

         if (fd->fd == event->data.fd)
         {
            fd->revents = event->events;
            j++;
            break;
         }
      }
   }

   ret = j;

done:
   free(events);
   sceNetEpollDestroy(epoll_fd);

   return ret;
#elif defined(_3DS)
   int i;
   int timeout_quotient;
   int timeout_remainder;
   int ret = -1;

#define TIMEOUT_DIVISOR 100
   if (timeout <= TIMEOUT_DIVISOR)
      return poll(fds, nfds, timeout);

   timeout_quotient = timeout / TIMEOUT_DIVISOR;
   for (i = 0; i < timeout_quotient; i++)
   {
      ret = poll(fds, nfds, TIMEOUT_DIVISOR);
      /* Success or error. */
      if (ret)
         return ret;
   }

   timeout_remainder = timeout % TIMEOUT_DIVISOR;
   if (timeout_remainder)
      ret = poll(fds, nfds, timeout_remainder);

   return ret;
#undef TIMEOUT_DIVISOR

#elif defined(GEKKO)
   return net_poll(fds, nfds, timeout);
#else
   return poll(fds, nfds, timeout);
#endif
}
#endif

bool socket_wait(int fd, bool *rd, bool *wr, int timeout)
{
#ifdef NETWORK_HAVE_POLL
   struct pollfd fds = {0};

   NET_POLL_FD(fd, &fds);

   if (rd && *rd)
   {
      NET_POLL_EVENT(POLLIN, &fds);
      *rd = false;
   }
   if (wr && *wr)
   {
      NET_POLL_EVENT(POLLOUT, &fds);
      *wr = false;
   }

   if (socket_poll(&fds, 1, timeout) < 0)
      return false;

   if (rd && NET_POLL_HAS_EVENT(POLLIN, &fds))
      *rd = true;
   if (wr && NET_POLL_HAS_EVENT(POLLOUT, &fds))
      *wr = true;

   return !NET_POLL_HAS_EVENT((POLLERR | POLLNVAL), &fds);
#else
   fd_set rfd, wfd, efd;
   struct timeval tv, *ptv = NULL;

   FD_ZERO(&rfd);
   FD_ZERO(&wfd);
   FD_ZERO(&efd);

   if (rd && *rd)
   {
      FD_SET(fd, &rfd);
      *rd = false;
   }
   if (wr && *wr)
   {
      FD_SET(fd, &wfd);
      *wr = false;
   }
   FD_SET(fd, &efd);

   if (timeout >= 0)
   {
      tv.tv_sec  = (unsigned)timeout / 1000;
      tv.tv_usec = ((unsigned)timeout % 1000) * 1000;
      ptv = &tv;
   }

   if (socket_select(fd + 1, &rfd, &wfd, &efd, ptv) < 0)
      return false;

   if (rd && FD_ISSET(fd, &rfd))
      *rd = true;
   if (wr && FD_ISSET(fd, &wfd))
      *wr = true;

   return !FD_ISSET(fd, &efd);
#endif
}

bool socket_send_all_blocking(int fd, const void *data_, size_t len,
      bool no_signal)
{
   const uint8_t *data = (const uint8_t*)data_;
   int           flags = no_signal ? MSG_NOSIGNAL : 0;

   while (len)
   {
      ssize_t ret = send(fd, (const char*)data, len, flags);

      if (!ret)
         continue;

      if (ret < 0)
      {
         if (!isagain((int)ret))
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

bool socket_send_all_blocking_with_timeout(int fd,
      const void *data_, size_t len,
      int timeout, bool no_signal)
{
   const uint8_t *data    = (const uint8_t*)data_;
   int           flags    = no_signal ? MSG_NOSIGNAL : 0;
   retro_time_t  deadline = cpu_features_get_time_usec();

   if (timeout > 0)
      deadline += (retro_time_t)timeout * 1000;
   else
      deadline += 5000000;

   while (len)
   {
      ssize_t ret = send(fd, (const char*)data, len, flags);

      if (!ret)
         continue;

      if (ret < 0)
      {
         int _timeout;
         bool ready = true;

         if (!isagain((int)ret))
            return false;

         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);
         if (_timeout <= 0)
            return false;

         if (!socket_wait(fd, NULL, &ready, _timeout) || !ready)
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t len,
      bool no_signal)
{
   const uint8_t *data = (const uint8_t*)data_;
   int           flags = no_signal ? MSG_NOSIGNAL : 0;

   while (len)
   {
      ssize_t ret = send(fd, (const char*)data, len, flags);

      if (!ret)
         break;

      if (ret < 0)
      {
         if (isagain((int)ret))
            break;

         return -1;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return (ssize_t)((size_t)data - (size_t)data_);
}

bool socket_bind(int fd, void *data)
{
   struct addrinfo *addr = (struct addrinfo*)data;

   {
      int on = 1;

      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
         (char*)&on, sizeof(on));
   }

   return !bind(fd, addr->ai_addr, addr->ai_addrlen);
}

int socket_connect(int fd, void *data)
{
   struct addrinfo *addr = (struct addrinfo*)data;

#ifdef WIIU
   {
      int op = 1;

      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));

      if (addr->ai_socktype == SOCK_STREAM)
      {
         int recvsz = WIIU_RCVBUF;
         int sendsz = WIIU_SNDBUF;

         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));
         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));
      }
   }
#endif

   return connect(fd, addr->ai_addr, addr->ai_addrlen);
}

bool socket_connect_with_timeout(int fd, void *data, int timeout)
{
   int res;
   struct addrinfo *addr = (struct addrinfo*)data;

   if (!socket_nonblock(fd))
      return false;

#ifdef WIIU
   {
      int op = 1;

      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));

      if (addr->ai_socktype == SOCK_STREAM)
      {
         int recvsz = WIIU_RCVBUF;
         int sendsz = WIIU_SNDBUF;

         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));
         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));
      }
   }
#endif

   res = connect(fd, addr->ai_addr, addr->ai_addrlen);
   if (res)
   {
      bool ready = true;

      if (!isinprogress(res) && !isagain(res))
         return false;

      if (timeout <= 0)
         timeout = 5000;

      if (!socket_wait(fd, NULL, &ready, timeout) || !ready)
         return false;
   }

#if defined(GEKKO)
   /* libogc does not have getsockopt implemented */
   res = connect(fd, addr->ai_addr, addr->ai_addrlen);
   if (res < 0 && -res != EISCONN)
      return false;
#elif defined(_3DS)
   /* libctru getsockopt does not return expected value */
   if ((connect(fd, addr->ai_addr, addr->ai_addrlen) < 0) && errno != EISCONN)
      return false;
#elif defined(WIIU)
   /* On WiiU, getsockopt() returns -1 and sets lastsocketerr() (Wii's
    * equivalent to errno) to 16. */
   if ((connect(fd, addr->ai_addr, addr->ai_addrlen) == -1)
         && socketlasterr() != SO_EISCONN)
      return false;
#else
   {
      int       err = -1;
      socklen_t errsz = sizeof(err);

      getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&err, &errsz);
      if (err)
         return false;
   }
#endif

   return true;
}

int socket_create(
      const char *name,
      enum socket_domain   domain_type,
      enum socket_type     socket_type,
      enum socket_protocol protocol_type)
{
   int domain   = 0;
   int type     = 0;
   int protocol = 0;

   switch (domain_type)
   {
      case SOCKET_DOMAIN_INET:
         domain = AF_INET;
         break;
      default:
         break;
   }

   switch (socket_type)
   {
      case SOCKET_TYPE_DATAGRAM:
         type = SOCK_DGRAM;
         break;
      case SOCKET_TYPE_STREAM:
         type = SOCK_STREAM;
         break;
      case SOCKET_TYPE_SEQPACKET:
      default:
         /* TODO/FIXME - implement */
         break;
   }

   switch (protocol_type)
   {
      case SOCKET_PROTOCOL_TCP:
         protocol = IPPROTO_TCP;
         break;
      case SOCKET_PROTOCOL_UDP:
         protocol = IPPROTO_UDP;
         break;
      case SOCKET_PROTOCOL_NONE:
      default:
         break;
   }

#ifdef VITA
   return sceNetSocket(name, domain, type, protocol);
#else
   return socket(domain, type, protocol);
#endif
}

void socket_set_target(void *data, socket_target_t *in_addr)
{
   struct sockaddr_in *out_target = (struct sockaddr_in*)data;

#ifdef GEKKO
   out_target->sin_len          = 8;
#endif
   switch (in_addr->domain)
   {
      case SOCKET_DOMAIN_INET:
         out_target->sin_family = AF_INET;
         break;
      default:
         out_target->sin_family = 0;
         break;
   }
   out_target->sin_port         = htons(in_addr->port);
   inet_pton(AF_INET, in_addr->server, &out_target->sin_addr);
}

./include/libretro-common/net/net_socket_ssl_bear.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <net/net_socket_ssl.h>
#include <net/net_socket.h>
#include <encodings/base64.h>
#include <streams/file_stream.h>
#include <string/stdstring.h>

#include "../../deps/bearssl-0.6/inc/bearssl.h"

struct ssl_state
{
   int fd;
   br_ssl_client_context sc;
   br_x509_minimal_context xc;
   uint8_t iobuf[BR_SSL_BUFSIZE_BIDI];
};

/* TODO/FIXME - static global variables */
static br_x509_trust_anchor TAs[500] = {};
static size_t TAs_NUM = 0;

static uint8_t* current_vdn;
static size_t current_vdn_size;

static uint8_t* blobdup(const void * src, size_t len)
{
   uint8_t *ret = (uint8_t*)malloc(len);
   memcpy(ret, src, len);
   return ret;
}
static void vdn_append(void* dest_ctx, const void * src, size_t len)
{
   current_vdn = (uint8_t*)realloc(current_vdn, current_vdn_size + len);
   memcpy(current_vdn + current_vdn_size, src, len);
   current_vdn_size += len;
}

static bool append_cert_x509(void* x509, size_t len)
{
   br_x509_pkey* pk;
   br_x509_decoder_context dc;
   br_x509_trust_anchor* ta = &TAs[TAs_NUM];

   current_vdn              = NULL;
   current_vdn_size         = 0;

   br_x509_decoder_init(&dc, vdn_append, NULL);
   br_x509_decoder_push(&dc, x509, len);
   pk                       = br_x509_decoder_get_pkey(&dc);
   if (!pk || !br_x509_decoder_isCA(&dc))
      return false;

   ta->dn.len               = current_vdn_size;
   ta->dn.data              = current_vdn;
   ta->flags                = BR_X509_TA_CA;

   switch (pk->key_type)
   {
      case BR_KEYTYPE_RSA:
         ta->pkey.key_type     = BR_KEYTYPE_RSA;
         ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;
         ta->pkey.key.rsa.n    = blobdup(pk->key.rsa.n, pk->key.rsa.nlen);
         ta->pkey.key.rsa.elen = pk->key.rsa.elen;
         ta->pkey.key.rsa.e    = blobdup(pk->key.rsa.e, pk->key.rsa.elen);
         break;
      case BR_KEYTYPE_EC:
         ta->pkey.key_type     = BR_KEYTYPE_EC;
         ta->pkey.key.ec.curve = pk->key.ec.curve;
         ta->pkey.key.ec.qlen  = pk->key.ec.qlen;
         ta->pkey.key.ec.q     = blobdup(pk->key.ec.q, pk->key.ec.qlen);
         break;
      default:
         return false;
   }

   TAs_NUM++;
   return true;
}

static char* delete_linebreaks(char* in)
{
   char* iter_in;
   char* iter_out;
   while (*in == '\n')
      in++;

   iter_in = in;

   while (*iter_in != '\n' && *iter_in != '\0')
      iter_in++;
   iter_out = iter_in;
   while (*iter_in != '\0')
   {
      while (*iter_in == '\n')
         iter_in++;
      *iter_out++ = *iter_in++;
   }

   return in;
}

/* this rearranges its input, it's easier to implement
 * that way and caller doesn't need it anymore anyways */
static void append_certs_pem_x509(char * certs_pem)
{
   void * cert_bin;
   int cert_bin_len;
   char *cert     = certs_pem;
   char *cert_end = certs_pem;

   for (;;)
   {
      cert      = strstr(cert_end, "-----BEGIN CERTIFICATE-----");
      if (!cert)
         break;
      cert     += STRLEN_CONST("-----BEGIN CERTIFICATE-----");
      cert_end  = strstr(cert, "-----END CERTIFICATE-----");

      *cert_end = '\0';
      cert      = delete_linebreaks(cert);

      cert_bin  = unbase64(cert, cert_end-cert, &cert_bin_len);
      append_cert_x509(cert_bin, cert_bin_len);
      free(cert_bin);

      cert_end++; /* skip the NUL we just added */
   }
}

/* TODO: not thread safe, rthreads doesn't provide any
 * statically allocatable mutex/etc */
static void initialize(void)
{
   void* certs_pem;
   if (TAs_NUM)
      return;
   /* filestream_read_file appends a NUL */
   filestream_read_file("/etc/ssl/certs/ca-certificates.crt", &certs_pem, NULL);
   append_certs_pem_x509((char*)certs_pem);
   free(certs_pem);
}

void* ssl_socket_init(int fd, const char *domain)
{
   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));

   initialize();

   br_ssl_client_init_full(&state->sc, &state->xc, TAs, TAs_NUM);
   br_ssl_engine_set_buffer(&state->sc.eng,
         state->iobuf, sizeof(state->iobuf), true);
   br_ssl_client_reset(&state->sc, domain, false);

   state->fd = fd;
   return state;
}

static bool process_inner(struct ssl_state *state, bool blocking)
{
   bool dummy;
   size_t buflen;
   ssize_t bytes;
   uint8_t *buf = br_ssl_engine_sendrec_buf(&state->sc.eng, &buflen);

   if (buflen)
   {
      if (blocking)
         bytes = (socket_send_all_blocking(state->fd, buf, buflen, true)
               ? buflen
               : -1);
      else
         bytes = socket_send_all_nonblocking(state->fd, buf, buflen, true);

      if (bytes > 0)
         br_ssl_engine_sendrec_ack(&state->sc.eng, bytes);
      if (bytes < 0)
         return false;
      /* if we did something, return immediately so we
       * don't try to read if Bear still wants to send */
      return true;
   }

   buf = br_ssl_engine_recvrec_buf(&state->sc.eng, &buflen);
   if (buflen)
   {
      /* if the socket is blocking, socket_receive_all_nonblocking blocks,
       * but only to read at least 1 byte which is exactly what we want */
      bytes = socket_receive_all_nonblocking(state->fd, &dummy, buf, buflen);
      if (bytes > 0)
         br_ssl_engine_recvrec_ack(&state->sc.eng, bytes);
      if (bytes < 0)
         return false;
   }

   return true;
}

int ssl_socket_connect(void *state_data,
      void *data, bool timeout_enable, bool nonblock)
{
   struct ssl_state *state = (struct ssl_state*)state_data;
   unsigned bearstate;

   if (timeout_enable)
   {
      if (!socket_connect_with_timeout(state->fd, data, 5000))
         return -1;
      /* socket_connect_with_timeout makes the socket non-blocking. */
      if (!socket_set_block(state->fd, true))
         return -1;
   }
   else
   {
      if (socket_connect(state->fd, data))
         return -1;
   }

   for (;;)
   {
      if (!process_inner(state, true))
         return -1;

      bearstate = br_ssl_engine_current_state(&state->sc.eng);
      if (bearstate & BR_SSL_SENDAPP)
         break; /* handshake done */
      if (bearstate & BR_SSL_CLOSED)
         return -1; /* failed */
   }

   return 1;
}

ssize_t ssl_socket_receive_all_nonblocking(void *state_data,
      bool *err, void *data_, size_t len)
{
   size_t __len;
   uint8_t *bear_data;
   struct ssl_state *state = (struct ssl_state*)state_data;
   socket_set_block(state->fd, false);
   if (!process_inner(state, false))
   {
      *err = true;
      return -1;
   }
   bear_data = br_ssl_engine_recvapp_buf(&state->sc.eng, &__len);
   if (__len > len)
      __len = len;
   memcpy(data_, bear_data, __len);
   if (__len)
      br_ssl_engine_recvapp_ack(&state->sc.eng, __len);
   return __len;
}

int ssl_socket_receive_all_blocking(void *state_data,
      void *data_, size_t len)
{
   size_t __len;
   struct ssl_state *state = (struct ssl_state*)state_data;
   uint8_t           *data = (uint8_t*)data_;
   uint8_t *         bear_data;

   socket_set_block(state->fd, true);

   for (;;)
   {
      bear_data = br_ssl_engine_recvapp_buf(&state->sc.eng, &__len);
      if (__len > len)
         __len = len;
      memcpy(data, bear_data, __len);
      if (__len)
         br_ssl_engine_recvapp_ack(&state->sc.eng, __len);
      data += __len;
      len -= __len;

      if (len)
         process_inner(state, true);
      else
         break;
   }
   return 1;
}

int ssl_socket_send_all_blocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   size_t __len;
   struct ssl_state *state = (struct ssl_state*)state_data;
   const     uint8_t *data = (const uint8_t*)data_;
   uint8_t *         bear_data;

   socket_set_block(state->fd, true);

   for (;;)
   {
      bear_data = br_ssl_engine_sendapp_buf(&state->sc.eng, &__len);
      if (__len > len)
         __len = len;
      memcpy(bear_data, data_, __len);
      if (__len)
         br_ssl_engine_sendapp_ack(&state->sc.eng, __len);
      data += __len;
      len  -= __len;

      if (len)
         process_inner(state, true);
      else
         break;
   }

   br_ssl_engine_flush(&state->sc.eng, false);
   process_inner(state, false);
   return 1;
}

ssize_t ssl_socket_send_all_nonblocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   size_t __len;
   uint8_t *bear_data;
   struct ssl_state *state = (struct ssl_state*)state_data;

   socket_set_block(state->fd, false);
   bear_data = br_ssl_engine_sendapp_buf(&state->sc.eng, &__len);
   if (__len > len)
      __len = len;
   memcpy(bear_data, data_, __len);
   if (__len)
   {
      br_ssl_engine_sendapp_ack(&state->sc.eng, __len);
      br_ssl_engine_flush(&state->sc.eng, false);
   }
   if (!process_inner(state, false))
      return -1;
   return __len;
}

void ssl_socket_close(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;

   br_ssl_engine_close(&state->sc.eng);
   process_inner(state, false); /* send close notification */
   socket_close(state->fd);     /* but immediately close socket
                                   and don't worry about recipient
                                   getting our message */
}

void ssl_socket_free(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;
   /* BearSSL does zero allocations of its own,
    * so other than this struct, there is nothing to free */
   free(state);
}

./include/libretro-common/net/net_socket_ssl_mbed.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>
#include <net/net_compat.h>
#include <net/net_socket.h>
#include <net/net_socket_ssl.h>

#ifdef _3DS
#include <3ds/types.h>
#include <3ds/services/ps.h>
#endif

#if defined(HAVE_BUILTINMBEDTLS)
#include "../../deps/mbedtls/mbedtls/config.h"
#include "../../deps/mbedtls/mbedtls/certs.h"
#include "../../deps/mbedtls/mbedtls/debug.h"
#include "../../deps/mbedtls/mbedtls/platform.h"
#include "../../deps/mbedtls/mbedtls/net_sockets.h"
#include "../../deps/mbedtls/mbedtls/ssl.h"
#include "../../deps/mbedtls/mbedtls/ctr_drbg.h"
#include "../../deps/mbedtls/mbedtls/entropy.h"
#else
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_MAJOR < 3
#include <mbedtls/config.h>
#include <mbedtls/certs.h>
#else
#include <mbedtls/build_info.h>
#endif
#include <mbedtls/debug.h>
#include <mbedtls/platform.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#endif

/* Not part of the mbedtls upstream source */
#include "cacert.h"

#define DEBUG_LEVEL 0

struct ssl_state
{
   mbedtls_net_context net_ctx;
   mbedtls_ssl_context ctx;
   mbedtls_entropy_context entropy;
   mbedtls_ctr_drbg_context ctr_drbg;
   mbedtls_ssl_config conf;
#if defined(MBEDTLS_X509_CRT_PARSE_C)
   mbedtls_x509_crt ca;
#endif
  const char *domain;
};

static void ssl_debug(void *ctx, int level,
      const char *file, int line,
      const char *str)
{
   fprintf((FILE*)ctx, "%s:%04d: %s", file, line, str);
   fflush((FILE*)ctx);
}

#ifdef _3DS
int ctr_entropy_func(void *data, unsigned char *s, size_t len)
{
   (void)data;
   PS_GenerateRandomBytes(s, len);
   return 0;
}
#endif

void* ssl_socket_init(int fd, const char *domain)
{
   static const char *pers = "libretro";
   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));

   state->domain           = domain;

#if defined(MBEDTLS_DEBUG_C)
   mbedtls_debug_set_threshold(DEBUG_LEVEL);
#endif

   mbedtls_net_init(&state->net_ctx);
   mbedtls_ssl_init(&state->ctx);
   mbedtls_ssl_config_init(&state->conf);
#if defined(MBEDTLS_X509_CRT_PARSE_C)
   mbedtls_x509_crt_init(&state->ca);
#endif
   mbedtls_ctr_drbg_init(&state->ctr_drbg);
   mbedtls_entropy_init(&state->entropy);

   state->net_ctx.fd = fd;

   if (mbedtls_ctr_drbg_seed(&state->ctr_drbg,
#ifdef _3DS
      ctr_entropy_func,
#else
      mbedtls_entropy_func,
#endif
      &state->entropy, (const unsigned char*)pers, strlen(pers)) != 0)
      goto error;

#if defined(MBEDTLS_X509_CRT_PARSE_C)
   if (mbedtls_x509_crt_parse(&state->ca, (const unsigned char*)cacert_pem, sizeof(cacert_pem) / sizeof(cacert_pem[0])) < 0)
      goto error;
#endif

   return state;

error:
   if (state)
      free(state);
   return NULL;
}

int ssl_socket_connect(void *state_data,
      void *data, bool timeout_enable, bool nonblock)
{
   int ret, flags;
   struct ssl_state *state = (struct ssl_state*)state_data;

   if (timeout_enable)
   {
      if (!socket_connect_with_timeout(state->net_ctx.fd, data, 5000))
         return -1;
      /* socket_connect_with_timeout makes the socket non-blocking. */
      if (!socket_set_block(state->net_ctx.fd, true))
         return -1;
   }
   else
   {
      if (socket_connect(state->net_ctx.fd, data))
         return -1;
   }

   if (mbedtls_ssl_config_defaults(&state->conf,
               MBEDTLS_SSL_IS_CLIENT,
               MBEDTLS_SSL_TRANSPORT_STREAM,
               MBEDTLS_SSL_PRESET_DEFAULT) != 0)
      return -1;

   mbedtls_ssl_conf_authmode(&state->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
   mbedtls_ssl_conf_ca_chain(&state->conf, &state->ca, NULL);
   mbedtls_ssl_conf_rng(&state->conf, mbedtls_ctr_drbg_random, &state->ctr_drbg);
   mbedtls_ssl_conf_dbg(&state->conf, ssl_debug, stderr);

   if (mbedtls_ssl_setup(&state->ctx, &state->conf) != 0)
      return -1;

#if defined(MBEDTLS_X509_CRT_PARSE_C)
   if (mbedtls_ssl_set_hostname(&state->ctx, state->domain) != 0)
      return -1;
#endif

   mbedtls_ssl_set_bio(&state->ctx, &state->net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL);

   while ((ret = mbedtls_ssl_handshake(&state->ctx)) != 0)
   {
      if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
         return -1;
   }

   if ((flags = mbedtls_ssl_get_verify_result(&state->ctx)) != 0)
   {
      char vrfy_buf[512];
      mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
   }

   return state->net_ctx.fd;
}

ssize_t ssl_socket_receive_all_nonblocking(void *state_data,
      bool *err, void *data_, size_t len)
{
   ssize_t ret;
   struct ssl_state *state = (struct ssl_state*)state_data;
   unsigned char     *data = (unsigned char*)data_;
   size_t       total_read = 0;
   int      max_iterations = 8;  /* Limit iterations to prevent infinite loops */

   mbedtls_net_set_nonblock(&state->net_ctx);

   /* Keep reading while we get data without blocking, up to max iterations
    * This allows us to read multiple TLS records (16KB each) in one call */
   while (len > 0 && max_iterations-- > 0)
   {
      ret = mbedtls_ssl_read(&state->ctx, data, len);

      if (ret > 0)
      {
         total_read += ret;
         data += ret;
         len -= ret;

         /* If we read less than requested, there's likely no more data available
          * But check if there's buffered data we can read without blocking */
         if ((size_t)ret < len)
         {
            size_t bytes_avail = mbedtls_ssl_get_bytes_avail(&state->ctx);
            if (bytes_avail == 0)

               break;  /* No more buffered data, don't risk blocking */
         }
         /* Continue looping to read more records */
      }
      else if (ret == 0)
      {
         /* Socket closed */
         if (total_read > 0)
            return total_read;  /* Return what we got before close */
         *err = true;
         return -1;
      }
      else if (isagain((int)ret) || ret == MBEDTLS_ERR_SSL_WANT_READ)
      {
         /* Would block - return what we have so far */
         if (total_read > 0)
            return total_read;
         return 0;  /* No data available yet */
      }
      else
      {
         /* Error */
         if (total_read > 0)
            return total_read;  /* Return what we got before error */
         *err = true;
         return -1;
      }
   }

   return total_read;
}

int ssl_socket_receive_all_blocking(void *state_data,
      void *data_, size_t len)
{
   struct ssl_state *state = (struct ssl_state*)state_data;
   const uint8_t     *data = (const uint8_t*)data_;

   mbedtls_net_set_block(&state->net_ctx);

   for (;;)
   {
      /* mbedtls_ssl_read wants non-const data but it only reads it,
       * so this cast is safe */
      int ret = mbedtls_ssl_read(&state->ctx, (unsigned char*)data, len);

      if (     ret == MBEDTLS_ERR_SSL_WANT_READ
            || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
         continue;

      if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
         break;

      if (ret == 0)
         break; /* normal EOF */

      if (ret < 0)
         return -1;
   }

   return 1;
}

int ssl_socket_send_all_blocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   int ret;
   struct ssl_state *state = (struct ssl_state*)state_data;
   const     uint8_t *data = (const uint8_t*)data_;

   mbedtls_net_set_block(&state->net_ctx);

   while (len)
   {
      ret = mbedtls_ssl_write(&state->ctx, data, len);

      if (!ret)
         continue;

      if (ret < 0)
      {
         if (  ret != MBEDTLS_ERR_SSL_WANT_READ &&
              ret != MBEDTLS_ERR_SSL_WANT_WRITE)
            return false;
      }
      else
      {
          data += ret;
          len  -= ret;
      }
   }

   return true;
}

ssize_t ssl_socket_send_all_nonblocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   int ret;
   ssize_t __len = len;
   struct ssl_state *state = (struct ssl_state*)state_data;
   const uint8_t     *data = (const uint8_t*)data_;
   mbedtls_net_set_nonblock(&state->net_ctx);
   ret = mbedtls_ssl_write(&state->ctx, data, len);
   if (ret <= 0)
      return -1;
   return __len;
}

void ssl_socket_close(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;

   mbedtls_ssl_close_notify(&state->ctx);

   socket_close(state->net_ctx.fd);
}

void ssl_socket_free(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;

   if (!state)
      return;

   mbedtls_ssl_free(&state->ctx);
   mbedtls_ssl_config_free(&state->conf);
   mbedtls_ctr_drbg_free(&state->ctr_drbg);
   mbedtls_entropy_free(&state->entropy);
#if defined(MBEDTLS_X509_CRT_PARSE_C)
   mbedtls_x509_crt_free(&state->ca);
#endif

   free(state);
}

./include/libretro-common/playlists/label_sanitization.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (label_sanitization.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <playlists/label_sanitization.h>
#include <compat/strl.h>
#include <retro_miscellaneous.h>
#include <string/stdstring.h>
#include <string.h>

#define DISC_STRINGS_LENGTH   5
#define REGION_STRINGS_LENGTH 20

const char *disc_strings[DISC_STRINGS_LENGTH] = {
   "(CD",
   "(Disc",
   "(Disk",
   "(Side",
   "(Tape"
};

/*
 * We'll use the standard No-Intro regions for now.
 */
const char *region_strings[REGION_STRINGS_LENGTH] = {
   "(Australia)", /* Don’t use with Europe */
   "(Brazil)",
   "(Canada)",    /* Don’t use with USA */
   "(China)",
   "(France)",
   "(Germany)",
   "(Hong Kong)",
   "(Italy)",
   "(Japan)",
   "(Korea)",
   "(Netherlands)",
   "(Spain)",
   "(Sweden)",
   "(USA)",       /* Includes Canada */
   "(World)",
   "(Europe)",    /* Includes Australia */
   "(Asia)",
   "(Japan, USA)",
   "(Japan, Europe)",
   "(USA, Europe)"
};

/**
 * label_sanitize:
 *
 * NOTE: Does not work with nested blocks.
 **/
void label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*))
{
   bool copy = true;
   int rindex = 0;
   int lindex = 0;
   char new_label[PATH_MAX_LENGTH];

   for (; lindex < PATH_MAX_LENGTH && label[lindex] != '\0'; lindex++)
   {
      if (copy)
      {
         /* check for the start of the range */
         if ((*left)(&label[lindex]))
            copy                = false;
         else
         {
            const bool whitespace = label[lindex] == ' ' && (rindex == 0 || new_label[rindex - 1] == ' ');

            /* Simplify consecutive whitespaces */
            if (!whitespace)
               new_label[rindex++] = label[lindex];
         }
      }
      else if ((*right)(&label[lindex]))
         copy = true;
   }

   /* Trim trailing whitespace */
   if (rindex > 0 && new_label[rindex - 1] == ' ')
      new_label[rindex - 1] = '\0';
   else
      new_label[rindex] = '\0';

   strlcpy(label, new_label, PATH_MAX_LENGTH);
}

static bool left_parens(char *left)
{
   return left[0] == '(';
}

static bool right_parens(char *right)
{
   return right[0] == ')';
}

static bool left_brackets(char *left)
{
   return left[0] == '[';
}

static bool right_brackets(char *right)
{
   return right[0] == ']';
}

static bool left_parens_or_brackets(char *left)
{
   return left[0] == '(' || left[0] == '[';
}

static bool right_parens_or_brackets(char *right)
{
   return right[0] == ')' || right[0] == ']';
}

static bool left_exclusion(char *left,
      const char **strings, const size_t strings_count)
{
   unsigned i;
   char exclusion_string[32];
   char comparison_string[32];

   strlcpy(exclusion_string, left, sizeof(exclusion_string));
   string_to_upper(exclusion_string);

   for (i = 0; i < (unsigned)strings_count; i++)
   {
      strlcpy(comparison_string, strings[i], sizeof(comparison_string));
      string_to_upper(comparison_string);

      if (string_starts_with(exclusion_string,
               comparison_string))
         return true;
   }

   return false;
}

static bool left_parens_or_brackets_excluding_region(char *left)
{
   return left_parens_or_brackets(left)
      && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH);
}

static bool left_parens_or_brackets_excluding_disc(char *left)
{
   return left_parens_or_brackets(left)
      && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
}

static bool left_parens_or_brackets_excluding_region_or_disc(char *left)
{
   return left_parens_or_brackets(left)
      && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH)
      && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
}

void label_remove_parens(char *label)
{
   label_sanitize(label, left_parens, right_parens);
}

void label_remove_brackets(char *label)
{
   label_sanitize(label, left_brackets, right_brackets);
}

void label_remove_parens_and_brackets(char *label)
{
   label_sanitize(label, left_parens_or_brackets,
         right_parens_or_brackets);
}

void label_keep_region(char *label)
{
   label_sanitize(label, left_parens_or_brackets_excluding_region,
         right_parens_or_brackets);
}

void label_keep_disc(char *label)
{
   label_sanitize(label, left_parens_or_brackets_excluding_disc,
         right_parens_or_brackets);
}

void label_keep_region_and_disc(char *label)
{
   label_sanitize(label, left_parens_or_brackets_excluding_region_or_disc,
         right_parens_or_brackets);
}

./include/libretro-common/queues/fifo_queue.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fifo_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <retro_common_api.h>
#include <retro_inline.h>
#include <boolean.h>

#include <queues/fifo_queue.h>

static bool fifo_initialize_internal(fifo_buffer_t *buf, size_t len)
{
   uint8_t *buffer    = (uint8_t*)calloc(1, len + 1);

   if (!buffer)
      return false;

   buf->buffer        = buffer;
   buf->size          = len + 1;
   buf->first         = 0;
   buf->end           = 0;

   return true;
}

bool fifo_initialize(fifo_buffer_t *buf, size_t len)
{
   return (buf && fifo_initialize_internal(buf, len));
}

void fifo_free(fifo_buffer_t *buffer)
{
   if (!buffer)
      return;

   free(buffer->buffer);
   free(buffer);
}

bool fifo_deinitialize(fifo_buffer_t *buffer)
{
   if (!buffer)
      return false;

   if (buffer->buffer)
      free(buffer->buffer);
   buffer->buffer = NULL;
   buffer->size   = 0;
   buffer->first  = 0;
   buffer->end    = 0;

   return true;
}

fifo_buffer_t *fifo_new(size_t len)
{
   fifo_buffer_t *buf = (fifo_buffer_t*)malloc(sizeof(*buf));

   if (!buf)
      return NULL;

   if (!fifo_initialize_internal(buf, len))
   {
      free(buf);
      return NULL;
   }

   return buf;
}

void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len)
{
   size_t first_write = len;
   size_t rest_write  = 0;

   if (buffer->end + len > buffer->size)
   {
      first_write = buffer->size - buffer->end;
      rest_write  = len - first_write;
   }

   memcpy(buffer->buffer + buffer->end, in_buf, first_write);
   if (rest_write > 0)
      memcpy(buffer->buffer, (const uint8_t*)in_buf + first_write, rest_write);

   buffer->end = (buffer->end + len) % buffer->size;
}

void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t len)
{
   size_t first_read = len;
   size_t rest_read  = 0;

   if (buffer->first + len > buffer->size)
   {
      first_read = buffer->size - buffer->first;
      rest_read  = len - first_read;
   }

   memcpy(in_buf, (const uint8_t*)buffer->buffer + buffer->first, first_read);
   if (rest_read > 0)
      memcpy((uint8_t*)in_buf + first_read, buffer->buffer, rest_read);

   buffer->first = (buffer->first + len) % buffer->size;
}

./include/libretro-common/queues/generic_queue.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (generic_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <boolean.h>
#include <stddef.h>
#include <stdlib.h>

#include <queues/generic_queue.h>

struct generic_queue_item_t
{
   void *value;
   struct generic_queue_item_t *previous;
   struct generic_queue_item_t *next;
};

struct generic_queue
{
   struct generic_queue_item_t *first_item;
   struct generic_queue_item_t *last_item;
   size_t length;
};

struct generic_queue_iterator
{
   generic_queue_t *queue;
   struct generic_queue_item_t *item;
   bool forward;
};

generic_queue_t *generic_queue_new(void)
{
   return (generic_queue_t *)calloc(1, sizeof(generic_queue_t));
}

void generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value))
{
   struct generic_queue_item_t *next_item;

   if (!queue)
      return;

   while (queue->first_item)
   {
      if (free_value)
         free_value(queue->first_item->value);

      next_item = queue->first_item->next;
      free(queue->first_item);
      queue->first_item = next_item;
   }

   free(queue);
}

void generic_queue_push(generic_queue_t *queue, void *value)
{
   struct generic_queue_item_t *new_item;

   new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t));
   new_item->value = value;
   new_item->previous = queue->last_item;
   new_item->next = NULL;

   queue->last_item = new_item;
   queue->length++;

   if (!queue->first_item)
      queue->first_item = new_item;
   else
      new_item->previous->next = new_item;
}

void *generic_queue_pop(generic_queue_t *queue)
{
   void *value;
   struct generic_queue_item_t *item;

   if (!queue || !queue->last_item)
      return NULL;

   item = queue->last_item;
   queue->last_item = queue->last_item->previous;
   queue->length--;

   if (queue->length == 0)
      queue->first_item = NULL;

   value = item->value;
   free(item);

   return value;
}

void *generic_queue_peek(generic_queue_t *queue)
{
   if (!queue || !queue->last_item)
      return NULL;

   return queue->last_item->value;
}

void *generic_queue_peek_first(generic_queue_t *queue)
{
   if (!queue || !queue->first_item)
      return NULL;

   return queue->first_item->value;
}

void generic_queue_shift(generic_queue_t *queue, void *value)
{
   struct generic_queue_item_t *new_item;

   if (!queue)
      return;

   new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t));
   new_item->value = value;
   new_item->previous = NULL;
   new_item->next = queue->first_item;

   queue->first_item = new_item;
   queue->length++;

   if (!queue->last_item)
      queue->last_item = new_item;
   else
      new_item->next->previous = new_item;
}

void *generic_queue_unshift(generic_queue_t *queue)
{
   void *value;
   struct generic_queue_item_t *item;

   if (!queue || !queue->first_item)
      return NULL;

   item = queue->first_item;
   queue->first_item = queue->first_item->next;
   queue->length--;

   if (queue->length == 0)
      queue->last_item = NULL;

   value = item->value;
   free(item);

   return value;
}

size_t generic_queue_length(generic_queue_t *queue)
{
   if (queue)
      return queue->length;

   return 0;
}

void *generic_queue_remove(generic_queue_t *queue, void *value)
{
   struct generic_queue_item_t *item;

   if (!queue)
      return NULL;

   for (item = queue->first_item; item; item = item->next)
   {
      if (item->value == value)
      {
         if (item->previous)
            item->previous->next = item->next;
         else
            queue->first_item = item->next;

         if (item->next)
            item->next->previous = item->previous;
         else
            queue->last_item = item->previous;

         free(item);
         queue->length--;

         return value;
      }
   }

   return NULL;
}

generic_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward)
{
   if (queue && queue->first_item)
   {
      generic_queue_iterator_t *iterator;

      iterator = (generic_queue_iterator_t *)malloc(sizeof(generic_queue_iterator_t));
      iterator->queue = queue;
      iterator->item = forward ? queue->first_item : queue->last_item;
      iterator->forward = forward;

      return iterator;
   }

   return NULL;
}

generic_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator)
{
   if (iterator)
   {
      struct generic_queue_item_t *item;

      item = iterator->forward ? iterator->item->next : iterator->item->previous;
      if (item)
      {
         iterator->item = item;
         return iterator;
      } else
      {
         free(iterator);
         return NULL;
      }
   }

   return NULL;
}

void *generic_queue_iterator_value(generic_queue_iterator_t *iterator)
{
   if (iterator)
      return iterator->item->value;

   return NULL;
}

generic_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator)
{
   struct generic_queue_item_t *item;

   if (!iterator)
      return NULL;

   item = iterator->forward ? iterator->queue->first_item : iterator->queue->last_item;
   while (item)
   {
      if (iterator->item == item)
      {
         if (iterator->queue->first_item == item)
            iterator->queue->first_item = item->next;
         else
            item->previous->next = item->next;

         if (iterator->queue->last_item == item)
            iterator->queue->last_item = item->previous;
         else
            item->next->previous = item->previous;

         iterator->queue->length--;

         iterator->item = iterator->forward ? item->next : item->previous;
         free(item);
         if (iterator->item)
            return iterator;
         free(iterator);
         return NULL;
      }

      item = iterator->forward ? item->next : item->previous;
   }

   return iterator;
}

void generic_queue_iterator_free(generic_queue_iterator_t *iterator)
{
   if (iterator)
      free(iterator);
}

./include/libretro-common/queues/message_queue.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (message_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <boolean.h>
#include <queues/message_queue.h>
#include <compat/strl.h>
#include <compat/posix_string.h>

bool msg_queue_initialize(msg_queue_t *queue, size_t len)
{
   struct queue_elem **elems = NULL;

   if (!queue)
      return false;

   if (!(elems = (struct queue_elem**)
            calloc(len + 1, sizeof(struct queue_elem*))))
      return false;

   queue->tmp_msg            = NULL;
   queue->elems              = elems;
   queue->ptr                = 1;
   queue->size               = len + 1;

   return true;
}

/**
 * msg_queue_new:
 * @len              : maximum size of message
 *
 * Creates a message queue with maximum size different messages.
 *
 * Returns: NULL if allocation error, pointer to a message queue
 * if successful. Has to be freed manually.
 **/
msg_queue_t *msg_queue_new(size_t len)
{
   msg_queue_t *queue = (msg_queue_t*)malloc(sizeof(*queue));

   if (!msg_queue_initialize(queue, len))
   {
      if (queue)
         free(queue);
      return NULL;
   }

   return queue;
}

/**
 * msg_queue_free:
 * @queue             : pointer to queue object
 *
 * Frees message queue..
 **/
void msg_queue_free(msg_queue_t *queue)
{
   if (!queue)
      return;
   msg_queue_clear(queue);
   free(queue->elems);
   free(queue);
}

bool msg_queue_deinitialize(msg_queue_t *queue)
{
   if (!queue)
      return false;
   msg_queue_clear(queue);
   free(queue->elems);
   queue->elems   = NULL;
   queue->tmp_msg = NULL;
   queue->ptr     = 0;
   queue->size    = 0;
   return true;
}

/**
 * msg_queue_push:
 * @queue             : pointer to queue object
 * @msg               : message to add to the queue
 * @prio              : priority level of the message
 * @duration          : how many times the message can be pulled
 *                      before it vanishes (E.g. show a message for
 *                      3 seconds @ 60fps = 180 duration).
 *
 * Push a new message onto the queue.
 **/
void msg_queue_push(msg_queue_t *queue, const char *msg,
      unsigned prio, unsigned duration,
      char *title,
      enum message_queue_icon icon, enum message_queue_category category)
{
   size_t tmp_ptr = 0;
   struct queue_elem *new_elem = NULL;

   if (!queue || queue->ptr >= queue->size)
      return;

   if (!(new_elem = (struct queue_elem*)malloc(sizeof(struct queue_elem))))
      return;

   new_elem->duration            = duration;
   new_elem->prio                = prio;
   new_elem->msg                 = msg   ? strdup(msg)   : NULL;
   new_elem->title               = title ? strdup(title) : NULL;
   new_elem->icon                = icon;
   new_elem->category            = category;

   queue->elems[queue->ptr]      = new_elem;

   tmp_ptr                       = queue->ptr++;

   while (tmp_ptr > 1)
   {
      struct queue_elem *parent  = queue->elems[tmp_ptr >> 1];
      struct queue_elem *child   = queue->elems[tmp_ptr];

      if (child->prio <= parent->prio)
         break;

      queue->elems[tmp_ptr >> 1] = child;
      queue->elems[tmp_ptr]      = parent;

      tmp_ptr >>= 1;
   }
}

/**
 * msg_queue_clear:
 * @queue             : pointer to queue object
 *
 * Clears out everything in the queue.
 **/
void msg_queue_clear(msg_queue_t *queue)
{
   size_t i;

   if (!queue)
      return;

   for (i = 1; i < queue->ptr; i++)
   {
      if (queue->elems[i])
      {
         free(queue->elems[i]->msg);
         free(queue->elems[i]->title);
         free(queue->elems[i]);
         queue->elems[i] = NULL;
      }
   }
   queue->ptr     = 1;
   free(queue->tmp_msg);
   queue->tmp_msg = NULL;
}

/**
 * msg_queue_pull:
 * @queue             : pointer to queue object
 *
 * Pulls highest priority message in queue.
 *
 * Returns: NULL if no message in queue, otherwise a string
 * containing the message.
 **/
const char *msg_queue_pull(msg_queue_t *queue)
{
   struct queue_elem *front  = NULL, *last = NULL;
   size_t tmp_ptr = 1;

   /* Nothing in queue. */
   if (!queue || queue->ptr == 1)
      return NULL;

   front = (struct queue_elem*)queue->elems[1];
   front->duration--;
   if (front->duration > 0)
      return front->msg;

   free(queue->tmp_msg);
   queue->tmp_msg = front->msg;
   front->msg = NULL;

   last  = (struct queue_elem*)queue->elems[--queue->ptr];
   queue->elems[1] = last;
   free(front->title);
   free(front);

   for (;;)
   {
      struct queue_elem *parent = NULL;
      struct queue_elem *child  = NULL;
      size_t switch_index       = tmp_ptr;
      bool left                 = (tmp_ptr * 2 <= queue->ptr)
         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);
      bool right                = (tmp_ptr * 2 + 1 <= queue->ptr)
         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);

      if (!left && !right)
         break;

      if (left && !right)
         switch_index <<= 1;
      else if (right && !left)
         switch_index += switch_index + 1;
      else
      {
         if (queue->elems[tmp_ptr * 2]
               >= queue->elems[tmp_ptr * 2 + 1])
            switch_index <<= 1;
         else
            switch_index += switch_index + 1;
      }

      parent = (struct queue_elem*)queue->elems[tmp_ptr];
      child  = (struct queue_elem*)queue->elems[switch_index];
      queue->elems[tmp_ptr]      = child;
      queue->elems[switch_index] = parent;
      tmp_ptr                    = switch_index;
   }

   return queue->tmp_msg;
}

/**
 * msg_queue_extract:
 * @queue             : pointer to queue object
 * @queue_entry       : pointer to external queue entry struct
 *
 * Removes highest priority message from queue, copying
 * contents into queue_entry struct.
 *
 * Returns: false if no messages in queue, otherwise true
 **/
bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry)
{
   struct queue_elem *front  = NULL, *last = NULL;
   size_t tmp_ptr = 1;

   /* Ensure arguments are valid and queue is not
    * empty */
   if (!queue || queue->ptr == 1 || !queue_entry)
      return false;

   front = (struct queue_elem*)queue->elems[1];
   last  = (struct queue_elem*)queue->elems[--queue->ptr];
   queue->elems[1] = last;

   /* Copy element parameters */
   queue_entry->duration = front->duration;
   queue_entry->prio     = front->prio;
   queue_entry->icon     = front->icon;
   queue_entry->category = front->category;
   queue_entry->msg[0]   = '\0';
   queue_entry->title[0] = '\0';

   if (front->msg)
      strlcpy(queue_entry->msg, front->msg, sizeof(queue_entry->msg));

   if (front->title)
      strlcpy(queue_entry->title, front->title, sizeof(queue_entry->title));

   /* Delete element */
   free(front->msg);
   free(front->title);
   free(front);

   for (;;)
   {
      struct queue_elem *parent = NULL;
      struct queue_elem *child  = NULL;
      size_t switch_index       = tmp_ptr;
      bool left                 = (tmp_ptr * 2 <= queue->ptr)
         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);
      bool right                = (tmp_ptr * 2 + 1 <= queue->ptr)
         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);

      if (!left && !right)
         break;

      if (left && !right)
         switch_index <<= 1;
      else if (right && !left)
         switch_index += switch_index + 1;
      else
      {
         if (queue->elems[tmp_ptr * 2]
               >= queue->elems[tmp_ptr * 2 + 1])
            switch_index <<= 1;
         else
            switch_index += switch_index + 1;
      }

      parent = (struct queue_elem*)queue->elems[tmp_ptr];
      child  = (struct queue_elem*)queue->elems[switch_index];
      queue->elems[tmp_ptr]      = child;
      queue->elems[switch_index] = parent;
      tmp_ptr                    = switch_index;
   }

   return true;
}

/**
 * msg_queue_size:
 * @queue             : pointer to queue object
 *
 * Fetches number of messages in queue.
 *
 * Returns: Number of messages in queue.
 **/
size_t msg_queue_size(msg_queue_t *queue)
{
   if (!queue || queue->ptr <= 1)
      return 0;

   return queue->ptr - 1;
}

./include/libretro-common/queues/task_queue.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (task_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <queues/task_queue.h>

#include <features/features_cpu.h>

#if defined(HAVE_GCD) && !defined(HAVE_THREADS)
#error "gcd uses threads, what are you doing"
#endif

#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#endif
#if defined(EMSCRIPTEN) || defined(_3DS)
#include <retro_timers.h>
#endif
#ifdef HAVE_GCD
#include <dispatch/dispatch.h>
#endif

typedef struct
{
   retro_task_t *front;
   retro_task_t *back;
} task_queue_t;

struct retro_task_impl
{
   retro_task_queue_msg_t msg_push;
   void (*push_running)(retro_task_t *);
   void (*cancel)(void *);
   void (*reset)(void);
   void (*wait)(retro_task_condition_fn_t, void *);
   void (*gather)(void);
   bool (*find)(retro_task_finder_t, void*);
   void (*retrieve)(task_retriever_data_t *data);
   void (*init)(void);
   void (*deinit)(void);
};

/* TODO/FIXME - static globals */
static retro_task_queue_msg_t msg_push_bak  = NULL;
static task_queue_t tasks_running           = {NULL, NULL};
static task_queue_t tasks_finished          = {NULL, NULL};

static struct retro_task_impl *impl_current = NULL;
static bool task_threaded_enable            = false;

#ifdef HAVE_THREADS
static uintptr_t main_thread_id             = 0;
static slock_t *running_lock                = NULL;
static slock_t *finished_lock               = NULL;
static slock_t *property_lock               = NULL;
static slock_t *queue_lock                  = NULL;
static scond_t *worker_cond                 = NULL;
static sthread_t *worker_thread             = NULL;
static bool worker_continue                 = true;
/* use running_lock when touching it */
#endif

#ifdef HAVE_GCD
static unsigned gcd_queue_count             = 0;
#endif

static void task_queue_msg_push(retro_task_t *task,
      unsigned prio, unsigned duration,
      bool flush, const char *fmt, ...)
{
   char buf[1024];
   va_list ap;

   buf[0] = '\0';

   va_start(ap, fmt);
   vsnprintf(buf, sizeof(buf), fmt, ap);
   va_end(ap);

   if (impl_current->msg_push)
      impl_current->msg_push(task, buf, prio, duration, flush);
}

static void task_queue_push_progress(retro_task_t *task)
{
#ifdef HAVE_THREADS
   /* msg_push callback interacts directly with the task properties (particularly title).
    * make sure another thread doesn't modify them while rendering
    */
   slock_lock(property_lock);
#endif

   if (task->title && (!((task->flags & RETRO_TASK_FLG_MUTE) > 0)))
   {
      if ((task->flags & RETRO_TASK_FLG_FINISHED) > 0)
      {
         if (task->error)
            task_queue_msg_push(task, 1, 60, true, "%s: %s",
               "Task failed", task->title);
         else
            task_queue_msg_push(task, 1, 60, false, "100%%: %s", task->title);
      }
      else
      {
         if (task->progress >= 0 && task->progress <= 100)
            task_queue_msg_push(task, 1, 60, true, "%i%%: %s",
                  task->progress, task->title);
         else
            task_queue_msg_push(task, 1, 60, false, "%s...", task->title);
      }

      if (task->progress_cb)
         task->progress_cb(task);
   }

#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

static void task_queue_put(task_queue_t *queue, retro_task_t *task)
{
   task->next                   = NULL;

   if (queue->front)
   {
      /* Make sure to insert in order - the queue is
       * sorted by 'when' so items that aren't scheduled
       * to run immediately are at the back of the queue.
       * Items with the same 'when' are inserted after
       * all the other items with the same 'when'.
       * This primarily affects items with a 'when' of 0.
       */
      if (queue->back)
      {
         if (queue->back->when > task->when)
         {
            retro_task_t** prev = &queue->front;
            while (*prev && (*prev)->when <= task->when)
               prev             = &((*prev)->next);

            task->next          = *prev;
            *prev               = task;
            return;
         }

         queue->back->next      = task;
      }
   }
   else
      queue->front              = task;

   queue->back                  = task;
}

static retro_task_t *task_queue_get(task_queue_t *queue)
{
   retro_task_t *task = queue->front;

   if (task)
   {
      queue->front = task->next;
      task->next   = NULL;
   }

   return task;
}

static void retro_task_internal_gather(void)
{
   retro_task_t *task = NULL;
   while ((task = task_queue_get(&tasks_finished)))
   {
      task_queue_push_progress(task);

      if (task->callback)
         task->callback(task, task->task_data, task->user_data, task->error);

      if (task->cleanup)
          task->cleanup(task);

      if (task->error)
         free(task->error);

      if (task->title)
         free(task->title);

      free(task);
   }
}

static void retro_task_regular_push_running(retro_task_t *task)
{
   task_queue_put(&tasks_running, task);
}

static void retro_task_regular_cancel(void *task)
{
   retro_task_t *t = (retro_task_t*)task;
   t->flags       |= RETRO_TASK_FLG_CANCELLED;
}

static void retro_task_regular_gather(void)
{
   retro_task_t *task  = NULL;
   retro_task_t *queue = NULL;
   retro_task_t *next  = NULL;

   while ((task = task_queue_get(&tasks_running)))
   {
      task->next = queue;
      queue = task;
   }

   for (task = queue; task; task = next)
   {
      next = task->next;

      if (!task->when || task->when < cpu_features_get_time_usec())
      {
         task->handler(task);

         task_queue_push_progress(task);
      }

      if ((task->flags & RETRO_TASK_FLG_FINISHED) > 0)
         task_queue_put(&tasks_finished, task);
      else
         task_queue_put(&tasks_running, task);
   }

   retro_task_internal_gather();
}

static void retro_task_regular_wait(retro_task_condition_fn_t cond, void* data)
{
   while ((tasks_running.front && !tasks_running.front->when) && (!cond || cond(data)))
      retro_task_regular_gather();
}

static void retro_task_regular_reset(void)
{
   retro_task_t *task = tasks_running.front;

   for (; task; task = task->next)
      task->flags |= RETRO_TASK_FLG_CANCELLED;
}

static void retro_task_regular_init(void) { }
static void retro_task_regular_deinit(void) { }

static bool retro_task_regular_find(retro_task_finder_t func, void *user_data)
{
   retro_task_t *task = tasks_running.front;

   for (; task; task = task->next)
   {
      if (func(task, user_data))
         return true;
   }

   return false;
}

static void retro_task_regular_retrieve(task_retriever_data_t *data)
{
   retro_task_t *task          = NULL;
   task_retriever_info_t *tail = NULL;

   /* Parse all running tasks and handle matching handlers */
   for (task = tasks_running.front; task != NULL; task = task->next)
   {
      task_retriever_info_t *info = NULL;
      if (task->handler != data->handler)
         continue;

      /* Create new link */
      info       = (task_retriever_info_t*)
         malloc(sizeof(task_retriever_info_t));
      info->data = malloc(data->element_size);
      info->next = NULL;

      /* Call retriever function and fill info-specific data */
      if (!data->func(task, info->data))
      {
         free(info->data);
         free(info);
         continue;
      }

      /* Add link to list */
      if (data->list)
      {
         if (tail)
         {
            tail->next = info;
            tail       = tail->next;
         }
         else
            tail       = info;
      }
      else
      {
         data->list    = info;
         tail          = data->list;
      }
   }
}

static struct retro_task_impl impl_regular = {
   NULL,
   retro_task_regular_push_running,
   retro_task_regular_cancel,
   retro_task_regular_reset,
   retro_task_regular_wait,
   retro_task_regular_gather,
   retro_task_regular_find,
   retro_task_regular_retrieve,
   retro_task_regular_init,
   retro_task_regular_deinit
};

#ifdef HAVE_THREADS

/* 'queue_lock' must be held for the duration of this function */
static void task_queue_remove(task_queue_t *queue, retro_task_t *task)
{
   retro_task_t     *t = NULL;
   retro_task_t *front = queue->front;

   /* Remove first element if needed */
   if (task == front)
   {
      queue->front     = task->next;
      if (queue->back == task) /* if only element, also update back */
         queue->back   = NULL;
      task->next       = NULL;
      return;
   }

   /* Parse queue */
   t = front;

   while (t && t->next)
   {
      /* Remove task and update queue */
      if (t->next == task)
      {
         t->next    = task->next;
         task->next = NULL;

         /* When removing the tail of the queue, update the tail pointer */
         if (queue->back == task)
         {
            if (queue->back == task)
               queue->back = t;
         }
         break;
      }

      /* Update iterator */
      t = t->next;
   }
}

static void retro_task_threaded_push_running(retro_task_t *task)
{
   slock_lock(running_lock);
   slock_lock(queue_lock);
   task_queue_put(&tasks_running, task);
   scond_signal(worker_cond);
   slock_unlock(queue_lock);
   slock_unlock(running_lock);
}

static void retro_task_threaded_cancel(void *task)
{
   retro_task_t *t;

   slock_lock(running_lock);

   for (t = tasks_running.front; t; t = t->next)
   {
      if (t == task)
      {
        t->flags |= RETRO_TASK_FLG_CANCELLED;
        break;
      }
   }

   slock_unlock(running_lock);
}

static void retro_task_threaded_gather(void)
{
   retro_task_t *task = NULL;

   slock_lock(running_lock);
   for (task = tasks_running.front; task; task = task->next)
      task_queue_push_progress(task);
   slock_unlock(running_lock);

   slock_lock(finished_lock);
   retro_task_internal_gather();
   slock_unlock(finished_lock);
}

static void retro_task_threaded_wait(retro_task_condition_fn_t cond, void* data)
{
   bool wait = false;

   do
   {
      retro_task_threaded_gather();

      slock_lock(running_lock);
      wait = (tasks_running.front && !tasks_running.front->when);
      slock_unlock(running_lock);

      if (!wait)
      {
         slock_lock(finished_lock);
         wait = (tasks_finished.front && !tasks_finished.front->when);
         slock_unlock(finished_lock);
      }
   } while (wait && (!cond || cond(data)));
}

static void retro_task_threaded_reset(void)
{
   retro_task_t *task = NULL;

   slock_lock(running_lock);
   for (task = tasks_running.front; task; task = task->next)
      task->flags |= RETRO_TASK_FLG_CANCELLED;
   slock_unlock(running_lock);
}

static bool retro_task_threaded_find(
      retro_task_finder_t func, void *user_data)
{
   retro_task_t *task = NULL;
   bool ret = false;

   slock_lock(running_lock);
   for (task = tasks_running.front; task; task = task->next)
   {
      if (func(task, user_data))
      {
         ret = true;
         break;
      }
   }
   slock_unlock(running_lock);

   return ret;
}

static void retro_task_threaded_retrieve(task_retriever_data_t *data)
{
   /* Protect access to running tasks */
   slock_lock(running_lock);
   /* Call regular retrieve function */
   retro_task_regular_retrieve(data);
   /* Release access to running tasks */
   slock_unlock(running_lock);
}

static void threaded_worker(void *userdata)
{
   for (;;)
   {
      retro_task_t *task  = NULL;
      bool       finished = false;

      slock_lock(running_lock);

      if (!worker_continue)
      {
         slock_unlock(running_lock);
         break; /* should we keep running until all tasks finished? */
      }

      /* Get first task to run */
      if (!(task = tasks_running.front))
      {
         scond_wait(worker_cond, running_lock);
         slock_unlock(running_lock);
         continue;
      }

      if (task->when)
      {
         retro_time_t now   = cpu_features_get_time_usec();
         retro_time_t delay = task->when - now - 500; /* allow half a millisecond for context switching */
         if (delay > 0)
         {
            scond_wait_timeout(worker_cond, running_lock, delay);
            slock_unlock(running_lock);
            continue;
         }
      }

      slock_unlock(running_lock);
      task->handler(task);
#if defined(EMSCRIPTEN) || defined(_3DS)
      /* Workaround emscripten pthread bug where not parking the
         thread will prevent other important stuff from
         happening. Maybe due to lack of signals implementation in
         emscripten's pthreads?  */
      retro_sleep(1);
#endif

      slock_lock(property_lock);
      finished = ((task->flags & RETRO_TASK_FLG_FINISHED) > 0) ? true : false;
      slock_unlock(property_lock);

      /* Update queue */
      if (!finished)
      {
         /* Move the task to the back of the queue */
         /* mimics retro_task_threaded_push_running,
          * but also includes a task_queue_remove */
         slock_lock(running_lock);
         slock_lock(queue_lock);

         /* do nothing if only item in queue */
         if (task->next)
         {
            task_queue_remove(&tasks_running, task);
            task_queue_put(&tasks_running, task);
            scond_signal(worker_cond);
         }
         slock_unlock(queue_lock);
         slock_unlock(running_lock);
      }
      else
      {
         /* Remove task from running queue */
         slock_lock(running_lock);
         slock_lock(queue_lock);
         task_queue_remove(&tasks_running, task);
         slock_unlock(queue_lock);
         slock_unlock(running_lock);

         /* Add task to finished queue */
         slock_lock(finished_lock);
         task_queue_put(&tasks_finished, task);
         slock_unlock(finished_lock);
      }
   }
}

static void retro_task_threaded_init(void)
{
   running_lock    = slock_new();
   finished_lock   = slock_new();
   property_lock   = slock_new();
   queue_lock      = slock_new();
   worker_cond     = scond_new();

   slock_lock(running_lock);
   worker_continue = true;
   slock_unlock(running_lock);

   worker_thread   = sthread_create(threaded_worker, NULL);
}

static void retro_task_threaded_deinit(void)
{
   slock_lock(running_lock);
   worker_continue = false;
   scond_signal(worker_cond);
   slock_unlock(running_lock);

   sthread_join(worker_thread);

   scond_free(worker_cond);
   slock_free(running_lock);
   slock_free(finished_lock);
   slock_free(property_lock);
   slock_free(queue_lock);

   worker_thread   = NULL;
   worker_cond     = NULL;
   running_lock    = NULL;
   finished_lock   = NULL;
   property_lock   = NULL;
   queue_lock      = NULL;
}

static struct retro_task_impl impl_threaded = {
   NULL,
   retro_task_threaded_push_running,
   retro_task_threaded_cancel,
   retro_task_threaded_reset,
   retro_task_threaded_wait,
   retro_task_threaded_gather,
   retro_task_threaded_find,
   retro_task_threaded_retrieve,
   retro_task_threaded_init,
   retro_task_threaded_deinit
};
#endif

#ifdef HAVE_GCD

static void gcd_worker(retro_task_t *task)
{
   bool       finished = false;
   slock_lock(running_lock);

   if (!worker_continue)
   {
      gcd_queue_count--;
      if (!gcd_queue_count)
         scond_signal(worker_cond);
      slock_unlock(running_lock);
      return;
   }

   if (task->when)
   {
      retro_time_t now   = cpu_features_get_time_usec();
      retro_time_t delay = task->when - now - 500;
      if (delay > 0)
      {
         dispatch_time_t after = dispatch_time(DISPATCH_TIME_NOW, delay);
         dispatch_after(after, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                        ^{ gcd_worker(task); });
         slock_unlock(running_lock);
         return;
      }
   }

   slock_unlock(running_lock);

   task->handler(task);

   slock_lock(property_lock);
   finished = ((task->flags & RETRO_TASK_FLG_FINISHED) > 0) ? true : false;
   slock_unlock(property_lock);

   if (!finished)
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                     ^{ gcd_worker(task); });
   else
   {
      /* Remove task from running queue */
      slock_lock(running_lock);
      slock_lock(queue_lock);
      gcd_queue_count--;
      if (!gcd_queue_count)
         scond_signal(worker_cond);
      task_queue_remove(&tasks_running, task);
      slock_unlock(queue_lock);
      slock_unlock(running_lock);

      /* Add task to finished queue */
      slock_lock(finished_lock);
      task_queue_put(&tasks_finished, task);
      slock_unlock(finished_lock);
   }
}

static void retro_task_gcd_push_running(retro_task_t *task)
{
   slock_lock(running_lock);
   slock_lock(queue_lock);
   task_queue_put(&tasks_running, task);
   gcd_queue_count++;
   dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                  ^{ gcd_worker(task); });
   slock_unlock(queue_lock);
   slock_unlock(running_lock);
}

static void retro_task_gcd_wait(retro_task_condition_fn_t cond, void* data)
{
   bool wait = false;

   do
   {
      retro_task_t *task = NULL;
      retro_task_threaded_gather();

      slock_lock(running_lock);
      wait = false;
      /* can't just look at the first task like threaded, they're not sorted by when */
      for (task = tasks_running.front; !wait && task; task = task->next)
         wait |= !task->when;
      slock_unlock(running_lock);

      if (!wait)
      {
         slock_lock(finished_lock);
         for (task = tasks_finished.front; !wait && task; task = task->next)
            wait |= !task->when;
         slock_unlock(finished_lock);
      }
   } while (wait && (!cond || cond(data)));
}

static void retro_task_gcd_init(void)
{
   retro_task_t *task = NULL;

   running_lock    = slock_new();
   finished_lock   = slock_new();
   property_lock   = slock_new();
   queue_lock      = slock_new();
   worker_cond     = scond_new();

   slock_lock(running_lock);
   worker_continue = true;
   for (task = tasks_running.front; task; task = task->next)
   {
      gcd_queue_count++;
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                     ^{ gcd_worker(task); });
   };
   slock_unlock(running_lock);
}

static void retro_task_gcd_deinit(void)
{
   slock_lock(running_lock);
   worker_continue = false;
   if (gcd_queue_count)
      scond_wait(worker_cond, running_lock);
   slock_unlock(running_lock);

   scond_free(worker_cond);
   slock_free(running_lock);
   slock_free(finished_lock);
   slock_free(property_lock);
   slock_free(queue_lock);

   worker_cond     = NULL;
   running_lock    = NULL;
   finished_lock   = NULL;
   property_lock   = NULL;
   queue_lock      = NULL;
}

static struct retro_task_impl impl_gcd = {
   NULL,
   retro_task_gcd_push_running,
   retro_task_threaded_cancel,
   retro_task_threaded_reset,
   retro_task_gcd_wait,
   retro_task_threaded_gather,
   retro_task_threaded_find,
   retro_task_threaded_retrieve,
   retro_task_gcd_init,
   retro_task_gcd_deinit
};
#endif

/* Deinitializes the task system.
 * This deinitializes the task system.
 * The tasks that are running at
 * the moment will stay on hold */
void task_queue_deinit(void)
{
   if (impl_current)
      impl_current->deinit();
   impl_current = NULL;
}

void task_queue_init(bool threaded, retro_task_queue_msg_t msg_push)
{
   impl_current   = &impl_regular;
#ifdef HAVE_THREADS
   main_thread_id = sthread_get_current_thread_id();
   if (threaded)
   {
      task_threaded_enable = true;
#ifdef HAVE_GCD
      impl_current         = &impl_gcd;
#else
      impl_current         = &impl_threaded;
#endif
   }
#endif

   msg_push_bak            = msg_push;

   impl_current->msg_push  = msg_push;
   impl_current->init();
}

void task_queue_set_threaded(void)
{
   task_threaded_enable = true;
}

void task_queue_unset_threaded(void)
{
   task_threaded_enable = false;
}

bool task_queue_is_threaded(void)
{
   return task_threaded_enable;
}

bool task_queue_find(task_finder_data_t *find_data)
{
   return impl_current->find(find_data->func, find_data->userdata);
}

void task_queue_retrieve(task_retriever_data_t *data)
{
   impl_current->retrieve(data);
}

void task_queue_check(void)
{
#ifdef HAVE_THREADS
   bool current_threaded = (impl_current != &impl_regular);
   bool want_threaded    = task_threaded_enable;

   if (want_threaded != current_threaded)
      task_queue_deinit();

   if (!impl_current)
      task_queue_init(want_threaded, msg_push_bak);
#endif

   impl_current->gather();
}

bool task_queue_push(retro_task_t *task)
{
   /* Ignore this task if a related one is already running */
   if (task->type == TASK_TYPE_BLOCKING)
   {
      retro_task_t *running = NULL;
      bool            found = false;

#ifdef HAVE_THREADS
      slock_lock(queue_lock);
#endif
      running = tasks_running.front;

      for (; running; running = running->next)
      {
         if (running->type == TASK_TYPE_BLOCKING)
         {
            found = true;
            break;
         }
      }

#ifdef HAVE_THREADS
      slock_unlock(queue_lock);
#endif

      /* skip this task, user must try again later */
      if (found)
         return false;
   }

   /* The lack of NULL checks in the following functions
    * is proposital to ensure correct control flow by the users. */
   impl_current->push_running(task);

   return true;
}

void task_queue_wait(retro_task_condition_fn_t cond, void* data)
{
   impl_current->wait(cond, data);
}

void task_queue_reset(void)
{
   impl_current->reset();
}

/**
 * Signals a task to end without waiting for
 * it to complete. */
void task_queue_cancel_task(void *task)
{
   impl_current->cancel(task);
}

void *task_queue_retriever_info_next(task_retriever_info_t **link)
{
   /* Grab data and move to next link */
   if (*link)
   {
      *link = (*link)->next;
      return (*link)->data;
   }
   return NULL;
}

void task_queue_retriever_info_free(task_retriever_info_t *list)
{
   task_retriever_info_t *info;

   /* Free links including retriever-specific data */
   while (list)
   {
      info = list->next;
      free(list->data);
      free(list);
      list = info;
   }
}

bool task_is_on_main_thread(void)
{
#ifdef HAVE_THREADS
   return sthread_get_current_thread_id() == main_thread_id;
#else
   return true;
#endif
}

void task_set_error(retro_task_t *task, char *err)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   task->error = err;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void task_set_progress(retro_task_t *task, int8_t progress)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   task->progress = progress;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void task_set_title(retro_task_t *task, char *title)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   task->title = title;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void task_set_data(retro_task_t *task, void *data)
{
#ifdef HAVE_THREADS
   slock_lock(running_lock);
#endif
   task->task_data = data;
#ifdef HAVE_THREADS
   slock_unlock(running_lock);
#endif
}

void task_free_title(retro_task_t *task)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   if (task->title)
      free(task->title);
   task->title = NULL;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void* task_get_data(retro_task_t *task)
{
   void *data = NULL;

#ifdef HAVE_THREADS
   slock_lock(running_lock);
#endif
   data = task->task_data;
#ifdef HAVE_THREADS
   slock_unlock(running_lock);
#endif

   return data;
}

void task_set_flags(retro_task_t *task, uint8_t flags, bool set)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   if (set)
      task->flags |=  (flags);
   else
      task->flags &= ~(flags);
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

uint8_t task_get_flags(retro_task_t *task)
{
   uint8_t _flags = 0;
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   _flags = task->flags;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
   return _flags;
}

char* task_get_error(retro_task_t *task)
{
   char *s = NULL;
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   s = task->error;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
   return s;
}

int8_t task_get_progress(retro_task_t *task)
{
   int8_t progress = 0;

#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   progress = task->progress;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif

   return progress;
}

char* task_get_title(retro_task_t *task)
{
   char *title = NULL;

#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   title = task->title;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif

   return title;
}

retro_task_t *task_init(void)
{
   /* TODO/FIXME - static local global */
   static uint32_t task_count = 0;
   retro_task_t *task         = (retro_task_t*)malloc(sizeof(*task));

   if (!task)
      return NULL;

   task->handler           = NULL;
   task->callback          = NULL;
   task->cleanup           = NULL;
   task->flags             = 0;
   task->task_data         = NULL;
   task->user_data         = NULL;
   task->state             = NULL;
   task->error             = NULL;
   task->progress          = 0;
   task->progress_cb       = NULL;
   task->title             = NULL;
   task->type              = TASK_TYPE_NONE;
   task->style             = TASK_STYLE_NONE;
   task->ident             = task_count++;
   task->frontend_userdata = NULL;
   task->next              = NULL;
   task->when              = 0;

   return task;
}

./include/libretro-common/rthreads/ctr_pthread.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gx_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _CTR_PTHREAD_WRAP_CTR_
#define _CTR_PTHREAD_WRAP_CTR_

#include <3ds/thread.h>
#include <3ds/synchronization.h>
#include <3ds/svc.h>
#include <3ds/services/apt.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <retro_inline.h>

#define STACKSIZE (32 * 1024)

#ifndef PTHREAD_SCOPE_PROCESS
/* An earlier version of devkitARM does not define the pthread types. Can remove in r54+. */

typedef Thread     pthread_t;
typedef LightLock  pthread_mutex_t;
typedef void*      pthread_mutexattr_t;
typedef int        pthread_attr_t;
typedef uint32_t   pthread_cond_t;
typedef int        pthread_condattr_t;
#endif

#ifndef USE_CTRULIB_2
/* Backported CondVar API from libctru 2.0, and under its license:
   https://github.com/devkitPro/libctru
   Slightly modified for compatibility with older libctru. */

typedef s32 CondVar;

static INLINE Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value)
{
   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, 0);
}

static INLINE Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns)
{
   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, timeout_ns);
}

static INLINE void __dmb(void)
{
	__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
}

static INLINE void CondVar_BeginWait(CondVar* cv, LightLock* lock)
{
	s32 val;
	do
		val = __ldrex(cv) - 1;
	while (__strex(cv, val));
	LightLock_Unlock(lock);
}

static INLINE bool CondVar_EndWait(CondVar* cv, s32 num_threads)
{
	bool hasWaiters;
	s32 val;

	do {
		val = __ldrex(cv);
		hasWaiters = val < 0;
		if (hasWaiters)
		{
			if (num_threads < 0)
				val = 0;
			else if (val <= -num_threads)
				val += num_threads;
			else
				val = 0;
		}
	} while (__strex(cv, val));

	return hasWaiters;
}

static INLINE void CondVar_Init(CondVar* cv)
{
	*cv = 0;
}

static INLINE void CondVar_Wait(CondVar* cv, LightLock* lock)
{
	CondVar_BeginWait(cv, lock);
	syncArbitrateAddress(cv, ARBITRATION_WAIT_IF_LESS_THAN, 0);
	LightLock_Lock(lock);
}

static INLINE int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns)
{
	CondVar_BeginWait(cv, lock);

	bool timedOut = false;
	Result rc = syncArbitrateAddressWithTimeout(cv, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, timeout_ns);
	if (R_DESCRIPTION(rc) == RD_TIMEOUT)
	{
		timedOut = CondVar_EndWait(cv, 1);
		__dmb();
	}

	LightLock_Lock(lock);
	return timedOut;
}

static INLINE void CondVar_WakeUp(CondVar* cv, s32 num_threads)
{
	__dmb();
	if (CondVar_EndWait(cv, num_threads))
		syncArbitrateAddress(cv, ARBITRATION_SIGNAL, num_threads);
	else
		__dmb();
}

static INLINE void CondVar_Signal(CondVar* cv)
{
	CondVar_WakeUp(cv, 1);
}

static INLINE void CondVar_Broadcast(CondVar* cv)
{
	CondVar_WakeUp(cv, ARBITRATION_SIGNAL_ALL);
}
/* End libctru 2.0 backport */
#endif

/* libctru threads return void but pthreads return void pointer */
static bool mutex_inited = false;
static LightLock safe_double_thread_launch;
static void *(*start_routine_jump)(void*);

static void ctr_thread_launcher(void* data)
{
	void *(*start_routine_jump_safe)(void*) = start_routine_jump;
	LightLock_Unlock(&safe_double_thread_launch);
	start_routine_jump_safe(data);
}

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   s32 prio = 0;
   Thread new_ctr_thread;
   int procnum = -2; /* use default cpu */
   bool isNew3DS;

   APT_CheckNew3DS(&isNew3DS);

   if (isNew3DS)
      procnum = 2;

   if (!mutex_inited)
   {
      LightLock_Init(&safe_double_thread_launch);
      mutex_inited = true;
   }

   /* Must wait if attempting to launch 2 threads at once to prevent corruption of function pointer*/
   while (LightLock_TryLock(&safe_double_thread_launch) != 0);

   svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);

   start_routine_jump = start_routine;
   new_ctr_thread     = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, procnum, false);

   if (!new_ctr_thread)
   {
      LightLock_Unlock(&safe_double_thread_launch);
      return EAGAIN;
   }

   *thread = (pthread_t)new_ctr_thread;
   return 0;
}

static INLINE pthread_t pthread_self(void)
{
   return (pthread_t)threadGetCurrent();
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   LightLock_Init((LightLock *)mutex);
   return 0;
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
   /*Nothing to destroy*/
   return 0;
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
   LightLock_Lock((LightLock *)mutex);
   return 0;
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
   LightLock_Unlock((LightLock *)mutex);
   return 0;
}

static INLINE void pthread_exit(void *retval)
{
   /*Yes the pointer to int cast is not ideal*/
   /*threadExit((int)retval);*/
   (void)retval;

   threadExit(0);
}

static INLINE int pthread_detach(pthread_t thread)
{
   threadDetach((Thread)thread);
   return 0;
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
   /*retval is ignored*/
   if (threadJoin((Thread)thread, INT64_MAX))
      return -1;

   threadFree((Thread)thread);

   return 0;
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
   return LightLock_TryLock((LightLock *)mutex);
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
   CondVar_Wait((CondVar *)cond, (LightLock *)mutex);
   return 0;
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
   /* Missing clock_gettime*/
   struct timespec now;
   struct timeval tm;
   int retval = 0;

   do
   {
      s64 timeout;
      gettimeofday(&tm, NULL);
      now.tv_sec  = tm.tv_sec;
      now.tv_nsec = tm.tv_usec * 1000;

      if ((timeout = (abstime->tv_sec - now.tv_sec) * 1000000000 +
(abstime->tv_nsec - now.tv_nsec)) < 0)
      {
         retval = ETIMEDOUT;
         break;
      }

      if (!CondVar_WaitTimeout((CondVar *)cond, (LightLock *)mutex, timeout))
         break;
   } while (1);

   return retval;
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
   CondVar_Init((CondVar *)cond);
   return 0;
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
   CondVar_Signal((CondVar *)cond);
   return 0;
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   CondVar_Broadcast((CondVar *)cond);
   return 0;
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
   /*Nothing to destroy*/
   return 0;
}

static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
{
	if (threadGetHandle((Thread)t1) == threadGetHandle((Thread)t2))
		return 1;
	return 0;
}

#endif

./include/libretro-common/rthreads/gx_pthread.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gx_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _GX_PTHREAD_WRAP_GX_
#define _GX_PTHREAD_WRAP_GX_

#include <ogcsys.h>
#include <gccore.h>
#include <ogc/cond.h>
#include <retro_inline.h>

#ifndef OSThread
#define OSThread lwp_t
#endif

#ifndef OSCond
#define OSCond lwpq_t
#endif

#ifndef OSThreadQueue
#define OSThreadQueue lwpq_t
#endif

#ifndef OSInitMutex
#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
#endif

#ifndef OSLockMutex
#define OSLockMutex(mutex) LWP_MutexLock(mutex)
#endif

#ifndef OSUnlockMutex
#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
#endif

#ifndef OSTryLockMutex
#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)
#endif

#ifndef OSInitCond
#define OSInitCond(cond) LWP_CondInit(cond)
#endif

#ifndef OSWaitCond
#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)
#endif

#ifndef OSInitThreadQueue
#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
#endif

#ifndef OSSleepThread
#define OSSleepThread(queue) LWP_ThreadSleep(queue)
#endif

#ifndef OSJoinThread
#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)
#endif

#ifndef OSCreateThread
#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)
#endif

#define STACKSIZE (8 * 1024)

typedef OSThread pthread_t;
typedef mutex_t pthread_mutex_t;
typedef OSCond pthread_cond_t;

#if defined(GX_PTHREAD_LEGACY)
typedef void* pthread_mutexattr_t;
typedef int pthread_attr_t;
typedef OSCond pthread_condattr_t;
#endif

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   *thread = 0;
   return OSCreateThread(thread, start_routine, 0 /* unused */, arg,
         0, STACKSIZE, 64, 0 /* unused */);
}

static INLINE pthread_t pthread_self(void)
{
   /* zero 20-mar-2016: untested */
   return LWP_GetSelf();
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   return OSInitMutex(mutex);
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
   return LWP_MutexDestroy(*mutex);
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
   return OSLockMutex(*mutex);
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
   return OSUnlockMutex(*mutex);
}

static INLINE void pthread_exit(void *retval)
{
   /* FIXME: No LWP equivalent for this? */
   (void)retval;
}

static INLINE int pthread_detach(pthread_t thread)
{
   /* FIXME: pthread_detach equivalent missing? */
   (void)thread;
   return 0;
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
   return OSJoinThread(thread, retval);
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
   return OSTryLockMutex(*mutex);
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
   return OSWaitCond(*cond, *mutex);
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
   return LWP_CondTimedWait(*cond, *mutex, abstime);
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
   return OSInitCond(cond);
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
   return LWP_CondSignal(*cond);
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   return LWP_CondBroadcast(*cond);
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
   return LWP_CondDestroy(*cond);
}

#endif

./include/libretro-common/rthreads/psp_pthread.h

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (psp_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* FIXME: unfinished on PSP, mutexes and condition variables basically a stub. */
#ifndef _PSP_PTHREAD_WRAP__
#define _PSP_PTHREAD_WRAP__

#ifdef VITA
#include <psp2/kernel/threadmgr.h>
#include <sys/time.h>
#else
#include <pspkernel.h>
#include <pspthreadman.h>
#include <pspthreadman_kernel.h>
#endif
#include <stdio.h>
#include <retro_inline.h>

#define STACKSIZE (8 * 1024)

typedef SceUID pthread_t;
typedef SceUID pthread_mutex_t;
typedef void* pthread_mutexattr_t;
typedef int pthread_attr_t;

typedef struct
{
	SceUID mutex;
	SceUID sema;
	int waiting;
} pthread_cond_t;

typedef SceUID pthread_condattr_t;

/* Use pointer values to create unique names for threads/mutexes */
char name_buffer[256];

typedef void* (*sthreadEntry)(void *argp);

typedef struct
{
   void* arg;
   sthreadEntry start_routine;
} sthread_args_struct;

static int psp_thread_wrap(SceSize args, void *argp)
{
   sthread_args_struct* sthread_args = (sthread_args_struct*)argp;

   return (int)sthread_args->start_routine(sthread_args->arg);
}

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) thread);

#ifdef VITA
   *thread = sceKernelCreateThread(name_buffer, psp_thread_wrap,
         0x10000100, 0x10000, 0, 0, NULL);
#else
   *thread = sceKernelCreateThread(name_buffer,
         psp_thread_wrap, 0x20, STACKSIZE, 0, NULL);
#endif

   sthread_args_struct sthread_args;
   sthread_args.arg = arg;
   sthread_args.start_routine = start_routine;

   return sceKernelStartThread(*thread, sizeof(sthread_args), &sthread_args);
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) mutex);

#ifdef VITA
   *mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);
	 if (*mutex<0)
	 		return *mutex;
	 return 0;
#else
   return *mutex = sceKernelCreateSema(name_buffer, 0, 1, 1, NULL);
#endif
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
#ifdef VITA
   return sceKernelDeleteMutex(*mutex);
#else
   return sceKernelDeleteSema(*mutex);
#endif
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
#ifdef VITA
	 int ret = sceKernelLockMutex(*mutex, 1, 0);
	 return ret;

#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
#ifdef VITA
	int ret = sceKernelUnlockMutex(*mutex, 1);
	return ret;
#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
#ifdef VITA
   int res = sceKernelWaitThreadEnd(thread, 0, 0);
   if (res < 0)
      return res;
   return sceKernelDeleteThread(thread);
#else
   SceUInt timeout = (SceUInt)-1;
   sceKernelWaitThreadEnd(thread, &timeout);
   exit_status = sceKernelGetThreadExitStatus(thread);
   sceKernelDeleteThread(thread);
   return exit_status;
#endif
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
#ifdef VITA
   return sceKernelTryLockMutex(*mutex, 1 /* not sure about this last param */);
#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
#ifdef VITA
   int ret = pthread_mutex_lock(&cond->mutex);
   if (ret < 0)
      return ret;
   ++cond->waiting;
   pthread_mutex_unlock(mutex);
   pthread_mutex_unlock(&cond->mutex);

   ret = sceKernelWaitSema(cond->sema, 1, 0);
   if (ret < 0)
      sceClibPrintf("Premature wakeup: %08X", ret);
   pthread_mutex_lock(mutex);
   return ret;
#else
   /* FIXME: stub */
   sceKernelDelayThread(10000);
   return 1;
#endif
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
#ifdef VITA
   int ret = pthread_mutex_lock(&cond->mutex);
   if (ret < 0)
      return ret;
   ++cond->waiting;
   pthread_mutex_unlock(mutex);
   pthread_mutex_unlock(&cond->mutex);

   SceUInt timeout = 0;

   timeout  = abstime->tv_sec;
   timeout += abstime->tv_nsec / 1.0e6;

   ret = sceKernelWaitSema(cond->sema, 1, &timeout);
   if (ret < 0)
      sceClibPrintf("Premature wakeup: %08X", ret);
   pthread_mutex_lock(mutex);
   return ret;

#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
#ifdef VITA

   pthread_mutex_init(&cond->mutex,NULL);

   if (cond->mutex<0)
      return cond->mutex;

   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) cond);
   cond->sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);

   if (cond->sema < 0)
   {
      pthread_mutex_destroy(&cond->mutex);
      return cond->sema;
   }

   cond->waiting = 0;

   return 0;

#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
#ifdef VITA
	pthread_mutex_lock(&cond->mutex);
	if (cond->waiting)
   {
		--cond->waiting;
		sceKernelSignalSema(cond->sema, 1);
	}
	pthread_mutex_unlock(&cond->mutex);
	return 0;
#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   /* FIXME: stub */
   return 1;
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
#ifdef VITA
   int ret = sceKernelDeleteSema(cond->sema);
   if (ret < 0)
    return ret;

   return sceKernelDeleteMutex(cond->mutex);
#else
  /* FIXME: stub */
  return 1;
#endif
}

static INLINE int pthread_detach(pthread_t thread)
{
   return 0;
}

static INLINE void pthread_exit(void *retval)
{
#ifdef VITA
   sceKernelExitDeleteThread(sceKernelGetThreadId());
#endif
}

static INLINE pthread_t pthread_self(void)
{
   /* zero 20-mar-2016: untested */
   return sceKernelGetThreadId();
}

static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
{
	 return t1 == t2;
}

#endif /* _PSP_PTHREAD_WRAP__ */

./include/libretro-common/rthreads/rthreads.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rthreads.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef __unix__
#ifndef __sun__
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309
#endif
#endif
#endif

#include <stdlib.h>
#include <string.h>

#include <boolean.h>
#include <rthreads/rthreads.h>

/* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32. Maybe only supported in MSVC>=2005  */

#if defined(_WIN32) && !defined(RETRO_WIN32_USE_PTHREADS)
#define USE_WIN32_THREADS
#ifdef _XBOX
#include <xtl.h>
#else
#define WIN32_LEAN_AND_MEAN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */
#endif
#include <windows.h>
#include <mmsystem.h>
#endif
#elif defined(GEKKO)
#include <ogc/lwp_watchdog.h>
#include "gx_pthread.h"
#elif defined(_3DS)
#include "ctr_pthread.h"
#else
#include <pthread.h>
#include <time.h>
#endif

#if defined(VITA) || defined(BSD) || defined(ORBIS) || defined(__mips__) || defined(_3DS)
#include <sys/time.h>
#endif

#if defined(PS2)
#include <ps2sdkapi.h>
#endif

#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif

struct thread_data
{
   void (*func)(void*);
   void *userdata;
};

struct sthread
{
#ifdef USE_WIN32_THREADS
   HANDLE thread;
   DWORD id;
#else
   pthread_t id;
#endif
};

struct slock
{
#ifdef USE_WIN32_THREADS
   CRITICAL_SECTION lock;
#else
   pthread_mutex_t lock;
#endif
};

#ifdef USE_WIN32_THREADS
/* The syntax we'll use is mind-bending unless we use a struct. Plus, we might want to store more info later */
/* This will be used as a linked list immplementing a queue of waiting threads */
struct queue_entry
{
   struct queue_entry *next;
};
#endif

struct scond
{
#ifdef USE_WIN32_THREADS
   /* With this implementation of scond, we don't have any way of waking
    * (or even identifying) specific threads
    * But we need to wake them in the order indicated by the queue.
    * This potato token will get get passed around every waiter.
    * The bearer can test whether he's next, and hold onto the potato if he is.
    * When he's done he can then put it back into play to progress
    * the queue further */
   HANDLE hot_potato;

   /* The primary signalled event. Hot potatoes are passed until this is set. */
   HANDLE event;

   /* the head of the queue; NULL if queue is empty */
   struct queue_entry *head;

   /* equivalent to the queue length */
   int waiters;

   /* how many waiters in the queue have been conceptually wakened by signals
    * (even if we haven't managed to actually wake them yet) */
   int wakens;

   /* used to control access to this scond, in case the user fails */
   CRITICAL_SECTION cs;

#else
   pthread_cond_t cond;
#endif
};

#ifdef USE_WIN32_THREADS
static DWORD CALLBACK thread_wrap(void *data_)
#else
static void *thread_wrap(void *data_)
#endif
{
   struct thread_data *data = (struct thread_data*)data_;
   if (!data)
	   return 0;
   data->func(data->userdata);
   free(data);
   return 0;
}

sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
{
	return sthread_create_with_priority(thread_func, userdata, 0);
}

/* TODO/FIXME - this needs to be implemented for Switch/3DS */
#if !defined(SWITCH) && !defined(USE_WIN32_THREADS) && !defined(_3DS) && !defined(GEKKO) && !defined(__HAIKU__) && !defined(EMSCRIPTEN)
#define HAVE_THREAD_ATTR
#endif

sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority)
{
#ifdef HAVE_THREAD_ATTR
   pthread_attr_t thread_attr;
   bool thread_attr_needed  = false;
#endif
   bool thread_created      = false;
   struct thread_data *data = NULL;
   sthread_t *thread        = (sthread_t*)malloc(sizeof(*thread));

   if (!thread)
      return NULL;

   if (!(data = (struct thread_data*)malloc(sizeof(*data))))
   {
      free(thread);
      return NULL;
   }

   data->func               = thread_func;
   data->userdata           = userdata;

   thread->id               = 0;
#ifdef USE_WIN32_THREADS
   thread->thread           = CreateThread(NULL, 0, thread_wrap,
         data, 0, &thread->id);
   thread_created           = !!thread->thread;
#else
#ifdef HAVE_THREAD_ATTR
   pthread_attr_init(&thread_attr);

   if ((thread_priority >= 1) && (thread_priority <= 100))
   {
      struct sched_param sp;
      memset(&sp, 0, sizeof(struct sched_param));
      sp.sched_priority = thread_priority;
      pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
      pthread_attr_setschedparam(&thread_attr, &sp);

      thread_attr_needed = true;
   }

#if defined(VITA)
   pthread_attr_setstacksize(&thread_attr , 0x10000 );
   thread_attr_needed = true;
#elif defined(__APPLE__)
   /* Default stack size on Apple is 512Kb;
    * for PS2 disc scanning and other reasons, we'd like 2MB. */
   pthread_attr_setstacksize(&thread_attr , 0x200000 );
   thread_attr_needed = true;
#endif

   if (thread_attr_needed)
      thread_created = pthread_create(&thread->id, &thread_attr, thread_wrap, data) == 0;
   else
      thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;

   pthread_attr_destroy(&thread_attr);
#else
   thread_created    = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
#endif

#endif

   if (thread_created)
      return thread;
   free(data);
   free(thread);
   return NULL;
}

int sthread_detach(sthread_t *thread)
{
#ifdef USE_WIN32_THREADS
   CloseHandle(thread->thread);
   free(thread);
   return 0;
#else
   int ret = pthread_detach(thread->id);
   free(thread);
   return ret;
#endif
}

void sthread_join(sthread_t *thread)
{
   if (!thread)
      return;
#ifdef USE_WIN32_THREADS
   WaitForSingleObject(thread->thread, INFINITE);
   CloseHandle(thread->thread);
#else
   pthread_join(thread->id, NULL);
#endif
   free(thread);
}

#if !defined(GEKKO)
bool sthread_isself(sthread_t *thread)
{
#ifdef USE_WIN32_THREADS
   return thread ? GetCurrentThreadId() == thread->id        : false;
#else
   return thread ? pthread_equal(pthread_self(), thread->id) : false;
#endif
}
#endif

slock_t *slock_new(void)
{
   slock_t      *lock = (slock_t*)calloc(1, sizeof(*lock));
   if (!lock)
      return NULL;
#ifdef USE_WIN32_THREADS
   InitializeCriticalSection(&lock->lock);
#else
   if (pthread_mutex_init(&lock->lock, NULL) != 0)
   {
      free(lock);
      return NULL;
   }
#endif
   return lock;
}

void slock_free(slock_t *lock)
{
   if (!lock)
      return;

#ifdef USE_WIN32_THREADS
   DeleteCriticalSection(&lock->lock);
#else
   pthread_mutex_destroy(&lock->lock);
#endif
   free(lock);
}

void slock_lock(slock_t *lock)
{
   if (!lock)
      return;
#ifdef USE_WIN32_THREADS
   EnterCriticalSection(&lock->lock);
#else
   pthread_mutex_lock(&lock->lock);
#endif
}

bool slock_try_lock(slock_t *lock)
{
#ifdef USE_WIN32_THREADS
   return lock && TryEnterCriticalSection(&lock->lock);
#else
   return lock && (pthread_mutex_trylock(&lock->lock) == 0);
#endif
}

void slock_unlock(slock_t *lock)
{
   if (!lock)
      return;
#ifdef USE_WIN32_THREADS
   LeaveCriticalSection(&lock->lock);
#else
   pthread_mutex_unlock(&lock->lock);
#endif
}

scond_t *scond_new(void)
{
   scond_t      *cond = (scond_t*)calloc(1, sizeof(*cond));

   if (!cond)
      return NULL;

#ifdef USE_WIN32_THREADS
   /* This is very complex because recreating condition variable semantics
    * with Win32 parts is not easy.
    *
    * The main problem is that a condition variable can't be used to
    * "pre-wake" a thread (it will get wakened only after it's waited).
    *
    * Whereas a win32 event can pre-wake a thread (the event will be set
    * in advance, so a 'waiter' won't even have to wait on it).
    *
    * Keep in mind a condition variable can apparently pre-wake a thread,
    * insofar as spurious wakeups are always possible,
    * but nobody will be expecting this and it does not need to be simulated.
    *
    * Moreover, we won't be doing this, because it counts as a spurious wakeup
    * -- someone else with a genuine claim must get wakened, in any case.
    *
    * Therefore we choose to wake only one of the correct waiting threads.
    * So at the very least, we need to do something clever. But there's
    * bigger problems.
    * We don't even have a straightforward way in win32 to satisfy
    * pthread_cond_wait's atomicity requirement. The bulk of this
    * algorithm is solving that.
    *
    * Note: We might could simplify this using vista+ condition variables,
    * but we wanted an XP compatible solution. */
   if (!(cond->event = CreateEvent(NULL, FALSE, FALSE, NULL)))
   {
      free(cond);
      return NULL;
   }
   if (!(cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL)))
   {
      CloseHandle(cond->event);
      free(cond);
      return NULL;
   }

   InitializeCriticalSection(&cond->cs);
#else
   if (pthread_cond_init(&cond->cond, NULL) != 0)
   {
      free(cond);
      return NULL;
   }
#endif

   return cond;
}

void scond_free(scond_t *cond)
{
   if (!cond)
      return;

#ifdef USE_WIN32_THREADS
   CloseHandle(cond->event);
   CloseHandle(cond->hot_potato);
   DeleteCriticalSection(&cond->cs);
#else
   pthread_cond_destroy(&cond->cond);
#endif
   free(cond);
}

#ifdef USE_WIN32_THREADS
static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds)
{
   struct queue_entry myentry;
   struct queue_entry **ptr;

#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
   static LARGE_INTEGER performanceCounterFrequency;
   LARGE_INTEGER tsBegin;
   static bool first_init  = true;
#else
   static bool beginPeriod = false;
   DWORD tsBegin;
#endif
   DWORD waitResult;
   DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head,
                                             we don't do the hot potato stuff,
                                             so this timeout needs presetting. */

   /* Reminder: `lock` is held before this is called. */
   /* however, someone else may have called scond_signal without the lock. soo... */
   EnterCriticalSection(&cond->cs);

   /* since this library is meant for realtime game software
    * I have no problem setting this to 1 and forgetting about it. */
#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
   if (first_init)
   {
      performanceCounterFrequency.QuadPart = 0;
      first_init = false;
   }

   if (performanceCounterFrequency.QuadPart == 0)
      QueryPerformanceFrequency(&performanceCounterFrequency);
#else
   if (!beginPeriod)
   {
      beginPeriod = true;
      timeBeginPeriod(1);
   }
#endif

   /* Now we can take a good timestamp for use in faking the timeout ourselves. */
   /* But don't bother unless we need to (to save a little time) */
   if (dwMilliseconds != INFINITE)
#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
      QueryPerformanceCounter(&tsBegin);
#else
      tsBegin = timeGetTime();
#endif

   /* add ourselves to a queue of waiting threads */
   ptr = &cond->head;

   /* walk to the end of the linked list */
   while (*ptr)
      ptr       = &((*ptr)->next);

   *ptr         = &myentry;
   myentry.next = NULL;

   cond->waiters++;

   /* now the conceptual lock release and condition block are supposed to be atomic.
    * we can't do that in Windows, but we can simulate the effects by using
    * the queue, by the following analysis:
    * What happens if they aren't atomic?
    *
    * 1. a signaller can rush in and signal, expecting a waiter to get it;
    * but the waiter wouldn't, because he isn't blocked yet.
    * Solution: Win32 events make this easy. The event will sit there enabled
    *
    * 2. a signaller can rush in and signal, and then turn right around and wait.
    * Solution: the signaller will get queued behind the waiter, who's
    * enqueued before he releases the mutex. */

   /* It's my turn if I'm the head of the queue.
    * Check to see if it's my turn. */
   while (cond->head != &myentry)
   {
      /* It isn't my turn: */
      DWORD timeout = INFINITE;

      /* As long as someone is even going to be able to wake up
       * when they receive the potato, keep it going round. */
      if (cond->wakens > 0)
         SetEvent(cond->hot_potato);

      /* Assess the remaining timeout time */
      if (dwMilliseconds != INFINITE)
      {
#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
         LARGE_INTEGER now;
         LONGLONG elapsed;

         QueryPerformanceCounter(&now);
         elapsed  = now.QuadPart - tsBegin.QuadPart;
         elapsed *= 1000;
         elapsed /= performanceCounterFrequency.QuadPart;
#else
         DWORD now     = timeGetTime();
         DWORD elapsed = now - tsBegin;
#endif

         /* Try one last time with a zero timeout (keeps the code simpler) */
         if (elapsed > dwMilliseconds)
            elapsed = dwMilliseconds;

         timeout = dwMilliseconds - elapsed;
      }

      /* Let someone else go */
      LeaveCriticalSection(&lock->lock);
      LeaveCriticalSection(&cond->cs);

      /* Wait a while to catch the hot potato..
       * someone else should get a chance to go */
      /* After all, it isn't my turn (and it must be someone else's) */
      Sleep(0);
      waitResult = WaitForSingleObject(cond->hot_potato, timeout);

      /* I should come out of here with the main lock taken */
      EnterCriticalSection(&lock->lock);
      EnterCriticalSection(&cond->cs);

      if (waitResult == WAIT_TIMEOUT)
      {
         /* Out of time! Now, let's think about this. I do have the potato now--
          * maybe it's my turn, and I have the event?
          * If that's the case, I could proceed right now without aborting
          * due to timeout.
          *
          * However.. I DID wait a real long time. The caller was willing
          * to wait that long.
          *
          * I choose to give him one last chance with a zero timeout
          * in the next step
          */
         if (cond->head == &myentry)
         {
            dwFinalTimeout = 0;
            break;
         }
         else
         {
            /* It's not our turn and we're out of time. Give up.
             * Remove ourself from the queue and bail. */
            struct queue_entry *curr = cond->head;

            while (curr->next != &myentry)
               curr = curr->next;
            curr->next = myentry.next;
            cond->waiters--;
            LeaveCriticalSection(&cond->cs);
            return false;
         }
      }

   }

   /* It's my turn now -- and I hold the potato */

   /* I still have the main lock, in any case */
   /* I need to release it so that someone can set the event */
   LeaveCriticalSection(&lock->lock);
   LeaveCriticalSection(&cond->cs);

   /* Wait for someone to actually signal this condition */
   /* We're the only waiter waiting on the event right now -- everyone else
    * is waiting on something different */
   waitResult = WaitForSingleObject(cond->event, dwFinalTimeout);

   /* Take the main lock so we can do work. Nobody else waits on this lock
    * for very long, so even though it's GO TIME we won't have to wait long */
   EnterCriticalSection(&lock->lock);
   EnterCriticalSection(&cond->cs);

   /* Remove ourselves from the queue */
   cond->head = myentry.next;
   cond->waiters--;

   if (waitResult == WAIT_TIMEOUT)
   {
      /* Oops! ran out of time in the final wait. Just bail. */
      LeaveCriticalSection(&cond->cs);
      return false;
   }

   /* If any other wakenings are pending, go ahead and set it up  */
   /* There may actually be no waiters. That's OK. The first waiter will come in,
    * find it's his turn, and immediately get the signaled event */
   cond->wakens--;
   if (cond->wakens > 0)
   {
      SetEvent(cond->event);

      /* Progress the queue: Put the hot potato back into play. It'll be
       * tossed around until next in line gets it */
      SetEvent(cond->hot_potato);
   }

   LeaveCriticalSection(&cond->cs);
   return true;
}
#endif

void scond_wait(scond_t *cond, slock_t *lock)
{
#ifdef USE_WIN32_THREADS
   _scond_wait_win32(cond, lock, INFINITE);
#else
   pthread_cond_wait(&cond->cond, &lock->lock);
#endif
}

int scond_broadcast(scond_t *cond)
{
#ifdef USE_WIN32_THREADS
   /* Remember, we currently have mutex */
   if (cond->waiters != 0)
   {
      /* Awaken everything which is currently queued up */
      if (cond->wakens == 0)
         SetEvent(cond->event);
      cond->wakens = cond->waiters;

      /* Since there is now at least one pending waken, the potato must be in play */
      SetEvent(cond->hot_potato);
   }
   return 0;
#else
   return pthread_cond_broadcast(&cond->cond);
#endif
}

void scond_signal(scond_t *cond)
{
#ifdef USE_WIN32_THREADS

   /* Unfortunately, pthread_cond_signal does not require that the
    * lock be held in advance */
   /* To avoid stomping on the condvar from other threads, we need
    * to control access to it with this */
   EnterCriticalSection(&cond->cs);

   /* remember: we currently have mutex */
   if (cond->waiters == 0)
   {
      LeaveCriticalSection(&cond->cs);
      return;
   }

   /* wake up the next thing in the queue */
   if (cond->wakens == 0)
      SetEvent(cond->event);

   cond->wakens++;

   /* The data structure is done being modified.. I think we can leave the CS now.
    * This would prevent some other thread from receiving the hot potato and then
    * immediately stalling for the critical section.
    * But remember, we were trying to replicate a semantic where this entire
    * scond_signal call was controlled (by the user) by a lock.
    * So in case there's trouble with this, we can move it after SetEvent() */
   LeaveCriticalSection(&cond->cs);

   /* Since there is now at least one pending waken, the potato must be in play */
   SetEvent(cond->hot_potato);

#else
   pthread_cond_signal(&cond->cond);
#endif
}

bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
{
#ifdef USE_WIN32_THREADS
   /* How to convert a microsecond (us) timeout to millisecond (ms)?
    *
    * Someone asking for a 0 timeout clearly wants immediate timeout.
    * Someone asking for a 1 timeout clearly wants an actual timeout
    * of the minimum length */
   /* The implementation of a 0 timeout here with pthreads is sketchy.
    * It isn't clear what happens if pthread_cond_timedwait is called with NOW.
    * Moreover, it is possible that this thread gets preempted after the
    * clock_gettime but before the pthread_cond_timedwait.
    * In order to help smoke out problems caused by this strange usage,
    * let's treat a 0 timeout as always timing out.
    */
   if (timeout_us == 0)
      return false;
   else if (timeout_us < 1000)
      return _scond_wait_win32(cond, lock, 1);
   /* Someone asking for 1000 or 1001 timeout shouldn't
    * accidentally get 2ms. */
   return _scond_wait_win32(cond, lock, timeout_us / 1000);
#else
   int64_t seconds, remainder;
   struct timespec now;
#ifdef __MACH__
   /* OSX doesn't have clock_gettime. */
   clock_serv_t cclock;
   mach_timespec_t mts;
   host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
   clock_get_time(cclock, &mts);
   mach_port_deallocate(mach_task_self(), cclock);
   now.tv_sec = mts.tv_sec;
   now.tv_nsec = mts.tv_nsec;
#elif !defined(__PSL1GHT__) && defined(__PS3__)
   sys_time_sec_t s;
   sys_time_nsec_t n;
   sys_time_get_current_time(&s, &n);
   now.tv_sec            = s;
   now.tv_nsec           = n;
#elif defined(PS2)
   int tickms            = ps2_clock();
   now.tv_sec            = tickms / 1000;
   now.tv_nsec           = tickms * 1000;
#elif !defined(DINGUX_BETA) && (defined(__mips__) || defined(VITA) || defined(_3DS))
   struct timeval tm;
   gettimeofday(&tm, NULL);
   now.tv_sec            = tm.tv_sec;
   now.tv_nsec           = tm.tv_usec * 1000;
#elif defined(RETRO_WIN32_USE_PTHREADS)
   _ftime64_s(&now);
#elif defined(GEKKO)
   /* Avoid gettimeofday due to it being reported to be broken */
   const uint64_t tickms = gettime() / TB_TIMER_CLOCK;
   now.tv_sec            = tickms / 1000;
   now.tv_nsec           = tickms * 1000;
#else
   clock_gettime(CLOCK_REALTIME, &now);
#endif

   seconds              = timeout_us / INT64_C(1000000);
   remainder            = timeout_us % INT64_C(1000000);

   now.tv_sec          += seconds;
   now.tv_nsec         += remainder * INT64_C(1000);

   if (now.tv_nsec > 1000000000)
   {
      now.tv_nsec      -= 1000000000;
      now.tv_sec       += 1;
   }

   return (pthread_cond_timedwait(&cond->cond, &lock->lock, &now) == 0);
#endif
}

#ifdef HAVE_THREAD_STORAGE
bool sthread_tls_create(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
   return (*tls = TlsAlloc()) != TLS_OUT_OF_INDEXES;
#else
   return pthread_key_create((pthread_key_t*)tls, NULL) == 0;
#endif
}

bool sthread_tls_delete(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
   return TlsFree(*tls) != 0;
#else
   /* TODO/FIXME - broken for UCRT */
   return pthread_key_delete(*tls) == 0;
#endif
}

void *sthread_tls_get(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
   return TlsGetValue(*tls);
#else
   /* TODO/FIXME - broken for UCRT */
   return pthread_getspecific(*tls);
#endif
}

bool sthread_tls_set(sthread_tls_t *tls, const void *data)
{
#ifdef USE_WIN32_THREADS
   return TlsSetValue(*tls, (void*)data) != 0;
#else
   /* TODO/FIXME - broken for UCRT */
   return pthread_setspecific(*tls, data) == 0;
#endif
}
#endif

uintptr_t sthread_get_thread_id(sthread_t *thread)
{
   if (thread)
      return (uintptr_t)thread->id;
   return 0;
}

uintptr_t sthread_get_current_thread_id(void)
{
#ifdef USE_WIN32_THREADS
   return (uintptr_t)GetCurrentThreadId();
#else
   return (uintptr_t)pthread_self();
#endif
}

./include/libretro-common/rthreads/tpool.c

/*
 * Copyright (c) 2010-2020 The RetroArch team
 * Copyright (c) 2017 John Schember <john@nachtimwald.com>
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (tpool.c).
 * ---------------------------------------------------------------------------------------
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE
 */

#include <stdlib.h>
#include <boolean.h>

#include <rthreads/rthreads.h>
#include <rthreads/tpool.h>

/* Work object which will sit in a queue
 * waiting for the pool to process it.
 *
 * It is a singly linked list acting as a FIFO queue. */
struct tpool_work
{
   thread_func_t      func;  /* Function to be called. */
   void              *arg;   /* Data to be passed to func. */
   struct tpool_work *next;  /* Next work item in the queue. */
};
typedef struct tpool_work tpool_work_t;

struct tpool
{
   tpool_work_t    *work_first;   /* First work item in the work queue. */
   tpool_work_t    *work_last;    /* Last work item in the work queue. */
   slock_t         *work_mutex;   /* Mutex protecting inserting and removing work from the work queue. */
   scond_t         *work_cond;    /* Conditional to signal when there is work to process. */
   scond_t         *working_cond; /* Conditional to signal when there is no work processing.
                                       This will also signal when there are no threads running. */
   size_t           working_cnt;  /* The number of threads processing work (Not waiting for work). */
   size_t           thread_cnt;   /* Total number of threads within the pool. */
   bool             stop;         /* Marker to tell the work threads to exit. */
};

static tpool_work_t *tpool_work_create(thread_func_t func, void *arg)
{
   tpool_work_t *work;

   if (!func)
      return NULL;

   work       = (tpool_work_t*)calloc(1, sizeof(*work));
   work->func = func;
   work->arg  = arg;
   work->next = NULL;
   return work;
}

static void tpool_work_destroy(tpool_work_t *work)
{
   if (work)
      free(work);
}

/* Pull the first work item out of the queue. */
static tpool_work_t *tpool_work_get(tpool_t *tp)
{
   tpool_work_t *work;

   if (!tp)
      return NULL;

   work = tp->work_first;
   if (!work)
      return NULL;

   if (!work->next)
   {
      tp->work_first = NULL;
      tp->work_last  = NULL;
   }
   else
      tp->work_first = work->next;

   return work;
}

static void tpool_worker(void *arg)
{
   tpool_work_t *work = NULL;
   tpool_t      *tp   = (tpool_t*)arg;

   for (;;)
   {
      slock_lock(tp->work_mutex);
      /* Keep running until told to stop. */
      if (tp->stop)
         break;

      /* If there is no work in the queue wait in the conditional until
       * there is work to take. */
      if (!tp->work_first)
         scond_wait(tp->work_cond, tp->work_mutex);

      /* Try to pull work from the queue. */
      work = tpool_work_get(tp);
      tp->working_cnt++;
      slock_unlock(tp->work_mutex);

      /* Call the work function and let it process.
       *
       * work can legitimately be NULL. Since multiple threads from the pool
       * will wake when there is work, a thread might not get any work. 1
       * piece of work and 2 threads, both will wake but with 1 only work 1
       * will get the work and the other won't.
       *
       * working_cnt has been increment and work could be NULL. While it's
       * not true there is work processing the thread is considered working
       * because it's not waiting in the conditional. Pedantic but...
       */
      if (work)
      {
         work->func(work->arg);
         tpool_work_destroy(work);
      }

      slock_lock(tp->work_mutex);
      tp->working_cnt--;
      /* Since we're in a lock no work can be added or removed form the queue.
       * Also, the working_cnt can't be changed (except the thread holding the lock).
       * At this point if there isn't any work processing and if there is no work
       * signal this is the case. */
      if (!tp->stop && tp->working_cnt == 0 && !tp->work_first)
         scond_signal(tp->working_cond);
      slock_unlock(tp->work_mutex);
   }

   tp->thread_cnt--;
   if (tp->thread_cnt == 0)
      scond_signal(tp->working_cond);
   slock_unlock(tp->work_mutex);
}

tpool_t *tpool_create(size_t num)
{
   tpool_t   *tp;
   sthread_t *thread;
   size_t     i;

   if (num == 0)
      num = 2;

   tp               = (tpool_t*)calloc(1, sizeof(*tp));
   tp->thread_cnt   = num;

   tp->work_mutex   = slock_new();
   tp->work_cond    = scond_new();
   tp->working_cond = scond_new();

   tp->work_first   = NULL;
   tp->work_last    = NULL;

   /* Create the requested number of thread and detach them. */
   for (i = 0; i < num; i++)
   {
      thread = sthread_create(tpool_worker, tp);
      sthread_detach(thread);
   }

   return tp;
}

void tpool_destroy(tpool_t *tp)
{
   tpool_work_t *work;
   tpool_work_t *work2;

   if (!tp)
      return;

   /* Take all work out of the queue and destroy it. */
   slock_lock(tp->work_mutex);
   work = tp->work_first;
   while (work)
   {
      work2 = work->next;
      tpool_work_destroy(work);
      work = work2;
   }

   /* Tell the worker threads to stop. */
   tp->stop = true;
   scond_broadcast(tp->work_cond);
   slock_unlock(tp->work_mutex);

   /* Wait for all threads to stop. */
   tpool_wait(tp);

   slock_free(tp->work_mutex);
   scond_free(tp->work_cond);
   scond_free(tp->working_cond);

   free(tp);
}

bool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg)
{
   tpool_work_t *work;

   if (!tp)
      return false;

   work = tpool_work_create(func, arg);
   if (!work)
      return false;

   slock_lock(tp->work_mutex);
   if (!tp->work_first)
   {
      tp->work_first      = work;
      tp->work_last       = tp->work_first;
   }
   else
   {
      tp->work_last->next = work;
      tp->work_last       = work;
   }

   scond_broadcast(tp->work_cond);
   slock_unlock(tp->work_mutex);

   return true;
}

void tpool_wait(tpool_t *tp)
{
   if (!tp)
      return;

   slock_lock(tp->work_mutex);

   for (;;)
   {
      /* working_cond is dual use. It signals when we're not stopping but the
       * working_cnt is 0 indicating there isn't any work processing. If we
       * are stopping it will trigger when there aren't any threads running. */
      if ((!tp->stop && tp->working_cnt != 0) || (tp->stop && tp->thread_cnt != 0))
         scond_wait(tp->working_cond, tp->work_mutex);
      else
         break;
   }

   slock_unlock(tp->work_mutex);
}

./include/libretro-common/rthreads/wiiu_pthread.h

/* Copyright  (C) 2010-2016 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (wiiu_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _WIIU_PTHREAD_WRAP_WIIU_
#define _WIIU_PTHREAD_WRAP_WIIU_

#include <retro_inline.h>
#include <wiiu/os/condition.h>
#include <wiiu/os/thread.h>
#include <wiiu/os/mutex.h>
#include <malloc.h>
#define STACKSIZE (8 * 1024)

typedef OSThread* pthread_t;
typedef OSMutex* pthread_mutex_t;
typedef void* pthread_mutexattr_t;
typedef int pthread_attr_t;
typedef OSCondition* pthread_cond_t;
typedef OSCondition* pthread_condattr_t;

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   OSThread *t = memalign(8, sizeof(OSThread));
   void *stack = memalign(32, STACKSIZE);
   bool ret = OSCreateThread(t, (OSThreadEntryPointFn)start_routine, 
      (uint32_t)arg, NULL, (void*)(((uint32_t)stack)+STACKSIZE), STACKSIZE, 8, OS_THREAD_ATTRIB_AFFINITY_ANY);
   if(ret == true)
   {
      OSResumeThread(t);
      *thread = t;
   }
   else
      *thread = NULL;
   return (ret == true) ? 0 : -1;
}

static INLINE pthread_t pthread_self(void)
{
   return OSGetCurrentThread();
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   OSMutex *m = malloc(sizeof(OSMutex));
   OSInitMutex(m);
   *mutex = m;
   return 0;
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
   if(*mutex)
      free(*mutex);
   *mutex = NULL;
   return 0;
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
   OSLockMutex(*mutex);
   return 0;
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
   OSUnlockMutex(*mutex);
   return 0;
}

static INLINE void pthread_exit(void *retval)
{
   (void)retval;
   OSExitThread(0);
}

static INLINE int pthread_detach(pthread_t thread)
{
   OSDetachThread(thread);
   return 0;
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
   (void)retval;
   bool ret = OSJoinThread(thread, NULL);
   if(ret == true)
   {
      free(thread->stackEnd);
      free(thread);
   }
   return (ret == true) ? 0 : -1;
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
   return OSTryLockMutex(*mutex);
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
   OSWaitCond(*cond, *mutex);
   return 0;
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
   //FIXME: actual timeout needed
   (void)abstime;
   return pthread_cond_wait(cond, mutex);
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
   OSCondition *c = malloc(sizeof(OSCondition));
   OSInitCond(c);
   *cond = c;
   return 0;
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
   OSSignalCond(*cond);
   return 0;
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   //FIXME: no OS equivalent
   (void)cond;
   return 0;
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
   if(*cond)
      free(*cond);
   *cond = NULL;
   return 0;
}

extern int pthread_equal(pthread_t t1, pthread_t t2);

#endif

./include/libretro-common/rthreads/xenon_sdl_threads.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (xenon_sdl_threads.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;) */

#include "SDL_thread.h"
#include "SDL_mutex.h"
#include <stdlib.h>
#include <boolean.h>

SDL_cond *SDL_CreateCond(void)
{
   bool *sleeping = calloc(1, sizeof(*sleeping));
   return (SDL_cond*)sleeping;
}

void SDL_DestroyCond(SDL_cond *sleeping)
{
   free(sleeping);
}

int SDL_CondWait(SDL_cond *cond, SDL_mutex *lock)
{
   (void)lock;
   volatile bool *sleeping = (volatile bool*)cond;

   SDL_mutexV(lock);
   *sleeping = true;
   while (*sleeping); /* Yeah, we all love busyloops don't we? ._. */
   SDL_mutexP(lock);

   return 0;
}

int SDL_CondSignal(SDL_cond *cond)
{
   *(volatile bool*)cond = false;
   return 0;
}

./include/libretro-common/samples/compat/fnmatch/compat_fnmatch_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_fnmatch_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <assert.h>
#include <stddef.h>

#include <compat/fnmatch.h>

int main(void)
{
   assert(rl_fnmatch("TEST", "TEST", 0) == 0);
   assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
   assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
   assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0);
   assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0);
   assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0);
   assert(rl_fnmatch("TEST*", "TEST", 0) == 0);
   assert(rl_fnmatch("TEST**", "TEST", 0) == 0);
   assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0);
   assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0);
   assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0);
   assert(rl_fnmatch("TE**ST", "TEST", 0) == 0);
   assert(rl_fnmatch("TE**ST", "TExST", 0) == 0);
   assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0);
   assert(rl_fnmatch("*.*", "test.jpg", 0) == 0);
   assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0);
   assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0);
   assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0);
   assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH);
}

./include/libretro-common/samples/compat/fnmatch/Makefile

TARGET := compat_fnmatch_test

LIBRETRO_COMM_DIR := ../../..

SOURCES := \
	compat_fnmatch_test.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_fnmatch.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/compat/snprintf/Makefile

TARGET := snprintf

CORE_DIR          := .
LIBRETRO_COMM_DIR := ../../..

SOURCES_C := 	\
	$(CORE_DIR)/snprintf_test.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c

OBJS := $(SOURCES_C:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/compat/snprintf/snprintf_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (snprintf_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <compat/strl.h>

int main(int argc, char *argv[])
{
   char s[128];
   char *variable      = "test1";
   char *variable2     = "test2";
   char *variable3     = "test3";
   char *variable4     = "test4";
   char *variable5     = "test5";
   char *variable6     = "test6";
   int ret             = snprintf(s,
         sizeof(s), "%s%s%s%s%s%s%s%s%s%s%s", variable,
         " : ", variable2,
         " : ", variable3,
         " : ", variable4,
         " : ", variable5,
         " : ", variable6
         );

   fprintf(stderr, "[%d], %s\n", ret, s);

   return 0;
}

./include/libretro-common/samples/compat/strl/Makefile

TARGET := strl

CORE_DIR          := .
LIBRETRO_COMM_DIR := ../../..

SOURCES_C := 	\
	$(CORE_DIR)/strl_test.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c

OBJS := $(SOURCES_C:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/compat/strl/strl_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (strl_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <compat/strl.h>

int main(int argc, char *argv[])
{
   char s[128];
   char *variable      = "test1";
   char *variable2     = "test2";
   char *variable3     = "test3";
   char *variable4     = "test4";
   char *variable5     = "test5";
   char *variable6     = "test6";
   int ret             = strlcpy(s, variable, sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable2,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable3,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable4,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable5,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable6,sizeof(s));

   fprintf(stderr, "[%d], %s\n", ret, s);

   return 0;
}

./include/libretro-common/samples/core_options/example_categories/conversion_scripts/core_option_regex.py

import re

# 0: full struct; 1: up to & including first []; 2: content between first {}
p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*'
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'=\s*'  # =
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};')  # captures full struct, it's beginning and it's content
# 0: type name[]; 1: type; 2: name
p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*'
                         r'(option_cats[a-z_]{0,8}|option_defs([a-z_]{0,8}))\s*\[]')
# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
p_option = re.compile(r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\"|'  # key start; group 1
                      r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|'
                      r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|'
                      r'[a-zA-Z0-9_]+\s*\".*?\")\s*'  # key end
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\")\s*'  # description; group 2
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # group 3
                      r'(?:NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')+)'
                      r'(?:'  # defs only start
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # key/value pairs start; group 4
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option key
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*)'  # key/value pairs end
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:'  # defaults start
                      r'(?:NULL|\".*?\")\s*'  # default value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*'  # defaults end
                      r')?'  # defs only end
                      r'},')  # closing braces
# analyse option group 3
p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                    r',\s*'  # comma
                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*')
# analyse option group 4
p_key_value = re.compile(r'{\s*'  # opening braces
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option key; 1
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r',\s*'  # comma
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option value; 2
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'}\s*'  # closing braces
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r',?\s*'  # comma
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*')

p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")')

./include/libretro-common/samples/core_options/example_categories/conversion_scripts/v1_to_v2_converter.py

#!/usr/bin/env python3

"""Core options v1 to v2 converter

Just copy 'libretro_core_options.h' & 'libretro_core_options_intl.h' into the same folder as this script
and run it! The original files will be preserved as *.v1
"""
import core_option_regex as cor
import os
import sys

if os.name == 'nt':
    joiner = '\\'
else:
    joiner = '/'
dir_path = os.path.dirname(os.path.realpath(__file__))
h_filename = joiner.join((dir_path, 'libretro_core_options.h'))
intl_filename = joiner.join((dir_path, 'libretro_core_options_intl.h'))


def create_v2_code_file(struct_text, file_name):
    def replace_option(option_match):
        _offset = option_match.start(0)

        if option_match.group(3):
            res = option_match.group(0)[:option_match.end(2) - _offset] + ',\n      NULL' + \
                  option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \
                  'NULL,\n      NULL,\n      ' + option_match.group(0)[option_match.end(3) - _offset:]
        else:
            return option_match.group(0)

        return res

    comment_v1 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 1.3\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    comment_v2 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 2.0\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 2.0: Add support for core options v2 interface\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    p_intl = cor.re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {'
                            r'((?:.|[\r\n])*?)};')
    p_set = cor.re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)'
                           r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif')
    new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\n' \
              '      bool *categories_supported)\n' \
              '{\n' \
              '   unsigned version  = 0;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '   unsigned language = 0;\n' \
              '#endif\n' \
              '\n' \
              '   if (!environ_cb || !categories_supported)\n' \
              '      return;\n' \
              '\n' \
              '   *categories_supported = false;\n' \
              '\n' \
              '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))\n' \
              '      version = 0;\n' \
              '\n' \
              '   if (version >= 2)\n' \
              '   {\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      struct retro_core_options_v2_intl core_options_intl;\n' \
              '\n' \
              '      core_options_intl.us    = &options_us;\n' \
              '      core_options_intl.local = NULL;\n' \
              '\n' \
              '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
              '          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))\n' \
              '         core_options_intl.local = options_intl[language];\n' \
              '\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n' \
              '            &core_options_intl);\n' \
              '#else\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n' \
              '            &options_us);\n' \
              '#endif\n' \
              '   }\n' \
              '   else\n' \
              '   {\n' \
              '      size_t i, j;\n' \
              '      size_t option_index              = 0;\n' \
              '      size_t num_options               = 0;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_us         = NULL;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      size_t num_options_intl          = 0;\n' \
              '      struct retro_core_option_v2_definition\n' \
              '            *option_defs_intl          = NULL;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_intl       = NULL;\n' \
              '      struct retro_core_options_intl\n' \
              '            core_options_v1_intl;\n' \
              '#endif\n' \
              '      struct retro_variable *variables = NULL;\n' \
              '      char **values_buf                = NULL;\n' \
              '\n' \
              '      /* Determine total number of options */\n' \
              '      while (true)\n' \
              '      {\n' \
              '         if (option_defs_us[num_options].key)\n' \
              '            num_options++;\n' \
              '         else\n' \
              '            break;\n' \
              '      }\n' \
              '\n' \
              '      if (version >= 1)\n' \
              '      {\n' \
              '         /* Allocate US array */\n' \
              '         option_v1_defs_us = (struct retro_core_option_definition *)\n' \
              '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i < num_options; i++)\n' \
              '         {\n' \
              '            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];\n' \
              '            struct retro_core_option_value *option_values         = option_def_us->values;\n' \
              '            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];\n' \
              '            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;\n' \
              '\n' \
              '            option_v1_def_us->key           = option_def_us->key;\n' \
              '            option_v1_def_us->desc          = option_def_us->desc;\n' \
              '            option_v1_def_us->info          = option_def_us->info;\n' \
              '            option_v1_def_us->default_value = option_def_us->default_value;\n' \
              '\n' \
              '            /* Values must be copied individually... */\n' \
              '            while (option_values->value)\n' \
              '            {\n' \
              '               option_v1_values->value = option_values->value;\n' \
              '               option_v1_values->label = option_values->label;\n' \
              '\n' \
              '               option_values++;\n' \
              '               option_v1_values++;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
              '             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&\n' \
              '             options_intl[language])\n' \
              '            option_defs_intl = options_intl[language]->definitions;\n' \
              '\n' \
              '         if (option_defs_intl)\n' \
              '         {\n' \
              '            /* Determine number of intl options */\n' \
              '            while (true)\n' \
              '            {\n' \
              '               if (option_defs_intl[num_options_intl].key)\n' \
              '                  num_options_intl++;\n' \
              '               else\n' \
              '                  break;\n' \
              '            }\n' \
              '\n' \
              '            /* Allocate intl array */\n' \
              '            option_v1_defs_intl = (struct retro_core_option_definition *)\n' \
              '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '            /* Copy parameters from option_defs_intl array */\n' \
              '            for (i = 0; i < num_options_intl; i++)\n' \
              '            {\n' \
              '               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_values           = option_def_intl->values;\n' \
              '               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;\n' \
              '\n' \
              '               option_v1_def_intl->key           = option_def_intl->key;\n' \
              '               option_v1_def_intl->desc          = option_def_intl->desc;\n' \
              '               option_v1_def_intl->info          = option_def_intl->info;\n' \
              '               option_v1_def_intl->default_value = option_def_intl->default_value;\n' \
              '\n' \
              '               /* Values must be copied individually... */\n' \
              '               while (option_values->value)\n' \
              '               {\n' \
              '                  option_v1_values->value = option_values->value;\n' \
              '                  option_v1_values->label = option_values->label;\n' \
              '\n' \
              '                  option_values++;\n' \
              '                  option_v1_values++;\n' \
              '               }\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         core_options_v1_intl.us    = option_v1_defs_us;\n' \
              '         core_options_v1_intl.local = option_v1_defs_intl;\n' \
              '\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);\n' \
              '#else\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\n' \
              '#endif\n' \
              '      }\n' \
              '      else\n' \
              '      {\n' \
              '         /* Allocate arrays */\n' \
              '         variables  = (struct retro_variable *)calloc(num_options + 1,\n' \
              '               sizeof(struct retro_variable));\n' \
              '         values_buf = (char **)calloc(num_options, sizeof(char *));\n' \
              '\n' \
              '         if (!variables || !values_buf)\n' \
              '            goto error;\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i < num_options; i++)\n' \
              '         {\n' \
              '            const char *key                        = option_defs_us[i].key;\n' \
              '            const char *desc                       = option_defs_us[i].desc;\n' \
              '            const char *default_value              = option_defs_us[i].default_value;\n' \
              '            struct retro_core_option_value *values = option_defs_us[i].values;\n' \
              '            size_t buf_len                         = 3;\n' \
              '            size_t default_index                   = 0;\n' \
              '\n' \
              '            values_buf[i] = NULL;\n' \
              '\n' \
              '            if (desc)\n' \
              '            {\n' \
              '               size_t num_values = 0;\n' \
              '\n' \
              '               /* Determine number of values */\n' \
              '               while (true)\n' \
              '               {\n' \
              '                  if (values[num_values].value)\n' \
              '                  {\n' \
              '                     /* Check if this is the default value */\n' \
              '                     if (default_value)\n' \
              '                        if (strcmp(values[num_values].value, default_value) == 0)\n' \
              '                           default_index = num_values;\n' \
              '\n' \
              '                     buf_len += strlen(values[num_values].value);\n' \
              '                     num_values++;\n' \
              '                  }\n' \
              '                  else\n' \
              '                     break;\n' \
              '               }\n' \
              '\n' \
              '               /* Build values string */\n' \
              '               if (num_values > 0)\n' \
              '               {\n' \
              '                  buf_len += num_values - 1;\n' \
              '                  buf_len += strlen(desc);\n' \
              '\n' \
              '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\n' \
              '                  if (!values_buf[i])\n' \
              '                     goto error;\n' \
              '\n' \
              '                  strcpy(values_buf[i], desc);\n' \
              '                  strcat(values_buf[i], "; ");\n' \
              '\n' \
              '                  /* Default value goes first */\n' \
              '                  strcat(values_buf[i], values[default_index].value);\n' \
              '\n' \
              '                  /* Add remaining values */\n' \
              '                  for (j = 0; j < num_values; j++)\n' \
              '                  {\n' \
              '                     if (j != default_index)\n' \
              '                     {\n' \
              '                        strcat(values_buf[i], "|");\n' \
              '                        strcat(values_buf[i], values[j].value);\n' \
              '                     }\n' \
              '                  }\n' \
              '               }\n' \
              '            }\n' \
              '\n' \
              '            variables[option_index].key   = key;\n' \
              '            variables[option_index].value = values_buf[i];\n' \
              '            option_index++;\n' \
              '         }\n' \
              '\n' \
              '         /* Set variables */\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n' \
              '      }\n' \
              '\n' \
              'error:\n' \
              '      /* Clean up */\n' \
              '\n' \
              '      if (option_v1_defs_us)\n' \
              '      {\n' \
              '         free(option_v1_defs_us);\n' \
              '         option_v1_defs_us = NULL;\n' \
              '      }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      if (option_v1_defs_intl)\n' \
              '      {\n' \
              '         free(option_v1_defs_intl);\n' \
              '         option_v1_defs_intl = NULL;\n' \
              '      }\n' \
              '#endif\n' \
              '\n' \
              '      if (values_buf)\n' \
              '      {\n' \
              '         for (i = 0; i < num_options; i++)\n' \
              '         {\n' \
              '            if (values_buf[i])\n' \
              '            {\n' \
              '               free(values_buf[i]);\n' \
              '               values_buf[i] = NULL;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         free(values_buf);\n' \
              '         values_buf = NULL;\n' \
              '      }\n' \
              '\n' \
              '      if (variables)\n' \
              '      {\n' \
              '         free(variables);\n' \
              '         variables = NULL;\n' \
              '      }\n' \
              '   }\n' \
              '}\n' \
              '\n' \
              '#ifdef __cplusplus\n' \
              '}\n' \
              '#endif'

    struct_groups = cor.p_struct.finditer(struct_text)
    out_text = struct_text

    for construct in struct_groups:
        repl_text = ''
        declaration = construct.group(1)
        struct_match = cor.p_type_name.search(declaration)
        if struct_match:
            struct_type_name = struct_match.group(1, 2)
        else:
            return -1

        if 'retro_core_option_definition' == struct_type_name[0]:
            import shutil
            shutil.copy(file_name, file_name + '.v1')
            new_declaration = f'\nstruct retro_core_option_v2_category option_cats_{struct_match.group(3)}[] = ' \
                              '{\n   { NULL, NULL, NULL },\n' \
                              '};\n\n' \
                              + declaration[:struct_match.start(1)] + \
                              'retro_core_option_v2_definition' \
                              + declaration[struct_match.end(1):]
            offset = construct.start(0)
            repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,
                                               construct.group(0)[:construct.start(2) - offset])
            content = construct.group(2)
            new_content = cor.p_option.sub(replace_option, content)

            repl_text = repl_text + new_content + cor.re.sub(r'{\s*NULL,\s*NULL,\s*NULL,\s*{\{0}},\s*NULL\s*},\s*};',
                                                             '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};'
                                                             '\n\nstruct retro_core_options_v2 options_' +
                                                             struct_match.group(3) + ' = {\n'
                                                             f'   option_cats_{struct_match.group(3)},\n'
                                                             f'   option_defs_{struct_match.group(3)}\n'
                                                             '};',
                                                             construct.group(0)[construct.end(2) - offset:])
            out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text)
        else:
            return -2
    with open(file_name, 'w', encoding='utf-8') as code_file:
        out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)
        intl = p_intl.search(out_text)
        if intl:
            new_intl = out_text[:intl.start(1)] \
                       + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \
                       + out_text[intl.end(1):intl.start(2)] + cor.re.sub(r'option_defs_', '&options_', intl.group(2)) \
                       + out_text[intl.end(2):]
            out_text = p_set.sub(new_set, new_intl)
        else:
            out_text = p_set.sub(new_set, out_text)
        code_file.write(out_text)

    return 1


# --------------------          MAIN          -------------------- #

if __name__ == '__main__':
    try:
        for file in (h_filename, intl_filename):
            if os.path.isfile(file):
                with open(file, 'r+', encoding='utf-8') as h_file:
                    text = h_file.read()
                    test = create_v2_code_file(text, file)
                    if -1 > test:
                        print('Your file looks like it already is v2? (' + file + ')')
                        continue
                    if 0 > test:
                        print('An error occurred! Please make sure to use the complete v1 struct! (' + file + ')')
                        continue
            else:
                print(file + ' not found.')
    except EnvironmentError:
        print('Something went wrong with reading or writing files!')
        sys.exit(1)

./include/libretro-common/samples/core_options/example_categories/libretro_core_options.h

#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include <stdlib.h>
#include <string.h>

#include <libretro.h>
#include <retro_inline.h>

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_v2_category option_cats_us[] = {
   {
      "video",                     /* key (category name) */
      "Video",                     /* category description (label) */
      "Configure display options." /* category sublabel */
   },
   {
      "hacks",
      "Advanced",
      "Options affecting low-level emulation performance and accuracy."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      NULL,                                       /* 'categorised' description (used instead of
                                                   * 'description' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * description is always used */
      "Specify which region the system is from.", /* sublabel */
      NULL,                                       /* 'categorised' sublabel (used instead of
                                                   * 'sublabel' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * sublabel is always used */
      NULL,                                       /* category key (must match an entry in
                                                   * option_cats_us; if NULL or empty,
                                                   * option is uncategorised */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video > Scale",   /* description: here a 'Video >' prefix is used to
                          * signify a category on frontends without explicit
                          * category support */
      "Scale",           /* 'categorised' description: will be displayed inside
                          * the 'Video' submenu */
      "Set internal video scale factor.",
      NULL,
      "video",           /* category key */
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   {
      "mycore_overclock",
      "Advanced > Reduce Slowdown",
      "Reduce Slowdown",
      "Enabling 'Advanced > Reduce Slowdown' will reduce accuracy.", /* sublabel */
      "Enabling 'Reduce Slowdown' will reduce accuracy.",            /* 'categorised' sublabel:
                               * will be displayed inside the 'Advanced' submenu; note that
                               * 'Advanced > Reduce Slowdown' is replaced with 'Reduce Slowdown' */
      "hacks",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_us = {
   option_cats_us,
   option_defs_us
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {
   &options_us, /* RETRO_LANGUAGE_ENGLISH */
   NULL,        /* RETRO_LANGUAGE_JAPANESE */
   &options_fr, /* RETRO_LANGUAGE_FRENCH */
   NULL,        /* RETRO_LANGUAGE_SPANISH */
   NULL,        /* RETRO_LANGUAGE_GERMAN */
   NULL,        /* RETRO_LANGUAGE_ITALIAN */
   NULL,        /* RETRO_LANGUAGE_DUTCH */
   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   NULL,        /* RETRO_LANGUAGE_RUSSIAN */
   NULL,        /* RETRO_LANGUAGE_KOREAN */
   NULL,        /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   NULL,        /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   NULL,        /* RETRO_LANGUAGE_ESPERANTO */
   NULL,        /* RETRO_LANGUAGE_POLISH */
   NULL,        /* RETRO_LANGUAGE_VIETNAMESE */
   NULL,        /* RETRO_LANGUAGE_ARABIC */
   NULL,        /* RETRO_LANGUAGE_GREEK */
   NULL,        /* RETRO_LANGUAGE_TURKISH */
   NULL,        /* RETRO_LANGUAGE_SLOVAK */
   NULL,        /* RETRO_LANGUAGE_PERSIAN */
   NULL,        /* RETRO_LANGUAGE_HEBREW */
   NULL,        /* RETRO_LANGUAGE_ASTURIAN */
   NULL,        /* RETRO_LANGUAGE_FINNISH */
   NULL,        /* RETRO_LANGUAGE_INDONESIAN */
   NULL,        /* RETRO_LANGUAGE_SWEDISH */
   NULL,        /* RETRO_LANGUAGE_UKRAINIAN */
   NULL,        /* RETRO_LANGUAGE_CZECH */
   NULL,        /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   NULL,        /* RETRO_LANGUAGE_CATALAN */
   NULL,        /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   NULL,        /* RETRO_LANGUAGE_HUNGARIAN */
   NULL,        /* RETRO_LANGUAGE_BELARUSIAN */
   NULL,        /* RETRO_LANGUAGE_GALICIAN */
   NULL,        /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * > We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
      bool *categories_supported)
{
   unsigned version  = 0;
#ifndef HAVE_NO_LANGEXTRA
   unsigned language = 0;
#endif

   if (!environ_cb || !categories_supported)
      return;

   *categories_supported = false;

   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))
      version = 0;

   if (version >= 2)
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_v2_intl core_options_intl;

      core_options_intl.us    = &options_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = options_intl[language];

      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
            &core_options_intl);
#else
      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
            &options_us);
#endif
   }
   else
   {
      size_t i, j;
      size_t option_index              = 0;
      size_t num_options               = 0;
      struct retro_core_option_definition
            *option_v1_defs_us         = NULL;
#ifndef HAVE_NO_LANGEXTRA
      size_t num_options_intl          = 0;
      struct retro_core_option_v2_definition
            *option_defs_intl          = NULL;
      struct retro_core_option_definition
            *option_v1_defs_intl       = NULL;
      struct retro_core_options_intl
            core_options_v1_intl;
#endif
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine total number of options */
      while (true)
      {
         if (option_defs_us[num_options].key)
            num_options++;
         else
            break;
      }

      if (version >= 1)
      {
         /* Allocate US array */
         option_v1_defs_us = (struct retro_core_option_definition *)
               calloc(num_options + 1, sizeof(struct retro_core_option_definition));

         /* Copy parameters from option_defs_us array */
         for (i = 0; i < num_options; i++)
         {
            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];
            struct retro_core_option_value *option_values         = option_def_us->values;
            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];
            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;

            option_v1_def_us->key           = option_def_us->key;
            option_v1_def_us->desc          = option_def_us->desc;
            option_v1_def_us->info          = option_def_us->info;
            option_v1_def_us->default_value = option_def_us->default_value;

            /* Values must be copied individually... */
            while (option_values->value)
            {
               option_v1_values->value = option_values->value;
               option_v1_values->label = option_values->label;

               option_values++;
               option_v1_values++;
            }
         }

#ifndef HAVE_NO_LANGEXTRA
         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&
             options_intl[language])
            option_defs_intl = options_intl[language]->definitions;

         if (option_defs_intl)
         {
            /* Determine number of intl options */
            while (true)
            {
               if (option_defs_intl[num_options_intl].key)
                  num_options_intl++;
               else
                  break;
            }

            /* Allocate intl array */
            option_v1_defs_intl = (struct retro_core_option_definition *)
                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));

            /* Copy parameters from option_defs_intl array */
            for (i = 0; i < num_options_intl; i++)
            {
               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];
               struct retro_core_option_value *option_values           = option_def_intl->values;
               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];
               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;

               option_v1_def_intl->key           = option_def_intl->key;
               option_v1_def_intl->desc          = option_def_intl->desc;
               option_v1_def_intl->info          = option_def_intl->info;
               option_v1_def_intl->default_value = option_def_intl->default_value;

               /* Values must be copied individually... */
               while (option_values->value)
               {
                  option_v1_values->value = option_values->value;
                  option_v1_values->label = option_values->label;

                  option_values++;
                  option_v1_values++;
               }
            }
         }

         core_options_v1_intl.us    = option_v1_defs_us;
         core_options_v1_intl.local = option_v1_defs_intl;

         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);
#else
         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);
#endif
      }
      else
      {
         /* Allocate arrays */
         variables  = (struct retro_variable *)calloc(num_options + 1,
               sizeof(struct retro_variable));
         values_buf = (char **)calloc(num_options, sizeof(char *));

         if (!variables || !values_buf)
            goto error;

         /* Copy parameters from option_defs_us array */
         for (i = 0; i < num_options; i++)
         {
            const char *key                        = option_defs_us[i].key;
            const char *desc                       = option_defs_us[i].desc;
            const char *default_value              = option_defs_us[i].default_value;
            struct retro_core_option_value *values = option_defs_us[i].values;
            size_t buf_len                         = 3;
            size_t default_index                   = 0;

            values_buf[i] = NULL;

            if (desc)
            {
               size_t num_values = 0;

               /* Determine number of values */
               while (true)
               {
                  if (values[num_values].value)
                  {
                     /* Check if this is the default value */
                     if (default_value)
                        if (strcmp(values[num_values].value, default_value) == 0)
                           default_index = num_values;

                     buf_len += strlen(values[num_values].value);
                     num_values++;
                  }
                  else
                     break;
               }

               /* Build values string */
               if (num_values > 0)
               {
                  buf_len += num_values - 1;
                  buf_len += strlen(desc);

                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));
                  if (!values_buf[i])
                     goto error;

                  strcpy(values_buf[i], desc);
                  strcat(values_buf[i], "; ");

                  /* Default value goes first */
                  strcat(values_buf[i], values[default_index].value);

                  /* Add remaining values */
                  for (j = 0; j < num_values; j++)
                  {
                     if (j != default_index)
                     {
                        strcat(values_buf[i], "|");
                        strcat(values_buf[i], values[j].value);
                     }
                  }
               }
            }

            variables[option_index].key   = key;
            variables[option_index].value = values_buf[i];
            option_index++;
         }

         /* Set variables */
         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
      }

error:
      /* Clean up */

      if (option_v1_defs_us)
      {
         free(option_v1_defs_us);
         option_v1_defs_us = NULL;
      }

#ifndef HAVE_NO_LANGEXTRA
      if (option_v1_defs_intl)
      {
         free(option_v1_defs_intl);
         option_v1_defs_intl = NULL;
      }
#endif

      if (values_buf)
      {
         for (i = 0; i < num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_categories/libretro_core_options_intl.h

#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include <libretro.h>

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

struct retro_core_option_v2_category option_cats_fr[] = {
   {
      "video",                              /* key must match option_cats_us entry */
      "Vidéo",                              /* translated category description */
      "Configurez les options d'affichage." /* translated category sublabel */
   },
   {
      "hacks",
      "Avancée",
      "Options affectant les performances et la précision de l'émulation de bas niveau."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_fr[] = {
   {
      "mycore_region",                             /* key must match option_defs_us entry */
      "Région de la console",                      /* translated description */
      NULL,
      "Spécifiez la région d'origine du système.", /* translated sublabel */
      NULL,
      NULL,                                        /* category key is taken from option_defs_us
                                                    * -> can set to NULL here */
      {
         { "auto",   "Auto" },                     /* value must match option_defs_us entry   */
         { "ntsc-j", "Japon" },                    /* > only value_label should be translated */
         { "ntsc-u", "Amérique" },
         { "pal",    "L'Europe" },
         { NULL, NULL },
      },
      NULL                                         /* default_value is taken from option_defs_us
                                                    * -> can set to NULL here */
   },
   {
      "mycore_video_scale",
      "Vidéo > Échelle", /* translated description */
      "Échelle",         /* translated 'categorised' description */
      "Définir le facteur d'échelle vidéo interne.",
      NULL,
      NULL,
      {
         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */
      },
      NULL
   },
   {
      "mycore_overclock",
      "Avancé > Réduire le ralentissement",
      "Réduire le ralentissement",
      "L'activation de « Avancé > Réduire le ralentissement » réduira la précision.", /* translated sublabel */
      "L'activation de « Réduire le ralentissement » réduira la précision.",          /* translated 'categorised'
                                                                                       * sublabel */
      NULL,
      {
         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */
      },
      NULL
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_fr = {
   option_cats_fr,
   option_defs_fr
};

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_default/libretro_core_options.h

#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include <stdlib.h>
#include <string.h>

#include <libretro.h>
#include <retro_inline.h>

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      "Specify which region the system is from.", /* sublabel */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video Scale",
      "Set internal video scale factor.",
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   {
      "mycore_overclock",
      "Reduce Slowdown",
      "Enable CPU overclock (unsafe).",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, {{0}}, NULL },
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_JAPANESE */
   NULL,           /* RETRO_LANGUAGE_FRENCH */
   NULL,           /* RETRO_LANGUAGE_SPANISH */
   NULL,           /* RETRO_LANGUAGE_GERMAN */
   NULL,           /* RETRO_LANGUAGE_ITALIAN */
   NULL,           /* RETRO_LANGUAGE_DUTCH */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
   NULL,           /* RETRO_LANGUAGE_KOREAN */
   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
   NULL,           /* RETRO_LANGUAGE_POLISH */
   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
   NULL,           /* RETRO_LANGUAGE_ARABIC */
   NULL,           /* RETRO_LANGUAGE_GREEK */
   NULL,           /* RETRO_LANGUAGE_TURKISH */
   NULL,           /* RETRO_LANGUAGE_SLOVAK */
   NULL,           /* RETRO_LANGUAGE_PERSIAN */
   NULL,           /* RETRO_LANGUAGE_HEBREW */
   NULL,           /* RETRO_LANGUAGE_ASTURIAN */
   NULL,           /* RETRO_LANGUAGE_FINNISH */
   NULL,           /* RETRO_LANGUAGE_INDONESIAN */
   NULL,           /* RETRO_LANGUAGE_SWEDISH */
   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
   NULL,           /* RETRO_LANGUAGE_CZECH */
   NULL,           /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   NULL,           /* RETRO_LANGUAGE_CATALAN */
   NULL,           /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_HUNGARIAN */
   NULL,           /* RETRO_LANGUAGE_BELARUSIAN */
   NULL,           /* RETRO_LANGUAGE_GALICIAN */
   NULL,           /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * > We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
{
   unsigned version = 0;

   if (!environ_cb)
      return;

   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_intl core_options_intl;
      unsigned language = 0;

      core_options_intl.us    = option_defs_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = option_defs_intl[language];

      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
#else
      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
#endif
   }
   else
   {
      size_t i;
      size_t num_options               = 0;
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine number of options */
      for (;;)
      {
         if (!option_defs_us[num_options].key)
            break;
         num_options++;
      }

      /* Allocate arrays */
      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
      values_buf = (char **)calloc(num_options, sizeof(char *));

      if (!variables || !values_buf)
         goto error;

      /* Copy parameters from option_defs_us array */
      for (i = 0; i < num_options; i++)
      {
         const char *key                        = option_defs_us[i].key;
         const char *desc                       = option_defs_us[i].desc;
         const char *default_value              = option_defs_us[i].default_value;
         struct retro_core_option_value *values = option_defs_us[i].values;
         size_t buf_len                         = 3;
         size_t default_index                   = 0;

         values_buf[i] = NULL;

         if (desc)
         {
            size_t num_values = 0;

            /* Determine number of values */
            for (;;)
            {
               if (!values[num_values].value)
                  break;

               /* Check if this is the default value */
               if (default_value)
                  if (strcmp(values[num_values].value, default_value) == 0)
                     default_index = num_values;

               buf_len += strlen(values[num_values].value);
               num_values++;
            }

            /* Build values string */
            if (num_values > 0)
            {
               size_t j;

               buf_len += num_values - 1;
               buf_len += strlen(desc);

               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
               if (!values_buf[i])
                  goto error;

               strcpy(values_buf[i], desc);
               strcat(values_buf[i], "; ");

               /* Default value goes first */
               strcat(values_buf[i], values[default_index].value);

               /* Add remaining values */
               for (j = 0; j < num_values; j++)
               {
                  if (j != default_index)
                  {
                     strcat(values_buf[i], "|");
                     strcat(values_buf[i], values[j].value);
                  }
               }
            }
         }

         variables[i].key   = key;
         variables[i].value = values_buf[i];
      }

      /* Set variables */
      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);

error:

      /* Clean up */
      if (values_buf)
      {
         for (i = 0; i < num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h

#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include <libretro.h>

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h

#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include <stdlib.h>
#include <string.h>

#include <libretro.h>
#include <retro_inline.h>

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      "Specify which region the system is from.", /* sublabel */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video Scale",
      "Set internal video scale factor.",
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   /* This 'mycore_show_speedhacks' option will only be shown
    * if the frontend supports core options API v1.
    * It will be hidden on older frontends.
    * See line 227 */
   {
      "mycore_show_speedhacks",
      "Show Unsafe Settings",
      "Enable configuration of emulation speed hacks.",
      {
         { "enabled",  NULL },
         { "disabled", NULL },
         { NULL, NULL},
      },
      "disabled"
   },
   {
      "mycore_overclock",
      "Reduce Slowdown",
      "Enable CPU overclock (unsafe).",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, {{0}}, NULL },
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_JAPANESE */
   NULL,           /* RETRO_LANGUAGE_FRENCH */
   NULL,           /* RETRO_LANGUAGE_SPANISH */
   NULL,           /* RETRO_LANGUAGE_GERMAN */
   NULL,           /* RETRO_LANGUAGE_ITALIAN */
   NULL,           /* RETRO_LANGUAGE_DUTCH */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
   NULL,           /* RETRO_LANGUAGE_KOREAN */
   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
   NULL,           /* RETRO_LANGUAGE_POLISH */
   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
   NULL,           /* RETRO_LANGUAGE_ARABIC */
   NULL,           /* RETRO_LANGUAGE_GREEK */
   NULL,           /* RETRO_LANGUAGE_TURKISH */
   NULL,           /* RETRO_LANGUAGE_SLOVAK */
   NULL,           /* RETRO_LANGUAGE_PERSIAN */
   NULL,           /* RETRO_LANGUAGE_HEBREW */
   NULL,           /* RETRO_LANGUAGE_ASTURIAN */
   NULL,           /* RETRO_LANGUAGE_FINNISH */
   NULL,           /* RETRO_LANGUAGE_INDONESIAN */
   NULL,           /* RETRO_LANGUAGE_SWEDISH */
   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
   NULL,           /* RETRO_LANGUAGE_CZECH */
   NULL,           /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   NULL,           /* RETRO_LANGUAGE_CATALAN */
   NULL,           /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_HUNGARIAN */
   NULL,           /* RETRO_LANGUAGE_BELARUSIAN */
   NULL,           /* RETRO_LANGUAGE_GALICIAN */
   NULL,           /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * > We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
{
   unsigned version = 0;

   if (!environ_cb)
      return;

   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_intl core_options_intl;
      unsigned language = 0;

      core_options_intl.us    = option_defs_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = option_defs_intl[language];

      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
#else
      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
#endif
   }
   else
   {
      size_t i;
      size_t option_index              = 0;
      size_t num_options               = 0;
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine number of options
       * > Note: We are going to skip a number of irrelevant
       *   core options when building the retro_variable array,
       *   but we'll allocate space for all of them. The difference
       *   in resource usage is negligible, and this allows us to
       *   keep the code 'cleaner' */
      for (;;)
      {
         if (!option_defs_us[num_options].key)
            break;
         num_options++;
      }

      /* Allocate arrays */
      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
      values_buf = (char **)calloc(num_options, sizeof(char *));

      if (!variables || !values_buf)
         goto error;

      /* Copy parameters from option_defs_us array */
      for (i = 0; i < num_options; i++)
      {
         const char *key                        = option_defs_us[i].key;
         const char *desc                       = option_defs_us[i].desc;
         const char *default_value              = option_defs_us[i].default_value;
         struct retro_core_option_value *values = option_defs_us[i].values;
         size_t buf_len                         = 3;
         size_t default_index                   = 0;

         values_buf[i] = NULL;

         /* Skip options that are irrelevant when using the
          * old style core options interface */
         if (strcmp(key, "mycore_show_speedhacks") == 0)
            continue;

         if (desc)
         {
            size_t num_values = 0;

            /* Determine number of values */
            for (;;)
            {
               if (!values[num_values].value)
                  break;

               /* Check if this is the default value */
               if (default_value)
                  if (strcmp(values[num_values].value, default_value) == 0)
                     default_index = num_values;

               buf_len += strlen(values[num_values].value);
               num_values++;
            }

            /* Build values string */
            if (num_values > 0)
            {
               size_t j;

               buf_len += num_values - 1;
               buf_len += strlen(desc);

               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
               if (!values_buf[i])
                  goto error;

               strcpy(values_buf[i], desc);
               strcat(values_buf[i], "; ");

               /* Default value goes first */
               strcat(values_buf[i], values[default_index].value);

               /* Add remaining values */
               for (j = 0; j < num_values; j++)
               {
                  if (j != default_index)
                  {
                     strcat(values_buf[i], "|");
                     strcat(values_buf[i], values[j].value);
                  }
               }
            }
         }

         variables[option_index].key   = key;
         variables[option_index].value = values_buf[i];
         option_index++;
      }

      /* Set variables */
      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);

error:

      /* Clean up */
      if (values_buf)
      {
         for (i = 0; i < num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h

#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include <libretro.h>

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_translation/libretro_core_options.h

#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include <stdlib.h>
#include <string.h>

#include <libretro.h>
#include <retro_inline.h>

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_v2_category option_cats_us[] = {
   {
      "video",                     /* key (category name) */
      "Video",                     /* category description (label) */
      "Configure display options." /* category sublabel */
   },
   {
      "hacks",
      "Advanced",
      "Options affecting low-level emulation performance and accuracy."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      NULL,                                       /* 'categorised' description (used instead of
                                                   * 'description' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * description is always used */
      "Specify which region the system is from.", /* sublabel */
      NULL,                                       /* 'categorised' sublabel (used instead of
                                                   * 'sublabel' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * sublabel is always used */
      NULL,                                       /* category key (must match an entry in
                                                   * option_cats_us; if NULL or empty,
                                                   * option is uncategorised */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video > Scale",   /* description: here a 'Video >' prefix is used to
                          * signify a category on frontends without explicit
                          * category support */
      "Scale",           /* 'categorised' description: will be displayed inside
                          * the 'Video' submenu */
      "Set internal video scale factor.",
      NULL,
      "video",           /* category key */
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   {
      "mycore_overclock",
      "Advanced > Reduce Slowdown",
      "Reduce Slowdown",
      "Enabling 'Advanced > Reduce Slowdown' will reduce accuracy.", /* sublabel */
      "Enabling 'Reduce Slowdown' will reduce accuracy.",            /* 'categorised' sublabel:
                               * will be displayed inside the 'Advanced' submenu; note that
                               * 'Advanced > Reduce Slowdown' is replaced with 'Reduce Slowdown' */
      "hacks",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_us = {
   option_cats_us,
   option_defs_us
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {
   &options_us,      /* RETRO_LANGUAGE_ENGLISH */
   &options_ja,      /* RETRO_LANGUAGE_JAPANESE */
   &options_fr,      /* RETRO_LANGUAGE_FRENCH */
   &options_es,      /* RETRO_LANGUAGE_SPANISH */
   &options_de,      /* RETRO_LANGUAGE_GERMAN */
   &options_it,      /* RETRO_LANGUAGE_ITALIAN */
   &options_nl,      /* RETRO_LANGUAGE_DUTCH */
   &options_pt_br,   /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   &options_pt_pt,   /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   &options_ru,      /* RETRO_LANGUAGE_RUSSIAN */
   &options_ko,      /* RETRO_LANGUAGE_KOREAN */
   &options_cht,     /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   &options_chs,     /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   &options_eo,      /* RETRO_LANGUAGE_ESPERANTO */
   &options_pl,      /* RETRO_LANGUAGE_POLISH */
   &options_vn,      /* RETRO_LANGUAGE_VIETNAMESE */
   &options_ar,      /* RETRO_LANGUAGE_ARABIC */
   &options_el,      /* RETRO_LANGUAGE_GREEK */
   &options_tr,      /* RETRO_LANGUAGE_TURKISH */
   &options_sk,      /* RETRO_LANGUAGE_SLOVAK */
   &options_fa,      /* RETRO_LANGUAGE_PERSIAN */
   &options_he,      /* RETRO_LANGUAGE_HEBREW */
   &options_ast,     /* RETRO_LANGUAGE_ASTURIAN */
   &options_fi,      /* RETRO_LANGUAGE_FINNISH */
   &options_id,      /* RETRO_LANGUAGE_INDONESIAN */
   &options_sv,      /* RETRO_LANGUAGE_SWEDISH */
   &options_uk,      /* RETRO_LANGUAGE_UKRAINIAN */
   &options_cs,      /* RETRO_LANGUAGE_CZECH */
   &options_val,     /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   &options_ca,      /* RETRO_LANGUAGE_CATALAN */
   &options_en,      /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   &options_hu,      /* RETRO_LANGUAGE_HUNGARIAN */
   &options_be,      /* RETRO_LANGUAGE_BELARUSIAN */
   &options_gl,      /* RETRO_LANGUAGE_GALICIAN */
   &options_no,      /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * > We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
      bool *categories_supported)
{
   unsigned version  = 0;
#ifndef HAVE_NO_LANGEXTRA
   unsigned language = 0;
#endif

   if (!environ_cb || !categories_supported)
      return;

   *categories_supported = false;

   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))
      version = 0;

   if (version >= 2)
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_v2_intl core_options_intl;

      core_options_intl.us    = &options_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = options_intl[language];

      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
            &core_options_intl);
#else
      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
            &options_us);
#endif
   }
   else
   {
      size_t i, j;
      size_t option_index              = 0;
      size_t num_options               = 0;
      struct retro_core_option_definition
            *option_v1_defs_us         = NULL;
#ifndef HAVE_NO_LANGEXTRA
      size_t num_options_intl          = 0;
      struct retro_core_option_v2_definition
            *option_defs_intl          = NULL;
      struct retro_core_option_definition
            *option_v1_defs_intl       = NULL;
      struct retro_core_options_intl
            core_options_v1_intl;
#endif
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine total number of options */
      while (true)
      {
         if (option_defs_us[num_options].key)
            num_options++;
         else
            break;
      }

      if (version >= 1)
      {
         /* Allocate US array */
         option_v1_defs_us = (struct retro_core_option_definition *)
               calloc(num_options + 1, sizeof(struct retro_core_option_definition));

         /* Copy parameters from option_defs_us array */
         for (i = 0; i < num_options; i++)
         {
            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];
            struct retro_core_option_value *option_values         = option_def_us->values;
            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];
            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;

            option_v1_def_us->key           = option_def_us->key;
            option_v1_def_us->desc          = option_def_us->desc;
            option_v1_def_us->info          = option_def_us->info;
            option_v1_def_us->default_value = option_def_us->default_value;

            /* Values must be copied individually... */
            while (option_values->value)
            {
               option_v1_values->value = option_values->value;
               option_v1_values->label = option_values->label;

               option_values++;
               option_v1_values++;
            }
         }

#ifndef HAVE_NO_LANGEXTRA
         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&
             options_intl[language])
            option_defs_intl = options_intl[language]->definitions;

         if (option_defs_intl)
         {
            /* Determine number of intl options */
            while (true)
            {
               if (option_defs_intl[num_options_intl].key)
                  num_options_intl++;
               else
                  break;
            }

            /* Allocate intl array */
            option_v1_defs_intl = (struct retro_core_option_definition *)
                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));

            /* Copy parameters from option_defs_intl array */
            for (i = 0; i < num_options_intl; i++)
            {
               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];
               struct retro_core_option_value *option_values           = option_def_intl->values;
               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];
               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;

               option_v1_def_intl->key           = option_def_intl->key;
               option_v1_def_intl->desc          = option_def_intl->desc;
               option_v1_def_intl->info          = option_def_intl->info;
               option_v1_def_intl->default_value = option_def_intl->default_value;

               /* Values must be copied individually... */
               while (option_values->value)
               {
                  option_v1_values->value = option_values->value;
                  option_v1_values->label = option_values->label;

                  option_values++;
                  option_v1_values++;
               }
            }
         }

         core_options_v1_intl.us    = option_v1_defs_us;
         core_options_v1_intl.local = option_v1_defs_intl;

         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);
#else
         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);
#endif
      }
      else
      {
         /* Allocate arrays */
         variables  = (struct retro_variable *)calloc(num_options + 1,
               sizeof(struct retro_variable));
         values_buf = (char **)calloc(num_options, sizeof(char *));

         if (!variables || !values_buf)
            goto error;

         /* Copy parameters from option_defs_us array */
         for (i = 0; i < num_options; i++)
         {
            const char *key                        = option_defs_us[i].key;
            const char *desc                       = option_defs_us[i].desc;
            const char *default_value              = option_defs_us[i].default_value;
            struct retro_core_option_value *values = option_defs_us[i].values;
            size_t buf_len                         = 3;
            size_t default_index                   = 0;

            values_buf[i] = NULL;

            if (desc)
            {
               size_t num_values = 0;

               /* Determine number of values */
               while (true)
               {
                  if (values[num_values].value)
                  {
                     /* Check if this is the default value */
                     if (default_value)
                        if (strcmp(values[num_values].value, default_value) == 0)
                           default_index = num_values;

                     buf_len += strlen(values[num_values].value);
                     num_values++;
                  }
                  else
                     break;
               }

               /* Build values string */
               if (num_values > 0)
               {
                  buf_len += num_values - 1;
                  buf_len += strlen(desc);

                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));
                  if (!values_buf[i])
                     goto error;

                  strcpy(values_buf[i], desc);
                  strcat(values_buf[i], "; ");

                  /* Default value goes first */
                  strcat(values_buf[i], values[default_index].value);

                  /* Add remaining values */
                  for (j = 0; j < num_values; j++)
                  {
                     if (j != default_index)
                     {
                        strcat(values_buf[i], "|");
                        strcat(values_buf[i], values[j].value);
                     }
                  }
               }
            }

            variables[option_index].key   = key;
            variables[option_index].value = values_buf[i];
            option_index++;
         }

         /* Set variables */
         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
      }

error:
      /* Clean up */

      if (option_v1_defs_us)
      {
         free(option_v1_defs_us);
         option_v1_defs_us = NULL;
      }

#ifndef HAVE_NO_LANGEXTRA
      if (option_v1_defs_intl)
      {
         free(option_v1_defs_intl);
         option_v1_defs_intl = NULL;
      }
#endif

      if (values_buf)
      {
         for (i = 0; i < num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h

#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include <libretro.h>

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

struct retro_core_option_v2_category option_cats_fr[] = {
   {
      "video",                              /* key must match option_cats_us entry */
      "Vidéo",                              /* translated category description */
      "Configurez les options d'affichage." /* translated category sublabel */
   },
   {
      "hacks",
      "Avancée",
      "Options affectant les performances et la précision de l'émulation de bas niveau."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_fr[] = {
   {
      "mycore_region",                             /* key must match option_defs_us entry */
      "Région de la console",                      /* translated description */
      NULL,
      "Spécifiez la région d'origine du système.", /* translated sublabel */
      NULL,
      NULL,                                        /* category key is taken from option_defs_us
                                                    * -> can set to NULL here */
      {
         { "auto",   "Auto" },                     /* value must match option_defs_us entry   */
         { "ntsc-j", "Japon" },                    /* > only value_label should be translated */
         { "ntsc-u", "Amérique" },
         { "pal",    "L'Europe" },
         { NULL, NULL },
      },
      NULL                                         /* default_value is taken from option_defs_us
                                                    * -> can set to NULL here */
   },
   {
      "mycore_video_scale",
      "Vidéo > Échelle", /* translated description */
      "Échelle",         /* translated 'categorised' description */
      "Définir le facteur d'échelle vidéo interne.",
      NULL,
      NULL,
      {
         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */
      },
      NULL
   },
   {
      "mycore_overclock",
      "Avancé > Réduire le ralentissement",
      "Réduire le ralentissement",
      "L'activation de « Avancé > Réduire le ralentissement » réduira la précision.", /* translated sublabel */
      "L'activation de « Réduire le ralentissement » réduira la précision.",          /* translated 'categorised'
                                                                                       * sublabel */
      NULL,
      {
         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */
      },
      NULL
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_fr = {
   option_cats_fr,
   option_defs_fr
};

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif

./include/libretro-common/samples/core_options/example_translation/translation scripts/crowdin.yml

files:
  - source: /intl/_us/*.json
    translation: /intl/_%two_letters_code%/%original_file_name%

./include/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_intl.yml

# Recreate libretro_core_options_intl.h using translations form Crowdin

name: Crowdin Translation Integration

on:
  push:
    branches:
      - master
    paths:
      - 'intl/*/*'

jobs:
  create_intl_file:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Python
        uses: actions/setup-python@v2
        
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
          fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.

      - name: Create intl file
        shell: bash
        run: |
          python3 intl/crowdin_intl.py '<path/to/libretro_core_options.h directory>'

      - name: Commit files
        run: |
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add <path/to/libretro_core_options_intl.h file>
          git commit -m "Recreate libretro_core_options_intl.h" -a

      - name: GitHub Push
        uses: ad-m/github-push-action@v0.6.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}

./include/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_prep.yml

# Prepare source for Crowdin sync

name: Crowdin Upload Preparation

on:
  push:
    branches:
      - master
    paths:
      - '<path/to/libretro_core_options.h file>'

jobs:
  prepare_source_file:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Python
        uses: actions/setup-python@v2
        
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
          fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.

      - name: Crowdin Prep
        shell: bash
        run: |
          python3 intl/crowdin_prep.py '<path/to/libretro_core_options.h directory>'
          
      - name: Commit files
        run: |
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add intl/*
          git commit -m "Recreate translation source text files" -a

      - name: GitHub Push
        uses: ad-m/github-push-action@v0.6.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}

./include/libretro-common/samples/core_options/example_translation/translation scripts/instructions.txt

Place 'crowdin.yml' & the 'intl' and '.github' folder, including content, into the root of the repo.

In '.github/workflows' are two files: 'crowdin_intl.yml' & 'crowdin_prep.yml'
In each of those are place holders, which need to be replaced as follows:

<path/to/libretro_core_options.h directory>
-> replace with the path from the root of the repo to the directory containing
'libretro_core_options.h' (it is assumed that 'libretro_core_options.h' &
'libretro_core_options_intl.h' are in the same directory)

<path/to/libretro_core_options.h file>
-> replace with the full path from the root of the repo to the 'libretro_core_options.h' file

<path/to/libretro_core_options_intl.h file>
-> replace with the full path from the root of the repo to the 'libretro_core_options_intl.h' file


From the root of the repo run (using bash):
python3 intl/core_opt_translation.py '<path/to/libretro_core_options.h directory>'

(If python3 doesn't work, try just python)

Push changes to repo. Once merged, request Crowdin integration.


Crowdin integration:

On the project page, go to the Applications tab. Choose GitHub.
There are two options: connecting a GitHub account, which has write/commit permissions to the repo
or providing a GitHub token, which will unlock these permissions.

Then add a repository, a new interface opens. Pick the repository as well as the branch, which you want to sync.
On the right, Crowdin will display the default name of the repository it will use for creating PRs.
Below, set the sync schedule and then save. With that the synchronisation should be set up.
If there are still problems, you might need to manually modify the configuration (double click on the branch in the lower frame).

Here's what the file paths should look like (the '/' at the start is very important!):

Source files path:
/intl/_us/*.json

Translated files path:
/intl/_%two_letters_code%/%original_file_name%


Once Crowdin successfully creates the PR & it has been merged, the automatically created branch can be deleted on GitHub.

./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_option_regex.py

import re

# 0: full struct; 1: up to & including first []; 2: content between first {}
p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*'
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'=\s*'  # =
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};')  # captures full struct, it's beginning and it's content
# 0: type name[]; 1: type; 2: name
p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*'
                         r'(option_cats([a-z_]{0,8})|option_defs([a-z_]{0,8}))\s*\[]')
# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
p_option = re.compile(r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\"|'  # key start; group 1
                      r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|'
                      r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|'
                      r'[a-zA-Z0-9_]+\s*\".*?\")\s*'  # key end
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\")\s*'  # description; group 2
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # group 3
                      r'(?:NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')+)'
                      r'(?:'  # defs only start
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # key/value pairs start; group 4
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option key
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*)'  # key/value pairs end
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:'  # defaults start
                      r'(?:NULL|\".*?\")\s*'  # default value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*'  # defaults end
                      r')?'  # defs only end
                      r'},')  # closing braces
# analyse option group 3
p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                    r',')
p_info_cat = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")')
# analyse option group 4
p_key_value = re.compile(r'{\s*'  # opening braces
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option key; 1
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r',\s*'  # comma
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option value; 2
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'}')

p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")')

p_intl = re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {'
                    r'((?:.|[\r\n])*?)};')
p_set = re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)'
                   r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif')

p_yaml = re.compile(r'"project_id": "[0-9]+".*\s*'
                    r'"api_token": "([a-zA-Z0-9]+)".*\s*'
                    r'"base_path": "\./intl".*\s*'
                    r'"base_url": "https://api\.crowdin\.com".*\s*'
                    r'"preserve_hierarchy": true.*\s*'
                    r'"files": \[\s*'
                    r'\{\s*'
                    r'"source": "/_us/\*\.json",.*\s*'
                    r'"translation": "/_%two_letters_code%/%original_file_name%",.*\s*'
                    r'"skip_untranslated_strings": true.*\s*'
                    r'},\s*'
                    r']')

./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_opt_translation.py

#!/usr/bin/env python3

"""Core options text extractor

The purpose of this script is to set up & provide functions for automatic generation of 'libretro_core_options_intl.h'
from 'libretro_core_options.h' using translations from Crowdin.

Both v1 and v2 structs are supported. It is, however, recommended to convert v1 files to v2 using the included
'v1_to_v2_converter.py'.

Usage:
python3 path/to/core_opt_translation.py "path/to/where/libretro_core_options.h & libretro_core_options_intl.h/are"

This script will:
1.) create key words for & extract the texts from libretro_core_options.h & save them into intl/_us/core_options.h
2.) do the same for any present translations in libretro_core_options_intl.h, saving those in their respective folder
"""
import core_option_regex as cor
import re
import os
import sys
import json
import urllib.request as req
import shutil

# for uploading translations to Crowdin, the Crowdin 'language id' is required
LANG_CODE_TO_ID = {'_ar': 'ar',
                   '_ast': 'ast',
                   '_chs': 'zh-CN',
                   '_cht': 'zh-TW',
                   '_cs': 'cs',
                   '_cy': 'cy',
                   '_da': 'da',
                   '_de': 'de',
                   '_el': 'el',
                   '_eo': 'eo',
                   '_es': 'es-ES',
                   '_fa': 'fa',
                   '_fi': 'fi',
                   '_fr': 'fr',
                   '_gl': 'gl',
                   '_he': 'he',
                   '_hu': 'hu',
                   '_id': 'id',
                   '_it': 'it',
                   '_ja': 'ja',
                   '_ko': 'ko',
                   '_nl': 'nl',
                   '_pl': 'pl',
                   '_pt_br': 'pt-BR',
                   '_pt_pt': 'pt-PT',
                   '_ru': 'ru',
                   '_sk': 'sk',
                   '_sv': 'sv-SE',
                   '_tr': 'tr',
                   '_uk': 'uk',
                   '_vn': 'vi'}
LANG_CODE_TO_R_LANG = {'_ar': 'RETRO_LANGUAGE_ARABIC',
                       '_ast': 'RETRO_LANGUAGE_ASTURIAN',
                       '_chs': 'RETRO_LANGUAGE_CHINESE_SIMPLIFIED',
                       '_cht': 'RETRO_LANGUAGE_CHINESE_TRADITIONAL',
                       '_cs': 'RETRO_LANGUAGE_CZECH',
                       '_cy': 'RETRO_LANGUAGE_WELSH',
                       '_da': 'RETRO_LANGUAGE_DANISH',
                       '_de': 'RETRO_LANGUAGE_GERMAN',
                       '_el': 'RETRO_LANGUAGE_GREEK',
                       '_eo': 'RETRO_LANGUAGE_ESPERANTO',
                       '_es': 'RETRO_LANGUAGE_SPANISH',
                       '_fa': 'RETRO_LANGUAGE_PERSIAN',
                       '_fi': 'RETRO_LANGUAGE_FINNISH',
                       '_fr': 'RETRO_LANGUAGE_FRENCH',
                       '_gl': 'RETRO_LANGUAGE_GALICIAN',
                       '_he': 'RETRO_LANGUAGE_HEBREW',
                       '_hu': 'RETRO_LANGUAGE_HUNGARIAN',
                       '_id': 'RETRO_LANGUAGE_INDONESIAN',
                       '_it': 'RETRO_LANGUAGE_ITALIAN',
                       '_ja': 'RETRO_LANGUAGE_JAPANESE',
                       '_ko': 'RETRO_LANGUAGE_KOREAN',
                       '_nl': 'RETRO_LANGUAGE_DUTCH',
                       '_pl': 'RETRO_LANGUAGE_POLISH',
                       '_pt_br': 'RETRO_LANGUAGE_PORTUGUESE_BRAZIL',
                       '_pt_pt': 'RETRO_LANGUAGE_PORTUGUESE_PORTUGAL',
                       '_ru': 'RETRO_LANGUAGE_RUSSIAN',
                       '_sk': 'RETRO_LANGUAGE_SLOVAK',
                       '_sv': 'RETRO_LANGUAGE_SWEDISH',
                       '_tr': 'RETRO_LANGUAGE_TURKISH',
                       '_uk': 'RETRO_LANGUAGE_UKRAINIAN',
                       '_us': 'RETRO_LANGUAGE_ENGLISH',
                       '_vn': 'RETRO_LANGUAGE_VIETNAMESE'}

# these are handled by RetroArch directly - no need to include them in core translations
ON_OFFS = {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'}


def remove_special_chars(text: str, char_set=0) -> str:
    """Removes special characters from a text.

    :param text: String to be cleaned.
    :param char_set: 0 -> remove all ASCII special chars except for '_' & 'space';
                     1 -> remove invalid chars from file names
    :return: Clean text.
    """
    command_chars = [chr(unicode) for unicode in tuple(range(0, 32)) + (127,)]
    special_chars = ([chr(unicode) for unicode in tuple(range(33, 48)) + tuple(range(58, 65)) + tuple(range(91, 95))
                      + (96,) + tuple(range(123, 127))],
                     ('\\', '/', ':', '*', '?', '"', '<', '>', '|'))
    res = text
    for cm in command_chars:
        res = res.replace(cm, '_')
    for sp in special_chars[char_set]:
        res = res.replace(sp, '_')
    while res.startswith('_'):
        res = res[1:]
    while res.endswith('_'):
        res = res[:-1]
    return res


def clean_file_name(file_name: str) -> str:
    """Removes characters which might make file_name inappropriate for files on some OS.

    :param file_name: File name to be cleaned.
    :return: The clean file name.
    """
    file_name = remove_special_chars(file_name, 1)
    file_name = re.sub(r'__+', '_', file_name.replace(' ', '_'))
    return file_name


def get_struct_type_name(decl: str) -> tuple:
    """ Returns relevant parts of the struct declaration:
    type, name of the struct and the language appendix, if present.
    :param decl: The struct declaration matched by cor.p_type_name.
    :return: Tuple, e.g.: ('retro_core_option_definition', 'option_defs_us', '_us')
    """
    struct_match = cor.p_type_name.search(decl)
    if struct_match:
        if struct_match.group(3):
            struct_type_name = struct_match.group(1, 2, 3)
            return struct_type_name
        elif struct_match.group(4):
            struct_type_name = struct_match.group(1, 2, 4)
            return struct_type_name
        else:
            struct_type_name = struct_match.group(1, 2)
            return struct_type_name
    else:
        raise ValueError(f'No or incomplete struct declaration: {decl}!\n'
                         'Please make sure all structs are complete, including the type and name declaration.')


def is_viable_non_dupe(text: str, comparison) -> bool:
    """text must be longer than 2 ('""'), not 'NULL' and not in comparison.

    :param text: String to be tested.
    :param comparison: Dictionary or set to search for text in.
    :return: bool
    """
    return 2 < len(text) and text != 'NULL' and text not in comparison


def is_viable_value(text: str) -> bool:
    """text must be longer than 2 ('""'), not 'NULL' and text.lower() not in
    {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'}.

    :param text: String to be tested.
    :return: bool
    """
    return 2 < len(text) and text != 'NULL' and text.lower() not in ON_OFFS


def create_non_dupe(base_name: str, opt_num: int, comparison) -> str:
    """Makes sure base_name is not in comparison, and if it is it's renamed.

    :param base_name: Name to check/make unique.
    :param opt_num: Number of the option base_name belongs to, used in making it unique.
    :param comparison: Dictionary or set to search for base_name in.
    :return: Unique name.
    """
    h = base_name
    if h in comparison:
        n = 0
        h = h + '_O' + str(opt_num)
        h_end = len(h)
        while h in comparison:
            h = h[:h_end] + '_' + str(n)
            n += 1
    return h


def get_texts(text: str) -> dict:
    """Extracts the strings, which are to be translated/are the translations,
    from text and creates macro names for them.

    :param text: The string to be parsed.
    :return: Dictionary of the form { '_<lang>': { 'macro': 'string', ... }, ... }.
    """
    # all structs: group(0) full struct, group(1) beginning, group(2) content
    structs = cor.p_struct.finditer(text)
    hash_n_string = {}
    just_string = {}
    for struct in structs:
        struct_declaration = struct.group(1)
        struct_type_name = get_struct_type_name(struct_declaration)
        if 3 > len(struct_type_name):
            lang = '_us'
        else:
            lang = struct_type_name[2]
        if lang not in just_string:
            hash_n_string[lang] = {}
            just_string[lang] = set()

        is_v2 = False
        pre_name = ''
        p = cor.p_info
        if 'retro_core_option_v2_definition' == struct_type_name[0]:
            is_v2 = True
        elif 'retro_core_option_v2_category' == struct_type_name[0]:
            pre_name = 'CATEGORY_'
            p = cor.p_info_cat

        struct_content = struct.group(2)
        # 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
        struct_options = cor.p_option.finditer(struct_content)
        for opt, option in enumerate(struct_options):
            # group 1: key
            if option.group(1):
                opt_name = pre_name + option.group(1)
                # no special chars allowed in key
                opt_name = remove_special_chars(opt_name).upper().replace(' ', '_')
            else:
                raise ValueError(f'No option name (key) found in struct {struct_type_name[1]} option {opt}!')

            # group 2: description0
            if option.group(2):
                desc0 = option.group(2)
                if is_viable_non_dupe(desc0, just_string[lang]):
                    just_string[lang].add(desc0)
                    m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL'), opt, hash_n_string[lang])
                    hash_n_string[lang][m_h] = desc0
            else:
                raise ValueError(f'No label found in struct {struct_type_name[1]} option {option.group(1)}!')

            # group 3: desc1, info0, info1, category
            if option.group(3):
                infos = option.group(3)
                option_info = p.finditer(infos)
                if is_v2:
                    desc1 = next(option_info).group(1)
                    if is_viable_non_dupe(desc1, just_string[lang]):
                        just_string[lang].add(desc1)
                        m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL_CAT'), opt, hash_n_string[lang])
                        hash_n_string[lang][m_h] = desc1
                    last = None
                    m_h = None
                    for j, info in enumerate(option_info):
                        last = info.group(1)
                        if is_viable_non_dupe(last, just_string[lang]):
                            just_string[lang].add(last)
                            m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,
                                                  hash_n_string[lang])
                            hash_n_string[lang][m_h] = last
                    if last in just_string[lang]:  # category key should not be translated
                        hash_n_string[lang].pop(m_h)
                        just_string[lang].remove(last)
                else:
                    for j, info in enumerate(option_info):
                        gr1 = info.group(1)
                        if is_viable_non_dupe(gr1, just_string[lang]):
                            just_string[lang].add(gr1)
                            m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,
                                                  hash_n_string[lang])
                            hash_n_string[lang][m_h] = gr1
            else:
                raise ValueError(f'Too few arguments in struct {struct_type_name[1]} option {option.group(1)}!')

            # group 4:
            if option.group(4):
                for j, kv_set in enumerate(cor.p_key_value.finditer(option.group(4))):
                    set_key, set_value = kv_set.group(1, 2)
                    if not is_viable_value(set_value):
                        if not is_viable_value(set_key):
                            continue
                        set_value = set_key
                    # re.fullmatch(r'(?:[+-][0-9]+)+', value[1:-1])
                    if set_value not in just_string[lang] and not re.sub(r'[+-]', '', set_value[1:-1]).isdigit():
                        clean_key = set_key.encode('ascii', errors='ignore').decode('unicode-escape')[1:-1]
                        clean_key = remove_special_chars(clean_key).upper().replace(' ', '_')
                        m_h = create_non_dupe(re.sub(r'__+', '_', f"OPTION_VAL_{clean_key}"), opt, hash_n_string[lang])
                        hash_n_string[lang][m_h] = set_value
                        just_string[lang].add(set_value)
    return hash_n_string


def create_msg_hash(intl_dir_path: str, core_name: str, keyword_string_dict: dict) -> dict:
    """Creates '<core_name>.h' files in 'intl/_<lang>/' containing the macro name & string combinations.

    :param intl_dir_path: Path to the intl directory.
    :param core_name: Name of the core, used for naming the files.
    :param keyword_string_dict: Dictionary of the form { '_<lang>': { 'macro': 'string', ... }, ... }.
    :return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.
    """
    files = {}
    for localisation in keyword_string_dict:
        path = os.path.join(intl_dir_path, localisation)  # intl/_<lang>
        files[localisation] = os.path.join(path, core_name + '.h')  # intl/_<lang>/<core_name>.h
        if not os.path.exists(path):
            os.makedirs(path)
        with open(files[localisation], 'w', encoding='utf-8') as crowdin_file:
            out_text = ''
            for keyword in keyword_string_dict[localisation]:
                out_text = f'{out_text}{keyword} {keyword_string_dict[localisation][keyword]}\n'
            crowdin_file.write(out_text)
    return files


def h2json(file_paths: dict) -> dict:
    """Converts .h files pointed to by file_paths into .jsons.

    :param file_paths: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.
    :return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.json)', ... }.
    """
    jsons = {}
    for file_lang in file_paths:
        jsons[file_lang] = file_paths[file_lang][:-2] + '.json'

        p = cor.p_masked

        with open(file_paths[file_lang], 'r+', encoding='utf-8') as h_file:
            text = h_file.read()
            result = p.finditer(text)
            messages = {}
            for msg in result:
                key, val = msg.group(1, 2)
                if key not in messages:
                    if key and val:
                        # unescape & remove "\n"
                        messages[key] = re.sub(r'"\s*(?:(?:/\*(?:.|[\r\n])*?\*/|//.*[\r\n]+)\s*)*"',
                                               '\\\n', val[1:-1].replace('\\\"', '"'))
                else:
                    print(f"DUPLICATE KEY in {file_paths[file_lang]}: {key}")
            with open(jsons[file_lang], 'w', encoding='utf-8') as json_file:
                json.dump(messages, json_file, indent=2)

    return jsons


def json2h(intl_dir_path: str, json_file_path: str, core_name: str) -> None:
    """Converts .json file in json_file_path into an .h ready to be included in C code.

    :param intl_dir_path: Path to the intl directory.
    :param json_file_path: Base path of translation .json.
    :param core_name: Name of the core, required for naming the files.
    :return: None
    """
    h_filename = os.path.join(json_file_path, core_name + '.h')
    json_filename = os.path.join(json_file_path, core_name + '.json')
    file_lang = os.path.basename(json_file_path).upper()

    if os.path.basename(json_file_path).lower() == '_us':
        print('    skipped')
        return

    p = cor.p_masked

    def update(s_messages, s_template, s_source_messages):
        translation = ''
        template_messages = p.finditer(s_template)
        for tp_msg in template_messages:
            old_key = tp_msg.group(1)
            if old_key in s_messages and s_messages[old_key] != s_source_messages[old_key]:
                tl_msg_val = s_messages[old_key]
                tl_msg_val = tl_msg_val.replace('"', '\\\"').replace('\n', '')  # escape
                translation = ''.join((translation, '#define ', old_key, file_lang, f' "{tl_msg_val}"\n'))

            else:  # Remove English duplicates and non-translatable strings
                translation = ''.join((translation, '#define ', old_key, file_lang, ' NULL\n'))
        return translation

    with open(os.path.join(intl_dir_path, '_us', core_name + '.h'), 'r', encoding='utf-8') as template_file:
        template = template_file.read()
    with open(os.path.join(intl_dir_path, '_us', core_name + '.json'), 'r+', encoding='utf-8') as source_json_file:
        source_messages = json.load(source_json_file)
    with open(json_filename, 'r+', encoding='utf-8') as json_file:
        messages = json.load(json_file)
        new_translation = update(messages, template, source_messages)
    with open(h_filename, 'w', encoding='utf-8') as h_file:
        h_file.seek(0)
        h_file.write(new_translation)
        h_file.truncate()
    return


def get_crowdin_client(dir_path: str) -> str:
    """Makes sure the Crowdin CLI client is present. If it isn't, it is fetched & extracted.

    :return: The path to 'crowdin-cli.jar'.
    """
    jar_name = 'crowdin-cli.jar'
    jar_path = os.path.join(dir_path, jar_name)

    if not os.path.isfile(jar_path):
        print('Downloading crowdin-cli.jar')
        crowdin_cli_file = os.path.join(dir_path, 'crowdin-cli.zip')
        crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/crowdin-cli.zip'
        req.urlretrieve(crowdin_cli_url, crowdin_cli_file)
        import zipfile
        with zipfile.ZipFile(crowdin_cli_file, 'r') as zip_ref:
            jar_dir = zip_ref.namelist()[0]
            for file in zip_ref.namelist():
                if file.endswith(jar_name):
                    jar_file = file
                    break
            zip_ref.extract(jar_file)
            os.rename(jar_file, jar_path)
            os.remove(crowdin_cli_file)
            shutil.rmtree(jar_dir)
    return jar_path


def create_intl_file(intl_file_path: str, intl_dir_path: str, text: str, core_name: str, file_path: str) -> None:
    """Creates 'libretro_core_options_intl.h' from Crowdin translations.

    :param intl_file_path: Path to 'libretro_core_options_intl.h'
    :param intl_dir_path: Path to the intl directory.
    :param text: Content of the 'libretro_core_options.h' being translated.
    :param core_name: Name of the core. Needed to identify the files to pull the translations from.
    :param file_path: Path to the '<core name>_us.h' file, containing the original English texts.
    :return: None
    """
    msg_dict = {}
    lang_up = ''

    def replace_pair(pair_match):
        """Replaces a key-value-pair of an option with the macros corresponding to the language.

        :param pair_match: The re match object representing the key-value-pair block.
        :return: Replacement string.
        """
        offset = pair_match.start(0)
        if pair_match.group(1):  # key
            if pair_match.group(2) in msg_dict:  # value
                val = msg_dict[pair_match.group(2)] + lang_up
            elif pair_match.group(1) in msg_dict:  # use key if value not viable (e.g. NULL)
                val = msg_dict[pair_match.group(1)] + lang_up
            else:
                return pair_match.group(0)
        else:
            return pair_match.group(0)
        res = pair_match.group(0)[:pair_match.start(2) - offset] + val \
            + pair_match.group(0)[pair_match.end(2) - offset:]
        return res

    def replace_info(info_match):
        """Replaces the 'additional strings' of an option with the macros corresponding to the language.

        :param info_match: The re match object representing the 'additional strings' block.
        :return: Replacement string.
        """
        offset = info_match.start(0)
        if info_match.group(1) in msg_dict:
            res = info_match.group(0)[:info_match.start(1) - offset] + \
                  msg_dict[info_match.group(1)] + lang_up + \
                  info_match.group(0)[info_match.end(1) - offset:]
            return res
        else:
            return info_match.group(0)

    def replace_option(option_match):
        """Replaces strings within an option
        '{ "opt_key", "label", "additional strings", ..., { {"key", "value"}, ... }, ... }'
        within a struct with the macros corresponding to the language:
        '{ "opt_key", MACRO_LABEL, MACRO_STRINGS, ..., { {"key", MACRO_VALUE}, ... }, ... }'

        :param option_match: The re match object representing the option.
        :return: Replacement string.
        """
        # label
        offset = option_match.start(0)
        if option_match.group(2):
            res = option_match.group(0)[:option_match.start(2) - offset] + msg_dict[option_match.group(2)] + lang_up
        else:
            return option_match.group(0)
        # additional block
        if option_match.group(3):
            res = res + option_match.group(0)[option_match.end(2) - offset:option_match.start(3) - offset]
            new_info = p.sub(replace_info, option_match.group(3))
            res = res + new_info
        else:
            return res + option_match.group(0)[option_match.end(2) - offset:]
        # key-value-pairs
        if option_match.group(4):
            res = res + option_match.group(0)[option_match.end(3) - offset:option_match.start(4) - offset]
            new_pairs = cor.p_key_value.sub(replace_pair, option_match.group(4))
            res = res + new_pairs + option_match.group(0)[option_match.end(4) - offset:]
        else:
            res = res + option_match.group(0)[option_match.end(3) - offset:]

        return res

    with open(file_path, 'r+', encoding='utf-8') as template:  # intl/_us/<core_name>.h
        masked_msgs = cor.p_masked.finditer(template.read())
        for msg in masked_msgs:
            msg_dict[msg.group(2)] = msg.group(1)

    with open(intl_file_path, 'r', encoding='utf-8') as intl:  # libretro_core_options_intl.h
        in_text = intl.read()
        intl_start = re.search(re.escape('/*\n'
                                         ' ********************************\n'
                                         ' * Core Option Definitions\n'
                                         ' ********************************\n'
                                         '*/\n'), in_text)
        if intl_start:
            out_txt = in_text[:intl_start.end(0)]
        else:
            intl_start = re.search(re.escape('#ifdef __cplusplus\n'
                                             'extern "C" {\n'
                                             '#endif\n'), in_text)
            out_txt = in_text[:intl_start.end(0)]

    for folder in os.listdir(intl_dir_path):  # intl/_*
        if os.path.isdir(os.path.join(intl_dir_path, folder)) and folder.startswith('_')\
                and folder != '_us' and folder != '__pycache__':
            translation_path = os.path.join(intl_dir_path, folder, core_name + '.h')  # <core_name>_<lang>.h
            # all structs: group(0) full struct, group(1) beginning, group(2) content
            struct_groups = cor.p_struct.finditer(text)
            lang_up = folder.upper()
            lang_low = folder.lower()
            out_txt = out_txt + f'/* {LANG_CODE_TO_R_LANG[lang_low]} */\n\n'  # /* RETRO_LANGUAGE_NAME */
            with open(translation_path, 'r+', encoding='utf-8') as f_in:  # <core name>.h
                out_txt = out_txt + f_in.read() + '\n'
            for construct in struct_groups:
                declaration = construct.group(1)
                struct_type_name = get_struct_type_name(declaration)
                if 3 > len(struct_type_name):  # no language specifier
                    new_decl = re.sub(re.escape(struct_type_name[1]), struct_type_name[1] + lang_low, declaration)
                else:
                    new_decl = re.sub(re.escape(struct_type_name[2]), lang_low, declaration)
                    if '_us' != struct_type_name[2]:
                        continue

                p = cor.p_info
                if 'retro_core_option_v2_category' == struct_type_name[0]:
                    p = cor.p_info_cat
                offset_construct = construct.start(0)
                start = construct.end(1) - offset_construct
                end = construct.start(2) - offset_construct
                out_txt = out_txt + new_decl + construct.group(0)[start:end]

                content = construct.group(2)
                new_content = cor.p_option.sub(replace_option, content)

                start = construct.end(2) - offset_construct
                out_txt = out_txt + new_content + construct.group(0)[start:] + '\n'

                if 'retro_core_option_v2_definition' == struct_type_name[0]:
                    out_txt = out_txt + f'struct retro_core_options_v2 options{lang_low}' \
                                        ' = {\n' \
                                        f'   option_cats{lang_low},\n' \
                                        f'   option_defs{lang_low}\n' \
                                        '};\n\n'
        #    shutil.rmtree(JOINER.join((intl_dir_path, folder)))

    with open(intl_file_path, 'w', encoding='utf-8') as intl:
        intl.write(out_txt + '\n#ifdef __cplusplus\n'
                             '}\n#endif\n'
                             '\n#endif')
    return


# --------------------          MAIN          -------------------- #

if __name__ == '__main__':
    #
    try:
        if os.path.isfile(sys.argv[1]):
            _temp = os.path.dirname(sys.argv[1])
        else:
            _temp = sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        TARGET_DIR_PATH = _temp
    except IndexError:
        TARGET_DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)

    DIR_PATH = os.path.dirname(os.path.realpath(__file__))
    H_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')
    INTL_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')

    _core_name = 'core_options'
    try:
        print('Getting texts from libretro_core_options.h')
        with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
            _main_text = _h_file.read()
        _hash_n_str = get_texts(_main_text)
        _files = create_msg_hash(DIR_PATH, _core_name, _hash_n_str)
        _source_jsons = h2json(_files)
    except Exception as e:
        print(e)

    print('Getting texts from libretro_core_options_intl.h')
    with open(INTL_FILE_PATH, 'r+', encoding='utf-8') as _intl_file:
        _intl_text = _intl_file.read()
        _hash_n_str_intl = get_texts(_intl_text)
        _intl_files = create_msg_hash(DIR_PATH, _core_name, _hash_n_str_intl)
        _intl_jsons = h2json(_intl_files)

    print('\nAll done!')

./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_intl.py

#!/usr/bin/env python3

import core_opt_translation as t


if __name__ == '__main__':
    try:
        if t.os.path.isfile(t.sys.argv[1]):
            _temp = t.os.path.dirname(t.sys.argv[1])
        else:
            _temp = t.sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        TARGET_DIR_PATH = _temp
    except IndexError:
        TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)

    DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))
    H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')
    INTL_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')

    _core_name = 'core_options'
    _core_name = t.clean_file_name(_core_name)

    print('Getting texts from libretro_core_options.h')
    with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
        _main_text = _h_file.read()
    _hash_n_str = t.get_texts(_main_text)
    _files = t.create_msg_hash(DIR_PATH, _core_name, _hash_n_str)

    print('Converting translations *.json to *.h:')
    for _folder in t.os.listdir(DIR_PATH):
        if t.os.path.isdir(t.os.path.join(DIR_PATH, _folder))\
                and _folder.startswith('_')\
                and _folder != '__pycache__':
            print(_folder)
            t.json2h(DIR_PATH, t.os.path.join(DIR_PATH, _folder), _core_name)

    print('Constructing libretro_core_options_intl.h')
    t.create_intl_file(INTL_FILE_PATH, DIR_PATH, _main_text, _core_name, _files['_us'])

    print('\nAll done!')

./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_prep.py

#!/usr/bin/env python3

import core_opt_translation as t


if __name__ == '__main__':
    _core_name = 'core_options'

    try:
        if t.os.path.isfile(t.sys.argv[1]):
            _temp = t.os.path.dirname(t.sys.argv[1])
        else:
            _temp = t.sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        TARGET_DIR_PATH = _temp
    except IndexError:
        TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)

    DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))
    H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')

    _core_name = t.clean_file_name(_core_name)

    print('Getting texts from libretro_core_options.h')
    with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
        _main_text = _h_file.read()
    _hash_n_str = t.get_texts(_main_text)
    _files = t.create_msg_hash(DIR_PATH, _core_name, _hash_n_str)

    _source_jsons = t.h2json(_files)

    print('\nAll done!')

./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/.gitignore

__pycache__

./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/v1_to_v2_converter.py

#!/usr/bin/env python3

"""Core options v1 to v2 converter

Just run this script as follows, to convert 'libretro_core_options.h' & 'Libretro_coreoptions_intl.h' to v2:
python3 "/path/to/v1_to_v2_converter.py" "/path/to/where/libretro_core_options.h & Libretro_coreoptions_intl.h/are"

The original files will be preserved as *.v1
"""
import core_option_regex as cor
import os
import sys


def create_v2_code_file(struct_text, file_name):
    def replace_option(option_match):
        _offset = option_match.start(0)

        if option_match.group(3):
            res = option_match.group(0)[:option_match.end(2) - _offset] + ',\n      NULL' + \
                  option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \
                  'NULL,\n      NULL,\n      ' + option_match.group(0)[option_match.end(3) - _offset:]
        else:
            return option_match.group(0)

        return res

    comment_v1 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 1.3\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    comment_v2 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 2.0\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 2.0: Add support for core options v2 interface\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    p_intl = cor.p_intl
    p_set = cor.p_set
    new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\n' \
              '      bool *categories_supported)\n' \
              '{\n' \
              '   unsigned version  = 0;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '   unsigned language = 0;\n' \
              '#endif\n' \
              '\n' \
              '   if (!environ_cb || !categories_supported)\n' \
              '      return;\n' \
              '\n' \
              '   *categories_supported = false;\n' \
              '\n' \
              '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))\n' \
              '      version = 0;\n' \
              '\n' \
              '   if (version >= 2)\n' \
              '   {\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      struct retro_core_options_v2_intl core_options_intl;\n' \
              '\n' \
              '      core_options_intl.us    = &options_us;\n' \
              '      core_options_intl.local = NULL;\n' \
              '\n' \
              '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
              '          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))\n' \
              '         core_options_intl.local = options_intl[language];\n' \
              '\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n' \
              '            &core_options_intl);\n' \
              '#else\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n' \
              '            &options_us);\n' \
              '#endif\n' \
              '   }\n' \
              '   else\n' \
              '   {\n' \
              '      size_t i, j;\n' \
              '      size_t option_index              = 0;\n' \
              '      size_t num_options               = 0;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_us         = NULL;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      size_t num_options_intl          = 0;\n' \
              '      struct retro_core_option_v2_definition\n' \
              '            *option_defs_intl          = NULL;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_intl       = NULL;\n' \
              '      struct retro_core_options_intl\n' \
              '            core_options_v1_intl;\n' \
              '#endif\n' \
              '      struct retro_variable *variables = NULL;\n' \
              '      char **values_buf                = NULL;\n' \
              '\n' \
              '      /* Determine total number of options */\n' \
              '      while (true)\n' \
              '      {\n' \
              '         if (option_defs_us[num_options].key)\n' \
              '            num_options++;\n' \
              '         else\n' \
              '            break;\n' \
              '      }\n' \
              '\n' \
              '      if (version >= 1)\n' \
              '      {\n' \
              '         /* Allocate US array */\n' \
              '         option_v1_defs_us = (struct retro_core_option_definition *)\n' \
              '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i < num_options; i++)\n' \
              '         {\n' \
              '            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];\n' \
              '            struct retro_core_option_value *option_values         = option_def_us->values;\n' \
              '            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];\n' \
              '            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;\n' \
              '\n' \
              '            option_v1_def_us->key           = option_def_us->key;\n' \
              '            option_v1_def_us->desc          = option_def_us->desc;\n' \
              '            option_v1_def_us->info          = option_def_us->info;\n' \
              '            option_v1_def_us->default_value = option_def_us->default_value;\n' \
              '\n' \
              '            /* Values must be copied individually... */\n' \
              '            while (option_values->value)\n' \
              '            {\n' \
              '               option_v1_values->value = option_values->value;\n' \
              '               option_v1_values->label = option_values->label;\n' \
              '\n' \
              '               option_values++;\n' \
              '               option_v1_values++;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
              '             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&\n' \
              '             options_intl[language])\n' \
              '            option_defs_intl = options_intl[language]->definitions;\n' \
              '\n' \
              '         if (option_defs_intl)\n' \
              '         {\n' \
              '            /* Determine number of intl options */\n' \
              '            while (true)\n' \
              '            {\n' \
              '               if (option_defs_intl[num_options_intl].key)\n' \
              '                  num_options_intl++;\n' \
              '               else\n' \
              '                  break;\n' \
              '            }\n' \
              '\n' \
              '            /* Allocate intl array */\n' \
              '            option_v1_defs_intl = (struct retro_core_option_definition *)\n' \
              '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '            /* Copy parameters from option_defs_intl array */\n' \
              '            for (i = 0; i < num_options_intl; i++)\n' \
              '            {\n' \
              '               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_values           = option_def_intl->values;\n' \
              '               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;\n' \
              '\n' \
              '               option_v1_def_intl->key           = option_def_intl->key;\n' \
              '               option_v1_def_intl->desc          = option_def_intl->desc;\n' \
              '               option_v1_def_intl->info          = option_def_intl->info;\n' \
              '               option_v1_def_intl->default_value = option_def_intl->default_value;\n' \
              '\n' \
              '               /* Values must be copied individually... */\n' \
              '               while (option_values->value)\n' \
              '               {\n' \
              '                  option_v1_values->value = option_values->value;\n' \
              '                  option_v1_values->label = option_values->label;\n' \
              '\n' \
              '                  option_values++;\n' \
              '                  option_v1_values++;\n' \
              '               }\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         core_options_v1_intl.us    = option_v1_defs_us;\n' \
              '         core_options_v1_intl.local = option_v1_defs_intl;\n' \
              '\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);\n' \
              '#else\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\n' \
              '#endif\n' \
              '      }\n' \
              '      else\n' \
              '      {\n' \
              '         /* Allocate arrays */\n' \
              '         variables  = (struct retro_variable *)calloc(num_options + 1,\n' \
              '               sizeof(struct retro_variable));\n' \
              '         values_buf = (char **)calloc(num_options, sizeof(char *));\n' \
              '\n' \
              '         if (!variables || !values_buf)\n' \
              '            goto error;\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i < num_options; i++)\n' \
              '         {\n' \
              '            const char *key                        = option_defs_us[i].key;\n' \
              '            const char *desc                       = option_defs_us[i].desc;\n' \
              '            const char *default_value              = option_defs_us[i].default_value;\n' \
              '            struct retro_core_option_value *values = option_defs_us[i].values;\n' \
              '            size_t buf_len                         = 3;\n' \
              '            size_t default_index                   = 0;\n' \
              '\n' \
              '            values_buf[i] = NULL;\n' \
              '\n' \
              '            if (desc)\n' \
              '            {\n' \
              '               size_t num_values = 0;\n' \
              '\n' \
              '               /* Determine number of values */\n' \
              '               while (true)\n' \
              '               {\n' \
              '                  if (values[num_values].value)\n' \
              '                  {\n' \
              '                     /* Check if this is the default value */\n' \
              '                     if (default_value)\n' \
              '                        if (strcmp(values[num_values].value, default_value) == 0)\n' \
              '                           default_index = num_values;\n' \
              '\n' \
              '                     buf_len += strlen(values[num_values].value);\n' \
              '                     num_values++;\n' \
              '                  }\n' \
              '                  else\n' \
              '                     break;\n' \
              '               }\n' \
              '\n' \
              '               /* Build values string */\n' \
              '               if (num_values > 0)\n' \
              '               {\n' \
              '                  buf_len += num_values - 1;\n' \
              '                  buf_len += strlen(desc);\n' \
              '\n' \
              '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\n' \
              '                  if (!values_buf[i])\n' \
              '                     goto error;\n' \
              '\n' \
              '                  strcpy(values_buf[i], desc);\n' \
              '                  strcat(values_buf[i], "; ");\n' \
              '\n' \
              '                  /* Default value goes first */\n' \
              '                  strcat(values_buf[i], values[default_index].value);\n' \
              '\n' \
              '                  /* Add remaining values */\n' \
              '                  for (j = 0; j < num_values; j++)\n' \
              '                  {\n' \
              '                     if (j != default_index)\n' \
              '                     {\n' \
              '                        strcat(values_buf[i], "|");\n' \
              '                        strcat(values_buf[i], values[j].value);\n' \
              '                     }\n' \
              '                  }\n' \
              '               }\n' \
              '            }\n' \
              '\n' \
              '            variables[option_index].key   = key;\n' \
              '            variables[option_index].value = values_buf[i];\n' \
              '            option_index++;\n' \
              '         }\n' \
              '\n' \
              '         /* Set variables */\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n' \
              '      }\n' \
              '\n' \
              'error:\n' \
              '      /* Clean up */\n' \
              '\n' \
              '      if (option_v1_defs_us)\n' \
              '      {\n' \
              '         free(option_v1_defs_us);\n' \
              '         option_v1_defs_us = NULL;\n' \
              '      }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      if (option_v1_defs_intl)\n' \
              '      {\n' \
              '         free(option_v1_defs_intl);\n' \
              '         option_v1_defs_intl = NULL;\n' \
              '      }\n' \
              '#endif\n' \
              '\n' \
              '      if (values_buf)\n' \
              '      {\n' \
              '         for (i = 0; i < num_options; i++)\n' \
              '         {\n' \
              '            if (values_buf[i])\n' \
              '            {\n' \
              '               free(values_buf[i]);\n' \
              '               values_buf[i] = NULL;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         free(values_buf);\n' \
              '         values_buf = NULL;\n' \
              '      }\n' \
              '\n' \
              '      if (variables)\n' \
              '      {\n' \
              '         free(variables);\n' \
              '         variables = NULL;\n' \
              '      }\n' \
              '   }\n' \
              '}\n' \
              '\n' \
              '#ifdef __cplusplus\n' \
              '}\n' \
              '#endif'

    struct_groups = cor.p_struct.finditer(struct_text)
    out_text = struct_text

    for construct in struct_groups:
        repl_text = ''
        declaration = construct.group(1)
        struct_match = cor.p_type_name.search(declaration)
        if struct_match:
            if struct_match.group(3):
                struct_type_name_lang = struct_match.group(1, 2, 3)
                declaration_end = declaration[struct_match.end(1):]
            elif struct_match.group(4):
                struct_type_name_lang = struct_match.group(1, 2, 4)
                declaration_end = declaration[struct_match.end(1):]
            else:
                struct_type_name_lang = sum((struct_match.group(1, 2), ('_us',)), ())
                declaration_end = f'{declaration[struct_match.end(1):struct_match.end(2)]}_us' \
                                  f'{declaration[struct_match.end(2):]}'
        else:
            return -1

        if 'retro_core_option_definition' == struct_type_name_lang[0]:
            import shutil
            shutil.copy(file_name, file_name + '.v1')
            new_declaration = f'\nstruct retro_core_option_v2_category option_cats{struct_type_name_lang[2]}[] = ' \
                              '{\n   { NULL, NULL, NULL },\n' \
                              '};\n\n' \
                              + declaration[:struct_match.start(1)] + \
                              'retro_core_option_v2_definition' \
                              + declaration_end
            offset = construct.start(0)
            repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,
                                               construct.group(0)[:construct.start(2) - offset])
            content = construct.group(2)
            new_content = cor.p_option.sub(replace_option, content)

            repl_text = repl_text + new_content + cor.re.sub(r'{\s*NULL,\s*NULL,\s*NULL,\s*{\{0}},\s*NULL\s*},\s*};',
                                                             '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};'
                                                             '\n\nstruct retro_core_options_v2 options' +
                                                             struct_type_name_lang[2] + ' = {\n'
                                                             f'   option_cats{struct_type_name_lang[2]},\n'
                                                             f'   option_defs{struct_type_name_lang[2]}\n'
                                                             '};',
                                                             construct.group(0)[construct.end(2) - offset:])
            out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text)
        else:
            return -2
    with open(file_name, 'w', encoding='utf-8') as code_file:
        out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)
        intl = p_intl.search(out_text)
        if intl:
            new_intl = out_text[:intl.start(1)] \
                       + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \
                       + out_text[intl.end(1):intl.start(2)] \
                       + '&options_us, /* RETRO_LANGUAGE_ENGLISH */' \
                       '   &options_ja,      /* RETRO_LANGUAGE_JAPANESE */' \
                       '   &options_fr,      /* RETRO_LANGUAGE_FRENCH */' \
                       '   &options_es,      /* RETRO_LANGUAGE_SPANISH */' \
                       '   &options_de,      /* RETRO_LANGUAGE_GERMAN */' \
                       '   &options_it,      /* RETRO_LANGUAGE_ITALIAN */' \
                       '   &options_nl,      /* RETRO_LANGUAGE_DUTCH */' \
                       '   &options_pt_br,   /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */' \
                       '   &options_pt_pt,   /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */' \
                       '   &options_ru,      /* RETRO_LANGUAGE_RUSSIAN */' \
                       '   &options_ko,      /* RETRO_LANGUAGE_KOREAN */' \
                       '   &options_cht,     /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */' \
                       '   &options_chs,     /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */' \
                       '   &options_eo,      /* RETRO_LANGUAGE_ESPERANTO */' \
                       '   &options_pl,      /* RETRO_LANGUAGE_POLISH */' \
                       '   &options_vn,      /* RETRO_LANGUAGE_VIETNAMESE */' \
                       '   &options_ar,      /* RETRO_LANGUAGE_ARABIC */' \
                       '   &options_el,      /* RETRO_LANGUAGE_GREEK */' \
                       '   &options_tr,      /* RETRO_LANGUAGE_TURKISH */' \
                       '   &options_sv,      /* RETRO_LANGUAGE_SLOVAK */' \
                       '   &options_fa,      /* RETRO_LANGUAGE_PERSIAN */' \
                       '   &options_he,      /* RETRO_LANGUAGE_HEBREW */' \
                       '   &options_ast,     /* RETRO_LANGUAGE_ASTURIAN */' \
                       '   &options_fi,      /* RETRO_LANGUAGE_FINNISH */' \
                       + out_text[intl.end(2):]
            out_text = p_set.sub(new_set, new_intl)
        else:
            out_text = p_set.sub(new_set, out_text)
        code_file.write(out_text)

    return 1


# --------------------          MAIN          -------------------- #

if __name__ == '__main__':
    try:
        if os.path.isfile(sys.argv[1]):
            _temp = os.path.dirname(sys.argv[1])
        else:
            _temp = sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        DIR_PATH = _temp
    except IndexError:
        DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + DIR_PATH)

    H_FILE_PATH = os.path.join(DIR_PATH, 'libretro_core_options.h')
    INTL_FILE_PATH = os.path.join(DIR_PATH, 'libretro_core_options_intl.h')

    for file in (H_FILE_PATH, INTL_FILE_PATH):
        if os.path.isfile(file):
            with open(file, 'r+', encoding='utf-8') as h_file:
                text = h_file.read()
                try:
                    test = create_v2_code_file(text, file)
                except Exception as e:
                    print(e)
                    test = -1
                if -1 > test:
                    print('Your file looks like it already is v2? (' + file + ')')
                    continue
                if 0 > test:
                    print('An error occurred! Please make sure to use the complete v1 struct! (' + file + ')')
                    continue
        else:
            print(file + ' not found.')

./include/libretro-common/samples/core_options/README.md

## Adding 'enhanced' core options to a core

The basic steps for updating a core to support core options v1 are as follows:

- Copy `example_default/libretro_core_options.h` to the same directory as `libretro.c/.cpp`

- Copy `example_default/libretro_core_options_intl.h` to the same directory as `libretro.c/.cpp`

- Add `#include "libretro_core_options.h"` to `libretro.c/.cpp`

- Replace any existing calls of `RETRO_ENVIRONMENT_SET_VARIABLES` with `libretro_set_core_options(retro_environment_t environ_cb)`  
  (Note: `libretro_set_core_options()` should be called as early as possible - preferably in `retro_set_environment()`  
  and no later than `retro_load_game()`)

- Open `libretro_core_options.h` and replace the contents of the existing `option_defs_us` struct array with all required core option parameters.  

## Adding core option translations

To add a translation, simply:

- Copy the contents of `option_defs_us` *from* `libretro_core_options.h` *to* `libretro_core_options_intl.h` into a new struct array with the appropriate language suffix

- Translate all human-readable strings

- Add the new struct array to the appropriate location in the `option_defs_intl` array inside `libretro_core_options.h`

This is most easily understood by considering the example in `example_translation/`. Here a French translation has been added (`option_defs_fr`), with comments explaining the appropriate formatting requirements.

NOTE: Since translations involve the use of UTF-8 characters, `libretro_core_options_intl.h` must include a BOM marker. *This renders translations incompatible with c89 builds*. When performing a c89 build, the flag `HAVE_NO_LANGEXTRA` *must* be defined (e.g. `-DHAVE_NO_LANGEXTRA`). This will disable all translations.

## Disabling core options on unsupported frontends

Sometimes it is desirable to only show a particular core option if the frontend supports the new core options v1 API. For example:

- The API v1 allows cores to hide options dynamically

- We can therefore create a specific 'toggle display' option to hide or show a number of other options (e.g. advanced settings)

- On frontends that do not support API v1, this 'toggle display' option will have no function - it should therefore be omitted

This can be handled easily by editing the `libretro_set_core_options()` function to ignore certain core name (key) values when generating option variable arrays for old-style frontends. Again, this is most easily understood by considering the example in `example_hide_option/libretro_core_options.h`:

- Here, a `mycore_show_speedhacks` option is added to `option_defs_us`

- On line 227, the following comparison allows the option to be skipped:  
  (Note that another `strcmp()` may be added for each option to be omitted)

```c
if (strcmp(key, "mycore_show_speedhacks") == 0)
	continue;
```

For any cores that require this functionality, `example_hide_option/libretro_core_options.h` should be used as a template in place of `example_default/libretro_core_options.h`

## Adding core option categories

Core options v2 adds a mechanism for assigning categories to options. On supported fontends, options of a particular category will be displayed in a submenu/subsection of the main core options menu. This functionality may be used to reduce visual clutter, or to effectively 'hide' advanced settings without requiring a dedicated 'toggle display' option.

A template for enabling categories via the core options v2 interface is provided in `example_categories`. The usage of this code is identical to that described in the `Adding 'enhanced' core options to a core` section, with one addition: the `libretro_set_core_options()` function here includes an additional argument identifying whether the frontend has option category support (a core may wish to selectively hide or reorganise options based upon this variable).

./include/libretro-common/samples/file/config_file/config_file_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>

#include <file/config_file.h>

static void test_config_file_parse_contains(
      const char *cfgtext,
      const char *key, const char *val)
{
   char *cfgtext_copy = strdup(cfgtext);
   config_file_t *cfg = config_file_new_from_string(cfgtext_copy, NULL);
   char          *out = NULL;
   bool            ok = false;

   free(cfgtext_copy);

   if (!cfg)
      abort();

   ok = config_get_string(cfg, key, &out);
   if (ok != (bool)val)
      abort();
   if (!val)
      return;

   if (!out)
      out = strdup("");
   if (strcmp(out, val) != 0)
   {
      printf("[FAILED] Key [%s] Doesn't contain val [%s]\n", key, val);
      abort();
   }
   printf("[SUCCESS] Key [%s] contains val [%s]\n", key, val);
   free(out);
}

int main(void)
{
   test_config_file_parse_contains("foo = \"bar\"\n",   "foo", "bar");
   test_config_file_parse_contains("foo = \"bar\"",     "foo", "bar");
   test_config_file_parse_contains("foo = \"bar\"\r\n", "foo", "bar");
   test_config_file_parse_contains("foo = \"bar\"",     "foo", "bar");

   test_config_file_parse_contains("foo = \"\"\n",   "foo", "");
   test_config_file_parse_contains("foo = \"\"",     "foo", "");
   test_config_file_parse_contains("foo = \"\"\r\n", "foo", "");
   test_config_file_parse_contains("foo = \"\"",     "foo", "");

   test_config_file_parse_contains("foo = \"\"\n",   "bar", NULL);
   test_config_file_parse_contains("foo = \"\"",     "bar", NULL);
   test_config_file_parse_contains("foo = \"\"\r\n", "bar", NULL);
   test_config_file_parse_contains("foo = \"\"",     "bar", NULL);
}

./include/libretro-common/samples/file/config_file/Makefile

TARGET := config_file_test

LIBRETRO_COMM_DIR := ../../..

SOURCES := \
	config_file_test.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/file/file_path.c \
	$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
	$(LIBRETRO_COMM_DIR)/file/config_file.c \
	$(LIBRETRO_COMM_DIR)/lists/string_list.c \
	$(LIBRETRO_COMM_DIR)/string/stdstring.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
	$(LIBRETRO_COMM_DIR)/time/rtime.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/file/nbio/Makefile

TARGET := nbio_test

LIBRETRO_COMM_DIR := ../../..

SOURCES := \
	nbio_test.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/file/nbio/nbio_test.c

#include <stdio.h>
#include <string.h>

#include <file/nbio.h>

static void nbio_write_test(void)
{
   size_t _len;
   bool looped = false;
   void *ptr   = NULL;
   struct nbio_t* write = nbio_open("test.bin", NBIO_WRITE);
   if (!write)
      puts("[ERROR] nbio_open failed (1)");

   nbio_resize(write, 1024*1024);

   ptr = nbio_get_ptr(write, &_len);
   if (_len != 1024*1024)
      puts("[ERROR] wrong size (1)");

   memset(ptr, 0x42, 1024*1024);
   nbio_begin_write(write);

   while (!nbio_iterate(write))
      looped=true;

   if (!looped)
      puts("[SUCCESS] Write finished immediately.");

   nbio_free(write);
}

static void nbio_read_test(void)
{
   size_t _len;
   bool looped = false;
   struct nbio_t* read = nbio_open("test.bin", NBIO_READ);
   void* ptr           = nbio_get_ptr(read, &_len);
   if (!read)
      puts("[ERROR] nbio_open failed (2)");

   if (_len != 1024*1024)
      puts("[ERROR] wrong size (2)");
   if (ptr)
      puts("[SUCCESS] Read pointer is available before iterating.");

   nbio_begin_read(read);

   while (!nbio_iterate(read))
      looped=true;

   if (!looped)
      puts("[SUCCESS] Read finished immediately.");

   ptr = nbio_get_ptr(read, &_len);

   if (_len != 1024*1024)
      puts("[ERROR] wrong size (3)");
   if (*(char*)ptr != 0x42 || memcmp(ptr, (char*)ptr+1, 1024*1024-1))
      puts("[ERROR] wrong data");

   nbio_free(read);
}

int main(void)
{
   nbio_write_test();
   nbio_read_test();
}

./include/libretro-common/samples/formats/png/Makefile

TARGET := rpng

CORE_DIR          := .
LIBRETRO_PNG_DIR  := ../../../formats/png
LIBRETRO_COMM_DIR := ../../..

HAVE_IMLIB2=0

LDFLAGS +=  -lz

ifeq ($(HAVE_IMLIB2),1)
CFLAGS += -DHAVE_IMLIB2
LDFLAGS += -lImlib2
endif

SOURCES_C := 	\
	$(CORE_DIR)/rpng_test.c \
	$(LIBRETRO_PNG_DIR)/rpng.c \
	$(LIBRETRO_PNG_DIR)/rpng_encode.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/string/stdstring.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \
	$(LIBRETRO_COMM_DIR)/file/archive_file.c \
	$(LIBRETRO_COMM_DIR)/file/archive_file_zlib.c \
	$(LIBRETRO_COMM_DIR)/file/file_path.c \
	$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
	$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
	$(LIBRETRO_COMM_DIR)/lists/string_list.c

OBJS := $(SOURCES_C:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB -DRPNG_TEST -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/formats/png/rpng_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#ifdef HAVE_IMLIB2
#include <Imlib2.h>
#endif

#include <file/nbio.h>
#include <formats/rpng.h>
#include <formats/image.h>

static bool rpng_load_image_argb(const char *path, uint32_t **data,
      unsigned *width, unsigned *height)
{
   int retval;
   size_t file_len;
   bool              ret = true;
   rpng_t          *rpng = NULL;
   void             *ptr = NULL;
   struct nbio_t* handle = (struct nbio_t*)nbio_open(path, NBIO_READ);

   if (!handle)
      goto end;

   nbio_begin_read(handle);

   while (!nbio_iterate(handle));

   ptr = nbio_get_ptr(handle, &file_len);

   if (!ptr)
   {
      ret = false;
      goto end;
   }

   rpng = rpng_alloc();

   if (!rpng)
   {
      ret = false;
      goto end;
   }

   if (!rpng_set_buf_ptr(rpng, (uint8_t*)ptr, file_len))
   {
      ret = false;
      goto end;
   }

   if (!rpng_start(rpng))
   {
      ret = false;
      goto end;
   }

   while (rpng_iterate_image(rpng));

   if (!rpng_is_valid(rpng))
   {
      ret = false;
      goto end;
   }

   do
   {
      retval = rpng_process_image(rpng,
            (void**)data, file_len, width, height);
   }while(retval == IMAGE_PROCESS_NEXT);

   if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)
      ret = false;

end:
   if (handle)
      nbio_free(handle);
   if (rpng)
      rpng_free(rpng);
   rpng = NULL;
   if (!ret)
      free(*data);
   return ret;
}

static int test_rpng(const char *in_path)
{
#ifdef HAVE_IMLIB2
   Imlib_Image img;
   const uint32_t *imlib_data = NULL;
#endif
   const uint32_t test_data[] = {
      0xff000000 | 0x50, 0xff000000 | 0x80,
      0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0x50, 0xff000000 | 0x80,
      0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
   };
   uint32_t *data = NULL;
   unsigned width = 0;
   unsigned height = 0;

   if (!rpng_save_image_argb("/tmp/test.png", test_data, 4, 4, 16))
      return 1;

   if (!rpng_load_image_argb(in_path, &data, &width, &height))
      return 2;

   fprintf(stderr, "Path: %s.\n", in_path);
   fprintf(stderr, "Got image: %u x %u.\n", width, height);

#if 0
   fprintf(stderr, "\nRPNG:\n");
   for (unsigned h = 0; h < height; h++)
   {
      unsigned w;
      for (w = 0; w < width; w++)
         fprintf(stderr, "[%08x] ", data[h * width + w]);
      fprintf(stderr, "\n");
   }
#endif

#ifdef HAVE_IMLIB2
   /* Validate with imlib2 as well. */
   img = imlib_load_image(in_path);
   if (!img)
      return 4;

   imlib_context_set_image(img);

   width      = imlib_image_get_width();
   height     = imlib_image_get_width();
   imlib_data = imlib_image_get_data_for_reading_only();

#if 0
   fprintf(stderr, "\nImlib:\n");
   for (unsigned h = 0; h < height; h++)
   {
      for (unsigned w = 0; w < width; w++)
         fprintf(stderr, "[%08x] ", imlib_data[h * width + w]);
      fprintf(stderr, "\n");
   }
#endif

   if (memcmp(imlib_data, data, width * height * sizeof(uint32_t)) != 0)
   {
      fprintf(stderr, "Imlib and RPNG differs!\n");
      return 5;
   }
   else
      fprintf(stderr, "Imlib and RPNG are equivalent!\n");

   imlib_free_image();
#endif
   free(data);

   return 0;
}

int main(int argc, char *argv[])
{
   const char *in_path = "/tmp/test.png";

   if (argc > 2)
   {
      fprintf(stderr, "Usage: %s <png file>\n", argv[0]);
      return 1;
   }

   if (argc == 2)
      in_path = argv[1];

   fprintf(stderr, "Doing tests...\n");

   if (test_rpng(in_path) != 0)
   {
      fprintf(stderr, "Test failed.\n");
      return -1;
   }

   return 0;
}

./include/libretro-common/samples/formats/xml/Makefile

TARGET := rxml

LIBRETRO_XML_DIR  := ../../../formats/xml
LIBRETRO_COMM_DIR := ../../../
LIBRETRO_DEPS_DIR := ../../../../deps

SOURCES := \
	rxml_test.c \
	$(LIBRETRO_XML_DIR)/rxml.c \
	$(LIBRETRO_DEPS_DIR)/yxml/yxml.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -DRXML_TEST -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/formats/xml/rxml_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <formats/rxml.h>
#include <stdio.h>

static void print_siblings(struct rxml_node *node, unsigned level)
{
   fprintf(stderr, "\n%*sName: %s\n", level * 4, "", node->name);
   if (node->data)
      fprintf(stderr, "%*sData: %s\n", level * 4, "", node->data);

   for (const struct rxml_attrib_node *attrib =
         node->attrib; attrib; attrib = attrib->next)
      fprintf(stderr, "%*s  Attrib: %s = %s\n", level * 4, "",
            attrib->attrib, attrib->value);

   if (node->children)
      print_siblings(node->children, level + 1);

   if (node->next)
      print_siblings(node->next, level);
}

static void rxml_log_document(const char *path)
{
   rxml_document_t *doc = rxml_load_document(path);
   if (!doc)
   {
      fprintf(stderr, "rxml: Failed to load document: %s\n", path);
      return;
   }

   print_siblings(rxml_root_node(doc), 0);
   rxml_free_document(doc);
}

int main(int argc, char *argv[])
{
   if (argc != 2)
   {
      fprintf(stderr, "Usage: %s <path>\n", argv[0]);
      return 1;
   }

   rxml_log_document(argv[1]);
}

./include/libretro-common/samples/net/http_test

ELF>@@pH@8	@@@@@@88@8@@@-- ..`.`08  . .` .`TT@T@DDPtdh$h$@h$@QtdRtd..`.`/lib64/ld-linux-x86-64.so.2GNU GNUKEs?W7>~_f75@#X*C QG18"kwlibc.so.6socketstrcpy__strdupconnectsignalselectreallocmemchrinet_ptonstrtolcallocstrlensendgetaddrinfostrstr__errno_locationbindrecvmemcpystrtoulsetsockoptmallocstrcasecmp__ctype_b_locclose__ctype_toupper_loc__ctype_tolower_locfreeaddrinfofcntlmemmovestrcmp__libc_start_mainsnprintffree__gmon_start__GLIBC_2.14GLIBC_2.2.5GLIBC_2.3Rui	]ii
i/`/`0` 0`(0`00`80`@0`H0`P0`X0`	`0`
h0`p0`x0`
0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`1` 1`!1`"1`# 1`$HH]$ HtH5R$ %T$ @%R$ h%J$ h%B$ h%:$ h%2$ h%*$ h%"$ h%$ hp%$ h`%
$ h	P%$ h
@%# h0%# h %# h
%# h%# h%# h%# h%# h%# h%# h%# h%# h%# hp%# h`%# hP%# h@%z# h0%r# h %j# h%b# h%Z# h%R# h %J# h!USH(HD$HD$##@.HfHT$Ht$0$@1*HT$Ht$HHtԿG$@H11H$tHt$1H
H¿a$@1HH
1H([]f.1I^HHPTIP#@H"@H
@! D?1`UH-81`HHvHt]81`f]@f.81`UH81`HHHH?HHtHt]81`]fD=! uUHn]! @.`H?uHtUH]zf.ATUSHHIlHHމuA$[]A\ff.ATU(SHHI]̉11@p JEHL
uxH11fD0q\5Ht+ u0%zr8200q\5HuID$d#@HuHID$I$L[]A\HLE1L[]A\ÿHt1HtKHG:wHHr%HHHGH:wHs@1f.Ht;HG8t2USHHHoG P}:tHHkH[]Ð1DHUHDPu1H[]H}Hs
vHkC }/t1DHtSHHHtH[@f.HGÐf.ATUSH HD$w HHH|$HD$Ht$
H|$ApEx}t	trHt$#@D$|$tsK Pt@H|$1#@HD$HD$s|$uHT$Ht$D$'	1H H[]A\fHSHt$p|$rHt$l#@T|$VHt$x#@8|$H7Ht$K P'bDHt$u#@|$NHt$#@|$2Ht$u#@|$0
(@@@	H@
H@H@H@ HHC(H1bH H[]A\fDHtøfHAWAVAUATIUSHH
H4$uuG<<H$HtID$HHtA|$	ttHEA|$H[]A\A]A^A_I\$ID$H9HI\$H9sAD$
AD$AD$H[]A\A]A^A_fID$HEDHWHO HG
HHD$H)HW(?HHxIID$ M|$HPI9NEl$M|$A~gfD#@HGHx	
1kI|$(AD$AD$IwI)LM9El$Mt$A\I|$(L
N4?^HIFID$(I9tA
A|$^#@H#@Hl	tAD$	I|$(?YA|$	AD$GAD$<HG
HD$IT$IL$ Ht$A<$H)IT$(HHIT$ ID$HJH9@AD$	<AD$<t;<ID$H9HH)AD$AD$IT$<IT$IT$uI\$M|$HI\$L)H<Ml$(H
K|=LHIK|=1I|$IvIH)I|$I|$(HeMMl$AD$!It$I|$(AD$It$ID$(AD$	H4I|$(It$ ID$(AGID$(HxAD$	
1jID$ID$(LID$AA,HuA|$
"A|$	iIt$I|$(1AD$VID$(1f.H)I\$ID$H4I|$(IIt$ M|$ID$(I|$(AD$It$ID$(ID$DHtGøÐHtCtHtHGHHG(fD
u
G-ȃcvHtH1fD1DHtSH?xH[@f.G
uG-ȃcBt@f.= tÐH
 Hff.@f.ff{f.AVAU1ATUISAιIH@H\$H$HD$HHQEAtZMtbͺ#@H1nLHHLxYIEHtPPpxH@[]A\A]A^DMD$uD$fD$yfSHHH1OH~	[txH[fDC8u1[f.HtEATAUHSH@HH)t 1HHDH[1]A\@[]A\øS1߾1[+f.f.Ht{AUATAUSHHHEAA@fDHH)t8DHHDHxH1[]A\A]Ð+8u@H[]A\A]øf.USHAHHL$D$UHuH[]fUSHHt)AHH$HD$SHsH[]1@t	1@ƃtEDUSHHH>|UfC1HuHSfH[]aHtTHHtnHN6HW@@7tcLfHqH@@rt3HH)I9uHH€>HtH)@H<u@HH1fATUHSHI~IH<HL)ȺI9HFL=[L]A\DATUISDI$tCHLHHHHtDX uI9t[HUL]A\@[]A\USHHH\H9tZCHfDHCH9t/HHBf% ufH[]f.HCHBf% HHPf% Ht?@f.HtHtHH1f.HtHtHH1f.USHHHt$JHHHJHuHH[]ÐUSHHHt$HHHJHuHH[]ÐUSHHHtOHDZHt uHrHHˈ
uH]HEHH[]{fAWAVAUATUSHH(HHT$HHI1H|$HD$HI@HL$HH<LHuH~LH+T$HH|(HHD$H9fDMHHI)LLHt$HLLHD$ILHjHIuHHHD$H([]A\A]A^A_H(H[]A\A]A^A_*f.HSHt
?tmH[HSHt
?tH[HSHt?u
H[D;tHH[ÐAWAVAAUATL% UH- SIIL)HHHt 1LLDAHH9uH[]A\A]A^A_Ðf.HHhttp:// HTTP/1.1
Host: :%iConnection: close
GET /HTTP/1.Content-Length: Transfer-Encoding: chunked%huhttp://buildbot.libretro.com/nightly/win-x86/latest/mednafen_psx_libretro.dll.zip%.9lu / %.9lu        
http://www.wikipedia.org/%.*s
;1Hx	XX8xP(hHx8Ph((hP8`8xHHxx8x@(Hx(	p	zRx+zRx$`0FJw?;*3$",DH4BAC jAB<tX
BAF 
ABAW
ABA(S<pOAG eAAJ Z
AAD"FU,DD:BAA D@
 DABJ2 DAB|KBB B(D0A8GPT
8A0A(B BBBA~8A0A(B BBBLP$<KT("FRt8@804T_XPHD@BBD A(D0Qp
0A(A BBBF$dFAW
HQ
GM<PGDD g
CBEAFB )Ag0(T GBD A(J0~
(C ABBBT(F ABB$tXGAAW0fFA$MAAI0AA;$?AAJ lAA,`;BAD mDB4Lp]BAD ~
HBIAAB,AAG J
AAK#NN#NN$0?AAG pDA$$H?AAG pDA,L`gAAG Q
DAA\|BBB B(A0A8G`
8A0A(B BBBDD8D0A(B BBB`DS`DS`/DN
FV$<pAAD@CADdHeBBE B(H0H8M@r8A0A(B BBBp@p@@
T#@.`.`o@0@@
s0`0`@0@0	o@oo@ .`@@@@@@&@6@F@V@f@v@@@@@@@@@
@
@&
@6
@F
@V
@f
@v
@
@
@
@
@
@
@GCC: (GNU) 6.1.1 20160802GCC: (GNU) 6.2.1 201608308@T@t@@@0@@@	0@
`@@@

@T#@`#@h$@&@.`.`.` .`/`0`(1`81`#.`0
@2
0@E
p@[81`j.`
@.`
@491` 
@]C
P@g-@u.`.` .`.`h$@0`
@
P#@+=Uo (1`s
`@
@G
 @g
"@/81`T#@
` @?
@F=QOe
@P
@"
@
0 @#
@;
@"

@-
P@:Ym(1`z 01`
P@M`#@
"@7K
"@e[o
@
p@@1`
p@s
@+
`@
 @#
 @?
p"@81`
`@K
@S8
@?J

@O
 @4\
 @)l~
p@
@@:
@
@
P!@
@
@
P@.C81`O
0@g
@;u
@
V@
 @init.cnet_http_test.ccrtstuff.c__JCR_LIST__deregister_tm_clones__do_global_dtors_auxcompleted.6916__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entrynet_http.cnet_http_send_str.part.0net_compat.cinited.4619net_socket.ccompat_strl.cstdstring.cstring_trim_whitespace_left.part.0string_trim_whitespace_right.part.1__FRAME_END____JCR_END____init_array_end_DYNAMIC__init_array_start__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE_freeaddrinfo_retro__libc_csu_fini__ctype_toupper_loc@@GLIBC_2.3free@@GLIBC_2.2.5recv@@GLIBC_2.2.5strcasecmp@@GLIBC_2.2.5__errno_location@@GLIBC_2.2.5strcpy@@GLIBC_2.2.5network_deinitsocket_bindsetsockopt@@GLIBC_2.2.5string_ucwordsfcntl@@GLIBC_2.2.5string_trim_whitespace_edatastrlen@@GLIBC_2.2.5string_to_uppersocket_receive_all_nonblockingsend@@GLIBC_2.2.5snprintf@@GLIBC_2.2.5socket_receive_all_blockingnet_http_connection_freeclose@@GLIBC_2.2.5getaddrinfo_retrostring_is_equal_noncasestrlcat_retro__net_http_delete__strdup@@GLIBC_2.2.5socket_initmemchr@@GLIBC_2.2.5socket_close__libc_start_main@@GLIBC_2.2.5calloc@@GLIBC_2.2.5__data_startstrcmp@@GLIBC_2.2.5signal@@GLIBC_2.2.5__gmon_start__strtol@@GLIBC_2.2.5__dso_handlememcpy@@GLIBC_2.14socket_connect_IO_stdin_usedinet_pton@@GLIBC_2.2.5string_trim_whitespace_rightselect@@GLIBC_2.2.5__libc_csu_initmalloc@@GLIBC_2.2.5net_http_updatenet_http_connection_doneinet_htonssocket_selectstring_is_equalstring_to_lowerrealloc@@GLIBC_2.2.5string_trim_whitespace_left__bss_startnet_http_datanet_http_connection_iteratesocket_set_targetmainnetwork_initsocket_nonblockbind@@GLIBC_2.2.5socket_send_all_blockingmemmove@@GLIBC_2.2.5net_http_newnet_http_errorinet_ptrtonstring_replace_substringstring_is_emptystrtoul@@GLIBC_2.2.5net_http_fdnet_http_statusconnect@@GLIBC_2.2.5__TMC_END__net_http_connection_urlsocket_creategetaddrinfo@@GLIBC_2.2.5net_http_connection_newstrstr@@GLIBC_2.2.5strlcpy_retro____ctype_tolower_loc@@GLIBC_2.3__ctype_b_loc@@GLIBC_2.3freeaddrinfo@@GLIBC_2.2.5socket@@GLIBC_2.2.5.symtab.strtab.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.dynamic.got.got.plt.data.bss.comment8@8#T@T 1t@t$Do@N@xV0@0s^o@Jko@@z0@00B`@`0@@0
@
rT#@T#	`#@`#h$@h$&@&.`..`..`. .` ./`/0`0((1`(181`810814hGp1
8	8?0

./include/libretro-common/samples/net/Makefile

TARGETS  = http_test http_parse_test net_ifinfo

LIBRETRO_COMM_DIR := ../..

INCFLAGS = -I$(LIBRETRO_COMM_DIR)/include

ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
   platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
   platform = osx
	arch = intel
ifeq ($(shell uname -p),powerpc)
	arch = ppc
endif
else ifneq ($(findstring MINGW,$(shell uname -a)),)
   platform = win
endif
endif

ifeq ($(DEBUG),1)
CFLAGS += -O0 -g
else
CFLAGS += -O2
endif
CFLAGS += -Wall -pedantic -std=gnu99

HTTP_TEST_C = \
				  $(LIBRETRO_COMM_DIR)/net/net_http.c \
				  $(LIBRETRO_COMM_DIR)/net/net_compat.c \
				  $(LIBRETRO_COMM_DIR)/net/net_socket.c \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
				  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
				  $(LIBRETRO_COMM_DIR)/string/stdstring.c \
				  net_http_test.c

HTTP_TEST_OBJS := $(HTTP_TEST_C:.c=.o)

HTTP_PARSE_TEST_C = \
				  $(LIBRETRO_COMM_DIR)/net/net_http.c \
				  $(LIBRETRO_COMM_DIR)/net/net_http_parse.c \
				  $(LIBRETRO_COMM_DIR)/net/net_compat.c \
				  $(LIBRETRO_COMM_DIR)/net/net_socket.c \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
				  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
				  $(LIBRETRO_COMM_DIR)/string/stdstring.c \
				  net_http_parse_test.c

HTTP_PARSE_TEST_OBJS := $(HTTP_PARSE_TEST_C:.c=.o)

NET_IFINFO_C = \
					$(LIBRETRO_COMM_DIR)/net/net_ifinfo.c \
					net_ifinfo_test.c

ifeq ($(platform), win)
CFLAGS += -liphlpapi -lws2_32
endif

NET_IFINFO_OBJS := $(NET_IFINFO_C:.c=.o)

.PHONY: all clean

all: $(TARGETS)

%.o: %.c
	$(CC) $(INCFLAGS) $< -c $(CFLAGS) -o $@

http_parse_test: $(HTTP_PARSE_TEST_OBJS)
	$(CC) $(INCFLAGS) $(HTTP_PARSE_TEST_OBJS) $(CFLAGS) -o $@

http_test: $(HTTP_TEST_OBJS)
	$(CC) $(INCFLAGS) $(HTTP_TEST_OBJS) $(CFLAGS) -o $@

net_ifinfo: $(NET_IFINFO_OBJS)
	$(CC) $(INCFLAGS) $(NET_IFINFO_OBJS) $(CFLAGS) -o $@

clean:
	rm -rf $(TARGETS) $(HTTP_TEST_OBJS) $(HTTP_PARSE_TEST_OBJS) $(NET_IFINFO_OBJS)

./include/libretro-common/samples/net/net_http_parse_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http_parse_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <compat/strcasestr.h>

int main(int argc, char *argv[])
{
   char link[1024];
   char name[1024];
   const char *line  = "<a href=\"http://www.test.com/somefile.zip\">Test</a>\n";

   link[0] = name[0] = '\0';

   string_parse_html_anchor(line, link, name, sizeof(link), sizeof(name));

   printf("link: %s\nname: %s\n", link, name);

   return 1;
}

./include/libretro-common/samples/net/net_http_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <net/net_http.h>
#include <net/net_compat.h>

#ifdef _WIN32
#include <winsock2.h>
#endif

int main(void)
{
   char   *data;
   struct http_t *http1, *http3;
   size_t _len, pos = 0, tot = 0;

   if (!network_init())
      return -1;

   http1 = net_http_new("http://buildbot.libretro.com/nightly/windows/x86_64/latest/mednafen_psx_libretro.dll.zip");

   while (!net_http_update(http1, &pos, &tot))
      printf("%.9lu / %.9lu        \r",pos,tot);

   http3 = net_http_new("http://www.wikipedia.org/");
   while (!net_http_update(http3, NULL, NULL)) {}

   data  = (char*)net_http_data(http3, &_len, false);

   printf("%.*s\n", (int)256, data);

   net_http_delete(http1);
   net_http_delete(http3);

   return 0;
}

./include/libretro-common/samples/net/net_ifinfo

ELF>@@8@8	@@@@@@88@8@@@ ```h   ` `TT@T@DDPtd		@	@DDQtdRtd``/lib64/ld-linux-x86-64.so.2GNU GNUBJlg-\nt_*M#d B6libc.so.6__strdupreallocprintfcallocgetnameinfofreeifaddrsgetifaddrs__libc_start_mainfree__gmon_start__GLIBC_2.3GLIBC_2.2.5ii
sui	}``` `(`0`8`@`H`	P`
HHm
 HtH5b
 %d
 @%b
 h%Z
 h%R
 h%J
 h%B
 h%:
 h%2
 h%*
 hpUSHHtVHHtG11H}t+@HHE	@HPH01=CH;EHrH1H[]Ãf.1I^HHPTI	@Hp	@H0@	 Do`UH-h`HHvHt]h`f]@f.h`UHh`HHHH?HHtHt]h`]fD=	 uUHn] @`H?uHtUH]zf.HATU1S1HIu*SH{?u:HHC]I;\$Hs+HI$H;?tH{?tfDI<$[L]A\{fDAWAVAUATIUSH(H|$HD$MH\$H1DHHH{Htf?uHE1E1jHT$ ZYDuI<$LH'HtjH{HI$L<(H|$II,$HHEMt$DHp@H\$HH([]A\A]A^A_@H|$LF1fAWAVAAUATL% UH- SIIL)HHHt 1LLDAHH9uH[]A\A]A^A_Ðf.HH%s:%s
;@4D\DttzRxP+zRx$FJw?;*3$",DKAC kDB\tX.BBB B(D0A8G[HWAz
8A0A(B BBBE,uAAN ]
AAADeBBE B(H0H8M@r8A0A(B BBBL @`@@
	@``o@@@
`@@0	o`@ooJ@ `@@@@@@@&@GCC: (GNU) 6.1.1 20160802GCC: (GNU) 6.2.1 201608308@T@t@@@@J@`@	@
@@@
0@	@	@	@@
@``` ```X`h`%`2
@4
 @G
`@]h`l`
@`@`` ``	@%`;
	@K X`]h`E	@dxX` ``	@
@"
p	@e2p`
@+H]h`i
0@unh`
@@.,@init.cnet_ifinfo_test.ccrtstuff.c__JCR_LIST__deregister_tm_clones__do_global_dtors_auxcompleted.6916__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entrynet_ifinfo.c__FRAME_END____JCR_END____init_array_end_DYNAMIC__init_array_start__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_csu_finifree@@GLIBC_2.2.5_edataprintf@@GLIBC_2.2.5getnameinfo@@GLIBC_2.2.5__strdup@@GLIBC_2.2.5__libc_start_main@@GLIBC_2.2.5calloc@@GLIBC_2.2.5__data_start__gmon_start____dso_handle_IO_stdin_usednet_ifinfo_free__libc_csu_initgetifaddrs@@GLIBC_2.3realloc@@GLIBC_2.2.5__bss_startmainfreeifaddrs@@GLIBC_2.3__TMC_END__net_ifinfo_new.symtab.strtab.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.dynamic.got.got.plt.data.bss.comment8@8#T@T 1t@t$Do@N@V@^oJ@Jko`@`0z@0B@@@0@0	@			@		@	D@
@@
``` ` ``XX`Xh`h0h400	

./include/libretro-common/samples/net/net_ifinfo_test.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_ifinfo_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <net/net_ifinfo.h>

int main(int argc, const char *argv[])
{
   unsigned k              = 0;
   net_ifinfo_t list;

   if (!net_ifinfo_new(&list))
      return -1;

   for (k = 0; k < list.size; k++)
   {
      printf("%s:%s\n", list.entries[k].name, list.entries[k].host);
   }

   net_ifinfo_free(&list);

   return 0;
}

./include/libretro-common/samples/net/udp-test.c

/* public domain */
/* gcc -o udptest udp-test.c */

/*
   will send "RETROPAD RIGHT" indefinely to player 1
   to send to player 2 change port to 55401 and so on
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define SERVER "127.0.0.1"
#define PORT 55400

void die(char *s)
{
    perror(s);
    exit(1);
}

int main(void)
{
   struct sockaddr_in si_other;
   int s, i, slen=sizeof(si_other);

   if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
      die("socket");

   memset((char *) &si_other, 0, sizeof(si_other));
   si_other.sin_family = AF_INET;
   si_other.sin_port = htons(PORT);

   if (inet_aton(SERVER , &si_other.sin_addr) == 0)
   {
      fprintf(stderr, "inet_aton() failed\n");
      exit(1);
   }

   for (;;)
   {
      char message[10]="128";
      /* send the message */
      if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other, slen)==-1)
         die("sendto()");

      /* sleep for 1 frame (60hz) */
      usleep(16*1000);
   }

   close(s);
   return 0;
}

./include/libretro-common/samples/streams/rzip/Makefile

TARGET := rzip

LIBRETRO_COMM_DIR := ../../..
LIBRETRO_DEPS_DIR := ../../../../deps

# Attempt to detect target platform
ifeq '$(findstring ;,$(PATH))' ';'
	UNAME := Windows
else
	UNAME := $(shell uname 2>/dev/null || echo Unknown)
	UNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))
	UNAME := $(patsubst MSYS%,MSYS,$(UNAME))
	UNAME := $(patsubst MINGW%,MSYS,$(UNAME))
endif

# Add '.exe' extension on Windows platforms
ifeq ($(UNAME), Windows)
	TARGET := rzip.exe
endif
ifeq ($(UNAME), MSYS)
	TARGET := rzip.exe
endif

SOURCES := \
	rzip.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
	$(LIBRETRO_COMM_DIR)/file/file_path.c \
	$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
	$(LIBRETRO_COMM_DIR)/string/stdstring.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
	$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/rzip_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/stdin_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
	$(LIBRETRO_COMM_DIR)/time/rtime.c

ifneq ($(wildcard $(LIBRETRO_DEPS_DIR)/*),)
	# If we are building from inside the RetroArch
	# directory (i.e. if an 'external' deps directory
	# is available), bake in zlib support
	SOURCES += \
		$(LIBRETRO_DEPS_DIR)/libz/adler32.c \
		$(LIBRETRO_DEPS_DIR)/libz/libz-crc32.c \
		$(LIBRETRO_DEPS_DIR)/libz/deflate.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzclose.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzlib.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzread.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzwrite.c \
		$(LIBRETRO_DEPS_DIR)/libz/inffast.c \
		$(LIBRETRO_DEPS_DIR)/libz/inflate.c \
		$(LIBRETRO_DEPS_DIR)/libz/inftrees.c \
		$(LIBRETRO_DEPS_DIR)/libz/trees.c \
		$(LIBRETRO_DEPS_DIR)/libz/zutil.c
	INCLUDE_DIRS := -I$(LIBRETRO_COMM_DIR)/include/compat/zlib
else
	# If this is a stand-alone libretro-common directory,
	# rely on system zlib library (note: only likely to
	# work on Unix-based platforms...)
	LDFLAGS += -lz
endif

OBJS := $(SOURCES:.c=.o)
INCLUDE_DIRS += -I$(LIBRETRO_COMM_DIR)/include
CFLAGS += -DHAVE_ZLIB -Wall -pedantic -std=gnu99 $(INCLUDE_DIRS)

# Silence "ISO C does not support the 'I64' ms_printf length modifier"
# warnings when using MinGW
ifeq ($(UNAME), Windows)
	CFLAGS += -Wno-format
endif
ifeq ($(UNAME), MSYS)
	CFLAGS += -Wno-format
endif

ifeq ($(DEBUG), 1)
	CFLAGS += -O0 -g -DDEBUG -D_DEBUG
else
	CFLAGS += -O2 -DNDEBUG
endif

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean

./include/libretro-common/samples/streams/rzip/rzip.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <inttypes.h>
#include <errno.h>
#include <time.h>

#include <string/stdstring.h>
#include <file/file_path.h>
#include <streams/interface_stream.h>
#include <streams/file_stream.h>
#include <streams/rzip_stream.h>
#include <retro_miscellaneous.h>

#define FILE_TRANSFER_CHUNK_SIZE 4096

enum rzip_action_type
{
	RZIP_ACTION_QUERY = 0,
	RZIP_ACTION_COMPRESS,
	RZIP_ACTION_EXTRACT
};

static void rand_str(char *dst, size_t len)
{
   char charset[] = "0123456789"
         "abcdefghijklmnopqrstuvwxyz"
         "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

   while (len-- > 0)
   {
      size_t i = (double)rand() / RAND_MAX * (sizeof(charset) - 1);
      *dst++   = charset[i];
   }
   *dst = '\0';
}

int main(int argc, char *argv[])
{
   char in_file_path[PATH_MAX_LENGTH];
   char out_file_path[PATH_MAX_LENGTH];
   enum rzip_action_type action = RZIP_ACTION_QUERY;
   intfstream_t *in_file        = NULL;
   intfstream_t *out_file       = NULL;
   int64_t in_file_size         = 0;
   int64_t in_file_raw_size     = 0;
   int64_t out_file_size        = 0;
   int64_t file_size_diff       = 0;
   int64_t total_data_read      = 0;
   bool in_file_compressed      = false;
   bool valid_args              = false;
   bool in_place                = false;
   int ret                      = 1;

   in_file_path[0]  = '\0';
   out_file_path[0] = '\0';

   /* Parse arguments */
   if ((argc > 1) && !string_is_empty(argv[1]))
   {
      valid_args = true;

      if (string_is_equal(argv[1], "i"))
         action = RZIP_ACTION_QUERY;
      else if (string_is_equal(argv[1], "a"))
         action = RZIP_ACTION_COMPRESS;
      else if (string_is_equal(argv[1], "x"))
         action = RZIP_ACTION_EXTRACT;
      else
         valid_args = false;
   }

   /* Get input file path */
   if (valid_args && (argc > 2) && !string_is_empty(argv[2]))
   {
      strlcpy(in_file_path, argv[2], sizeof(in_file_path));
      path_resolve_realpath(in_file_path, sizeof(in_file_path), true);
      valid_args = valid_args && !string_is_empty(in_file_path);
   }
   else
      valid_args = false;

   /* Ensure arguments are valid */
   if (!valid_args)
   {
      fprintf(stderr, "Usage:\n");
      fprintf(stderr, "- Query file status: %s i <input file>\n", argv[0]);
      fprintf(stderr, "- Compress file:     %s a <input file> <output file (optional)>\n", argv[0]);
      fprintf(stderr, "- Extract file:      %s x <input file> <output file (optional)>\n", argv[0]);
      fprintf(stderr, "Omitting <output file> will overwrite <input file>\n");
      goto end;
   }

   /* Ensure that input file exists */
   if (!path_is_valid(in_file_path))
   {
      fprintf(stderr, "ERROR: Input file does not exist: %s\n", in_file_path);
      goto end;
   }

   /* Get output file path, if specified */
   if ((argc > 3) && !string_is_empty(argv[3]))
   {
      strlcpy(out_file_path, argv[3], sizeof(out_file_path));
      path_resolve_realpath(out_file_path, sizeof(out_file_path), true);
   }

   /* If we are compressing/extracting and an
    * output file was not specified, generate a
    * temporary output file path */
   if ((action != RZIP_ACTION_QUERY) &&
       string_is_empty(out_file_path))
   {
      const char *in_file_name = path_basename(in_file_path);
      char in_file_dir[DIR_MAX_LENGTH];

      in_file_dir[0] = '\0';

      fill_pathname_parent_dir(in_file_dir, in_file_path, sizeof(in_file_dir));

      if (string_is_empty(in_file_name))
      {
         fprintf(stderr, "ERROR: Invalid input file: %s\n", in_file_path);
         goto end;
      }

      srand((unsigned int)time(NULL));

      for (;;)
      {
         char tmp_str[10] = {0};

         /* Generate 'random' file name */
         rand_str(tmp_str, sizeof(tmp_str) - 1);
         tmp_str[0] = '.';

         if (!string_is_empty(in_file_dir))
            fill_pathname_join_special(out_file_path, in_file_dir,
                  tmp_str, sizeof(out_file_path));
         else
            strlcpy(out_file_path, tmp_str, sizeof(out_file_path));

         strlcat(out_file_path, ".", sizeof(out_file_path));
         strlcat(out_file_path, in_file_name, sizeof(out_file_path));
         path_resolve_realpath(out_file_path, sizeof(out_file_path), true);

         if (!path_is_valid(out_file_path))
            break;
      }

      in_place = true;
   }

   /* Ensure that input and output files
    * are different */
   if (string_is_equal(in_file_path, out_file_path))
   {
      fprintf(stderr, "ERROR: Input and output are the same file: %s\n", in_file_path);
      goto end;
   }

   /* Get input file size */
   in_file_size = (int64_t)path_get_size(in_file_path);

   if (in_file_size < 1)
   {
      fprintf(stderr, "ERROR: Input file is empty: %s\n", in_file_path);
      goto end;
   }

   /* Open input file
    * > Always use RZIP interface */
   in_file = intfstream_open_rzip_file(
         in_file_path, RETRO_VFS_FILE_ACCESS_READ);

   if (!in_file)
   {
      fprintf(stderr, "ERROR: Failed to open input file: %s\n", in_file_path);
      goto end;
   }

   /* Get input file compression status */
   in_file_compressed = intfstream_is_compressed(in_file);

   /* Get raw (uncompressed) input file size */
   in_file_raw_size   = intfstream_get_size(in_file);

   /* If this is a query operation, just
    * print current state */
   if (action == RZIP_ACTION_QUERY)
   {
      printf("%s: %s\n",
            in_file_compressed ? "File is in RZIP format" : "File is NOT in RZIP format",
            in_file_path);
      printf("   Size on disk:      %" PRIi64 " bytes\n", in_file_size);
      if (in_file_compressed)
         printf("   Uncompressed size: %" PRIi64 " bytes\n", in_file_raw_size);
      goto end;
   }

   /* Check whether file is already in the
    * requested state */
   if ((in_file_compressed  && (action == RZIP_ACTION_COMPRESS)) ||
       (!in_file_compressed && (action == RZIP_ACTION_EXTRACT)))
   {
      printf("Input file is %s: %s\n",
            in_file_compressed ?
                  "already in RZIP format - cannot compress" :
                        "not in RZIP format - cannot extract",
            in_file_path);
      goto end;
   }

   /* Check whether output file already exists */
   if (path_is_valid(out_file_path))
   {
      char reply[8];

      reply[0] = '\0';

      printf("WARNING: Output file already exists: %s\n", out_file_path);
      printf("         Overwrite? [Y/n]: ");
      fgets(reply, sizeof(reply), stdin);
      if (reply[0] != 'Y')
         goto end;
   }

   /* Open output file */
   if (in_file_compressed)
      out_file = intfstream_open_file(
            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE,
            RETRO_VFS_FILE_ACCESS_HINT_NONE);
   else
      out_file = intfstream_open_rzip_file(
            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE);

   if (!out_file)
   {
      fprintf(stderr, "ERROR: Failed to open output file: %s\n", out_file_path);
      goto end;
   }

   /* Start file transfer */
   printf("%s file\n", in_file_compressed ? "Extracting" : "Compressing");
   printf("   From: %s\n", in_file_path);
   printf("   To:   %s\n", in_place ? in_file_path : out_file_path);

   for (;;)
   {
      int64_t data_written = 0;
      uint8_t buffer[FILE_TRANSFER_CHUNK_SIZE];
      /* Read a single chunk from input file */
      int64_t data_read    = intfstream_read(
            in_file, buffer, sizeof(buffer));

      if (data_read < 0)
      {
         fprintf(stderr, "ERROR: Failed to read from input file: %s\n", in_file_path);
         goto end;
      }

      total_data_read += data_read;

      /* Check whether we have reached the end of the file */
      if (data_read == 0)
      {
         /* Close files */
         intfstream_flush(out_file);
         intfstream_close(out_file);
         free(out_file);
         out_file = NULL;

         intfstream_close(in_file);
         free(in_file);
         in_file = NULL;

         break;
      }

      /* Write chunk to backup file */
      data_written = intfstream_write(out_file, buffer, data_read);

      if (data_written != data_read)
      {
         fprintf(stderr, "ERROR: Failed to write to output file: %s\n", out_file_path);
         goto end;
      }

      /* Update progress */
      printf("\rProgress: %" PRIi64 " %%", total_data_read * 100 / in_file_raw_size);
      fflush(stdout);
   }
   printf("\rProgress: 100 %%\n");

   /* Display final status 'report' */
   printf("%s complete:\n", in_file_compressed ? "Extraction" : "Compression");

   out_file_size  = (int64_t)path_get_size(out_file_path);
   file_size_diff = (in_file_size > out_file_size) ?
         (in_file_size - out_file_size) :
               (out_file_size - in_file_size);

   printf("   %" PRIi64 " -> %" PRIi64 " bytes [%" PRIi64 " %% %s]\n",
         in_file_size, out_file_size,
               file_size_diff * 100 / in_file_size,
               (out_file_size >= in_file_size) ?
                     "increase" : "decrease");

   /* If this was an in-place operation,
    * replace input file with output file */
   if (in_place)
   {
      filestream_delete(in_file_path);
      if (filestream_rename(out_file_path, in_file_path))
      {
         fprintf(stderr, "ERROR: Failed to rename temporary file\n");
         fprintf(stderr, "   From: %s\n", out_file_path);
         fprintf(stderr, "   To:   %s\n", in_file_path);
         goto end;
      }
   }

   ret = 0;

end:
   if (in_file)
   {
      intfstream_close(in_file);
      free(in_file);
   }

   if (out_file)
   {
      intfstream_close(out_file);
      free(out_file);
   }

   return ret;
}

./include/libretro-common/samples/utils/crc32.c

/* gcc -O3 -o crc32 crc32.c -lz */

#include <stdio.h>
#include <errno.h>
#include <string.h>

#include <encodings/crc32.h>

int main(int argc, const char* argv[])
{
   if (argc != 2 )
   {
      fprintf( stderr, "Usage: crc32 <filename>\n" );
      return 1;
   }

   FILE *file = fopen(argv[1], "rb");

   if (file)
   {
      uint32_t crc = encoding_crc32(0L, NULL, 0 );

      for (;;)
      {
         uint8_t buffer[16384];

         int numread = fread((void*)buffer, 1, sizeof(buffer), file);

         if (numread > 0)
            crc = encoding_crc32( crc, buffer, numread );
         else
            break;
      }

      fclose(file);

      printf("%08x\n", crc);
      return 0;
   }

   fprintf(stderr, "Error opening input file: %s\n", strerror(errno));
   return 1;
}

./include/libretro-common/samples/utils/Makefile

compiler    := gcc
extra_flags :=
use_neon    := 0
release	   := release
EXE_EXT	      :=

ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
   platform = win
else ifneq ($(findstring MINGW,$(shell uname -a)),)
   platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
   platform = osx
   arch = intel
ifeq ($(shell uname -p),powerpc)
   arch = ppc
endif
else ifneq ($(findstring win,$(shell uname -a)),)
   platform = win
endif
endif

ifeq ($(compiler),gcc)
extra_rules_gcc := $(shell $(compiler) -dumpmachine)
endif

ifneq (,$(findstring armv7,$(extra_rules_gcc)))
extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon
use_neon := 1
endif

ifneq (,$(findstring hardfloat,$(extra_rules_gcc)))
extra_flags += -mfloat-abi=hard
endif

ifeq (release,$(build))
extra_flags += -O2
endif

ifeq (debug,$(build))
extra_flags += -O0 -g
endif

ldflags :=

EXE_EXT :=
ifeq ($(platform), unix)
else ifeq ($(platform), osx)
compiler := $(CC)
else
EXE_EXT = .exe
endif

PWD_DIR := .
LIBRETRO_COMM_DIR := ../..
CORE_DIR := $(LIBRETRO_COMM_DIR)/utils

CC      := $(compiler)
CXX     := $(subst CC,++,$(compiler))
flags   := -I$(LIBRETRO_COMM_DIR)/include
asflags := $(extra_flags)
LDFLAGS :=
flags   += -std=c99 -DMD5_BUILD_UTILITY -DSHA1_BUILD_UTILITY

ifeq (1,$(use_neon))
ASMFLAGS := -INEON/asm
asflags += -mfpu=neon
endif

DJB2_OBJS := $(CORE_DIR)/djb2.o

MD5_OBJS  := $(CORE_DIR)/md5.o \
				 $(PWD_DIR)/md5_test.o

SHA1_OBJS := $(CORE_DIR)/sha1.o \
				 $(PWD_DIR)/sha1_main.o

CRC32_OBJS := $(PWD_DIR)/crc32.o \
				  $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.o \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strl.o \
				  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.o \
				  $(LIBRETRO_COMM_DIR)/streams/file_stream.o \
				  $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.o \
			     $(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.o

UTILS := djb2$(EXE_EXT) md5$(EXE_EXT) sha1$(EXE_EXT) crc32$(EXE_EXT)

all: $(UTILS)

djb2$(EXE_EXT): $(DJB2_OBJS)

md5$(EXE_EXT): $(MD5_OBJS)

sha1$(EXE_EXT): $(SHA1_OBJS)

crc32$(EXE_EXT): $(CRC32_OBJS)

%.o: %.S
	$(CC) -c -o $@ $(asflags) $(LDFLAGS)  $(ASMFLAGS)  $<

%.o: %.c
	$(CC) -c -o $@ $(flags) $<

$(UTILS):
	$(CC) -o $@ $(ldflags) $(flags) $^

clean:
	rm -f $(CORE_DIR)/*.o
	rm -f $(UTILS)

strip:
	strip -s $(UTILS)

./include/libretro-common/samples/utils/md5_test.c

/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there's no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's.  No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible.  Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */
#include <stdio.h>
#include <string.h>

#include <lrc_hash.h>

int main (int argc, char *argv[])
{
   /* For each command line argument in turn:
    ** filename          -- prints message digest and name of file
    */
   int i;
   MD5_CTX ctx;
   FILE* file;
   size_t numread;
   char buffer[16384];
   unsigned char result[16];

   for (i = 1; i < argc; i++)
   {
      MD5_Init(&ctx);
      file = fopen(argv[i], "rb");

      if (file)
      {
         do
         {
            numread = fread((void*)buffer, 1, sizeof(buffer), file);

            if (numread)
            {
               MD5_Update(&ctx,(void*)buffer, numread);
            }
         }
         while (numread);

         fclose(file);
         MD5_Final(result, &ctx);
         printf("%02x%02x%02x%02x%02x%02x%02x%02x"
			          "%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
			          result[ 0 ], result[ 1 ], result[ 2 ], result[ 3 ],
                result[ 4 ], result[ 5 ], result[ 6 ], result[ 7 ],
                result[ 8 ], result[ 9 ], result[ 10 ], result[ 11 ],
                result[ 12 ], result[ 13 ], result[ 14 ], result[ 15 ],
                argv[i]);
      }
   }

   return 0;
}

./include/libretro-common/samples/utils/sha1_main.c

/*
 *  sha.cpp
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones <paulej@packetizer.com>
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha.c 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This utility will display the message digest (fingerprint) for
 *      the specified file(s).
 *
 *  Portability Issues:
 *      None.
 */

#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include <string/stdstring.h>
/*#include "sha1.h"*/

/*
 *  Function prototype
 */
void usage(void);

/*
 *  main
 *
 *  Description:
 *      This is the entry point for the program
 *
 *  Parameters:
 *      argc: [in]
 *          This is the count of arguments in the argv array
 *      argv: [in]
 *          This is an array of filenames for which to compute message
 *          digests
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
typedef struct SHA1Context
{
   unsigned Message_Digest[5]; /* Message Digest (output)          */

   unsigned Length_Low;        /* Message length in bits           */
   unsigned Length_High;       /* Message length in bits           */

   unsigned char Message_Block[64]; /* 512-bit message blocks      */
   int Message_Block_Index;    /* Index into message block array   */

   int Computed;               /* Is the digest computed?          */
   int Corrupted;              /* Is the message digest corruped?  */
} SHA1Context;

int main(int argc, char *argv[])
{
   struct SHA1Context sha;         /* SHA-1 context                 */
   FILE        *fp;                /* File pointer for reading files*/
   char        c;                  /* Character read from file      */
   int         i;                  /* Counter                       */
   int         reading_stdin;      /* Are we reading standard in?   */
   int         read_stdin = 0;     /* Have we read stdin?           */

   /*
    *  Check the program arguments and print usage information if -?
    *  or --help is passed as the first argument.
    */
   if (argc > 1 && (string_is_equal(argv[1],"-?") ||
            string_is_equal(argv[1],"--help")))
   {
      usage();
      return 1;
   }

   /*
    *  For each filename passed in on the command line, calculate the
    *  SHA-1 value and display it.
    */
   for (i = 0; i < argc; i++)
   {
      /*
       *  We start the counter at 0 to guarantee entry into the for
       *  loop. So if 'i' is zero, we will increment it now.  If there
       *  is no argv[1], we will use STDIN below.
       */
      if (i == 0)
         i++;

      if (argc == 1 || string_is_equal(argv[i],"-"))
      {
#ifdef WIN32
         setmode(fileno(stdin), _O_BINARY);
#endif
         fp = stdin;
         reading_stdin = 1;
      }
      else
      {
         if (!(fp = fopen(argv[i],"rb")))
         {
            fprintf(stderr,
                  "sha: unable to open file %s\n",
                  argv[i]);
            return 2;
         }
         reading_stdin = 0;
      }

      /*
       *  We do not want to read STDIN multiple times
       */
      if (reading_stdin)
      {
         if (read_stdin)
            continue;

         read_stdin = 1;
      }

      /*
       *  Reset the SHA-1 context and process input
       */
      SHA1Reset(&sha);

      c = fgetc(fp);
      while(!feof(fp))
      {
         SHA1Input(&sha, &c, 1);
         c = fgetc(fp);
      }

      if (!reading_stdin)
         fclose(fp);

      if (!SHA1Result(&sha))
      {
         fprintf(stderr,
               "sha: could not compute message digest for %s\n",
               reading_stdin?"STDIN":argv[i]);
      }
      else
      {
         printf( "%08X %08X %08X %08X %08X - %s\n",
               sha.Message_Digest[0],
               sha.Message_Digest[1],
               sha.Message_Digest[2],
               sha.Message_Digest[3],
               sha.Message_Digest[4],
               reading_stdin?"STDIN":argv[i]);
      }
   }

   return 0;
}

/*
 *  usage
 *
 *  Description:
 *      This function will display program usage information to the
 *      user.
 *
 *  Parameters:
 *      None.
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void usage(void)
{
   printf("usage: sha <file> [<file> ...]\n");
   printf("\tThis program will display the message digest\n");
   printf("\tfor files using the Secure Hashing Algorithm (SHA-1).\n");
}

./include/libretro-common/streams/chd_stream.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (chd_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <boolean.h>

#include <streams/chd_stream.h>
#include <retro_endianness.h>
#include <libchdr/chd.h>
#include <string/stdstring.h>

#define SECTOR_RAW_SIZE 2352
#define SECTOR_SIZE 2048
#define SUBCODE_SIZE 96
#define TRACK_PAD 4

struct chdstream
{
   chd_file *chd;
   /* Loaded hunk */
   uint8_t *hunkmem;
   /* Byte offset where track data starts (after pregap) */
   size_t track_start;
   /* Byte offset where track data ends */
   size_t track_end;
   /* Byte offset of read cursor */
   size_t offset;
   /* Loaded hunk number */
   int32_t hunknum;
   /* Size of frame taken from each hunk */
   uint32_t frame_size;
   /* Offset of data within frame */
   uint32_t frame_offset;
   /* Number of frames per hunk */
   uint32_t frames_per_hunk;
   /* First frame of track in chd */
   uint32_t track_frame;
   /* Should we swap bytes? */
   bool swab;
};

typedef struct metadata
{
   uint32_t frame_offset;
   uint32_t frames;
   uint32_t pad;
   uint32_t extra;
   uint32_t pregap;
   uint32_t postgap;
   uint32_t track;
   char type[64];
   char subtype[32];
   char pgtype[32];
   char pgsub[32];
} metadata_t;

static uint32_t padding_frames(uint32_t frames)
{
   return ((frames + TRACK_PAD - 1) & ~(TRACK_PAD - 1)) - frames;
}

static bool
chdstream_get_meta(chd_file *chd, int idx, metadata_t *md)
{
   char meta[256];
   uint32_t meta_size = 0;
   chd_error err;

   meta[0] = '\0';

   memset(md, 0, sizeof(*md));

   err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, idx, meta,
         sizeof(meta), &meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      sscanf(meta, CDROM_TRACK_METADATA2_FORMAT,
            &md->track, md->type,
            md->subtype, &md->frames, &md->pregap,
            md->pgtype, md->pgsub,
            &md->postgap);
      md->extra = padding_frames(md->frames);
      return true;
   }

   err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, idx, meta,
         sizeof(meta), &meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      sscanf(meta, CDROM_TRACK_METADATA_FORMAT, &md->track, md->type,
             md->subtype, &md->frames);
      md->extra = padding_frames(md->frames);
      return true;
   }

   err = chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, idx, meta,
         sizeof(meta), &meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      sscanf(meta, GDROM_TRACK_METADATA_FORMAT, &md->track, md->type,
             md->subtype, &md->frames, &md->pad, &md->pregap, md->pgtype,
             md->pgsub, &md->postgap);
      md->extra = padding_frames(md->frames);
      return true;
   }

   err = chd_get_metadata(chd, DVD_METADATA_TAG, idx, meta,
         sizeof(meta), &meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      md->track = 1;
      strlcpy(md->type, "DVD", sizeof(md->type));
      return true;
   }

   return false;
}

static bool
chdstream_find_track_number(chd_file *fd, int32_t track, metadata_t *meta)
{
   uint32_t i;
   uint32_t frame_offset = 0;

   for (i = 0; true; ++i)
   {
      if (!chdstream_get_meta(fd, i, meta))
         return false;

      if (track == (int)meta->track)
      {
         meta->frame_offset = frame_offset;
         return true;
      }

      frame_offset += meta->frames + meta->extra;
   }
}

static bool
chdstream_find_special_track(chd_file *fd, int32_t track, metadata_t *meta)
{
   int32_t i;
   metadata_t iter;
   int32_t largest_track = 0;
   uint32_t largest_size = 0;

   for (i = 1; true; ++i)
   {
      if (!chdstream_find_track_number(fd, i, &iter))
      {
         if (track == CHDSTREAM_TRACK_LAST && i > 1)
            return chdstream_find_track_number(fd, i - 1, meta);

         if (track == CHDSTREAM_TRACK_PRIMARY && largest_track != 0)
            return chdstream_find_track_number(fd, largest_track, meta);

         return false;
      }

      switch (track)
      {
         case CHDSTREAM_TRACK_FIRST_DATA:
            if (strcmp(iter.type, "AUDIO"))
            {
               *meta = iter;
               return true;
            }
            break;
         case CHDSTREAM_TRACK_PRIMARY:
            if (strcmp(iter.type, "AUDIO") && iter.frames > largest_size)
            {
               largest_size  = iter.frames;
               largest_track = iter.track;
            }
            break;
         default:
            break;
      }
   }
}

static bool
chdstream_find_track(chd_file *fd, int32_t track, metadata_t *meta)
{
   if (track < 0)
      return chdstream_find_special_track(fd, track, meta);
   return chdstream_find_track_number(fd, track, meta);
}

chdstream_t *chdstream_open(const char *path, int32_t track)
{
   metadata_t meta;
   uint32_t pregap         = 0;
   uint8_t *hunkmem        = NULL;
   const chd_header *hd    = NULL;
   chdstream_t *stream     = NULL;
   chd_file *chd           = NULL;
   chd_error err           = chd_open(path, CHD_OPEN_READ, NULL, &chd);

   if (err != CHDERR_NONE)
      return NULL;

   if (!chdstream_find_track(chd, track, &meta))
      goto error;

   stream                  = (chdstream_t*)malloc(sizeof(*stream));
   if (!stream)
      goto error;

   stream->chd             = NULL;
   stream->swab            = false;
   stream->frame_size      = 0;
   stream->frame_offset    = 0;
   stream->frames_per_hunk = 0;
   stream->track_frame     = 0;
   stream->track_start     = 0;
   stream->track_end       = 0;
   stream->offset          = 0;
   stream->hunkmem         = NULL;
   stream->hunknum         = -1;

   hd                      = chd_get_header(chd);
   hunkmem                 = (uint8_t*)malloc(hd->hunkbytes);
   if (!hunkmem)
      goto error;

   stream->hunkmem         = hunkmem;

   if (string_is_equal(meta.type, "MODE1_RAW"))
      stream->frame_size   = SECTOR_RAW_SIZE;
   else if (string_is_equal(meta.type, "MODE2_RAW"))
      stream->frame_size   = SECTOR_RAW_SIZE;
   else if (string_is_equal(meta.type, "MODE1"))
      stream->frame_size   = SECTOR_SIZE;
   else if (string_is_equal(meta.type, "AUDIO"))
   {
      stream->frame_size   = SECTOR_RAW_SIZE;
      stream->swab         = true;
   }
   else if (string_is_equal(meta.type, "DVD"))
   {
      stream->frame_size   = hd->unitbytes;
      meta.frames          = hd->totalhunks;
   }
   else
      stream->frame_size   = hd->unitbytes;

   /* Only include pregap data if it was in the track file */
   if (meta.pgtype[0] != 'V')
      pregap               = meta.pregap;

   stream->chd             = chd;
   stream->frames_per_hunk = hd->hunkbytes / hd->unitbytes;
   stream->track_frame     = meta.frame_offset;
   stream->track_start     = (size_t)pregap * stream->frame_size;
   stream->track_end       = stream->track_start +
                             (size_t)meta.frames * stream->frame_size;

   return stream;

error:
   chdstream_close(stream);

   if (chd)
      chd_close(chd);

   return NULL;
}

void chdstream_close(chdstream_t *stream)
{
   if (!stream)
      return;

   if (stream->hunkmem)
      free(stream->hunkmem);
   if (stream->chd)
      chd_close(stream->chd);
   free(stream);
}

static bool
chdstream_load_hunk(chdstream_t *stream, uint32_t hunknum)
{
   uint16_t *array;

   if ((int)hunknum == stream->hunknum)
      return true;

   if (chd_read(stream->chd, hunknum, stream->hunkmem) != CHDERR_NONE)
      return false;

   if (stream->swab)
   {
      uint32_t i;
      uint32_t count = chd_get_header(stream->chd)->hunkbytes / 2;
      array          = (uint16_t*)stream->hunkmem;
      for (i = 0; i < count; ++i)
         array[i] = SWAP16(array[i]);
   }

   stream->hunknum = hunknum;
   return true;
}

ssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes)
{
   size_t end;
   size_t data_offset   = 0;
   const chd_header *hd = chd_get_header(stream->chd);
   uint8_t         *out = (uint8_t*)data;

   if (stream->track_end - stream->offset < bytes)
      bytes             = stream->track_end - stream->offset;

   end                  = stream->offset + bytes;

   while (stream->offset < end)
   {
      uint32_t frame_offset = stream->offset % stream->frame_size;
      uint32_t amount       = stream->frame_size - frame_offset;

      if (amount > end - stream->offset)
         amount = (uint32_t)(end - stream->offset);

      /* In pregap */
      if (stream->offset < stream->track_start)
         memset(out + data_offset, 0, amount);
      else
      {
         uint32_t chd_frame   = (uint32_t)(stream->track_frame +
            (stream->offset - stream->track_start) / stream->frame_size);
         uint32_t hunk        = chd_frame / stream->frames_per_hunk;
         uint32_t hunk_offset = (chd_frame % stream->frames_per_hunk)
            * hd->unitbytes;

         if (!chdstream_load_hunk(stream, hunk))
            return -1;

         memcpy(out + data_offset,
                stream->hunkmem + frame_offset
                + hunk_offset + stream->frame_offset, amount);
      }

      data_offset    += amount;
      stream->offset += amount;
   }

   return bytes;
}

int chdstream_getc(chdstream_t *stream)
{
   char c = 0;

   if (chdstream_read(stream, &c, sizeof(c) != sizeof(c)))
      return EOF;

   return c;
}

char *chdstream_gets(chdstream_t *stream, char *s, size_t len)
{
   int c;
   size_t _len = 0;
   while (_len < len && (c = chdstream_getc(stream)) != EOF)
      s[_len++] = c;
   if (_len < len)
      s[_len]   = '\0';
   return s;
}

uint64_t chdstream_tell(chdstream_t *stream)
{
   return stream->offset;
}

void chdstream_rewind(chdstream_t *stream)
{
   stream->offset = 0;
}

int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence)
{
   int64_t new_offset;

   switch (whence)
   {
      case SEEK_SET:
         new_offset = offset;
         break;
      case SEEK_CUR:
         new_offset = stream->offset + offset;
         break;
      case SEEK_END:
         new_offset = stream->track_end + offset;
         break;
      default:
         return -1;
   }

   if (new_offset < 0)
      return -1;

   if ((size_t)new_offset > stream->track_end)
      new_offset = stream->track_end;

   stream->offset = new_offset;
   return 0;
}

ssize_t chdstream_get_size(chdstream_t *stream)
{
   return stream->track_end - stream->track_start;
}

uint32_t chdstream_get_track_start(chdstream_t *stream)
{
   uint32_t i;
   metadata_t meta;
   uint32_t frame_offset = 0;

   for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i)
   {
      if (stream->track_frame == frame_offset)
         return meta.pregap * stream->frame_size;

      frame_offset += meta.frames + meta.extra;
   }

   return 0;
}

uint32_t chdstream_get_frame_size(chdstream_t *stream)
{
   return stream->frame_size;
}

uint32_t chdstream_get_first_track_sector(chdstream_t* stream)
{
   uint32_t i;
   metadata_t meta;
   uint32_t frame_offset = 0;
   uint32_t sector_offset = 0;

   for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i)
   {
      if (stream->track_frame == frame_offset)
         return sector_offset;

      sector_offset += meta.frames;
      frame_offset += meta.frames + meta.extra;
   }

   return 0;
}

./include/libretro-common/streams/file_stream.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef _MSC_VER
#include <compat/msvc.h>
#endif

#include <retro_miscellaneous.h>
#include <file/file_path.h>
#include <string/stdstring.h>
#include <streams/file_stream.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>

#define VFS_ERROR_RETURN_VALUE -1

struct RFILE
{
   struct retro_vfs_file_handle *hfile;
   bool err_flag;
};

static retro_vfs_get_path_t filestream_get_path_cb = NULL;
static retro_vfs_open_t filestream_open_cb         = NULL;
static retro_vfs_close_t filestream_close_cb       = NULL;
static retro_vfs_size_t filestream_size_cb         = NULL;
static retro_vfs_truncate_t filestream_truncate_cb = NULL;
static retro_vfs_tell_t filestream_tell_cb         = NULL;
static retro_vfs_seek_t filestream_seek_cb         = NULL;
static retro_vfs_read_t filestream_read_cb         = NULL;
static retro_vfs_write_t filestream_write_cb       = NULL;
static retro_vfs_flush_t filestream_flush_cb       = NULL;
static retro_vfs_remove_t filestream_remove_cb     = NULL;
static retro_vfs_rename_t filestream_rename_cb     = NULL;

/* VFS Initialization */

void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
   const struct retro_vfs_interface *
      vfs_iface           = vfs_info->iface;

   filestream_get_path_cb = NULL;
   filestream_open_cb     = NULL;
   filestream_close_cb    = NULL;
   filestream_tell_cb     = NULL;
   filestream_size_cb     = NULL;
   filestream_truncate_cb = NULL;
   filestream_seek_cb     = NULL;
   filestream_read_cb     = NULL;
   filestream_write_cb    = NULL;
   filestream_flush_cb    = NULL;
   filestream_remove_cb   = NULL;
   filestream_rename_cb   = NULL;

   if (
             (vfs_info->required_interface_version <
             FILESTREAM_REQUIRED_VFS_VERSION)
         || !vfs_iface)
      return;

   filestream_get_path_cb = vfs_iface->get_path;
   filestream_open_cb     = vfs_iface->open;
   filestream_close_cb    = vfs_iface->close;
   filestream_size_cb     = vfs_iface->size;
   filestream_truncate_cb = vfs_iface->truncate;
   filestream_tell_cb     = vfs_iface->tell;
   filestream_seek_cb     = vfs_iface->seek;
   filestream_read_cb     = vfs_iface->read;
   filestream_write_cb    = vfs_iface->write;
   filestream_flush_cb    = vfs_iface->flush;
   filestream_remove_cb   = vfs_iface->remove;
   filestream_rename_cb   = vfs_iface->rename;
}

/* Callback wrappers */
bool filestream_exists(const char *path)
{
   RFILE *dummy           = NULL;

   if (!path || !*path)
      return false;
   if (!(dummy = filestream_open(
         path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return false;

   if (filestream_close(dummy) != 0)
      free(dummy);

   dummy = NULL;
   return true;
}

int64_t filestream_get_size(RFILE *stream)
{
   int64_t output;

   if (filestream_size_cb)
      output = filestream_size_cb(stream->hfile);
   else
      output = retro_vfs_file_size_impl(
            (libretro_vfs_implementation_file*)stream->hfile);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream->err_flag = true;

   return output;
}

int64_t filestream_truncate(RFILE *stream, int64_t length)
{
   int64_t output;

   if (filestream_truncate_cb)
      output = filestream_truncate_cb(stream->hfile, length);
   else
      output = retro_vfs_file_truncate_impl(
            (libretro_vfs_implementation_file*)stream->hfile, length);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream->err_flag = true;

   return output;
}

RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
{
   struct retro_vfs_file_handle  *fp = NULL;
   RFILE* output                     = (RFILE*)malloc(sizeof(RFILE));

   if (!output)
      return NULL;

   if (filestream_open_cb)
      fp = (struct retro_vfs_file_handle*)
         filestream_open_cb(path, mode, hints);
   else
      fp = (struct retro_vfs_file_handle*)
         retro_vfs_file_open_impl(path, mode, hints);

   if (!fp)
   {
      free(output);
      return NULL;
   }

   output->err_flag = false;
   output->hfile    = fp;
   return output;
}

char* filestream_gets(RFILE *stream, char *s, size_t len)
{
   int c   = 0;
   char *p = s;
   if (!stream)
      return NULL;

   /* get max bytes or up to a newline */

   for (len--; len > 0; len--)
   {
      if ((c = filestream_getc(stream)) == EOF)
         break;
      *p++ = c;
      if (c == '\n')
         break;
   }
   *p = 0;

   if (p == s && c == EOF)
      return NULL;
   return (s);
}

int filestream_getc(RFILE *stream)
{
   char c = 0;
   if (stream && filestream_read(stream, &c, 1) == 1)
      return (int)(unsigned char)c;
   return EOF;
}

int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
{
   char buf[4096];
   char subfmt[64];
   va_list args_copy;
   const char *bufiter  = buf;
   int        ret       = 0;
   int64_t startpos     = filestream_tell(stream);
   int64_t maxlen       = filestream_read(stream, buf, sizeof(buf)-1);

   if (maxlen <= 0)
      return EOF;

   buf[maxlen] = '\0';

   /* Have to copy the input va_list here
    * > Calling va_arg() on 'args' directly would
    *   cause the va_list to have an indeterminate value
    *   in the function calling filestream_vscanf(),
    *   leading to unexpected behaviour */
#ifdef __va_copy
   __va_copy(args_copy, *args);
#else
   va_copy(args_copy, *args);
#endif

   while (*format)
   {
      if (*format == '%')
      {
         int sublen       = 0;
         char* subfmtiter = subfmt;
         bool asterisk    = false;

         *subfmtiter++    = *format++; /* '%' */

         /* %[*][width][length]specifier */

         if (*format == '*')
         {
            asterisk      = true;
            *subfmtiter++ = *format++;
         }

         while (ISDIGIT((unsigned char)*format))
            *subfmtiter++ = *format++; /* width */

         /* length */
         if (*format == 'h' || *format == 'l')
         {
            if (format[1] == format[0])
               *subfmtiter++ = *format++;
            *subfmtiter++    = *format++;
         }
         else if (
               *format == 'j' ||
               *format == 'z' ||
               *format == 't' ||
               *format == 'L')
         {
            *subfmtiter++ = *format++;
         }

         /* specifier - always a single character (except ]) */
         if (*format == '[')
         {
            while (*format != ']')
               *subfmtiter++ = *format++;
            *subfmtiter++    = *format++;
         }
         else
            *subfmtiter++    = *format++;

         *subfmtiter++       = '%';
         *subfmtiter++       = 'n';
         *subfmtiter++       = '\0';

         if (sizeof(void*) != sizeof(long*))
            abort(); /* all pointers must have the same size */

         if (asterisk)
         {
            int v = sscanf(bufiter, subfmt, &sublen);
            if (v == EOF)
               return EOF;
            if (v != 0)
               break;
         }
         else
         {
            int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &sublen);
            if (v == EOF)
               return EOF;
            if (v != 1)
               break;
         }

         ret++;
         bufiter += sublen;
      }
      else if (isspace((unsigned char)*format))
      {
         while (isspace((unsigned char)*bufiter))
            bufiter++;
         format++;
      }
      else
      {
         if (*bufiter != *format)
            break;
         bufiter++;
         format++;
      }
   }

   va_end(args_copy);
   filestream_seek(stream, startpos + (bufiter - buf),
         RETRO_VFS_SEEK_POSITION_START);

   return ret;
}

int filestream_scanf(RFILE *stream, const char* format, ...)
{
   int ret;
   va_list vl;
   va_start(vl, format);
   ret = filestream_vscanf(stream, format, &vl);
   va_end(vl);
   return ret;
}

int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
{
   int64_t output;

   if (filestream_seek_cb)
      output = filestream_seek_cb(stream->hfile, offset, seek_position);
   else
      output = retro_vfs_file_seek_impl(
            (libretro_vfs_implementation_file*)stream->hfile,
            offset, seek_position);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream->err_flag = true;

   return output;
}

int filestream_eof(RFILE *stream)
{
   return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
}

int64_t filestream_tell(RFILE *stream)
{
   int64_t output;

   if (filestream_size_cb)
      output = filestream_tell_cb(stream->hfile);
   else
      output = retro_vfs_file_tell_impl(
            (libretro_vfs_implementation_file*)stream->hfile);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream->err_flag = true;

   return output;
}

void filestream_rewind(RFILE *stream)
{
   if (!stream)
      return;
   filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
   stream->err_flag = false;
}

int64_t filestream_read(RFILE *stream, void *s, int64_t len)
{
   int64_t output;

   if (filestream_read_cb)
      output = filestream_read_cb(stream->hfile, s, len);
   else
      output = retro_vfs_file_read_impl(
            (libretro_vfs_implementation_file*)stream->hfile, s, len);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream->err_flag = true;

   return output;
}

int filestream_flush(RFILE *stream)
{
   int output;

   if (filestream_flush_cb)
      output = filestream_flush_cb(stream->hfile);
   else
      output = retro_vfs_file_flush_impl(
            (libretro_vfs_implementation_file*)stream->hfile);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream->err_flag = true;

   return output;
}

int filestream_delete(const char *path)
{
   if (filestream_remove_cb)
      return filestream_remove_cb(path);

   return retro_vfs_file_remove_impl(path);
}

int filestream_rename(const char *old_path, const char *new_path)
{
   if (filestream_rename_cb)
      return filestream_rename_cb(old_path, new_path);

   return retro_vfs_file_rename_impl(old_path, new_path);
}

int filestream_copy(const char *src, const char *dst)
{
   char buf[256] = {0};
   int64_t n     = 0;
   int ret       = 0;
   char path_dst[PATH_MAX_LENGTH] = {0};

   RFILE *fp_src = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
   RFILE *fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fp_src || !fp_dst)
      ret = -1;

   if (ret < 0)
      goto close;

   snprintf(path_dst, sizeof(path_dst), "%s", dst);
   path_basedir(path_dst);

   if (!path_is_directory(path_dst))
      path_mkdir(path_dst);

   while ((n = filestream_read(fp_src, buf, sizeof(buf))) > 0 && ret == 0)
   {
      if (filestream_write(fp_dst, buf, n) != n)
         ret = -1;
   }

close:
   if (fp_src)
      filestream_close(fp_src);
   if (fp_dst)
      filestream_close(fp_dst);
   return ret;
}

int filestream_cmp(const char *src, const char *dst)
{
   int ret           = 0;
   RFILE *fp_src     = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   RFILE *fp_dst     = filestream_open(dst, RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fp_src || !fp_dst || filestream_get_size(fp_src) != filestream_get_size(fp_dst))
      ret = -1;

   if (ret >= 0)
   {
      char buf_src[256] = {0};
      char buf_dst[256] = {0};
      while ((filestream_read(fp_src, buf_src, sizeof(buf_src))) > 0 && ret == 0)
      {
         filestream_read(fp_dst, buf_dst, sizeof(buf_dst));
         ret = memcmp(buf_src, buf_dst, sizeof(buf_src));
      }
   }

   if (fp_src)
   {
      filestream_close(fp_src);
      fp_src = NULL;
   }
   if (fp_dst)
   {
      filestream_close(fp_dst);
      fp_dst = NULL;
   }
   return ret;
}

const char* filestream_get_path(RFILE *stream)
{
   if (filestream_get_path_cb)
      return filestream_get_path_cb(stream->hfile);

   return retro_vfs_file_get_path_impl(
         (libretro_vfs_implementation_file*)stream->hfile);
}

int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
{
   int64_t output;

   if (filestream_write_cb)
      output = filestream_write_cb(stream->hfile, s, len);
   else
      output = retro_vfs_file_write_impl(
            (libretro_vfs_implementation_file*)stream->hfile, s, len);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream->err_flag = true;

   return output;
}

int filestream_putc(RFILE *stream, int c)
{
   char c_char = (char)c;
   if (!stream)
      return EOF;
   return filestream_write(stream, &c_char, 1) == 1
      ? (int)(unsigned char)c
      : EOF;
}

int filestream_vprintf(RFILE *stream, const char* format, va_list args)
{
   static char buffer[8 * 1024];
   int _len = vsnprintf(buffer, sizeof(buffer),
         format, args);
   if (_len < 0)
      return -1;
   else if (_len == 0)
      return 0;
   return (int)filestream_write(stream, buffer, _len);
}

int filestream_printf(RFILE *stream, const char* format, ...)
{
   va_list vl;
   int ret;
   va_start(vl, format);
   ret = filestream_vprintf(stream, format, vl);
   va_end(vl);
   return ret;
}

int filestream_error(RFILE *stream)
{
   return (stream && stream->err_flag);
}

int filestream_close(RFILE *stream)
{
   int output;
   struct retro_vfs_file_handle* fp = stream->hfile;

   if (filestream_close_cb)
      output = filestream_close_cb(fp);
   else
      output = retro_vfs_file_close_impl(
            (libretro_vfs_implementation_file*)fp);

   if (output == 0)
      free(stream);

   return output;
}

int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
{
   int64_t ret              = 0;
   int64_t content_buf_size = 0;
   void *content_buf        = NULL;
   RFILE *file              = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!file)
   {
      *buf = NULL;
      return 0;
   }

   if ((content_buf_size = filestream_get_size(file)) < 0)
      goto error;

   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
      goto error;
   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
      goto error;

   if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) <
         0)
      goto error;

   if (filestream_close(file) != 0)
      free(file);

   *buf    = content_buf;

   /* Allow for easy reading of strings to be safe.
    * Will only work with sane character formatting (Unix). */
   ((char*)content_buf)[ret] = '\0';

   if (len)
      *len = ret;

   return 1;

error:
   if (filestream_close(file) != 0)
      free(file);
   if (content_buf)
      free(content_buf);
   if (len)
      *len = -1;
   *buf = NULL;
   return 0;
}

bool filestream_write_file(const char *path, const void *data, int64_t size)
{
   int64_t ret   = 0;
   RFILE *file   = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!file)
      return false;
   ret = filestream_write(file, data, size);
   if (filestream_close(file) != 0)
      free(file);
   return (ret == size);
}

char *filestream_getline(RFILE *stream)
{
   char *newline_tmp  = NULL;
   size_t cur_size    = 8;
   size_t idx         = 0;
   int in             = 0;
   char *newline      = (char*)malloc(9);

   if (!stream || !newline)
   {
      if (newline)
         free(newline);
      return NULL;
   }

   in = filestream_getc(stream);

   while (in != EOF && in != '\n')
   {
      if (idx == cur_size)
      {
         cur_size    *= 2;

         if (!(newline_tmp = (char*)realloc(newline, cur_size + 1)))
         {
            free(newline);
            return NULL;
         }

         newline     = newline_tmp;
      }

      newline[idx++] = in;
      in             = filestream_getc(stream);
   }

   newline[idx]      = '\0';
   return newline;
}

libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
{
   return (libretro_vfs_implementation_file*)stream->hfile;
}

./include/libretro-common/streams/file_stream_transforms.c

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream_transforms.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <string.h>
#include <stdarg.h>

#include <libretro.h>
#include <streams/file_stream.h>

RFILE* rfopen(const char *path, const char *mode)
{
   RFILE          *output  = NULL;
   unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;
   bool position_to_end    = false;

   if (strstr(mode, "r"))
   {
      retro_mode = RETRO_VFS_FILE_ACCESS_READ;
      if (strstr(mode, "+"))
      {
         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
      }
   }
   else if (strstr(mode, "w"))
   {
      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE;
      if (strstr(mode, "+"))
         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE;
   }
   else if (strstr(mode, "a"))
   {
      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE |
         RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
      position_to_end = true;
      if (strstr(mode, "+"))
      {
         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
      }
   }

   output = filestream_open(path, retro_mode,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (output && position_to_end)
      filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END);

   return output;
}

int rfclose(RFILE* stream)
{
   if (!stream)
      return EOF;

   return filestream_close(stream);
}

int64_t rftell(RFILE* stream)
{
   if (!stream)
      return -1;

   return filestream_tell(stream);
}

int64_t rfseek(RFILE* stream, int64_t offset, int origin)
{
   int seek_position = -1;

   if (!stream)
      return -1;

   switch (origin)
   {
      case SEEK_SET:
         seek_position = RETRO_VFS_SEEK_POSITION_START;
         break;
      case SEEK_CUR:
         seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
         break;
      case SEEK_END:
         seek_position = RETRO_VFS_SEEK_POSITION_END;
         break;
   }

   return filestream_seek(stream, offset, seek_position);
}

int64_t rfread(void* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream)
{
   if (!stream || (elem_size == 0) || (elem_count == 0))
      return 0;

   return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
}

char *rfgets(char *s, int maxCount, RFILE* stream)
{
   if (!stream)
      return NULL;
   return filestream_gets(stream, s, maxCount);
}

int rfgetc(RFILE* stream)
{
   if (!stream)
      return EOF;

   return filestream_getc(stream);
}

int64_t rfwrite(void const* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream)
{
   if (!stream || (elem_size == 0) || (elem_count == 0))
      return 0;

   return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);
}

int rfputc(int character, RFILE * stream)
{
   if (!stream)
      return EOF;

   return filestream_putc(stream, character);
}

int64_t rfflush(RFILE * stream)
{
   if (!stream)
      return EOF;

   return filestream_flush(stream);
}

int rfprintf(RFILE * stream, const char * format, ...)
{
   int ret;
   va_list vl;

   if (!stream)
      return -1;

   va_start(vl, format);
   ret = filestream_vprintf(stream, format, vl);
   va_end(vl);
   return ret;
}

int rferror(RFILE* stream)
{
   return filestream_error(stream);
}

int rfeof(RFILE* stream)
{
   return filestream_eof(stream);
}

int rfscanf(RFILE * stream, const char * format, ...)
{
   int ret;
   va_list vl;

   if (!stream)
      return 0;

   va_start(vl, format);
   ret = filestream_vscanf(stream, format, &vl);
   va_end(vl);
   return ret;
}

./include/libretro-common/streams/interface_stream.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (interface_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>

#include <streams/interface_stream.h>
#include <streams/file_stream.h>
#include <streams/memory_stream.h>
#ifdef HAVE_CHD
#include <streams/chd_stream.h>
#endif
#if defined(HAVE_ZLIB)
#include <streams/rzip_stream.h>
#endif
#include <encodings/crc32.h>

struct intfstream_internal
{
   struct
   {
      RFILE *fp;
   } file;

   struct
   {
      memstream_t *fp;
      struct
      {
         uint8_t *data;
         uint64_t size;
      } buf;
      bool writable;
   } memory;
#ifdef HAVE_CHD
   struct
   {
      chdstream_t *fp;
      int32_t track;
   } chd;
#endif
#if defined(HAVE_ZLIB)
   struct
   {
      rzipstream_t *fp;
   } rzip;
#endif
   enum intfstream_type type;
};

int64_t intfstream_get_size(intfstream_internal_t *intf)
{
   if (!intf)
      return 0;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_get_size(intf->file.fp);
      case INTFSTREAM_MEMORY:
         return intf->memory.buf.size;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
        return chdstream_get_size(intf->chd.fp);
#else
        break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_get_size(intf->rzip.fp);
#else
         break;
#endif
   }

   return 0;
}

bool intfstream_resize(intfstream_internal_t *intf, intfstream_info_t *info)
{
   if (!intf || !info)
      return false;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         break;
      case INTFSTREAM_MEMORY:
         intf->memory.buf.data = info->memory.buf.data;
         intf->memory.buf.size = info->memory.buf.size;

         memstream_set_buffer(intf->memory.buf.data,
               intf->memory.buf.size);
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
#endif
         break;
      case INTFSTREAM_RZIP:
         /* Unsupported */
         return false;
   }

   return true;
}

bool intfstream_open(intfstream_internal_t *intf, const char *path,
      unsigned mode, unsigned hints)
{
   if (!intf)
      return false;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         intf->file.fp = filestream_open(path, mode, hints);
         if (!intf->file.fp)
            return false;
         break;
      case INTFSTREAM_MEMORY:
         intf->memory.fp = memstream_open(intf->memory.writable);
         if (!intf->memory.fp)
            return false;
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         intf->chd.fp = chdstream_open(path, intf->chd.track);
         if (!intf->chd.fp)
            return false;
         break;
#else
         return false;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         intf->rzip.fp = rzipstream_open(path, mode);
         if (!intf->rzip.fp)
            return false;
         break;
#else
         return false;
#endif
   }

   return true;
}

int intfstream_flush(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_flush(intf->file.fp);
      case INTFSTREAM_MEMORY:
      case INTFSTREAM_CHD:
      case INTFSTREAM_RZIP:
         /* Should we stub this for these interfaces? */
         break;
   }

   return 0;
}

int intfstream_close(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         if (intf->file.fp)
            return filestream_close(intf->file.fp);
         return 0;
      case INTFSTREAM_MEMORY:
         if (intf->memory.fp)
            memstream_close(intf->memory.fp);
         return 0;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         if (intf->chd.fp)
            chdstream_close(intf->chd.fp);
#endif
         return 0;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         if (intf->rzip.fp)
            return rzipstream_close(intf->rzip.fp);
#endif
         return 0;
   }

   return -1;
}

void *intfstream_init(intfstream_info_t *info)
{
   intfstream_internal_t *intf = NULL;
   if (!info)
      return NULL;

   if (!(intf = (intfstream_internal_t*)malloc(sizeof(*intf))))
      return NULL;

   intf->type            = info->type;
   intf->file.fp         = NULL;
   intf->memory.buf.data = NULL;
   intf->memory.buf.size = 0;
   intf->memory.fp       = NULL;
   intf->memory.writable = false;
#ifdef HAVE_CHD
   intf->chd.track       = 0;
   intf->chd.fp          = NULL;
#endif
#ifdef HAVE_ZLIB
   intf->rzip.fp         = NULL;
#endif

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         break;
      case INTFSTREAM_MEMORY:
         intf->memory.writable = info->memory.writable;
         if (!intfstream_resize(intf, info))
         {
            free(intf);
            return NULL;
         }
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         intf->chd.track = info->chd.track;
         break;
#else
         free(intf);
         return NULL;
#endif
      case INTFSTREAM_RZIP:
         break;
   }

   return intf;
}

int64_t intfstream_seek(
      intfstream_internal_t *intf, int64_t offset, int whence)
{
   if (!intf)
      return -1;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         {
            int seek_position = 0;
            switch (whence)
            {
               case SEEK_SET:
                  seek_position = RETRO_VFS_SEEK_POSITION_START;
                  break;
               case SEEK_CUR:
                  seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
                  break;
               case SEEK_END:
                  seek_position = RETRO_VFS_SEEK_POSITION_END;
                  break;
            }
            return (int64_t)filestream_seek(intf->file.fp, (int64_t)offset,
                  seek_position);
         }
      case INTFSTREAM_MEMORY:
         return (int64_t)memstream_seek(intf->memory.fp, offset, whence);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return (int64_t)chdstream_seek(intf->chd.fp, offset, whence);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
         /* Unsupported */
         break;
   }

   return -1;
}

int64_t intfstream_truncate(intfstream_internal_t *intf, uint64_t len)
{
   if (!intf)
      return 0;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_truncate(intf->file.fp, len);
      case INTFSTREAM_MEMORY:
         break;
      case INTFSTREAM_CHD:
         break;
      case INTFSTREAM_RZIP:
         break;
   }

   return 0;
}

int64_t intfstream_read(intfstream_internal_t *intf, void *s, uint64_t len)
{
   if (!intf)
      return 0;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_read(intf->file.fp, s, len);
      case INTFSTREAM_MEMORY:
         return memstream_read(intf->memory.fp, s, len);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return chdstream_read(intf->chd.fp, s, len);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_read(intf->rzip.fp, s, len);
#else
         break;
#endif
   }

   return -1;
}

int64_t intfstream_write(intfstream_internal_t *intf,
      const void *s, uint64_t len)
{
   if (!intf)
      return 0;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_write(intf->file.fp, s, len);
      case INTFSTREAM_MEMORY:
         return memstream_write(intf->memory.fp, s, len);
      case INTFSTREAM_CHD:
         return -1;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_write(intf->rzip.fp, s, len);
#else
         return -1;
#endif
   }

   return 0;
}

int intfstream_printf(intfstream_internal_t *intf,
      const char* format, ...)
{
   int ret;
   va_list vl;

   if (!intf)
      return 0;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         va_start(vl, format);
         ret = filestream_vprintf(intf->file.fp, format, vl);
         va_end(vl);
         return ret;
      case INTFSTREAM_MEMORY:
         return -1;
      case INTFSTREAM_CHD:
         return -1;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         va_start(vl, format);
         ret = rzipstream_vprintf(intf->rzip.fp, format, vl);
         va_end(vl);
         return ret;
#else
         return -1;
#endif
   }

   return 0;
}

int64_t intfstream_get_ptr(intfstream_internal_t* intf)
{
   if (!intf)
      return 0;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return -1;
      case INTFSTREAM_MEMORY:
         return memstream_get_ptr(intf->memory.fp);
      case INTFSTREAM_CHD:
         return -1;
      case INTFSTREAM_RZIP:
         return -1;
   }

   return 0;
}

char *intfstream_gets(intfstream_internal_t *intf,
      char *s, uint64_t len)
{
   if (!intf)
      return NULL;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_gets(intf->file.fp,
               s, (size_t)len);
      case INTFSTREAM_MEMORY:
         return memstream_gets(intf->memory.fp,
               s, (size_t)len);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return chdstream_gets(intf->chd.fp, s, len);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_gets(intf->rzip.fp, s, (size_t)len);
#else
         break;
#endif
   }

   return NULL;
}

int intfstream_getc(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_getc(intf->file.fp);
      case INTFSTREAM_MEMORY:
         return memstream_getc(intf->memory.fp);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return chdstream_getc(intf->chd.fp);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_getc(intf->rzip.fp);
#else
         break;
#endif
   }

   return -1;
}

int64_t intfstream_tell(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return (int64_t)filestream_tell(intf->file.fp);
      case INTFSTREAM_MEMORY:
         return (int64_t)memstream_pos(intf->memory.fp);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return (int64_t)chdstream_tell(intf->chd.fp);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return (int64_t)rzipstream_tell(intf->rzip.fp);
#else
         break;
#endif
   }

   return -1;
}

int intfstream_eof(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return filestream_eof(intf->file.fp);
      case INTFSTREAM_MEMORY:
         /* TODO: Add this functionality to
          * memory_stream interface */
         break;
      case INTFSTREAM_CHD:
         /* TODO: Add this functionality to
          * chd_stream interface */
         break;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_eof(intf->rzip.fp);
#else
         break;
#endif
   }

   return -1;
}

void intfstream_rewind(intfstream_internal_t *intf)
{
   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         filestream_rewind(intf->file.fp);
         break;
      case INTFSTREAM_MEMORY:
         memstream_rewind(intf->memory.fp);
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         chdstream_rewind(intf->chd.fp);
#endif
         break;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         rzipstream_rewind(intf->rzip.fp);
#endif
         break;
   }
}

void intfstream_putc(intfstream_internal_t *intf, int c)
{
   if (!intf)
      return;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         filestream_putc(intf->file.fp, c);
         break;
      case INTFSTREAM_MEMORY:
         memstream_putc(intf->memory.fp, c);
         break;
      case INTFSTREAM_CHD:
         break;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         rzipstream_putc(intf->rzip.fp, c);
#else
         break;
#endif
   }
}

uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf)
{
   if (intf)
   {
#ifdef HAVE_CHD
      if (intf->type == INTFSTREAM_CHD)
         return chdstream_get_track_start(intf->chd.fp);
#endif
   }

   return 0;
}

uint32_t intfstream_get_frame_size(intfstream_internal_t *intf)
{
   if (intf)
   {
#ifdef HAVE_CHD
      if (intf->type == INTFSTREAM_CHD)
         return chdstream_get_frame_size(intf->chd.fp);
#endif
   }

   return 0;
}

uint32_t intfstream_get_first_sector(intfstream_internal_t* intf)
{
   if (intf)
   {
#ifdef HAVE_CHD
      if (intf->type == INTFSTREAM_CHD)
         return chdstream_get_first_track_sector(intf->chd.fp);
#endif
   }

   return 0;
}

bool intfstream_is_compressed(intfstream_internal_t *intf)
{
   if (!intf)
      return false;

   switch (intf->type)
   {
      case INTFSTREAM_FILE:
         return false;
      case INTFSTREAM_MEMORY:
         return false;
      case INTFSTREAM_CHD:
         return true;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_is_compressed(intf->rzip.fp);
#else
         break;
#endif
   }

   return false;
}

bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc)
{
   int64_t data_read    = 0;
   uint32_t accumulator = 0;
   uint8_t buffer[4096];

   if (!intf || !crc)
      return false;

   /* Ensure we start at the beginning of the file */
   intfstream_rewind(intf);

   while ((data_read = intfstream_read(intf, buffer, sizeof(buffer))) > 0)
      accumulator = encoding_crc32(accumulator, buffer, (size_t)data_read);

   if (data_read < 0)
      return false;

   *crc = accumulator;

   /* Reset file to the beginning */
   intfstream_rewind(intf);

   return true;
}

intfstream_t* intfstream_open_file(const char *path,
      unsigned mode, unsigned hints)
{
   intfstream_info_t info;
   intfstream_t *fd = NULL;

   info.type        = INTFSTREAM_FILE;
   fd               = (intfstream_t*)intfstream_init(&info);

   if (!fd)
      return NULL;

   if (intfstream_open(fd, path, mode, hints))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}

intfstream_t *intfstream_open_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size)
{
   intfstream_info_t info;
   intfstream_t *fd     = NULL;

   info.type            = INTFSTREAM_MEMORY;
   info.memory.buf.data = (uint8_t*)data;
   info.memory.buf.size = size;
   info.memory.writable = (mode & RETRO_VFS_FILE_ACCESS_WRITE) != 0;

   if (!(fd = (intfstream_t*)intfstream_init(&info)))
      return NULL;

   if (intfstream_open(fd, NULL, mode, hints))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}

intfstream_t *intfstream_open_writable_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size)
{
   return intfstream_open_memory(data, mode | RETRO_VFS_FILE_ACCESS_WRITE, hints, size);
}

intfstream_t *intfstream_open_chd_track(const char *path,
      unsigned mode, unsigned hints, int32_t track)
{
   intfstream_info_t info;
   intfstream_t *fd = NULL;

   info.type        = INTFSTREAM_CHD;
   info.chd.track   = track;

   if (!(fd = (intfstream_t*)intfstream_init(&info)))
      return NULL;

   if (intfstream_open(fd, path, mode, hints))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}

intfstream_t* intfstream_open_rzip_file(const char *path,
      unsigned mode)
{
   intfstream_info_t info;
   intfstream_t *fd = NULL;

   info.type        = INTFSTREAM_RZIP;
   fd               = (intfstream_t*)intfstream_init(&info);

   if (!fd)
      return NULL;

   if (intfstream_open(fd, path, mode, RETRO_VFS_FILE_ACCESS_HINT_NONE))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}

./include/libretro-common/streams/memory_stream.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memory_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <streams/memory_stream.h>

/* TODO/FIXME - static globals */
static uint8_t* g_buffer      = NULL;
static uint64_t g_size         = 0;
static uint64_t last_file_size = 0;

struct memstream
{
   uint64_t size;
   uint64_t ptr;
   uint64_t max_ptr;
   uint8_t *buf;
   unsigned writing;
};

void memstream_set_buffer(uint8_t *s, uint64_t len)
{
   g_buffer = s;
   g_size   = len;
}

memstream_t *memstream_open(unsigned writing)
{
   memstream_t *stream;
   if (!g_buffer || !g_size)
      return NULL;

   stream = (memstream_t*)malloc(sizeof(*stream));

   if (!stream)
      return NULL;

   stream->buf       = g_buffer;
   stream->size      = g_size;
   stream->ptr       = 0;
   stream->max_ptr   = 0;
   stream->writing   = writing;

   g_buffer          = NULL;
   g_size            = 0;

   return stream;
}

void memstream_close(memstream_t *stream)
{
   if (!stream)
      return;

   last_file_size = stream->writing ? stream->max_ptr : stream->size;
   free(stream);
}

uint64_t memstream_get_ptr(memstream_t *stream)
{
   return stream->ptr;
}

uint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes)
{
   uint64_t avail = 0;

   if (!stream)
      return 0;

   avail               = stream->size - stream->ptr;
   if (bytes > avail)
      bytes            = avail;

   memcpy(data, stream->buf + stream->ptr, (size_t)bytes);
   stream->ptr        += bytes;
   if (stream->ptr > stream->max_ptr)
      stream->max_ptr  = stream->ptr;
   return bytes;
}

uint64_t memstream_write(memstream_t *stream,
      const void *data, uint64_t bytes)
{
   uint64_t avail = 0;

   if (!stream)
      return 0;

   avail = stream->size - stream->ptr;
   if (bytes > avail)
      bytes = avail;

   memcpy(stream->buf + stream->ptr, data, (size_t)bytes);
   stream->ptr += bytes;
   if (stream->ptr > stream->max_ptr)
      stream->max_ptr = stream->ptr;
   return bytes;
}

int64_t memstream_seek(memstream_t *stream, int64_t offset, int whence)
{
   uint64_t ptr;

   switch (whence)
   {
      case SEEK_SET:
         ptr = offset;
         break;
      case SEEK_CUR:
         ptr = stream->ptr + offset;
         break;
      case SEEK_END:
         ptr = (stream->writing ? stream->max_ptr : stream->size) + offset;
         break;
      default:
         return -1;
   }

   if (ptr <= stream->size)
   {
      stream->ptr = ptr;
      return 0;
   }

   return -1;
}

void memstream_rewind(memstream_t *stream)
{
   memstream_seek(stream, 0L, SEEK_SET);
}

uint64_t memstream_pos(memstream_t *stream) { return stream->ptr; }
char *memstream_gets(memstream_t *stream, char *s, size_t len) { return NULL; }
uint64_t memstream_get_last_size(void) { return last_file_size; }

int memstream_getc(memstream_t *stream)
{
   int ret = 0;
   if (stream->ptr >= stream->size)
      return EOF;
   ret = stream->buf[stream->ptr++];

   if (stream->ptr > stream->max_ptr)
      stream->max_ptr = stream->ptr;

   return ret;
}

void memstream_putc(memstream_t *stream, int c)
{
   if (stream->ptr < stream->size)
      stream->buf[stream->ptr++] = c;

   if (stream->ptr > stream->max_ptr)
      stream->max_ptr = stream->ptr;
}

./include/libretro-common/streams/network_stream.c

/* Copyright  (C) 2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (network_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <retro_endianness.h>

#include <streams/network_stream.h>

bool netstream_open(netstream_t *stream, void *buf, size_t len, size_t used)
{
   if (buf)
   {
      /* Pre-allocated buffer must have a non-zero size. */
      if (!len || used > len)
         return false;
   }
   else
   {
      if (len)
      {
         buf = malloc(len);
         if (!buf)
            return false;
      }

      used = 0;
   }

   stream->buf  = buf;
   stream->size = len;
   stream->used = used;
   stream->pos  = 0;

   return true;
}

void netstream_close(netstream_t *stream, bool dealloc)
{
   if (dealloc)
      free(stream->buf);
   memset(stream, 0, sizeof(*stream));
}

void netstream_reset(netstream_t *stream)
{
   stream->pos  = 0;
   stream->used = 0;
}

bool netstream_truncate(netstream_t *stream, size_t used)
{
   if (used > stream->size)
      return false;

   stream->used = used;

   /* If the current stream position is past our new end of stream,
      set the current position to the end of the stream. */
   if (stream->pos > used)
      stream->pos = used;

   return true;
}

void netstream_data(netstream_t *stream, void **data, size_t *len)
{
   *data = stream->buf;
   *len  = stream->used;
}

bool netstream_eof(netstream_t *stream)
{
   return stream->pos >= stream->used;
}

size_t netstream_tell(netstream_t *stream)
{
   return stream->pos;
}

bool netstream_seek(netstream_t *stream, long offset, int origin)
{
   long pos  = (long)stream->pos;
   long used = (long)stream->used;

   switch (origin)
   {
      case NETSTREAM_SEEK_SET:
         pos  = offset;
         break;
      case NETSTREAM_SEEK_CUR:
         pos += offset;
         break;
      case NETSTREAM_SEEK_END:
         pos  = used + offset;
         break;
      default:
         return false;
   }

   if (pos < 0 || pos > used)
      return false;

   stream->pos = (size_t)pos;

   return true;
}

bool netstream_read(netstream_t *stream, void *data, size_t len)
{
   size_t remaining = stream->used - stream->pos;

   if (!data || !remaining || len > remaining)
      return false;

   /* If len is 0, read all remaining bytes. */
   if (!len)
      len = remaining;

   memcpy(data, (uint8_t*)stream->buf + stream->pos, len);

   stream->pos += len;

   return true;
}

/* This one doesn't require any swapping. */
bool netstream_read_byte(netstream_t *stream, uint8_t *data)
{
   return netstream_read(stream, data, sizeof(*data));
}

#define NETSTREAM_READ_TYPE(name, type, swap) \
bool netstream_read_##name(netstream_t *stream, type *data) \
{ \
   if (!netstream_read(stream, data, sizeof(*data))) \
      return false; \
   *data = swap(*data); \
   return true; \
}

NETSTREAM_READ_TYPE(word,  uint16_t, retro_be_to_cpu16)
NETSTREAM_READ_TYPE(dword, uint32_t, retro_be_to_cpu32)
NETSTREAM_READ_TYPE(qword, uint64_t, retro_be_to_cpu64)

#undef NETSTREAM_READ_TYPE

#ifdef __STDC_IEC_559__
#define NETSTREAM_READ_TYPE(name, type, type_alt, swap) \
bool netstream_read_##name(netstream_t *stream, type *data) \
{ \
   type_alt *data_alt = (type_alt*)data; \
   if (!netstream_read(stream, data, sizeof(*data))) \
      return false; \
   *data_alt = swap(*data_alt); \
   return true; \
}

NETSTREAM_READ_TYPE(float,  float,  uint32_t, retro_be_to_cpu32)
NETSTREAM_READ_TYPE(double, double, uint64_t, retro_be_to_cpu64)

#undef NETSTREAM_READ_TYPE
#endif

int netstream_read_string(netstream_t *stream, char *s, size_t len)
{
   char c;
   int ret = 0;

   if (!s || !len)
      return -1;

   for (; --len; ret++)
   {
      if (!netstream_read(stream, &c, sizeof(c)))
         return -1;

      *s++ = c;

      if (!c)
         break;
   }

   if (!len)
   {
      *s = '\0';

      for (;; ret++)
      {
         if (!netstream_read(stream, &c, sizeof(c)))
            return -1;
         if (!c)
            break;
      }
   }

   return ret;
}

bool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len)
{
   if (!len)
      return false;

   if (!netstream_read(stream, s, len))
      return false;

   /* Ensure the string is always null-terminated. */
   s[len - 1] = '\0';

   return true;
}

bool netstream_write(netstream_t *stream, const void *data, size_t len)
{
   size_t remaining = stream->size - stream->pos;

   if (!data || !len)
      return false;

   if (len > remaining)
   {
      if (!stream->size)
      {
         if (stream->buf)
            free(stream->buf);
         stream->buf  = malloc(len);
         if (!stream->buf)
            return false;
         stream->size = len;
      }
      else
      {
         size_t _len = stream->size + (len - remaining);
         void   *buf = realloc(stream->buf, _len);

         if (!buf)
            return false;

         stream->buf  = buf;
         stream->size = _len;
      }
   }

   memcpy((uint8_t*)stream->buf + stream->pos, data, len);

   stream->pos += len;

   if (stream->pos > stream->used)
      stream->used = stream->pos;

   return true;
}

/* This one doesn't require any swapping. */
bool netstream_write_byte(netstream_t *stream, uint8_t data)
{
   return netstream_write(stream, &data, sizeof(data));
}

#define NETSTREAM_WRITE_TYPE(name, type, swap) \
bool netstream_write_##name(netstream_t *stream, type data) \
{ \
   data = swap(data); \
   return netstream_write(stream, &data, sizeof(data)); \
}

NETSTREAM_WRITE_TYPE(word,  uint16_t, retro_cpu_to_be16)
NETSTREAM_WRITE_TYPE(dword, uint32_t, retro_cpu_to_be32)
NETSTREAM_WRITE_TYPE(qword, uint64_t, retro_cpu_to_be64)

#undef NETSTREAM_WRITE_TYPE

#ifdef __STDC_IEC_559__
#define NETSTREAM_WRITE_TYPE(name, type, type_alt, swap) \
bool netstream_write_##name(netstream_t *stream, type data) \
{ \
   type_alt *data_alt = (type_alt*)&data; \
   *data_alt = swap(*data_alt); \
   return netstream_write(stream, &data, sizeof(data)); \
}

NETSTREAM_WRITE_TYPE(float,  float,  uint32_t, retro_cpu_to_be32)
NETSTREAM_WRITE_TYPE(double, double, uint64_t, retro_cpu_to_be64)

#undef NETSTREAM_WRITE_TYPE
#endif

bool netstream_write_string(netstream_t *stream, const char *s)
{
   if (!s)
      return false;

   return netstream_write(stream, s, strlen(s) + 1);
}

bool netstream_write_fixed_string(netstream_t *stream, const char *s,
      size_t len)
{
   char end = '\0';

   if (!netstream_write(stream, s, len))
      return false;

   /* Ensure the string is always null-terminated. */
   netstream_seek(stream, -1, NETSTREAM_SEEK_CUR);
   netstream_write(stream, &end, sizeof(end));

   return true;
}

./include/libretro-common/streams/rzip_stream.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rzip_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string/stdstring.h>
#include <file/file_path.h>

#include <streams/file_stream.h>
#include <streams/trans_stream.h>

#include <streams/rzip_stream.h>

/* Current RZIP file format version */
#define RZIP_VERSION 1

/* Compression level
 * > zlib default of 6 provides the best
 *   balance between file size and
 *   compression speed */
#define RZIP_COMPRESSION_LEVEL 6

/* Default chunk size: 128kb */
#define RZIP_DEFAULT_CHUNK_SIZE 131072

/* Header sizes (in bytes) */
#define RZIP_HEADER_SIZE 20
#define RZIP_CHUNK_HEADER_SIZE 4

/* Holds all metadata for an RZIP file stream */
struct rzipstream
{
   uint64_t size;
   /* virtual_ptr: Used to track how much
    * uncompressed data has been read */
   uint64_t virtual_ptr;
   RFILE* file;
   const struct trans_stream_backend *deflate_backend;
   void *deflate_stream;
   const struct trans_stream_backend *inflate_backend;
   void *inflate_stream;
   uint8_t *in_buf;
   uint8_t *out_buf;
   uint32_t in_buf_size;
   uint32_t in_buf_ptr;
   uint32_t out_buf_size;
   uint32_t out_buf_ptr;
   uint32_t out_buf_occupancy;
   uint32_t chunk_size;
   bool is_compressed;
   bool is_writing;
};

/* Header Functions */

/* Reads header information from RZIP file
 * > Detects whether file is compressed or
 *   uncompressed data
 * > If compressed, extracts uncompressed
 *   file/chunk sizes */
static bool rzipstream_read_file_header(rzipstream_t *stream)
{
   unsigned i;
   int64_t length;
   uint8_t header_bytes[RZIP_HEADER_SIZE];

   if (!stream)
      return false;

   for (i = 0; i < RZIP_HEADER_SIZE; i++)
      header_bytes[i] = 0;

   /* Attempt to read header bytes */
   if ((length = filestream_read(stream->file,
        header_bytes, sizeof(header_bytes))) <= 0)
      return false;

   /* If file length is less than header size
    * then assume this is uncompressed data */

   /* Check 'magic numbers' - first 8 bytes
    * of header */
   if (
          (length       < RZIP_HEADER_SIZE)
       || (header_bytes[0] !=           35)  /* # */
       || (header_bytes[1] !=           82)  /* R */
       || (header_bytes[2] !=           90)  /* Z */
       || (header_bytes[3] !=           73)  /* I */
       || (header_bytes[4] !=           80)  /* P */
       || (header_bytes[5] !=          118)  /* v */
       || (header_bytes[6] != RZIP_VERSION)  /* file format version number */
       || (header_bytes[7] !=           35)) /* # */
   {
      /* Reset file to start */
      filestream_seek(stream->file, 0, SEEK_SET);
      /* Get 'raw' file size */
      stream->size          = filestream_get_size(stream->file);
      stream->is_compressed = false;
      return true;
   }

   /* Get uncompressed chunk size - next 4 bytes */
   if ((stream->chunk_size = (
                            (uint32_t)header_bytes[11] << 24)
                         | ((uint32_t)header_bytes[10] << 16)
                         | ((uint32_t)header_bytes[9]  <<  8)
                         | (uint32_t)header_bytes[8]) == 0)
      return false;

   /* Get total uncompressed data size - next 8 bytes */
   if ((stream->size = (
                      (uint64_t)header_bytes[19] << 56)
                   | ((uint64_t)header_bytes[18] << 48)
                   | ((uint64_t)header_bytes[17] << 40)
                   | ((uint64_t)header_bytes[16] << 32)
                   | ((uint64_t)header_bytes[15] << 24)
                   | ((uint64_t)header_bytes[14] << 16)
                   | ((uint64_t)header_bytes[13] <<  8)
                   | (uint64_t)header_bytes[12]) == 0)
      return false;

   stream->is_compressed = true;
   return true;
}

/* Writes header information to RZIP file
 * > ID 'magic numbers' + uncompressed
 *   file/chunk sizes */
static bool rzipstream_write_file_header(rzipstream_t *stream)
{
   unsigned i;
   uint8_t header_bytes[RZIP_HEADER_SIZE];

   if (!stream)
      return false;

   /* Populate header array */
   for (i = 0; i < RZIP_HEADER_SIZE; i++)
      header_bytes[i] = 0;

   /* > 'Magic numbers' - first 8 bytes */
   header_bytes[0]    =        35;    /* # */
   header_bytes[1]    =        82;    /* R */
   header_bytes[2]    =        90;    /* Z */
   header_bytes[3]    =        73;    /* I */
   header_bytes[4]    =        80;    /* P */
   header_bytes[5]    =       118;    /* v */
   header_bytes[6]    = RZIP_VERSION; /* file format version number */
   header_bytes[7]    =        35;    /* # */

   /* > Uncompressed chunk size - next 4 bytes */
   header_bytes[11]   = (stream->chunk_size >> 24) & 0xFF;
   header_bytes[10]   = (stream->chunk_size >> 16) & 0xFF;
   header_bytes[9]    = (stream->chunk_size >>  8) & 0xFF;
   header_bytes[8]    =  stream->chunk_size        & 0xFF;

   /* > Total uncompressed data size - next 8 bytes */
   header_bytes[19]   = (stream->size >> 56) & 0xFF;
   header_bytes[18]   = (stream->size >> 48) & 0xFF;
   header_bytes[17]   = (stream->size >> 40) & 0xFF;
   header_bytes[16]   = (stream->size >> 32) & 0xFF;
   header_bytes[15]   = (stream->size >> 24) & 0xFF;
   header_bytes[14]   = (stream->size >> 16) & 0xFF;
   header_bytes[13]   = (stream->size >>  8) & 0xFF;
   header_bytes[12]   =  stream->size        & 0xFF;

   /* Reset file to start */
   filestream_seek(stream->file, 0, SEEK_SET);

   /* Write header bytes */
   return (filestream_write(stream->file,
         header_bytes, sizeof(header_bytes)) == RZIP_HEADER_SIZE);
}

/* Stream Initialisation/De-initialisation */

/* Initialises all members of an rzipstream_t struct,
 * reading config from existing file header if available */
static bool rzipstream_init_stream(
      rzipstream_t *stream, const char *path, bool is_writing)
{
   unsigned file_mode;

   if (!stream)
      return false;

   /* Ensure stream has valid initial values */
   stream->size              = 0;
   stream->chunk_size        = RZIP_DEFAULT_CHUNK_SIZE;
   stream->file              = NULL;
   stream->deflate_backend   = NULL;
   stream->deflate_stream    = NULL;
   stream->inflate_backend   = NULL;
   stream->inflate_stream    = NULL;
   stream->in_buf            = NULL;
   stream->in_buf_size       = 0;
   stream->in_buf_ptr        = 0;
   stream->out_buf           = NULL;
   stream->out_buf_size      = 0;
   stream->out_buf_ptr       = 0;
   stream->out_buf_occupancy = 0;

   /* Check whether this is a read or write stream */
   stream->is_writing = is_writing;
   if (stream->is_writing)
   {
      /* Written files are always compressed */
      stream->is_compressed = true;
      file_mode             = RETRO_VFS_FILE_ACCESS_WRITE;
   }
   /* For read files, must get compression status
    * from file itself... */
   else
      file_mode             = RETRO_VFS_FILE_ACCESS_READ;

   /* Open file */
   if (!(stream->file = filestream_open(
         path, file_mode, RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return false;

   /* If file is open for writing, output header
    * (Size component cannot be written until
    * file is closed...) */
   if (stream->is_writing)
   {
      /* Note: could just write zeros here, but
       * still want to identify this as an RZIP
       * file if writing fails partway through */
      if (!rzipstream_write_file_header(stream))
         return false;
   }
   /* If file is open for reading, parse any existing
    * header */
   else if (!rzipstream_read_file_header(stream))
      return false;

   /* Initialise appropriate transform stream
    * and determine associated buffer sizes */
   if (stream->is_writing)
   {
      /* Compression */
      if (!(stream->deflate_backend = trans_stream_get_zlib_deflate_backend()))
         return false;

      if (!(stream->deflate_stream = stream->deflate_backend->stream_new()))
         return false;

      /* Set compression level */
      if (!stream->deflate_backend->define(
            stream->deflate_stream, "level", RZIP_COMPRESSION_LEVEL))
         return false;

      /* Buffers
       * > Input: uncompressed
       * > Output: compressed */
      stream->in_buf_size  = stream->chunk_size;
      stream->out_buf_size = stream->chunk_size * 2;
      /* > Account for minimum zlib overhead
       *   of 11 bytes... */
      stream->out_buf_size =
            (stream->out_buf_size < (stream->in_buf_size + 11)) ?
                  stream->out_buf_size + 11 :
                  stream->out_buf_size;

      /* Redundant safety check */
      if (   (stream->in_buf_size  == 0)
          || (stream->out_buf_size == 0))
         return false;
   }
   /* When reading, don't need an inflate transform
    * stream (or buffers) if source file is uncompressed */
   else if (stream->is_compressed)
   {
      /* Decompression */
      if (!(stream->inflate_backend = trans_stream_get_zlib_inflate_backend()))
         return false;

      if (!(stream->inflate_stream = stream->inflate_backend->stream_new()))
         return false;

      /* Buffers
       * > Input: compressed
       * > Output: uncompressed
       * Note 1: Actual compressed chunk sizes are read
       *         from the file - just allocate a sensible
       *         default to minimise memory reallocations
       * Note 2: If file header is valid, output buffer
       *         should have a size of exactly stream->chunk_size.
       *         Allocate some additional space, just for
       *         redundant safety... */
      stream->in_buf_size  = stream->chunk_size * 2;
      stream->out_buf_size = stream->chunk_size + (stream->chunk_size >> 2);

      /* Redundant safety check */
      if (   (stream->in_buf_size  == 0)
          || (stream->out_buf_size == 0))
         return false;
   }

   /* Allocate buffers */
   if (stream->in_buf_size > 0)
   {
      if (!(stream->in_buf = (uint8_t *)calloc(stream->in_buf_size, 1)))
         return false;
   }

   if (stream->out_buf_size > 0)
   {
      if (!(stream->out_buf = (uint8_t *)calloc(stream->out_buf_size, 1)))
         return false;
   }

   return true;
}

/* free()'s all members of an rzipstream_t struct
 * > Also closes associated file, if currently open */
static int rzipstream_free_stream(rzipstream_t *stream)
{
   int ret = 0;

   if (!stream)
      return -1;

   /* Free transform streams */
   if (stream->deflate_stream && stream->deflate_backend)
      stream->deflate_backend->stream_free(stream->deflate_stream);

   stream->deflate_stream  = NULL;
   stream->deflate_backend = NULL;

   if (stream->inflate_stream && stream->inflate_backend)
      stream->inflate_backend->stream_free(stream->inflate_stream);

   stream->inflate_stream  = NULL;
   stream->inflate_backend = NULL;

   /* Free buffers */
   if (stream->in_buf)
      free(stream->in_buf);
   stream->in_buf = NULL;

   if (stream->out_buf)
      free(stream->out_buf);
   stream->out_buf = NULL;

   /* Close file */
   if (stream->file)
      ret = filestream_close(stream->file);
   stream->file = NULL;

   free(stream);

   return ret;
}

/* File Open */

/* Opens a new or existing RZIP file
 * > Supported 'mode' values are:
 *   - RETRO_VFS_FILE_ACCESS_READ
 *   - RETRO_VFS_FILE_ACCESS_WRITE
 * > When reading, 'path' may reference compressed
 *   or uncompressed data
 * Returns NULL if arguments are invalid, file
 * is invalid or an IO error occurs */
rzipstream_t* rzipstream_open(const char *path, unsigned mode)
{
   rzipstream_t *stream = NULL;

   /* Sanity check
    * > Only RETRO_VFS_FILE_ACCESS_READ and
    *   RETRO_VFS_FILE_ACCESS_WRITE are supported */
   if (string_is_empty(path)
       || (   (mode != RETRO_VFS_FILE_ACCESS_READ)
           && (mode != RETRO_VFS_FILE_ACCESS_WRITE)))
      return NULL;

   /* If opening in read mode, ensure file exists */
   if (   (mode == RETRO_VFS_FILE_ACCESS_READ)
       && !path_is_valid(path))
      return NULL;

   /* Allocate stream object */
   if (!(stream = (rzipstream_t*)malloc(sizeof(*stream))))
      return NULL;

   stream->is_compressed   = false;
   stream->is_writing      = false;
   stream->size            = 0;
   stream->chunk_size      = 0;
   stream->virtual_ptr     = 0;
   stream->file            = NULL;
   stream->deflate_backend = NULL;
   stream->deflate_stream  = NULL;
   stream->inflate_backend = NULL;
   stream->inflate_stream  = NULL;
   stream->in_buf          = NULL;
   stream->in_buf_size     = 0;
   stream->in_buf_ptr      = 0;
   stream->out_buf         = NULL;
   stream->out_buf_size    = 0;
   stream->out_buf_ptr     = 0;
   stream->out_buf_occupancy = 0;

   /* Initialise stream */
   if (!rzipstream_init_stream(
         stream, path,
         (mode == RETRO_VFS_FILE_ACCESS_WRITE)))
   {
      rzipstream_free_stream(stream);
      return NULL;
   }

   return stream;
}

/* File Read */

/* Reads and decompresses the next chunk of data
 * in the RZIP file */
static bool rzipstream_read_chunk(rzipstream_t *stream)
{
   unsigned i;
   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];
   uint32_t compressed_chunk_size;
   uint32_t inflate_read;
   uint32_t inflate_written;

   if (!stream || !stream->inflate_backend || !stream->inflate_stream)
      return false;

   for (i = 0; i < RZIP_CHUNK_HEADER_SIZE; i++)
      chunk_header_bytes[i] = 0;

   /* Attempt to read chunk header bytes */
   if (filestream_read(
         stream->file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=
         RZIP_CHUNK_HEADER_SIZE)
      return false;

   /* Get size of next compressed chunk */
   compressed_chunk_size = ( (uint32_t)chunk_header_bytes[3]  << 24)
                           | ((uint32_t)chunk_header_bytes[2] << 16)
                           | ((uint32_t)chunk_header_bytes[1] <<  8)
                           | (uint32_t)chunk_header_bytes[0];
   if (compressed_chunk_size == 0)
      return false;

   /* Resize input buffer, if required */
   if (compressed_chunk_size > stream->in_buf_size)
   {
      free(stream->in_buf);
      stream->in_buf      = NULL;

      stream->in_buf_size = compressed_chunk_size;
      stream->in_buf      = (uint8_t *)calloc(stream->in_buf_size, 1);
      if (!stream->in_buf)
         return false;

      /* Note: Uncompressed data size is fixed, and read
       * from the file header - we therefore don't attempt
       * to resize the output buffer (if it's too small, then
       * that's an error condition) */
   }

   /* Read compressed chunk from file */
   if (filestream_read(
         stream->file, stream->in_buf, compressed_chunk_size) !=
         compressed_chunk_size)
      return false;

   /* Decompress chunk data */
   stream->inflate_backend->set_in(
         stream->inflate_stream,
         stream->in_buf, compressed_chunk_size);

   stream->inflate_backend->set_out(
         stream->inflate_stream,
         stream->out_buf, stream->out_buf_size);

   /* Note: We have to set 'flush == true' here, otherwise we
    * can't guarantee that the entire chunk will be written
    * to the output buffer - this is inefficient, but not
    * much we can do... */
   if (!stream->inflate_backend->trans(
         stream->inflate_stream, true,
         &inflate_read, &inflate_written, NULL))
      return false;

   /* Error checking */
   if (inflate_read != compressed_chunk_size)
      return false;

   if (   (inflate_written == 0)
       || (inflate_written > stream->out_buf_size))
      return false;

   /* Record current output buffer occupancy
    * and reset pointer */
   stream->out_buf_occupancy = inflate_written;
   stream->out_buf_ptr       = 0;

   return true;
}

/* Reads (a maximum of) 'len' bytes from an RZIP file.
 * Returns actual number of bytes read, or -1 in
 * the event of an error */
int64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len)
{
   int64_t _len      = len;
   uint8_t *data_ptr = (uint8_t *)data;
   int64_t data_read = 0;

   if (!stream || stream->is_writing || !data)
      return -1;

   /* If we are reading uncompressed data, simply
    * 'pass on' the direct file access request */
   if (!stream->is_compressed)
      return filestream_read(stream->file, data, len);

   /* Process input data */
   while (_len > 0)
   {
      int64_t read_size = 0;

      /* Check whether we have reached the end
       * of the file */
      if (stream->virtual_ptr >= stream->size)
         return data_read;

      /* If everything in the output buffer has already
       * been read, grab and extract the next chunk
       * from disk */
      if (stream->out_buf_ptr >= stream->out_buf_occupancy)
         if (!rzipstream_read_chunk(stream))
            return -1;

      /* Get amount of data to 'read out' this loop
       * > i.e. minimum of remaining output buffer
       *   occupancy and remaining 'read data' size */
      if ((read_size = stream->out_buf_occupancy - stream->out_buf_ptr) >
            _len)
         read_size = _len;

      /* Copy as much cached data as possible into
       * the read buffer */
      memcpy(data_ptr, stream->out_buf + stream->out_buf_ptr, (size_t)read_size);

      /* Increment pointers and remaining length */
      stream->out_buf_ptr += read_size;
      data_ptr            += read_size;
      _len                -= read_size;

      stream->virtual_ptr += read_size;

      data_read           += read_size;
   }

   return data_read;
}

/* Reads next character from an RZIP file.
 * Returns character value, or EOF if no data
 * remains.
 * Note: Always returns EOF if file is open
 * for writing. */
int rzipstream_getc(rzipstream_t *stream)
{
   char c = 0;

   if (!stream || stream->is_writing)
      return EOF;

   /* Attempt to read a single character */
   if (rzipstream_read(stream, &c, 1) == 1)
      return (int)(unsigned char)c;

   return EOF;
}

/* Reads one line from an RZIP file and stores it
 * in the character array pointed to by 's'.
 * It stops reading when either (len-1) characters
 * are read, the newline character is read, or the
 * end-of-file is reached, whichever comes first.
 * On success, returns 's'. In the event of an error,
 * or if end-of-file is reached and no characters
 * have been read, returns NULL. */
char* rzipstream_gets(rzipstream_t *stream, char *s, size_t len)
{
   size_t str_len;
   int c         = 0;
   char *str_ptr = s;

   if (!stream || stream->is_writing || (len == 0))
      return NULL;

   /* Read bytes until newline or EOF is reached,
    * or string buffer is full */
   for (str_len = (len - 1); str_len > 0; str_len--)
   {
      /* Get next character */
      c = rzipstream_getc(stream);

      /* Check for newline and EOF */
      if (c == EOF)
         break;

      /* Copy character to string buffer */
      *str_ptr++ = c;

      /* Check for newline and EOF */
      if (c == '\n')
          break;
   }

   /* Add NUL termination */
   *str_ptr = '\0';

   /* Check whether EOF has been reached without
    * reading any characters */
   if ((str_ptr == s) && (c == EOF))
      return NULL;

   return (s);
}

/* Reads all data from file specified by 'path' and
 * copies it to 'buf'.
 * - 'buf' will be allocated and must be free()'d manually.
 * - Allocated 'buf' size is equal to 'len'.
 * Returns false in the event of an error */
bool rzipstream_read_file(const char *path, void **s, int64_t *len)
{
   int64_t bytes_read       = 0;
   void *content_buf        = NULL;
   int64_t content_buf_size = 0;
   rzipstream_t *stream     = NULL;

   if (!s)
      return false;

   /* Attempt to open file */
   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_READ)))
   {
      *s = NULL;
      return false;
   }

   /* Get file size */
   if ((content_buf_size = rzipstream_get_size(stream)) < 0)
      goto error;

   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
      goto error;

   /* Allocate buffer */
   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
      goto error;

   /* Read file contents */
   if ((bytes_read = rzipstream_read(stream, content_buf, content_buf_size)) <
         0)
      goto error;

   /* Close file */
   rzipstream_close(stream);
   stream = NULL;

   /* Add NUL termination for easy/safe handling of strings.
    * Will only work with sane character formatting (Unix). */
   ((char*)content_buf)[bytes_read] = '\0';

   /* Assign buffer */
   *s = content_buf;

   /* Assign length value, if required */
   if (len)
      *len = bytes_read;

   return true;

error:
   if (stream)
      rzipstream_close(stream);
   stream = NULL;

   if (content_buf)
      free(content_buf);
   content_buf = NULL;

   if (len)
      *len = -1;

   *s = NULL;

   return false;
}

/* File Write */

/* Compresses currently cached data and writes it
 * as the next RZIP file chunk */
static bool rzipstream_write_chunk(rzipstream_t *stream)
{
   unsigned i;
   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];
   uint32_t deflate_read;
   uint32_t deflate_written;

   if (!stream || !stream->deflate_backend || !stream->deflate_stream)
      return false;

   for (i = 0; i < RZIP_CHUNK_HEADER_SIZE; i++)
      chunk_header_bytes[i] = 0;

   /* Compress data currently held in input buffer */
   stream->deflate_backend->set_in(
         stream->deflate_stream,
         stream->in_buf, stream->in_buf_ptr);

   stream->deflate_backend->set_out(
         stream->deflate_stream,
         stream->out_buf, stream->out_buf_size);

   /* Note: We have to set 'flush == true' here, otherwise we
    * can't guarantee that the entire chunk will be written
    * to the output buffer - this is inefficient, but not
    * much we can do... */
   if (!stream->deflate_backend->trans(
         stream->deflate_stream, true,
         &deflate_read, &deflate_written, NULL))
      return false;

   /* Error checking */
   if (deflate_read != stream->in_buf_ptr)
      return false;

   if (   (deflate_written == 0)
       || (deflate_written > stream->out_buf_size))
      return false;

   /* Write compressed chunk size to file */
   chunk_header_bytes[3] = (deflate_written >> 24) & 0xFF;
   chunk_header_bytes[2] = (deflate_written >> 16) & 0xFF;
   chunk_header_bytes[1] = (deflate_written >>  8) & 0xFF;
   chunk_header_bytes[0] =  deflate_written        & 0xFF;

   if (filestream_write(
         stream->file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=
         RZIP_CHUNK_HEADER_SIZE)
      return false;

   /* Write compressed data to file */
   if (filestream_write(
         stream->file, stream->out_buf, deflate_written) != deflate_written)
      return false;

   /* Reset input buffer pointer */
   stream->in_buf_ptr = 0;

   return true;
}

/* Writes 'len' bytes to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len)
{
   int64_t _len = len;
   const uint8_t *data_ptr = (const uint8_t *)data;

   if (!stream || !stream->is_writing || !data)
      return -1;

   /* Process input data */
   while (_len > 0)
   {
      int64_t cache_size = 0;

      /* If input buffer is full, compress and write to disk */
      if (stream->in_buf_ptr >= stream->in_buf_size)
         if (!rzipstream_write_chunk(stream))
            return -1;

      /* Get amount of data to cache during this loop
       * > i.e. minimum of space remaining in input buffer
       *   and remaining 'write data' size */
      if ((cache_size = stream->in_buf_size - stream->in_buf_ptr) > _len)
         cache_size = _len;

      /* Copy as much data as possible into
       * the input buffer */
      memcpy(stream->in_buf + stream->in_buf_ptr, data_ptr, (size_t)cache_size);

      /* Increment pointers and remaining length */
      stream->in_buf_ptr  += cache_size;
      data_ptr            += cache_size;
      _len                -= cache_size;

      stream->size        += cache_size;
      stream->virtual_ptr += cache_size;
   }

   /* We always write the specified number of bytes
    * (unless rzipstream_write_chunk() fails, in
    * which we register a complete failure...) */
   return len;
}

/* Writes a single character to an RZIP file.
 * Returns character written, or EOF in the event
 * of an error */
int rzipstream_putc(rzipstream_t *stream, int c)
{
   char c_char = (char)c;
   if (   stream && stream->is_writing
         && (rzipstream_write(stream, &c_char, 1) == 1))
      return (int)(unsigned char)c;
   return EOF;
}

/* Writes a variable argument list to an RZIP file.
 * Ugly 'internal' function, required to enable
 * 'printf' support in the higher level 'interface_stream'.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args)
{
   static char buffer[8 * 1024] = {0};
   int _len = vsnprintf(buffer,
         sizeof(buffer), format, args);
   if (_len < 0)
      return -1;
   else if (_len == 0)
      return 0;
   return (int)rzipstream_write(stream, buffer, _len);
}

/* Writes formatted output to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_printf(rzipstream_t *stream, const char* format, ...)
{
   va_list vl;
   int ret = 0;

   /* Initialise variable argument list */
   va_start(vl, format);

   /* Write variable argument list to file */
   ret = rzipstream_vprintf(stream, format, vl);

   /* End using variable argument list */
   va_end(vl);

   return ret;
}

/* Writes contents of 'data' buffer to file
 * specified by 'path'.
 * Returns false in the event of an error */
bool rzipstream_write_file(const char *path, const void *data, int64_t len)
{
   int64_t bytes_written = 0;
   rzipstream_t *stream  = NULL;

   if (!data)
      return false;

   /* Attempt to open file */
   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_WRITE)))
      return false;

   /* Write contents of data buffer to file */
   bytes_written = rzipstream_write(stream, data, len);

   /* Close file */
   if (rzipstream_close(stream) == -1)
      return false;

   /* Check that the correct number of bytes
    * were written */
   return (bytes_written == len);
}

/* File Control */

/* Sets file position to the beginning of the
 * specified RZIP file.
 * Note: It is not recommended to rewind a file
 * that is open for writing, since the caller
 * may end up with a file containing junk data
 * at the end (harmless, but a waste of space). */
void rzipstream_rewind(rzipstream_t *stream)
{
   if (!stream)
      return;

   /* Note: rzipstream_rewind() has no way of
    * reporting errors (higher level interface
    * requires a void return type) - so if anything
    * goes wrong, all we can do is print to stderr
    * and bail out... */

   /* If we are handling uncompressed data, simply
    * 'pass on' the direct file access request */
   if (!stream->is_compressed)
   {
      filestream_rewind(stream->file);
      return;
   }

   /* If no file access has yet occurred, file is
    * already at the beginning -> do nothing */
   if (stream->virtual_ptr == 0)
      return;

   /* Check whether we are reading or writing */
   if (stream->is_writing)
   {
      /* Reset file position to first chunk location */
      filestream_seek(stream->file, RZIP_HEADER_SIZE, SEEK_SET);
      if (filestream_error(stream->file))
         return;

      /* Reset pointers */
      stream->virtual_ptr = 0;
      stream->in_buf_ptr  = 0;

      /* Reset file size */
      stream->size        = 0;
   }
   else
   {
      /* Check whether first file chunk is currently
       * buffered in memory */
      if ((stream->virtual_ptr < stream->chunk_size) &&
          (stream->out_buf_ptr < stream->out_buf_occupancy))
      {
         /* It is: No file access is therefore required
          * > Just reset pointers */
         stream->virtual_ptr = 0;
         stream->out_buf_ptr = 0;
      }
      else
      {
         /* It isn't: Have to re-read the first chunk
          * from disk... */

         /* Reset file position to first chunk location */
         filestream_seek(stream->file, RZIP_HEADER_SIZE, SEEK_SET);
         if (filestream_error(stream->file))
            return;

         /* Read chunk */
         if (!rzipstream_read_chunk(stream))
            return;

         /* Reset pointers */
         stream->virtual_ptr = 0;
         stream->out_buf_ptr = 0;
      }
   }
}

/* File Status */

/* Returns total size (in bytes) of the *uncompressed*
 * data in an RZIP file.
 * (If reading an uncompressed file, this corresponds
 * to the 'physical' file size in bytes)
 * Returns -1 in the event of a error. */
int64_t rzipstream_get_size(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   if (stream->is_compressed)
      return stream->size;
   return filestream_get_size(stream->file);
}

/* Returns EOF when no further *uncompressed* data
 * can be read from an RZIP file. */
int rzipstream_eof(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   if (stream->is_compressed)
      return (stream->virtual_ptr >= stream->size) ?
            EOF : 0;
   return filestream_eof(stream->file);
}

/* Returns the offset of the current byte of *uncompressed*
 * data relative to the beginning of an RZIP file.
 * Returns -1 in the event of a error. */
int64_t rzipstream_tell(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   if (stream->is_compressed)
      return (int64_t)stream->virtual_ptr;
   return filestream_tell(stream->file);
}

/* Returns true if specified RZIP file contains
 * compressed content */
bool rzipstream_is_compressed(rzipstream_t *stream)
{
   return stream && stream->is_compressed;
}

/* File Close */

/* Closes RZIP file. If file is open for writing,
 * flushes any remaining buffered data to disk.
 * Returns -1 in the event of a error. */
int rzipstream_close(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   /* If we are writing, ensure that any
    * remaining uncompressed data is flushed to
    * disk and update file header */
   if (stream->is_writing)
   {
      if (    ((stream->in_buf_ptr > 0)
            && !rzipstream_write_chunk(stream))
            || !rzipstream_write_file_header(stream))
      {
         /* Stream must be free()'d regardless */
         rzipstream_free_stream(stream);
         return -1;
      }
   }

   /* Free stream
    * > This also closes the file */
   return rzipstream_free_stream(stream);
}

./include/libretro-common/streams/stdin_stream.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdin_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>

#ifdef _WIN32
#ifndef _XBOX
#include <windows.h>
#endif
#include <direct.h>
#else
#include <unistd.h>
#endif

#include <boolean.h>
#include <retro_environment.h>
#include <streams/stdin_stream.h>

#if (defined(_WIN32) && defined(_XBOX)) || defined(__WINRT__) || !defined(__PSL1GHT__) && defined(__PS3__)
size_t read_stdin(char *s, size_t len) { return 0; } /* not implemented */
#elif defined(_WIN32)
size_t read_stdin(char *s, size_t len)
{
   DWORD i;
   DWORD has_read = 0;
   DWORD avail    = 0;
   bool echo      = false;
   HANDLE hnd     = GetStdHandle(STD_INPUT_HANDLE);

   if (hnd == INVALID_HANDLE_VALUE)
      return 0;

   /* Check first if we're a pipe
    * (not console). */

   /* If not a pipe, check if we're running in a console. */
   if (!PeekNamedPipe(hnd, NULL, 0, NULL, &avail, NULL))
   {
      INPUT_RECORD recs[256];
      bool has_key   = false;
      DWORD mode     = 0;
      DWORD has_read = 0;

      if (!GetConsoleMode(hnd, &mode))
         return 0;

      if ((mode & (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))
            && !SetConsoleMode(hnd,
               mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)))
         return 0;

      /* Win32, Y U NO SANE NONBLOCK READ!? */
      if (!PeekConsoleInput(hnd, recs,
               sizeof(recs) / sizeof(recs[0]), &has_read))
         return 0;

      for (i = 0; i < has_read; i++)
      {
         /* Very crude, but should get the job done. */
         if (recs[i].EventType == KEY_EVENT &&
               recs[i].Event.KeyEvent.bKeyDown &&
               (isgraph(recs[i].Event.KeyEvent.wVirtualKeyCode) ||
                recs[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN))
         {
            has_key = true;
            echo    = true;
            avail   = len;
            break;
         }
      }

      if (!has_key)
      {
         FlushConsoleInputBuffer(hnd);
         return 0;
      }
   }

   if (!avail)
      return 0;

   if (avail > len)
      avail = len;

   if (!ReadFile(hnd, s, avail, &has_read, NULL))
      return 0;

   for (i = 0; i < has_read; i++)
      if (s[i] == '\r')
         s[i] = '\n';

   /* Console won't echo for us while in non-line mode,
    * so do it manually ... */
   if (echo)
   {
      HANDLE hnd_out = GetStdHandle(STD_OUTPUT_HANDLE);
      if (hnd_out != INVALID_HANDLE_VALUE)
      {
         DWORD has_written;
         WriteConsole(hnd_out, s, has_read, &has_written, NULL);
      }
   }
   return has_read;
}
#else
size_t read_stdin(char *s, size_t len)
{
   size_t has_read = 0;
   while (len)
   {
      ssize_t ret = read(STDIN_FILENO, s, len);
      if (ret <= 0)
         break;
      s        += ret;
      has_read += ret;
      len      -= ret;
   }
   return has_read;
}
#endif

./include/libretro-common/streams/trans_stream.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <streams/trans_stream.h>

/**
 * trans_stream_trans_full:
 * @data                        : (optional) existing stream data, or a target
 *                                for the new stream data to be saved
 * @in                          : input data
 * @in_size                     : input size
 * @s                           : output data
 * @len                         : output size
 * @err                         : (optional) output for error code
 *
 * Perform a full transcoding from a source to a destination.
 */
bool trans_stream_trans_full(
    struct trans_stream_backend *backend, void **data,
    const uint8_t *in, uint32_t in_size,
    uint8_t *s, uint32_t len,
    enum trans_stream_error *err)
{
   void *rdata;
   bool ret;
   uint32_t rd, wn;

   if (data && *data)
      rdata = *data;
   else
   {
      if (!(rdata = backend->stream_new()))
      {
         if (err)
            *err = TRANS_STREAM_ERROR_ALLOCATION_FAILURE;
         return false;
      }
   }

   backend->set_in(rdata, in, in_size);
   backend->set_out(rdata, s, len);
   ret = backend->trans(rdata, true, &rd, &wn, err);

   if (data)
      *data = rdata;
   else
      backend->stream_free(rdata);

   return ret;
}

const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void)
{
#if HAVE_ZLIB
   return &zlib_deflate_backend;
#else
   return NULL;
#endif
}

const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void)
{
#if HAVE_ZLIB
   return &zlib_inflate_backend;
#else
   return NULL;
#endif
}

const struct trans_stream_backend* trans_stream_get_pipe_backend(void)
{
   return &pipe_backend;
}

./include/libretro-common/streams/trans_stream_pipe.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream_pipe.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <streams/trans_stream.h>

struct pipe_trans_stream
{
   const uint8_t *in;
   uint8_t *out;
   uint32_t in_size, out_size;
};

static void *pipe_stream_new(void)
{
   struct pipe_trans_stream *stream =
      (struct pipe_trans_stream*)malloc(sizeof(*stream));
   if (!stream)
      return NULL;

   stream->in                       = NULL;
   stream->out                      = NULL;
   stream->in_size                  = 0;
   stream->out_size                 = 0;

   return stream;
}

static void pipe_stream_free(void *data)
{
   free(data);
}

static void pipe_set_in(void *data, const uint8_t *in, uint32_t in_size)
{
   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;

   if (!p)
      return;

   p->in                       = in;
   p->in_size                  = in_size;
}

static void pipe_set_out(void *data, uint8_t *out, uint32_t out_size)
{
   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;

   if (!p)
      return;

   p->out                      = out;
   p->out_size                 = out_size;
}

static bool pipe_trans(void *data, bool flush,
   uint32_t *rd, uint32_t *wn, enum trans_stream_error *err)
{
   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;

   if (p->out_size < p->in_size)
   {
      memcpy(p->out, p->in, p->out_size);
      *rd     = *wn = p->out_size;
      p->in  += p->out_size;
      p->out += p->out_size;
      *err    = TRANS_STREAM_ERROR_BUFFER_FULL;
      return false;
   }

   memcpy(p->out, p->in, p->in_size);
   *rd     = *wn = p->in_size;
   p->in  += p->in_size;
   p->out += p->in_size;
   *err    = TRANS_STREAM_ERROR_NONE;
   return true;
}

const struct trans_stream_backend pipe_backend = {
   "pipe",
   &pipe_backend,
   pipe_stream_new,
   pipe_stream_free,
   NULL,
   pipe_set_in,
   pipe_set_out,
   pipe_trans
};

./include/libretro-common/streams/trans_stream_zlib.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream_zlib.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <string.h>

#include <zlib.h>
#include <string/stdstring.h>
#include <streams/trans_stream.h>

struct zlib_trans_stream
{
   z_stream z;
   int window_bits;
   int level;
   bool inited;
};

static void *zlib_deflate_stream_new(void)
{
   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
      malloc(sizeof(*ret));
   if (!ret)
      return NULL;
   ret->inited      = false;
   ret->level       = 9;
   ret->window_bits = 15;

   ret->z.next_in   = NULL;
   ret->z.avail_in  = 0;
   ret->z.total_in  = 0;
   ret->z.next_out  = NULL;
   ret->z.avail_out = 0;
   ret->z.total_out = 0;

   ret->z.msg       = NULL;
   ret->z.state     = NULL;

   ret->z.zalloc    = NULL;
   ret->z.zfree     = NULL;
   ret->z.opaque    = NULL;

   ret->z.data_type = 0;
   ret->z.adler     = 0;
   ret->z.reserved  = 0;
   return (void *)ret;
}

static void *zlib_inflate_stream_new(void)
{
   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
      malloc(sizeof(*ret));
   if (!ret)
      return NULL;
   ret->inited      = false;
   ret->window_bits = MAX_WBITS;

   ret->z.next_in   = NULL;
   ret->z.avail_in  = 0;
   ret->z.total_in  = 0;
   ret->z.next_out  = NULL;
   ret->z.avail_out = 0;
   ret->z.total_out = 0;

   ret->z.msg       = NULL;
   ret->z.state     = NULL;

   ret->z.zalloc    = NULL;
   ret->z.zfree     = NULL;
   ret->z.opaque    = NULL;

   ret->z.data_type = 0;
   ret->z.adler     = 0;
   ret->z.reserved  = 0;
   return (void *)ret;
}

static void zlib_deflate_stream_free(void *data)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
   if (!z)
      return;
   if (z->inited)
      deflateEnd(&z->z);
   free(z);
}

static void zlib_inflate_stream_free(void *data)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
   if (!z)
      return;
   if (z->inited)
      inflateEnd(&z->z);
   if (z)
      free(z);
}

static bool zlib_deflate_define(void *data, const char *prop, uint32_t val)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream*)data;
   if (!data)
      return false;

   if (string_is_equal(prop, "level"))
      z->level = (int) val;
   else if (string_is_equal(prop, "window_bits"))
      z->window_bits = (int) val;
   else
      return false;

   return true;
}

static bool zlib_inflate_define(void *data, const char *prop, uint32_t val)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream*)data;
   if (!data)
      return false;

   if (string_is_equal(prop, "window_bits"))
   {
      z->window_bits = (int) val;
      return true;
   }
   return false;
}

static void zlib_deflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;

   if (!z)
      return;

   z->z.next_in                = (uint8_t *) in;
   z->z.avail_in               = in_size;

   if (!z->inited)
   {
      deflateInit2(&z->z, z->level, Z_DEFLATED , z->window_bits, 8,  Z_DEFAULT_STRATEGY );
      z->inited = true;
   }
}

static void zlib_inflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;

   if (!z)
      return;

   z->z.next_in                = (uint8_t *) in;
   z->z.avail_in               = in_size;
   if (!z->inited)
   {
      inflateInit2(&z->z, z->window_bits);
      z->inited = true;
   }
}

static void zlib_set_out(void *data, uint8_t *out, uint32_t out_size)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;

   if (!z)
      return;

   z->z.next_out               = out;
   z->z.avail_out              = out_size;
}

static bool zlib_deflate_trans(
   void *data, bool flush,
   uint32_t *rd, uint32_t *wn,
   enum trans_stream_error *err)
{
   int zret                     = 0;
   bool ret                     = false;
   uint32_t pre_avail_in        = 0;
   uint32_t pre_avail_out       = 0;
   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
   z_stream                  *z = &zt->z;

   if (!zt->inited)
   {
      deflateInit2(z, zt->level, Z_DEFLATED , zt->window_bits, 8,  Z_DEFAULT_STRATEGY );
      zt->inited = true;
   }

   pre_avail_in  = z->avail_in;
   pre_avail_out = z->avail_out;
   zret          = deflate(z, flush ? Z_FINISH : Z_NO_FLUSH);

   if (zret == Z_OK)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_AGAIN;
   }
   else if (zret == Z_STREAM_END)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_NONE;
   }
   else
   {
      if (err)
         *err = TRANS_STREAM_ERROR_OTHER;
      return false;
   }
   ret = true;

   if (z->avail_out == 0)
   {
      /* Filled buffer, maybe an error */
      if (z->avail_in != 0)
      {
         ret = false;
         if (err)
            *err = TRANS_STREAM_ERROR_BUFFER_FULL;
      }
   }

   *rd = pre_avail_in - z->avail_in;
   *wn = pre_avail_out - z->avail_out;

   if (flush && zret == Z_STREAM_END)
   {
      deflateEnd(z);
      zt->inited = false;
   }

   return ret;
}

static bool zlib_inflate_trans(
   void *data, bool flush,
   uint32_t *rd, uint32_t *wn,
   enum trans_stream_error *err)
{
   int zret;
   bool ret                     = false;
   uint32_t pre_avail_in        = 0;
   uint32_t pre_avail_out       = 0;
   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
   z_stream                  *z = &zt->z;

   if (!zt->inited)
   {
      inflateInit2(z, zt->window_bits);
      zt->inited = true;
   }

   pre_avail_in  = z->avail_in;
   pre_avail_out = z->avail_out;
   zret          = inflate(z, flush ? Z_FINISH : Z_NO_FLUSH);

   if (zret == Z_OK)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_AGAIN;
   }
   else if (zret == Z_STREAM_END)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_NONE;
   }
   else
   {
      if (err)
         *err = TRANS_STREAM_ERROR_OTHER;
      return false;
   }
   ret = true;

   if (z->avail_out == 0)
   {
      /* Filled buffer, maybe an error */
      if (z->avail_in != 0)
      {
         ret = false;
         if (err)
            *err = TRANS_STREAM_ERROR_BUFFER_FULL;
      }
   }

   *rd = pre_avail_in - z->avail_in;
   *wn = pre_avail_out - z->avail_out;

   if (flush && zret == Z_STREAM_END)
   {
      inflateEnd(z);
      zt->inited = false;
   }

   return ret;
}

const struct trans_stream_backend zlib_deflate_backend = {
   "zlib_deflate",
   &zlib_inflate_backend,
   zlib_deflate_stream_new,
   zlib_deflate_stream_free,
   zlib_deflate_define,
   zlib_deflate_set_in,
   zlib_set_out,
   zlib_deflate_trans
};

const struct trans_stream_backend zlib_inflate_backend = {
   "zlib_inflate",
   &zlib_deflate_backend,
   zlib_inflate_stream_new,
   zlib_inflate_stream_free,
   zlib_inflate_define,
   zlib_inflate_set_in,
   zlib_set_out,
   zlib_inflate_trans
};

./include/libretro-common/string/stdstring.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdint.h>
#include <ctype.h>
#include <string.h>

#include <compat/strl.h>
#include <string/stdstring.h>
#include <encodings/utf.h>

const uint8_t lr_char_props[256] = {
	/*x0   x1   x2   x3   x4   x5   x6   x7   x8   x9   xA   xB   xC   xD   xE   xF */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x                  */
	0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x  !"#$%&'()*+,-./ */
	0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
	0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
	0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
	0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
	0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx                  */
};

char *string_to_upper(char *s)
{
   char *cs = (char *)s;
   for ( ; *cs != '\0'; cs++)
      *cs = toupper((unsigned char)*cs);
   return s;
}

char *string_to_lower(char *s)
{
   char *cs = (char *)s;
   for ( ; *cs != '\0'; cs++)
      *cs = tolower((unsigned char)*cs);
   return s;
}

char *string_ucwords(char *s)
{
   char *cs = (char *)s;
   for ( ; *cs != '\0'; cs++)
   {
      if (*cs == ' ')
         *(cs+1) = toupper((unsigned char)*(cs+1));
   }

   s[0] = toupper((unsigned char)s[0]);
   return s;
}

char *string_replace_substring(
      const char *in,          size_t in_len,
      const char *pattern,     size_t pattern_len,
      const char *replacement, size_t replacement_len)
{
   size_t outlen;
   size_t numhits     = 0;
   const char *inat   = NULL;
   const char *inprev = NULL;
   char          *out = NULL;
   char        *outat = NULL;

   /* if either pattern or replacement is NULL,
    * duplicate in and let caller handle it. */
   if (!pattern || !replacement)
      return strdup(in);

   inat            = in;

   while ((inat = strstr(inat, pattern)))
   {
      inat += pattern_len;
      numhits++;
   }

   outlen = in_len - pattern_len * numhits + replacement_len*numhits;

   if (!(out = (char *)malloc(outlen+1)))
      return NULL;

   outat           = out;
   inat            = in;
   inprev          = in;

   while ((inat = strstr(inat, pattern)))
   {
      memcpy(outat, inprev, inat-inprev);
      outat += inat-inprev;
      memcpy(outat, replacement, replacement_len);
      outat += replacement_len;
      inat  += pattern_len;
      inprev = inat;
   }
   strcpy(outat, inprev);

   return out;
}

/**
 * string_trim_whitespace_left:
 *
 * Remove leading whitespaces
 **/
char *string_trim_whitespace_left(char *const s)
{
   if (s && *s)
   {
      size_t _len    = strlen(s);
      char *current  = s;

      while (*current && ISSPACE((unsigned char)*current))
      {
         ++current;
         --_len;
      }

      if (s != current)
         memmove(s, current, _len + 1);
   }

   return s;
}

/**
 * string_trim_whitespace_right:
 *
 * Remove trailing whitespaces
 **/
char *string_trim_whitespace_right(char *const s)
{
   if (s && *s)
   {
      size_t _len    = strlen(s);
      char  *current = s + _len - 1;

      while (current != s && ISSPACE((unsigned char)*current))
      {
         --current;
         --_len;
      }

      current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
   }

   return s;
}

/**
 * string_trim_whitespace:
 *
 * Remove leading and trailing whitespaces
 **/
char *string_trim_whitespace(char *const s)
{
   string_trim_whitespace_right(s);  /* order matters */
   string_trim_whitespace_left(s);

   return s;
}

/**
 * word_wrap:
 * @s                  : pointer to destination buffer.
 * @len                : size of destination buffer.
 * @src                : pointer to input string.
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : not used, but is necessary to keep
 *                       compatibility with word_wrap_wideglyph().
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by @src to destination buffer
 * specified by @s and @len.
 * This function assumes that all glyphs in the string
 * have an on-screen pixel width similar to that of
 * regular Latin characters - i.e. it will not wrap
 * correctly any text containing so-called 'wide' Unicode
 * characters (e.g. CJK languages, emojis, etc.).
 **/
size_t word_wrap(
      char *s,         size_t len,
      const char *src, size_t src_len,
      int line_width,  int wideglyph_width, unsigned max_lines)
{
   char *last_space    = NULL;
   unsigned counter    = 0;
   unsigned lines      = 1;
   const char *src_end = src + src_len;

   /* Prevent buffer overflow */
   if (len < src_len + 1)
      return 0;

   /* Early return if src string length is less
    * than line width */
   if (src_len < (size_t)line_width)
      return strlcpy(s, src, len);

   while (*src != '\0')
   {
      unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
      counter++;

      if (*src == ' ')
         last_space = s; /* Remember the location of the whitespace */
      else if (*src == '\n')
      {
         /* If newlines embedded in the input,
          * reset the index */
         lines++;
         counter   = 0;

         /* Early return if remaining src string
          * length is less than line width */
         if (src_end - src <= line_width)
            return strlcpy(s, src, len);
     }

      while (char_len--)
         *s++ = *src++;

      if (counter >= (unsigned)line_width)
      {
         counter = 0;

         if (last_space && (max_lines == 0 || lines < max_lines))
         {
            /* Replace nearest (previous) whitespace
             * with newline character */
            *last_space = '\n';
            lines++;

            src        -= s - last_space - 1;
            s           = last_space + 1;
            last_space  = NULL;

            /* Early return if remaining src string
             * length is less than line width */
            if (src_end - src < line_width)
               return strlcpy(s, src, len);
         }
      }
   }

   *s = '\0';
   return 0;
}

/**
 * word_wrap_wideglyph:
 * @dst                : pointer to destination buffer.
 * @len                : size of destination buffer.
 * @src                : pointer to input string.
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : effective width of 'wide' Unicode glyphs.
 *                       the value here is normalised relative to the
 *                       typical on-screen pixel width of a regular
 *                       Latin character:
 *                       - a regular Latin character is defined to
 *                         have an effective width of 100
 *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
 *                       - e.g. if 'wide' Unicode characters in 'src'
 *                         have an on-screen pixel width twice that of
 *                         regular Latin characters, wideglyph_width
 *                         would be 200
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by @src to destination buffer
 * specified by @dst and @len.
 * This function assumes that all glyphs in the string
 * are:
 * - EITHER 'non-wide' Unicode glyphs, with an on-screen
 *   pixel width similar to that of regular Latin characters
 * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
 *   with an on-screen pixel width defined by @wideglyph_width
 * Note that wrapping may occur in inappropriate locations
 * if @src string contains 'wide' Unicode characters whose
 * on-screen pixel width deviates greatly from the set
 * @wideglyph_width value.
 **/
size_t word_wrap_wideglyph(char *s, size_t len,
      const char *src, size_t src_len, int line_width,
      int wideglyph_width, unsigned max_lines)
{
   char *lastspace                   = NULL;
   char *lastwideglyph               = NULL;
   const char *src_end               = src + src_len;
   unsigned lines                    = 1;
   /* 'line_width' means max numbers of characters per line,
    * but this metric is only meaningful when dealing with
    * 'regular' glyphs that have an on-screen pixel width
    * similar to that of regular Latin characters.
    * When handing so-called 'wide' Unicode glyphs, it is
    * necessary to consider the actual on-screen pixel width
    * of each character.
    * In order to do this, we create a distinction between
    * regular Latin 'non-wide' glyphs and 'wide' glyphs, and
    * normalise all values relative to the on-screen pixel
    * width of regular Latin characters:
    * - Regular 'non-wide' glyphs have a normalised width of 100
    * - 'line_width' is therefore normalised to 100 * (width_in_characters)
    * - 'wide' glyphs have a normalised width of
    *   100 * (wide_character_pixel_width / latin_character_pixel_width)
    * - When a character is detected, the position in the current
    *   line is incremented by the regular normalised width of 100
    * - If that character is then determined to be a 'wide'
    *   glyph, the position in the current line is further incremented
    *   by the difference between the normalised 'wide' and 'non-wide'
    *   width values */
   unsigned counter_normalized       = 0;
   int line_width_normalized         = line_width * 100;
   int additional_counter_normalized = wideglyph_width - 100;

   /* Early return if src string length is less
    * than line width */
   if (src_end - src < line_width)
      return strlcpy(s, src, len);

   while (*src != '\0')
   {
      unsigned char_len   = (unsigned)(utf8skip(src, 1) - src);
      counter_normalized += 100;

      /* Prevent buffer overflow */
      if (char_len >= len)
         break;

      if (*src == ' ')
         lastspace          = s; /* Remember the location of the whitespace */
      else if (*src == '\n')
      {
         /* If newlines embedded in the input,
          * reset the index */
         lines++;
         counter_normalized = 0;

         /* Early return if remaining src string
          * length is less than line width */
         if (src_end - src <= line_width)
            return strlcpy(s, src, len);
      }
      else if (char_len >= 3)
      {
         /* Remember the location of the first byte
          * whose length as UTF-8 >= 3*/
         lastwideglyph       = s;
         counter_normalized += additional_counter_normalized;
      }

      len -= char_len;
      while (char_len--)
         *s++ = *src++;

      if (counter_normalized >= (unsigned)line_width_normalized)
      {
         counter_normalized = 0;

         if (max_lines != 0 && lines >= max_lines)
            continue;
         else if (lastwideglyph && (!lastspace || lastwideglyph > lastspace))
         {
            /* Insert newline character */
            *lastwideglyph = '\n';
            lines++;
            src           -= s - lastwideglyph;
            s              = lastwideglyph + 1;
            lastwideglyph  = NULL;

            /* Early return if remaining src string
             * length is less than line width */
            if (src_end - src <= line_width)
               return strlcpy(s, src, len);
         }
         else if (lastspace)
         {
            /* Replace nearest (previous) whitespace
             * with newline character */
            *lastspace = '\n';
            lines++;
            src       -= s - lastspace - 1;
            s          = lastspace + 1;
            lastspace  = NULL;

            /* Early return if remaining src string
             * length is less than line width */
            if (src_end - src < line_width)
               return strlcpy(s, src, len);
         }
      }
   }

   *s = '\0';
   return 0;
}

/**
 * string_tokenize:
 *
 * Splits string into tokens separated by @delim
 * > Returned token string must be free()'d
 * > Returns NULL if token is not found
 * > After each call, @str is set to the position after the
 *   last found token
 * > Tokens *include* empty strings
 * Usage example:
 *    char *str      = "1,2,3,4,5,6,7,,,10,";
 *    char **str_ptr = &str;
 *    char *token    = NULL;
 *    while ((token = string_tokenize(str_ptr, ",")))
 *    {
 *        printf("%s\n", token);
 *        free(token);
 *        token = NULL;
 *    }
 **/
char* string_tokenize(char **str, const char *delim)
{
   /* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
   char *str_ptr    = NULL;
   char *delim_ptr  = NULL;
   char *token      = NULL;
   size_t token_len = 0;

   /* Sanity checks */
   if (!str || string_is_empty(delim))
      return NULL;

   /* Note: we don't check string_is_empty() here,
    * empty strings are valid */
   if (!(str_ptr = *str))
      return NULL;

   /* Search for delimiter */
   if ((delim_ptr = strstr(str_ptr, delim)))
      token_len = delim_ptr - str_ptr;
   else
      token_len = strlen(str_ptr);

   /* Allocate token string */
   if (!(token = (char *)malloc((token_len + 1) * sizeof(char))))
      return NULL;

   /* Copy token */
   strlcpy(token, str_ptr, (token_len + 1) * sizeof(char));
   token[token_len] = '\0';

   /* Update input string pointer */
   *str = delim_ptr ? delim_ptr + strlen(delim) : NULL;

   return token;
}

/**
 * string_remove_all_chars:
 * @s                 : input string (must be non-NULL, otherwise UB)
 *
 * Leaf function.
 *
 * Removes every instance of character @c from @s
 **/
void string_remove_all_chars(char *s, char c)
{
   char *read_ptr  = s;
   char *write_ptr = s;

   while (*read_ptr != '\0')
   {
      /* Only write if the character is not the one to remove */
      if (*read_ptr != c)
         *write_ptr++ = *read_ptr;
      read_ptr++;
   }

   *write_ptr = '\0';
}

/**
 * string_replace_all_chars:
 * @s                  : input string (must be non-NULL, otherwise UB)
 * @find               : character to find
 * @replace            : character to replace @find with
 *
 * Replaces every instance of character @find in @s
 * with character @replace
 **/
void string_replace_all_chars(char *s, char find, char replace)
{
   char *str_ptr = s;
   while ((str_ptr = strchr(str_ptr, find)))
      *str_ptr++ = replace;
}

/**
 * string_to_unsigned:
 * @str                : input string
 *
 * Converts string to unsigned integer.
 *
 * @return 0 if string is invalid, otherwise > 0
 **/
unsigned string_to_unsigned(const char *str)
{
   const char *ptr = NULL;

   if (string_is_empty(str))
      return 0;

   for (ptr = str; *ptr != '\0'; ptr++)
   {
      if (!ISDIGIT((unsigned char)*ptr))
         return 0;
   }

   return (unsigned)strtoul(str, NULL, 10);
}

/**
 * string_hex_to_unsigned:
 * @str                : input string (must be non-NULL, otherwise UB)
 *
 * Converts hexadecimal string to unsigned integer.
 * Handles optional leading '0x'.
 *
 * @return 0 if string is invalid, otherwise > 0
 **/
unsigned string_hex_to_unsigned(const char *str)
{
   const char *hex_str = str;
   const char *ptr     = NULL;

   /* Remove leading '0x', if required */
   if (str[0] != '\0' && str[1] != '\0')
   {
      if (     (str[0] == '0')
           && ((str[1] == 'x')
           ||  (str[1] == 'X')))
      {
         hex_str = str + 2;
         if (string_is_empty(hex_str))
            return 0;
      }
   }
   else
      return 0;

   /* Check for valid characters */
   for (ptr = hex_str; *ptr != '\0'; ptr++)
   {
      if (!isxdigit((unsigned char)*ptr))
         return 0;
   }

   return (unsigned)strtoul(hex_str, NULL, 16);
}

/**
 * string_count_occurrences_single_character:
 *
 * Leaf function.
 *
 * Get the total number of occurrences of character @c in @str.
 *
 * @return Total number of occurrences of character @c
 */
int string_count_occurrences_single_character(const char *str, char c)
{
   int count = 0;

   for (; *str; str++)
      if (*str == c)
         count++;

   return count;
}

/**
 * string_replace_whitespace_with_single_character:
 *
 * Leaf function.
 *
 * Replaces all spaces with given character @c.
 **/
void string_replace_whitespace_with_single_character(char *s, char c)
{
   for (; *s; s++)
      if (ISSPACE(*s))
         *s = c;
}

/**
 * string_replace_multi_space_with_single_space:
 *
 * Leaf function.
 *
 * Replaces multiple spaces with a single space in a string.
 **/
void string_replace_multi_space_with_single_space(char *s)
{
   char *str_trimmed  = s;
   bool prev_is_space = false;
   bool curr_is_space = false;

   for (; *s; s++)
   {
      curr_is_space  = ISSPACE(*s);
      if (prev_is_space && curr_is_space)
         continue;
      *str_trimmed++ = *s;
      prev_is_space  = curr_is_space;
   }
   *str_trimmed = '\0';
}

/**
 * string_remove_all_whitespace:
 *
 * Leaf function.
 *
 * Remove all spaces from the given string.
 **/
void string_remove_all_whitespace(char *s, const char *str)
{
   for (; *str; str++)
      if (!ISSPACE(*str))
         *s++ = *str;
   *s = '\0';
}

/**
 * Retrieve the last occurance of the given character in a string.
 */
int string_index_last_occurance(const char *str, char c)
{
   const char *pos = strrchr(str, c);
   if (pos)
      return (int)(pos - str);
   return -1;
}

/**
 * string_find_index_substring_string:
 * @str                : input string (must be non-NULL, otherwise UB)
 * @substr             : substring to find in @str
 *
 * Find the position of substring @substr in string @str.
 **/
int string_find_index_substring_string(const char *str, const char *substr)
{
   const char *pos = strstr(str, substr);
   if (pos)
      return (int)(pos - str);
   return -1;
}

/**
 * string_copy_only_ascii:
 *
 * Leaf function.
 *
 * Strips non-ASCII characters from a string.
 **/
void string_copy_only_ascii(char *s, const char *str)
{
   for (; *str; str++)
      if (*str > 0x1F && *str < 0x7F)
         *s++ = *str;
   *s = '\0';
}

./include/libretro-common/test/hash/test_hash.c

/* Copyright  (C) 2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <check.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#include <lrc_hash.h>

#define SUITE_NAME "hash"

START_TEST (test_sha256)
{
   char output[65];
   sha256_hash(output, (uint8_t*)"abc", 3);
   ck_assert(!strcmp(output,
      "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"));
}
END_TEST

START_TEST (test_sha1)
{
   char output[41];
   char tmpfile[512];
   FILE *fd;
   tmpnam(tmpfile);
   fd = fopen(tmpfile, "wb");
   ck_assert(fd != NULL);
   fwrite("abc", 1, 3, fd);
   fclose(fd);
   sha1_calculate(tmpfile, output);

   ck_assert(!strcmp(output,
      "A9993E364706816ABA3E25717850C26C9CD0D89D"));
}
END_TEST

START_TEST (test_djb2)
{
   ck_assert_uint_eq(djb2_calculate("retroarch"), 0xFADF3BCF);
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_sha256);
   tcase_add_test(tc_core, test_sha1);
   tcase_add_test(tc_core, test_djb2);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

./include/libretro-common/test/lists/test_linked_list.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_linked_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <check.h>
#include <stdarg.h>
#include <stdlib.h>

#include <lists/linked_list.h>

#define SUITE_NAME "Linked List"

static char *_value_1 = "value1";
static char *_value_2 = "value2";
static char *_value_3 = "value3";

START_TEST (test_linked_list_create)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_nonnull(list);
   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_free)
{
   linked_list_t *queue = linked_list_new();
   linked_list_free(queue, NULL);
   linked_list_free(NULL, NULL);
}
END_TEST

static int _free_alloced_value_count;
static void _free_alloced_value(void *value)
{
   _free_alloced_value_count++;
   free(value);
}

START_TEST (test_linked_list_free_with_fn)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, malloc(1));
   linked_list_add(list, malloc(1));
   linked_list_add(list, malloc(1));

   _free_alloced_value_count = 0;
   linked_list_free(list, &_free_alloced_value);

   ck_assert_int_eq(3, _free_alloced_value_count);
}
END_TEST

static void _verify_list(linked_list_t *list, int size, ...)
{
   va_list values_list;
   void **values;
   int i;
   linked_list_iterator_t *iterator;

   values = (void **)malloc(size * sizeof(void *));

   ck_assert_int_eq(linked_list_size(list), size);

   va_start(values_list, size);
   for (i = 0; i < size; i++)
   {
      values[i] = va_arg(values_list, void *);
      ck_assert_ptr_eq(values[i], linked_list_get(list, i));
   }
   va_end(values_list);

   iterator = linked_list_iterator(list, true);
   for (i = 0; i < size; i++)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));
      iterator = linked_list_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   iterator = linked_list_iterator(list, false);
   for (i = size - 1; i >= 0; i--)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));
      iterator = linked_list_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   free(values);
}

START_TEST (test_linked_list_add)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_empty)
{
   linked_list_t *list = linked_list_new();
   linked_list_insert(list, 0, _value_1);

   ck_assert_int_eq(linked_list_size(list), 1);
   ck_assert_ptr_eq(linked_list_get(list, 0), _value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_insert(list, 0, _value_1);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);
   linked_list_insert(list, 1, _value_2);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_insert(list, 2, _value_3);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_invalid)
{
   linked_list_t *list = linked_list_new();
   linked_list_insert(list, 2, _value_1);

   ck_assert_int_eq(linked_list_size(list), 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_null)
{
   linked_list_insert(NULL, 0, _value_1);
}
END_TEST

START_TEST (test_linked_list_get_invalid)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get(list, 2));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_null)
{
   ck_assert_ptr_null(linked_list_get(NULL, 0));
}
END_TEST

START_TEST (test_linked_list_get_first_matching_null)
{
   ck_assert_ptr_null(linked_list_get_first_matching(NULL, NULL, NULL));
}
END_TEST

START_TEST (test_linked_list_get_first_matching_function_null)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_first_matching(list, NULL, NULL));

   linked_list_free(list, NULL);
}

bool _matches_function(void *value, void *state)
{
   ck_assert_ptr_eq(_value_1, state);
   return value == _value_2;
}

START_TEST (test_linked_list_get_first_matching_no_match)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_first_matching(list, &_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_first_matching_with_match)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(_value_2, linked_list_get_first_matching(list, &_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_last_matching_null)
{
   ck_assert_ptr_null(linked_list_get_last_matching(NULL, NULL, NULL));
}
END_TEST

START_TEST (test_linked_list_get_last_matching_function_null)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_last_matching(list, NULL, NULL));

   linked_list_free(list, NULL);
}

START_TEST (test_linked_list_get_last_matching_no_match)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_last_matching(list, &_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_last_matching_with_match)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(_value_2, linked_list_get_last_matching(list, &_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_null)
{
   ck_assert_ptr_null(linked_list_remove_at(NULL, 0));
}
END_TEST

START_TEST (test_linked_list_remove_at_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_at(list, 0));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_invalid)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 3);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 0);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 1);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 2);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   linked_list_remove_at(list, 0);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_null)
{
   ck_assert_ptr_null(linked_list_remove_first(NULL, _value_1));
}
END_TEST

START_TEST (test_linked_list_remove_first_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_first(list, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_first(list, "foo"));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_2), _value_2);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_3), _value_3);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_null)
{
   ck_assert_ptr_null(linked_list_remove_last(NULL, _value_1));
}
END_TEST

START_TEST (test_linked_list_remove_last_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_last(list, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_last(list, "foo"));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_2), _value_2);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_3), _value_3);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_null)
{
   ck_assert_ptr_null(linked_list_remove_all(NULL, _value_1));
}
END_TEST

START_TEST (test_linked_list_remove_all_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_all(list, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_all(list, "foo"));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_2), _value_2);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_3), _value_3);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);

   _verify_list(list, 1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

bool _match_value_1(void *value)
{
   return _value_1 == value;
}

bool _no_match(void *value)
{
   return false;
}

START_TEST (test_linked_list_remove_first_matching_null)
{
   ck_assert_ptr_null(linked_list_remove_first_matching(NULL, &_match_value_1));
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_first_matching(list, &_match_value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_first_matching(list, &_no_match));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_null)
{
   ck_assert_ptr_null(linked_list_remove_last_matching(NULL, &_match_value_1));
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_last_matching(list, &_match_value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_last_matching(list, &_no_match));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_null)
{
   linked_list_remove_all_matching(NULL, &_match_value_1);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_empty)
{
   linked_list_t *list = linked_list_new();
   linked_list_remove_all_matching(list, &_match_value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_all_matching(list, &_no_match);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_all_matching(list, &_match_value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);

   linked_list_remove_all_matching(list, &_match_value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_add(list, _value_1);

   linked_list_remove_all_matching(list, &_match_value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   linked_list_remove_all_matching(list, &_match_value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   linked_list_remove_all_matching(list, &_match_value_1);

   _verify_list(list, 1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_null)
{
   ck_assert_int_eq(linked_list_set_at(NULL, 0, _value_1) == true, 0);
}
END_TEST

START_TEST (test_linked_list_set_at_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_int_eq(linked_list_set_at(list, 0, _value_1) == true, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_invalid)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   ck_assert_int_eq(linked_list_set_at(list, 1, _value_2) == true, 0);

   linked_list_free(list, NULL);
}
END_TEST

static char *_replacement_value = "foo";

START_TEST (test_linked_list_set_at_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_int_eq(linked_list_set_at(list, 0, _replacement_value) == false, 0);

   _verify_list(list, 3, _replacement_value, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_int_eq(linked_list_set_at(list, 1, _replacement_value) == false, 0);

   _verify_list(list, 3, _value_1, _replacement_value, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_int_eq(linked_list_set_at(list, 2, _replacement_value) == false, 0);

   _verify_list(list, 3, _value_1, _value_2, _replacement_value);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_remove_null)
{
   ck_assert_ptr_null(linked_list_iterator_remove(NULL));
}
END_TEST

START_TEST (test_linked_list_iterator_remove_first)
{
   linked_list_t *list;
   linked_list_iterator_t *iterator;

   list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   iterator = linked_list_iterator(list, true);
   iterator = linked_list_iterator_remove(iterator);

   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_2);
   _verify_list(list, 2, _value_2, _value_3);

   linked_list_iterator_free(iterator);
   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_remove_middle)
{
   linked_list_t *list;
   linked_list_iterator_t *iterator;

   list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   iterator = linked_list_iterator(list, true);
   iterator = linked_list_iterator_next(iterator);
   iterator = linked_list_iterator_remove(iterator);

   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_3);
   _verify_list(list, 2, _value_1, _value_3);

   linked_list_iterator_free(iterator);
   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_remove_last)
{
   linked_list_t *list;
   linked_list_iterator_t *iterator;

   list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   iterator = linked_list_iterator(list, true);
   iterator = linked_list_iterator_next(iterator);
   iterator = linked_list_iterator_next(iterator);
   iterator = linked_list_iterator_remove(iterator);

   ck_assert_ptr_null(iterator);
   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_free_null)
{
   linked_list_iterator_free(NULL);
}
END_TEST

static size_t _foreach_count;
static void _foreach_fn(size_t index, void *value)
{
   _foreach_count++;
}

START_TEST (test_linked_list_foreach_null_list)
{
   linked_list_foreach(NULL, _foreach_fn);
}
END_TEST

START_TEST (test_linked_list_foreach_null_fn)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_foreach(list, NULL);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_foreach_valid)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   _foreach_count = 0;
   linked_list_foreach(list, &_foreach_fn);
   ck_assert_uint_eq(3, _foreach_count);

   linked_list_free(list, NULL);
}

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_linked_list_create);
   tcase_add_test(tc_core, test_linked_list_free);
   tcase_add_test(tc_core, test_linked_list_free_with_fn);
   tcase_add_test(tc_core, test_linked_list_add);
   tcase_add_test(tc_core, test_linked_list_insert_empty);
   tcase_add_test(tc_core, test_linked_list_insert_first);
   tcase_add_test(tc_core, test_linked_list_insert_middle);
   tcase_add_test(tc_core, test_linked_list_insert_last);
   tcase_add_test(tc_core, test_linked_list_insert_invalid);
   tcase_add_test(tc_core, test_linked_list_insert_null);
   tcase_add_test(tc_core, test_linked_list_get_invalid);
   tcase_add_test(tc_core, test_linked_list_get_null);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_null);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_function_null);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_no_match);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_with_match);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_null);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_function_null);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_no_match);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_with_match);
   tcase_add_test(tc_core, test_linked_list_remove_at_null);
   tcase_add_test(tc_core, test_linked_list_remove_at_empty);
   tcase_add_test(tc_core, test_linked_list_remove_at_invalid);
   tcase_add_test(tc_core, test_linked_list_remove_at_first);
   tcase_add_test(tc_core, test_linked_list_remove_at_middle);
   tcase_add_test(tc_core, test_linked_list_remove_at_last);
   tcase_add_test(tc_core, test_linked_list_remove_at_only);
   tcase_add_test(tc_core, test_linked_list_remove_first_null);
   tcase_add_test(tc_core, test_linked_list_remove_first_empty);
   tcase_add_test(tc_core, test_linked_list_remove_first_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_first_first);
   tcase_add_test(tc_core, test_linked_list_remove_first_middle);
   tcase_add_test(tc_core, test_linked_list_remove_first_last);
   tcase_add_test(tc_core, test_linked_list_remove_first_only);
   tcase_add_test(tc_core, test_linked_list_remove_first_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_last_null);
   tcase_add_test(tc_core, test_linked_list_remove_last_empty);
   tcase_add_test(tc_core, test_linked_list_remove_last_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_last_first);
   tcase_add_test(tc_core, test_linked_list_remove_last_middle);
   tcase_add_test(tc_core, test_linked_list_remove_last_last);
   tcase_add_test(tc_core, test_linked_list_remove_last_only);
   tcase_add_test(tc_core, test_linked_list_remove_last_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_all_null);
   tcase_add_test(tc_core, test_linked_list_remove_all_empty);
   tcase_add_test(tc_core, test_linked_list_remove_all_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_all_first);
   tcase_add_test(tc_core, test_linked_list_remove_all_middle);
   tcase_add_test(tc_core, test_linked_list_remove_all_last);
   tcase_add_test(tc_core, test_linked_list_remove_all_only);
   tcase_add_test(tc_core, test_linked_list_remove_all_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_null);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_empty);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_first);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_middle);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_last);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_only);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_null);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_empty);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_first);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_middle);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_last);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_only);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_null);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_empty);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_first);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_middle);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_last);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_only);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_multiple);
   tcase_add_test(tc_core, test_linked_list_set_at_null);
   tcase_add_test(tc_core, test_linked_list_set_at_empty);
   tcase_add_test(tc_core, test_linked_list_set_at_invalid);
   tcase_add_test(tc_core, test_linked_list_set_at_first);
   tcase_add_test(tc_core, test_linked_list_set_at_middle);
   tcase_add_test(tc_core, test_linked_list_set_at_last);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_null);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_first);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_middle);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_last);
   tcase_add_test(tc_core, test_linked_list_iterator_free_null);
   tcase_add_test(tc_core, test_linked_list_foreach_null_list);
   tcase_add_test(tc_core, test_linked_list_foreach_null_fn);
   tcase_add_test(tc_core, test_linked_list_foreach_valid);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

./include/libretro-common/test/queues/test_generic_queue.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_generic_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <check.h>
#include <stdarg.h>
#include <stdlib.h>

#include <queues/generic_queue.h>

#define SUITE_NAME "Generic Queue"

static char *_value_1 = "value1";
static char *_value_2 = "value2";
static char *_value_3 = "value3";

START_TEST (test_generic_queue_create)
{
   generic_queue_t *queue = generic_queue_new();
   ck_assert_ptr_nonnull(queue);
   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_free)
{
   generic_queue_t *queue = generic_queue_new();
   generic_queue_free(queue, NULL);
   generic_queue_free(NULL, NULL);
}
END_TEST

START_TEST (test_generic_queue_push_pop)
{
   generic_queue_t *queue;
   char *value;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_pop(queue);
   ck_assert_ptr_eq(value, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_push(queue, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   generic_queue_push(queue, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 2);
   value = (char *) generic_queue_pop(queue);
   ck_assert_ptr_eq(value, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_pop(queue);
   ck_assert_ptr_eq(value, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_peek)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   ck_assert_ptr_null(generic_queue_peek(queue));
   ck_assert_ptr_null(generic_queue_peek_first(queue));

   generic_queue_push(queue, _value_1);
   ck_assert_ptr_eq(_value_1, generic_queue_peek(queue));
   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));

   generic_queue_push(queue, _value_2);
   ck_assert_ptr_eq(_value_2, generic_queue_peek(queue));
   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));

   generic_queue_push(queue, _value_3);
   ck_assert_ptr_eq(_value_3, generic_queue_peek(queue));
   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));

   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_shift_unshift)
{
   generic_queue_t *queue;
   char *value;

   queue = generic_queue_new();
   generic_queue_shift(queue, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_unshift(queue);
   ck_assert_ptr_eq(value, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_shift(queue, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   generic_queue_shift(queue, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 2);
   value = (char *) generic_queue_unshift(queue);
   ck_assert_ptr_eq(value, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_unshift(queue);
   ck_assert_ptr_eq(value, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_empty)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   ck_assert_ptr_null(generic_queue_pop(queue));
   ck_assert_ptr_null(generic_queue_unshift(queue));
   generic_queue_free(queue, NULL);
}
END_TEST

void _free_value(void *value)
{
   return;
}

START_TEST (test_generic_queue_iterator)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, true);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_null(iterator);

   iterator = generic_queue_iterator(queue, false);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_null(iterator);

   generic_queue_free(queue, &_free_value);
}
END_TEST

START_TEST (test_generic_queue_shift_free)
{
   generic_queue_t *queue;

   queue = generic_queue_new();

   generic_queue_shift(queue, _value_1);
   generic_queue_shift(queue, _value_2);
   generic_queue_shift(queue, _value_3);

   generic_queue_free(queue, &_free_value);
}
END_TEST

START_TEST (test_generic_queue_remove_one)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);

   iterator = generic_queue_iterator(queue, true);
   iterator = generic_queue_iterator_remove(iterator);
   ck_assert_ptr_null(iterator);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_free(queue, NULL);
}
END_TEST

static void _verify_queue_values(generic_queue_t *queue, int count, ...)
{
   va_list values_list;
   void **values;
   int i;
   generic_queue_iterator_t *iterator;

   values = (void **)malloc(count * sizeof(void *));

   ck_assert_int_eq(count, generic_queue_length(queue));

   va_start(values_list, count);
   for (i = 0; i < count; i++)
      values[i] = va_arg(values_list, void *);
   va_end(values_list);

   iterator = generic_queue_iterator(queue, true);
   for (i = 0; i < count; i++)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));
      iterator = generic_queue_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   iterator = generic_queue_iterator(queue, false);
   for (i = count - 1; i >= 0; i--)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));
      iterator = generic_queue_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   free(values);
}

START_TEST (test_generic_queue_iterator_remove_first)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, true);
   iterator = generic_queue_iterator_remove(iterator);
   generic_queue_iterator_free(iterator);

   _verify_queue_values(queue, 2, _value_2, _value_3);

   generic_queue_free(queue, &_free_value);
}
END_TEST

START_TEST (test_generic_queue_iterator_remove_middle)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, true);
   iterator = generic_queue_iterator_next(iterator);
   iterator = generic_queue_iterator_remove(iterator);
   generic_queue_iterator_free(iterator);

   _verify_queue_values(queue, 2, _value_1, _value_3);

   generic_queue_free(queue, &_free_value);
}
END_TEST

START_TEST (test_generic_queue_iterator_remove_last)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, false);
   iterator = generic_queue_iterator_remove(iterator);
   generic_queue_iterator_free(iterator);

   _verify_queue_values(queue, 2, _value_1, _value_2);

   generic_queue_free(queue, &_free_value);
}
END_TEST

START_TEST (test_generic_queue_remove_first)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   ck_assert_ptr_eq(generic_queue_remove(queue, _value_1), _value_1);

   _verify_queue_values(queue, 2, _value_2, _value_3);

   generic_queue_free(queue, &_free_value);
}

START_TEST (test_generic_queue_remove_middle)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   ck_assert_ptr_eq(generic_queue_remove(queue, _value_2), _value_2);

   _verify_queue_values(queue, 2, _value_1, _value_3);

   generic_queue_free(queue, &_free_value);
}

START_TEST (test_generic_queue_remove_last)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   ck_assert_ptr_eq(generic_queue_remove(queue, _value_3), _value_3);

   _verify_queue_values(queue, 2, _value_1, _value_2);

   generic_queue_free(queue, &_free_value);
}

START_TEST (test_generic_queue_iterator_free)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   iterator = generic_queue_iterator(queue, true);

   generic_queue_iterator_free(iterator);
   generic_queue_iterator_free(NULL);

   generic_queue_free(queue, _free_value);
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_generic_queue_create);
   tcase_add_test(tc_core, test_generic_queue_free);
   tcase_add_test(tc_core, test_generic_queue_push_pop);
   tcase_add_test(tc_core, test_generic_queue_peek);
   tcase_add_test(tc_core, test_generic_queue_shift_unshift);
   tcase_add_test(tc_core, test_generic_queue_empty);
   tcase_add_test(tc_core, test_generic_queue_iterator);
   tcase_add_test(tc_core, test_generic_queue_shift_free);
   tcase_add_test(tc_core, test_generic_queue_remove_one);
   tcase_add_test(tc_core, test_generic_queue_iterator_remove_first);
   tcase_add_test(tc_core, test_generic_queue_iterator_remove_middle);
   tcase_add_test(tc_core, test_generic_queue_iterator_remove_last);
   tcase_add_test(tc_core, test_generic_queue_remove_first);
   tcase_add_test(tc_core, test_generic_queue_remove_middle);
   tcase_add_test(tc_core, test_generic_queue_remove_last);
   tcase_add_test(tc_core, test_generic_queue_iterator_free);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
	int num_fail;
	Suite *s = create_suite();
	SRunner *sr = srunner_create(s);
	srunner_run_all(sr, CK_NORMAL);
	num_fail = srunner_ntests_failed(sr);
	srunner_free(sr);
	return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

./include/libretro-common/test/string/test_stdstring.c

/* Copyright  (C) 2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <check.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#include <string/stdstring.h>
#include <encodings/utf.h>

#define SUITE_NAME "stdstring"

START_TEST (test_string_filter)
{
   char test1[] = "foo bar some string";
   char test2[] = "";
   string_remove_all_chars(test1, 's');
   string_remove_all_chars(test2, '0');
   string_remove_all_chars(NULL, 'a');
   ck_assert(!strcmp(test1, "foo bar ome tring"));
   ck_assert(!strcmp(test2, ""));
}
END_TEST

START_TEST (test_string_replace)
{
   char test1[] = "foo bar some string";
   string_replace_all_chars(test1, 's', 'S');
   string_replace_all_chars(NULL, 'a', 'A');
   ck_assert(!strcmp(test1, "foo bar Some String"));
}
END_TEST

START_TEST (test_string_case)
{
   char test1[] = "foo";
   char test2[] = "01foOo[]_";
   ck_assert(!strcmp(string_to_upper(test1), "FOO"));
   ck_assert(!strcmp(string_to_upper(test2), "01FOOO[]_"));
   ck_assert(!strcmp(string_to_lower(test2), "01fooo[]_"));
}
END_TEST

START_TEST (test_string_char_classify)
{
   ck_assert(ISSPACE(' '));
   ck_assert(ISSPACE('\n'));
   ck_assert(ISSPACE('\r'));
   ck_assert(ISSPACE('\t'));
   ck_assert(!ISSPACE('a'));

   ck_assert(ISALPHA('a'));
   ck_assert(ISALPHA('Z'));
   ck_assert(!ISALPHA('5'));

   ck_assert(ISALNUM('a'));
   ck_assert(ISALNUM('Z'));
   ck_assert(ISALNUM('5'));
}
END_TEST

START_TEST (test_string_num_conv)
{
   ck_assert_uint_eq(3, string_to_unsigned("3"));
   ck_assert_uint_eq(2147483647, string_to_unsigned("2147483647"));
   ck_assert_uint_eq(0, string_to_unsigned("foo"));
   ck_assert_uint_eq(0, string_to_unsigned("-1"));
   ck_assert_uint_eq(0, string_to_unsigned(NULL));

   ck_assert_uint_eq(10, string_hex_to_unsigned("0xa"));
   ck_assert_uint_eq(10, string_hex_to_unsigned("a"));
   ck_assert_uint_eq(255, string_hex_to_unsigned("FF"));
   ck_assert_uint_eq(255, string_hex_to_unsigned("0xff"));
   ck_assert_uint_eq(0, string_hex_to_unsigned("0xfzzf"));
   ck_assert_uint_eq(0, string_hex_to_unsigned("0x"));
   ck_assert_uint_eq(0, string_hex_to_unsigned("0xx"));
   ck_assert_uint_eq(0, string_hex_to_unsigned(NULL));
}
END_TEST

START_TEST (test_string_tokenizer)
{
   char *testinput = "@@1@@2@@3@@@@9@@@";
   char **ptr = &testinput;
   char *token = NULL;
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, ""));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "1"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "2"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "3"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, ""));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "9"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "@"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token == NULL);
}
END_TEST

START_TEST (test_string_replacesubstr)
{
   char *res = string_replace_substring("foobaarhellowooorldtest", "oo", "ooo");
   ck_assert(res != NULL);
   ck_assert(!strcmp(res, "fooobaarhellowoooorldtest"));
   free(res);
}
END_TEST

START_TEST (test_string_trim)
{
   char test1[] = "\t \t\nhey there \n \n";
   char test2[] = "\t \t\nhey there \n \n";
   char test3[] = "\t \t\nhey there \n \n";
   ck_assert(string_trim_whitespace_left(test1) ==  (char*)test1);
   ck_assert(!strcmp(test1, "hey there \n \n"));
   ck_assert(string_trim_whitespace_right(test2) ==  (char*)test2);
   ck_assert(!strcmp(test2, "\t \t\nhey there"));
   ck_assert(string_trim_whitespace(test3) ==  (char*)test3);
   ck_assert(!strcmp(test3, "hey there"));
}
END_TEST

START_TEST (test_string_comparison)
{
   ck_assert(memcmp("foo", "bar", 3)   != 0);
   ck_assert(memcmp("foo2", "foo2", 4) == 0);
   ck_assert(memcmp("foo1", "foo2", 4) != 0);
   ck_assert(memcmp("foo1", "foo2", 3) == 0);
}
END_TEST

START_TEST (test_word_wrap)
{
   const char *testtxt = (
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam nec "
      "enim quis orci euismod efficitur at nec arcu. Vivamus imperdiet est "
      "feugiat massa rhoncus porttitor at vitae ante. Nunc a orci vel ipsum "
      "tempor posuere sed a lacus. Ut erat odio, ultrices vitae iaculis "
      "fringilla, iaculis ut eros.\nSed facilisis viverra lectus et "
      "ullamcorper. Aenean risus ex, ornare eget scelerisque ac, imperdiet eu "
      "ipsum. Morbi pellentesque erat metus, sit amet aliquet libero rutrum "
      "et. Integer non ullamcorper tellus.");
   const char *expected = (
      "Lorem ipsum dolor sit amet, consectetur\n"
      "adipiscing elit. Nam nec enim quis orci\n"
      "euismod efficitur at nec arcu. Vivamus\n"
      "imperdiet est feugiat massa rhoncus\n"
      "porttitor at vitae ante. Nunc a orci\n"
      "vel ipsum tempor posuere sed a lacus.\n"
      "Ut erat odio, ultrices vitae iaculis\n"
      "fringilla, iaculis ut eros.\n"
      "Sed facilisis viverra lectus et\n"
      "ullamcorper. "
      "Aenean risus ex, ornare eget scelerisque ac, imperdiet eu ipsum. Morbi "
      "pellentesque erat metus, sit amet aliquet libero rutrum et. Integer "
      "non ullamcorper tellus.");

   char output[1024];

   word_wrap(output, sizeof(output), testtxt, strlen(testtxt), 40, 100, 10);
   ck_assert(!strcmp(output, expected));
}
END_TEST

START_TEST (test_strlcpy)
{
   char buf1[8];
   ck_assert_uint_eq(3, strlcpy(buf1, "foo", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foo", 4));
   ck_assert_uint_eq(11, strlcpy(buf1, "foo12345678", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foo1234", 8));
}
END_TEST

START_TEST (test_strlcat)
{
   char buf1[8];
   buf1[0] = 'f';
   buf1[1] = '\0';
   ck_assert_uint_eq(10, strlcat(buf1, "ooooooooo", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foooooo\0", 8));
   ck_assert_uint_eq(13, strlcat(buf1, "123456", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foooooo\0", 8));
}
END_TEST

START_TEST (test_strldup)
{
   char buf1[8] = "foo";
   char *tv1 = strldup(buf1, 16);
   char *tv2 = strldup(buf1, 2);
   ck_assert(tv1 != (char*)buf1);
   ck_assert(tv2 != (char*)buf1);
   ck_assert_uint_eq(strlen(tv2), 1);
   ck_assert(tv2[0] == 'f' && tv2[1] == 0);
   free(tv1);
   free(tv2);
}
END_TEST

START_TEST (test_utf8_conv_utf32)
{
   uint32_t output[12];
   const char test1[] = "aæ⠻จйγチℝ\xff";
   ck_assert_uint_eq(8, utf8_conv_utf32(output, 12, test1, strlen(test1)));
   ck_assert_uint_eq(97, output[0]);
   ck_assert_uint_eq(230, output[1]);
   ck_assert_uint_eq(10299, output[2]);
   ck_assert_uint_eq(3592, output[3]);
   ck_assert_uint_eq(1081, output[4]);
   ck_assert_uint_eq(947, output[5]);
   ck_assert_uint_eq(12481, output[6]);
   ck_assert_uint_eq(8477, output[7]);
}
END_TEST

START_TEST (test_utf8_util)
{
   const char *test1 = "aæ⠻จ𠀤";
   const char **tptr = &test1;
   char out[64];
   ck_assert_uint_eq(utf8len(test1), 5);
   ck_assert_uint_eq(utf8len(NULL), 0);
   ck_assert(&test1[1 + 2 + 3] == utf8skip(test1, 3));

   ck_assert_uint_eq(97, utf8_walk(tptr));
   ck_assert_uint_eq(230, utf8_walk(tptr));
   ck_assert_uint_eq(10299, utf8_walk(tptr));
   ck_assert_uint_eq(3592, utf8_walk(tptr));
   ck_assert_uint_eq(131108, utf8_walk(tptr));

#if 0
   ck_assert_uint_eq(1, utf8cpy(out, 64, test1, 1));
#endif
}
END_TEST

START_TEST (test_utf16_conv)
{
   const uint16_t test1[] = {0x0061, 0x00e6, 0x283b, 0x0e08, 0xd840, 0xdc24};
   char out[64];
   size_t outlen = sizeof(out);
   ck_assert(utf16_conv_utf8((uint8_t*)out, &outlen, test1, sizeof(test1) / 2));
   ck_assert_uint_eq(outlen, 13);
   ck_assert(!memcmp(out, "aæ⠻จ𠀤", 13));
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_string_comparison);
   tcase_add_test(tc_core, test_string_num_conv);
   tcase_add_test(tc_core, test_string_char_classify);
   tcase_add_test(tc_core, test_string_case);
   tcase_add_test(tc_core, test_string_filter);
   tcase_add_test(tc_core, test_string_replace);
   tcase_add_test(tc_core, test_string_tokenizer);
   tcase_add_test(tc_core, test_string_trim);
   tcase_add_test(tc_core, test_string_replacesubstr);
   tcase_add_test(tc_core, test_word_wrap);
   tcase_add_test(tc_core, test_strlcpy);
   tcase_add_test(tc_core, test_strlcat);
   tcase_add_test(tc_core, test_strldup);
   tcase_add_test(tc_core, test_utf8_conv_utf32);
   tcase_add_test(tc_core, test_utf16_conv);
   tcase_add_test(tc_core, test_utf8_util);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

./include/libretro-common/test/utils/test_utils.c

/* Copyright  (C) 2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <check.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#include <utils/md5.h>
#include <encodings/crc32.h>
#include <streams/file_stream.h>

#define SUITE_NAME "hash"

START_TEST (test_md5)
{
   uint8_t output[16];
   MD5_CTX ctx;
   MD5_Init(&ctx);
   MD5_Final(output, &ctx);
   ck_assert(!memcmp(
      "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e",
      output, 16));
   MD5_Init(&ctx);
   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Final(output, &ctx);
   ck_assert(!memcmp(
      "\x9e\x10\x7d\x9d\x37\x2b\xb6\x82\x6b\xd8\x1d\x35\x42\xa4\x19\xd6",
      output, 16));
   MD5_Init(&ctx);
   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Final(output, &ctx);
   ck_assert(!memcmp(
      "\x4e\x67\xdb\x4a\x7a\x40\x6b\x0c\xfd\xad\xd8\x87\xcd\xe7\x88\x8e",
      output, 16));
}
END_TEST

START_TEST (test_crc32)
{
   char buf1[] = "retroarch";
   char buf2[] = "12345678";
   char buf3[] = "The quick brown fox jumps over the lazy dog";
   uint32_t test1 = encoding_crc32(0, (uint8_t*)buf1, strlen(buf1));
   uint32_t test2 = encoding_crc32(0, (uint8_t*)buf2, strlen(buf2));
   uint32_t test3 = encoding_crc32(0, (uint8_t*)buf3, strlen(buf3));
   ck_assert_uint_eq(0x3cae141a, test1);
   ck_assert_uint_eq(0x9ae0daaf, test2);
   ck_assert_uint_eq(0x414fa339, test3);
}
END_TEST

#define CRC32_BUFFER_SIZE 1048576
#define CRC32_MAX_MB 64

/**
 * Calculate a CRC32 from the first part of the given file.
 * "first part" being the first (CRC32_BUFFER_SIZE * CRC32_MAX_MB)
 * bytes.
 *
 * Returns: the crc32, or 0 if there was an error.
 */
static uint32_t file_crc32(uint32_t crc, const char *path)
{
   unsigned i;
   RFILE *file        = NULL;
   unsigned char *buf = NULL;
   if (!path)
      return 0;

   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))
      return 0;

   if (!(buf = (unsigned char*)malloc(CRC32_BUFFER_SIZE)))
   {
      filestream_close(file);
      return 0;
   }

   for (i = 0; i < CRC32_MAX_MB; i++)
   {
      int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);
      if (nread < 0)		
      {
         free(buf);
         filestream_close(file);
         return 0;
      }

      crc = encoding_crc32(crc, buf, (size_t)nread);
      if (filestream_eof(file))
         break;
   }
   free(buf);
   filestream_close(file);
   return crc;
}

START_TEST (test_crc32_file)
{
   char tmpfile[512];
   FILE *fd;
   tmpnam(tmpfile);
   fd = fopen(tmpfile, "wb");
   ck_assert(fd != NULL);
   fwrite("12345678", 1, 8, fd);
   fclose(fd);

   ck_assert_uint_eq(file_crc32(0, tmpfile), 0x9ae0daaf);
   /* Error checking */
   ck_assert_uint_eq(file_crc32(0, "/this/path/should/not/exist"), 0);
   ck_assert_uint_eq(file_crc32(0, NULL), 0);
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_md5);
   tcase_add_test(tc_core, test_crc32);
   tcase_add_test(tc_core, test_crc32_file);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

./include/libretro-common/time/rtime.c

/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtime.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#include <stdlib.h>
#endif

#include <string.h>
#include <time/rtime.h>

#ifdef HAVE_THREADS
/* TODO/FIXME - global */
slock_t *rtime_localtime_lock = NULL;
#endif

/* Must be called before using rtime_localtime() */
void rtime_init(void)
{
   rtime_deinit();
#ifdef HAVE_THREADS
   if (!rtime_localtime_lock)
      rtime_localtime_lock = slock_new();
#endif
}

/* Must be called upon program termination */
void rtime_deinit(void)
{
#ifdef HAVE_THREADS
   if (rtime_localtime_lock)
   {
      slock_free(rtime_localtime_lock);
      rtime_localtime_lock = NULL;
   }
#endif
}

/* Thread-safe wrapper for localtime() */
struct tm *rtime_localtime(const time_t *timep, struct tm *result)
{
   struct tm *time_info = NULL;

   /* Lock mutex */
#ifdef HAVE_THREADS
   slock_lock(rtime_localtime_lock);
#endif

   time_info = localtime(timep);
   if (time_info)
      memcpy(result, time_info, sizeof(struct tm));

   /* Unlock mutex */
#ifdef HAVE_THREADS
   slock_unlock(rtime_localtime_lock);
#endif

   return result;
}

./include/libretro-common/utils/debugbreak/debugbreak.c

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif

#if _WIN32_WINNT < 0x0501
#error Must target Windows NT 5.0.1 or later for DebugBreakProcess
#endif

#include <Windows.h>

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

/* Compile with this line:

gcc -o debugbreak -mno-cygwin -mthreads debugbreak.c

*/

static char errbuffer[256];

static const char *geterrstr(DWORD errcode)
{
size_t skip = 0;
DWORD chars;
chars = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errcode, 0, errbuffer, sizeof(errbuffer)-1, 0);
errbuffer[sizeof(errbuffer)-1] = 0;
if (chars) {
while (errbuffer[chars-1] == '\r' || errbuffer[chars-1] == '\n') {
errbuffer[--chars] = 0;
}
}
if (chars && errbuffer[chars-1] == '.') errbuffer[--chars] = 0;
if (chars >= 2 && errbuffer[0] == '%' && errbuffer[1] >= '0'
&& errbuffer[1] <= '9')
{
skip = 2;
while (chars > skip && errbuffer[skip] == ' ') ++skip;
if (chars >= skip+2 && errbuffer[skip] == 'i'
&& errbuffer[skip+1] == 's')
{
skip += 2;
while (chars > skip && errbuffer[skip] == ' ') ++skip;
}
}
if (chars > skip && errbuffer[skip] >= 'A' && errbuffer[skip] <= 'Z') {
errbuffer[skip] += 'a' - 'A';
}
return errbuffer+skip;
}

int main(int argc, char *argv[])
{
    HANDLE proc;
    unsigned proc_id = 0;
    BOOL break_result;

    if (argc != 2) {
        printf("Usage: debugbreak process_id_number\n");
        return 1;
    }
    proc_id = (unsigned) strtol(argv[1], NULL, 0);
    if (proc_id == 0) {
        printf("Invalid process id %u\n", proc_id);
        return 1;
    }
    proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)proc_id);
    if (proc == NULL) {
        DWORD lastError = GetLastError();
        printf("Failed to open process %u\n", proc_id);
        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
            geterrstr(lastError));
        return 1;
    }
    break_result = DebugBreakProcess(proc);
    if (!break_result) {
        DWORD lastError = GetLastError();
        printf("Failed to debug break process %u\n", proc_id);
        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
            geterrstr(lastError));
        CloseHandle(proc);
        return 1;
    }
    printf("DebugBreak sent successfully to process id %u\n", proc_id);
    CloseHandle(proc);
    return 0;
}

/* END debugbreak.c */

./include/libretro-common/utils/djb2.c

/* public domain */
/* gcc -O3 -o djb2 djb2.c */

#include <stdio.h>
#include <stdint.h>

static uint32_t djb2(const char* str)
{
   const unsigned char* aux = (const unsigned char*)str;
   uint32_t hash = 5381;

   while (*aux)
      hash = (hash << 5) + hash + *aux++;

   return hash;
}

int main(int argc, const char* argv[])
{
   int i;

   for (i = 1; i < argc; i++)
      printf( "0x%08xU: %s\n", djb2( argv[ i ] ), argv[ i ] );

   return 0;
}

./include/libretro-common/utils/md5.c

/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there's no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's.  No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible.  Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */
#include <lrc_hash.h>

#include <string.h>

/*
 * The basic MD5 functions.
 *
 * F and G are optimized compared to their RFC 1321 definitions for
 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
 * implementation.
 */
#define MD5_F(x, y, z)			((z) ^ ((x) & ((y) ^ (z))))
#define MD5_G(x, y, z)			((y) ^ ((z) & ((x) ^ (y))))
#define MD5_H(x, y, z)			(((x) ^ (y)) ^ (z))
#define MD5_H2(x, y, z)			((x) ^ ((y) ^ (z)))
#define MD5_I(x, y, z)			((y) ^ ((x) | ~(z)))

/*
 * The MD5 transformation for all four rounds.
 */
#define MD5_STEP(f, a, b, c, d, x, t, s) \
	(a) += f((b), (c), (d)) + (x) + (t); \
	(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
	(a) += (b);

/*
 * MD5_SET reads 4 input bytes in little-endian byte order and stores them
 * in a properly aligned word in host byte order.
 *
 * The check for little-endian architectures that tolerate unaligned
 * memory accesses is just an optimization.  Nothing will break if it
 * doesn't work.
 */
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define MD5_SET(n) \
	(*(MD5_u32plus *)&ptr[(n) * 4])
#define MD5_GET(n) \
	MD5_SET(n)
#else
#define MD5_SET(n) \
	(ctx->block[(n)] = \
	(MD5_u32plus)ptr[(n) * 4] | \
	((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
	((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
	((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define MD5_GET(n) \
	(ctx->block[(n)])
#endif

/*
 * This processes one or more 64-byte data blocks, but does NOT update
 * the bit counters.  There are no alignment requirements.
 */
static const void *MD5_body(MD5_CTX *ctx, const void *data, unsigned long size)
{
	MD5_u32plus saved_a, saved_b, saved_c, saved_d;
	const unsigned char *ptr = (const unsigned char *)data;
	MD5_u32plus a = ctx->a;
	MD5_u32plus b = ctx->b;
	MD5_u32plus c = ctx->c;
	MD5_u32plus d = ctx->d;

	do {
		saved_a = a;
		saved_b = b;
		saved_c = c;
		saved_d = d;

/* Round 1 */
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(3), 0xc1bdceee, 22)
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(4), 0xf57c0faf, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(5), 0x4787c62a, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(6), 0xa8304613, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(7), 0xfd469501, 22)
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(8), 0x698098d8, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(9), 0x8b44f7af, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(10), 0xffff5bb1, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(11), 0x895cd7be, 22)
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(12), 0x6b901122, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(13), 0xfd987193, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22)

/* Round 2 */
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(0), 0xe9b6c7aa, 20)
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(5), 0xd62f105d, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(10), 0x02441453, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(15), 0xd8a1e681, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(4), 0xe7d3fbc8, 20)
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(9), 0x21e1cde6, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(14), 0xc33707d6, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(3), 0xf4d50d87, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(8), 0x455a14ed, 20)
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(13), 0xa9e3e905, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(2), 0xfcefa3f8, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20)

/* Round 3 */
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(14), 0xfde5380c, 23)
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(1), 0xa4beea44, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(4), 0x4bdecfa9, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(7), 0xf6bb4b60, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(10), 0xbebfbc70, 23)
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(13), 0x289b7ec6, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(0), 0xeaa127fa, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(3), 0xd4ef3085, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(6), 0x04881d05, 23)
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(9), 0xd9d4d039, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(12), 0xe6db99e5, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23)

/* Round 4 */
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(5), 0xfc93a039, 21)
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(12), 0x655b59c3, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(3), 0x8f0ccc92, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(10), 0xffeff47d, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(1), 0x85845dd1, 21)
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(8), 0x6fa87e4f, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(15), 0xfe2ce6e0, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(6), 0xa3014314, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(13), 0x4e0811a1, 21)
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(4), 0xf7537e82, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(11), 0xbd3af235, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(2), 0x2ad7d2bb, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(9), 0xeb86d391, 21)

		a += saved_a;
		b += saved_b;
		c += saved_c;
		d += saved_d;

		ptr += 64;
	} while (size -= 64);

	ctx->a = a;
	ctx->b = b;
	ctx->c = c;
	ctx->d = d;

	return ptr;
}

void MD5_Init(MD5_CTX *ctx)
{
	ctx->a = 0x67452301;
	ctx->b = 0xefcdab89;
	ctx->c = 0x98badcfe;
	ctx->d = 0x10325476;

	ctx->lo = 0;
	ctx->hi = 0;
}

void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
{
	unsigned long used;
	MD5_u32plus saved_lo = ctx->lo;
	if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
		ctx->hi++;
	ctx->hi += size >> 29;

	used = saved_lo & 0x3f;

	if (used)
   {
      unsigned long available = 64 - used;

      if (size < available)
      {
         memcpy(&ctx->buffer[used], data, size);
         return;
      }

      memcpy(&ctx->buffer[used], data, available);
      data = (const unsigned char *)data + available;
      size -= available;
      MD5_body(ctx, ctx->buffer, 64);
   }

	if (size >= 64)
   {
      data = MD5_body(ctx, data, size & ~(unsigned long)0x3f);
      size &= 0x3f;
   }

	memcpy(ctx->buffer, data, size);
}

void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
	unsigned long available;
	unsigned long used = ctx->lo & 0x3f;

	ctx->buffer[used++] = 0x80;

	available = 64 - used;

	if (available < 8)
   {
      memset(&ctx->buffer[used], 0, available);
      MD5_body(ctx, ctx->buffer, 64);
      used = 0;
      available = 64;
   }

	memset(&ctx->buffer[used], 0, available - 8);

	ctx->lo <<= 3;
	ctx->buffer[56] = ctx->lo;
	ctx->buffer[57] = ctx->lo >> 8;
	ctx->buffer[58] = ctx->lo >> 16;
	ctx->buffer[59] = ctx->lo >> 24;
	ctx->buffer[60] = ctx->hi;
	ctx->buffer[61] = ctx->hi >> 8;
	ctx->buffer[62] = ctx->hi >> 16;
	ctx->buffer[63] = ctx->hi >> 24;

	MD5_body(ctx, ctx->buffer, 64);

	result[0] = ctx->a;
	result[1] = ctx->a >> 8;
	result[2] = ctx->a >> 16;
	result[3] = ctx->a >> 24;
	result[4] = ctx->b;
	result[5] = ctx->b >> 8;
	result[6] = ctx->b >> 16;
	result[7] = ctx->b >> 24;
	result[8] = ctx->c;
	result[9] = ctx->c >> 8;
	result[10] = ctx->c >> 16;
	result[11] = ctx->c >> 24;
	result[12] = ctx->d;
	result[13] = ctx->d >> 8;
	result[14] = ctx->d >> 16;
	result[15] = ctx->d >> 24;

	memset(ctx, 0, sizeof(*ctx));
}

./include/libretro-common/utils/sha1.c

/*
 *  sha1.h
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones <paulej@packetizer.com>
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This class implements the Secure Hashing Standard as defined
 *      in FIPS PUB 180-1 published April 17, 1995.
 *
 *      Many of the variable names in the SHA1Context, especially the
 *      single character names, were used because those were the names
 *      used in the publication.
 *
 *      Please read the file sha1.c for more information.
 *
 */

#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include <string/stdstring.h>

#ifndef _SHA1_H_
#define _SHA1_H_

/*
 *  This structure will hold context information for the hashing
 *  operation
 */
typedef struct SHA1Context
{
   unsigned Message_Digest[5]; /* Message Digest (output)          */

   unsigned Length_Low;        /* Message length in bits           */
   unsigned Length_High;       /* Message length in bits           */

   unsigned char Message_Block[64]; /* 512-bit message blocks      */
   int Message_Block_Index;    /* Index into message block array   */

   int Computed;               /* Is the digest computed?          */
   int Corrupted;              /* Is the message digest corruped?  */
} SHA1Context;

/*
 *  Function Prototypes
 */
void SHA1Reset(SHA1Context *);
int SHA1Result(SHA1Context *);
void SHA1Input( SHA1Context *,
      const unsigned char *,
      unsigned);

#endif

/*
 *  sha1.c
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones <paulej@packetizer.com>
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This file implements the Secure Hashing Standard as defined
 *      in FIPS PUB 180-1 published April 17, 1995.
 *
 *      The Secure Hashing Standard, which uses the Secure Hashing
 *      Algorithm (SHA), produces a 160-bit message digest for a
 *      given data stream.  In theory, it is highly improbable that
 *      two messages will produce the same message digest.  Therefore,
 *      this algorithm can serve as a means of providing a "fingerprint"
 *      for a message.
 *
 *  Portability Issues:
 *      SHA-1 is defined in terms of 32-bit "words".  This code was
 *      written with the expectation that the processor has at least
 *      a 32-bit machine word size.  If the machine word size is larger,
 *      the code should still function properly.  One caveat to that
 *      is that the input functions taking characters and character
 *      arrays assume that only 8 bits of information are stored in each
 *      character.
 *
 *  Caveats:
 *      SHA-1 is designed to work with messages less than 2^64 bits
 *      long. Although SHA-1 allows a message digest to be generated for
 *      messages of any number of bits less than 2^64, this
 *      implementation only works with messages with a length that is a
 *      multiple of the size of an 8-bit character.
 *
 */

/*#include "sha1.h"*/

/*
 *  Define the circular shift macro
 */
#define SHA1CircularShift(bits,word) \
                ((((word) << (bits)) & 0xFFFFFFFF) | \
                ((word) >> (32-(bits))))

/* Function prototypes */
void SHA1ProcessMessageBlock(SHA1Context *);
void SHA1PadMessage(SHA1Context *);

/*
 *  SHA1Reset
 *
 *  Description:
 *      This function will initialize the SHA1Context in preparation
 *      for computing a new message digest.
 *
 *  Parameters:
 *      context: [in/out]
 *          The context to reset.
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void SHA1Reset(SHA1Context *context)
{
   context->Length_Low             = 0;
   context->Length_High            = 0;
   context->Message_Block_Index    = 0;

   context->Message_Digest[0]      = 0x67452301;
   context->Message_Digest[1]      = 0xEFCDAB89;
   context->Message_Digest[2]      = 0x98BADCFE;
   context->Message_Digest[3]      = 0x10325476;
   context->Message_Digest[4]      = 0xC3D2E1F0;

   context->Computed   = 0;
   context->Corrupted  = 0;
}

/*
 *  SHA1Result
 *
 *  Description:
 *      This function will return the 160-bit message digest into the
 *      Message_Digest array within the SHA1Context provided
 *
 *  Parameters:
 *      context: [in/out]
 *          The context to use to calculate the SHA-1 hash.
 *
 *  Returns:
 *      1 if successful, 0 if it failed.
 *
 *  Comments:
 *
 */
int SHA1Result(SHA1Context *context)
{
   if (context->Corrupted)
      return 0;

   if (!context->Computed)
   {
      SHA1PadMessage(context);
      context->Computed = 1;
   }

   return 1;
}

/*
 *  SHA1Input
 *
 *  Description:
 *      This function accepts an array of octets as the next portion of
 *      the message.
 *
 *  Parameters:
 *      context: [in/out]
 *          The SHA-1 context to update
 *      message_array: [in]
 *          An array of characters representing the next portion of the
 *          message.
 *      length: [in]
 *          The length of the message in message_array
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void SHA1Input(     SHA1Context         *context,
                    const unsigned char *message_array,
                    unsigned            length)
{
   if (!length)
      return;

   if (context->Computed || context->Corrupted)
   {
      context->Corrupted = 1;
      return;
   }

   while(length-- && !context->Corrupted)
   {
      context->Message_Block[context->Message_Block_Index++] =
         (*message_array & 0xFF);

      context->Length_Low += 8;
      /* Force it to 32 bits */
      context->Length_Low &= 0xFFFFFFFF;
      if (context->Length_Low == 0)
      {
         context->Length_High++;
         /* Force it to 32 bits */
         context->Length_High &= 0xFFFFFFFF;
         /* Message is too long */
         if (context->Length_High == 0)
            context->Corrupted = 1;
      }

      if (context->Message_Block_Index == 64)
         SHA1ProcessMessageBlock(context);

      message_array++;
   }
}

/*
 *  SHA1ProcessMessageBlock
 *
 *  Description:
 *      This function will process the next 512 bits of the message
 *      stored in the Message_Block array.
 *
 *  Parameters:
 *      None.
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *      Many of the variable names in the SHAContext, especially the
 *      single character names, were used because those were the names
 *      used in the publication.
 *
 *
 */
void SHA1ProcessMessageBlock(SHA1Context *context)
{
   const unsigned K[] =            /* Constants defined in SHA-1   */
   {
      0x5A827999,
      0x6ED9EBA1,
      0x8F1BBCDC,
      0xCA62C1D6
   };
   int         t;                  /* Loop counter                 */
   unsigned    temp;               /* Temporary word value         */
   unsigned    W[80];              /* Word sequence                */
   unsigned    A, B, C, D, E;      /* Word buffers                 */

   /*
    *  Initialize the first 16 words in the array W
    */
   for (t = 0; t < 16; t++)
   {
      W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
      W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
      W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
      W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
   }

   for (t = 16; t < 80; t++)
      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);

   A = context->Message_Digest[0];
   B = context->Message_Digest[1];
   C = context->Message_Digest[2];
   D = context->Message_Digest[3];
   E = context->Message_Digest[4];

   for (t = 0; t < 20; t++)
   {
      temp =  SHA1CircularShift(5,A) +
         ((B & C) | ((~B) & D)) + E + W[t] + K[0];
      temp &= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   for (t = 20; t < 40; t++)
   {
      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
      temp &= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   for (t = 40; t < 60; t++)
   {
      temp = SHA1CircularShift(5,A) +
         ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
      temp &= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   for (t = 60; t < 80; t++)
   {
      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
      temp &= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   context->Message_Digest[0] =
      (context->Message_Digest[0] + A) & 0xFFFFFFFF;
   context->Message_Digest[1] =
      (context->Message_Digest[1] + B) & 0xFFFFFFFF;
   context->Message_Digest[2] =
      (context->Message_Digest[2] + C) & 0xFFFFFFFF;
   context->Message_Digest[3] =
      (context->Message_Digest[3] + D) & 0xFFFFFFFF;
   context->Message_Digest[4] =
      (context->Message_Digest[4] + E) & 0xFFFFFFFF;

   context->Message_Block_Index = 0;
}

/*
 *  SHA1PadMessage
 *
 *  Description:
 *      According to the standard, the message must be padded to an even
 *      512 bits.  The first padding bit must be a '1'.  The last 64
 *      bits represent the length of the original message.  All bits in
 *      between should be 0.  This function will pad the message
 *      according to those rules by filling the Message_Block array
 *      accordingly.  It will also call SHA1ProcessMessageBlock()
 *      appropriately.  When it returns, it can be assumed that the
 *      message digest has been computed.
 *
 *  Parameters:
 *      context: [in/out]
 *          The context to pad
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void SHA1PadMessage(SHA1Context *context)
{
   /*
    *  Check to see if the current message block is too small to hold
    *  the initial padding bits and length.  If so, we will pad the
    *  block, process it, and then continue padding into a second
    *  block.
    */
   if (context->Message_Block_Index > 55)
   {
      context->Message_Block[context->Message_Block_Index++] = 0x80;
      while(context->Message_Block_Index < 64)
         context->Message_Block[context->Message_Block_Index++] = 0;

      SHA1ProcessMessageBlock(context);

      while(context->Message_Block_Index < 56)
         context->Message_Block[context->Message_Block_Index++] = 0;
   }
   else
   {
      context->Message_Block[context->Message_Block_Index++] = 0x80;
      while(context->Message_Block_Index < 56)
         context->Message_Block[context->Message_Block_Index++] = 0;
   }

   /*
    *  Store the message length as the last 8 octets
    */
   context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
   context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
   context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
   context->Message_Block[59] = (context->Length_High) & 0xFF;
   context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
   context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
   context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
   context->Message_Block[63] = (context->Length_Low) & 0xFF;

   SHA1ProcessMessageBlock(context);
}

./include/libretro-common/vfs/vfs_implementation.c

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>

#include <string/stdstring.h> /* string_is_empty */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#if defined(_WIN32)
#  ifdef _MSC_VER
#    define setmode _setmode
#  endif
#include <sys/stat.h>
#  ifdef _XBOX
#    include <xtl.h>
#    define INVALID_FILE_ATTRIBUTES -1
#  else

#    include <fcntl.h>
#    include <direct.h>
#    include <windows.h>
#  endif
#    include <io.h>
#else
#  if defined(PSP)
#    include <pspiofilemgr.h>
#  endif
#  include <sys/types.h>
#  include <sys/stat.h>
#  if !defined(VITA)
#  include <dirent.h>
#  endif
#  include <unistd.h>
#  if defined(WIIU)
#  include <malloc.h>
#  endif
#endif

#include <fcntl.h>

/* TODO: Some things are duplicated but I'm really afraid of breaking other platforms by touching this */
#if defined(VITA)
#  include <psp2/io/fcntl.h>
#  include <psp2/io/dirent.h>
#  include <psp2/io/stat.h>
#elif !defined(_WIN32)
#  if defined(PSP)
#    include <pspiofilemgr.h>
#  endif
#  include <sys/types.h>
#  include <sys/stat.h>
#  include <dirent.h>
#  include <unistd.h>
#endif

#if defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */
#endif

#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifdef __HAIKU__
#include <kernel/image.h>
#endif
#ifndef __MACH__
#include <compat/strl.h>
#include <compat/posix_string.h>
#endif
#include <compat/strcasestr.h>
#include <retro_miscellaneous.h>
#include <encodings/utf.h>

#if defined(_WIN32)
#ifndef _XBOX
#if defined(_MSC_VER) && _MSC_VER <= 1200
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
#endif
#elif defined(VITA)
#define SCE_ERROR_ERRNO_EEXIST 0x80010011
#include <psp2/io/fcntl.h>
#include <psp2/io/dirent.h>
#include <psp2/io/stat.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif


#if defined(PSP)
#include <pspkernel.h>
#endif

#if defined(__PS3__) || defined(__PSL1GHT__)
#define FS_SUCCEEDED 0
#define FS_TYPE_DIR 1
#ifdef __PSL1GHT__
#include <lv2/sysfs.h>
#ifndef O_RDONLY
#define O_RDONLY SYS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY SYS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT SYS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC SYS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR SYS_O_RDWR
#endif
#else
#include <cell/cell_fs.h>
#ifndef O_RDONLY
#define O_RDONLY CELL_FS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY CELL_FS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT CELL_FS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC CELL_FS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR CELL_FS_O_RDWR
#endif
#ifndef sysFsStat
#define sysFsStat cellFsStat
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsOpendir
#define sysFsOpendir cellFsOpendir
#endif
#ifndef sysFsReaddir
#define sysFsReaddir cellFsReaddir
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsClosedir
#define sysFsClosedir cellFsClosedir
#endif
#endif
#endif

#if defined(VITA)
#define FIO_S_ISDIR SCE_S_ISDIR
#endif

#if defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */
#endif

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1400
#define ATLEAST_VC2005
#endif
#endif

#include <vfs/vfs_implementation.h>
#include <libretro.h>
#if defined(HAVE_MMAP)
#include <memmap.h>
#endif
#include <encodings/utf.h>
#include <compat/fopen_utf8.h>
#include <file/file_path.h>

#ifdef HAVE_CDROM
#include <vfs/vfs_implementation_cdrom.h>
#endif

#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
#endif

#define RFILE_HINT_UNBUFFERED (1 << 8)

int64_t retro_vfs_file_seek_internal(
      libretro_vfs_implementation_file *stream,
      int64_t offset, int whence)
{
   int64_t val;

   if (!stream)
      return -1;

   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
   {
#ifdef HAVE_CDROM
      if (stream->scheme == VFS_SCHEME_CDROM)
         return retro_vfs_file_seek_cdrom(stream, offset, whence);
#endif
#ifdef ATLEAST_VC2005
      /* VC2005 and up have a special 64-bit fseek */
      return _fseeki64(stream->fp, offset, whence);
#elif defined(HAVE_64BIT_OFFSETS)
      return fseeko(stream->fp, (off_t)offset, whence);
#else
      return fseek(stream->fp, (long)offset, whence);
#endif
   }
#ifdef HAVE_MMAP
   /* Need to check stream->mapped because this function is
    * called in filestream_open() */
   if (stream->mapped && stream->hints &
         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
   {
      /* fseek() returns error on under/overflow but
       * allows cursor > EOF for
       read-only file descriptors. */
      /* The file position must never be negative. */
      switch (whence)
      {
         case SEEK_SET:
            if (offset < 0)
               return -1;

            stream->mappos = offset;
            break;

         case SEEK_CUR:
            if (stream->mappos + offset < 0)
              return -1;

            stream->mappos += offset;
            break;

         case SEEK_END:
            /* RETRO_VFS_SEEK_POSITION_END states offset should be negative.
             * However, this is impractical because we would be forcing the
             * end of file to always be off by one.
             */
            if (offset > 0 || stream->mapsize + offset < 0)
               return -1;

            stream->mappos = stream->mapsize + offset;
            break;
      }
      return stream->mappos;
   }
#endif

   if ((val = lseek(stream->fd, (off_t)offset, whence)) < 0)
      return -1;

   return val;
}

/**
 * retro_vfs_file_open_impl:
 * @path               : path to file
 * @mode               : file mode to use when opening (read/write)
 * @hints              :
 *
 * Opens a file for reading or writing, depending on the requested mode.
 * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
 **/

libretro_vfs_implementation_file *retro_vfs_file_open_impl(
      const char *path, unsigned mode, unsigned hints)
{
   int                                flags = 0;
   const char                     *mode_str = NULL;
   libretro_vfs_implementation_file *stream =
      (libretro_vfs_implementation_file*)
      malloc(sizeof(*stream));

   if (!stream)
      return NULL;

   stream->fd                     = 0;
   stream->hints                  = hints;
   stream->size                   = 0;
   stream->buf                    = NULL;
   stream->fp                     = NULL;
#ifdef _WIN32
   stream->fh                     = 0;
#endif
   stream->orig_path              = NULL;
   stream->mappos                 = 0;
   stream->mapsize                = 0;
   stream->mapped                 = NULL;
   stream->scheme                 = VFS_SCHEME_NONE;

#ifdef VFS_FRONTEND
   if (     path
         && path[0] == 'v'
         && path[1] == 'f'
         && path[2] == 's'
         && path[3] == 'o'
         && path[4] == 'n'
         && path[5] == 'l'
         && path[6] == 'y'
         && path[7] == ':'
         && path[8] == '/'
         && path[9] == '/')
         path             += sizeof("vfsonly://")-1;
#endif

#ifdef HAVE_CDROM
   stream->cdrom.cue_buf          = NULL;
   stream->cdrom.cue_len          = 0;
   stream->cdrom.byte_pos         = 0;
   stream->cdrom.drive            = 0;
   stream->cdrom.cur_min          = 0;
   stream->cdrom.cur_sec          = 0;
   stream->cdrom.cur_frame        = 0;
   stream->cdrom.cur_track        = 0;
   stream->cdrom.cur_lba          = 0;
   stream->cdrom.last_frame_lba   = 0;
   stream->cdrom.last_frame[0]    = '\0';
   stream->cdrom.last_frame_valid = false;

   if (     path
         && path[0] == 'c'
         && path[1] == 'd'
         && path[2] == 'r'
         && path[3] == 'o'
         && path[4] == 'm'
         && path[5] == ':'
         && path[6] == '/'
         && path[7] == '/'
         && path[8] != '\0')
   {
      path             += sizeof("cdrom://")-1;
      stream->scheme    = VFS_SCHEME_CDROM;
   }
#endif

   if (path)
      stream->orig_path = strdup(path);

#ifdef HAVE_MMAP
   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS && mode == RETRO_VFS_FILE_ACCESS_READ)
      stream->hints |= RFILE_HINT_UNBUFFERED;
   else
#endif
      stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;

   switch (mode)
   {
      case RETRO_VFS_FILE_ACCESS_READ:
         mode_str = "rb";

         flags    = O_RDONLY;
#ifdef _WIN32
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_WRITE:
         mode_str = "wb";

         flags    = O_WRONLY | O_CREAT | O_TRUNC;
#if !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_READ_WRITE:
         mode_str = "w+b";
         flags    = O_RDWR | O_CREAT | O_TRUNC;
#if !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
      case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
         mode_str = "r+b";

         flags    = O_RDWR;
#if !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      default:
         goto error;
   }

   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
   {
      FILE *fp;
#ifdef HAVE_CDROM
      if (stream->scheme == VFS_SCHEME_CDROM)
      {
         retro_vfs_file_open_cdrom(stream, path, mode, hints);
#if defined(_WIN32) && !defined(_XBOX)
         if (!stream->fh)
            goto error;
#else
         if (!stream->fp)
            goto error;
#endif
      }
      else
#endif
      {
         if (!(fp = (FILE*)fopen_utf8(path, mode_str)))
         {
#ifdef IOS
            if (errno == EEXIST)
            {
               retro_vfs_file_remove_impl(path);
               fp = (FILE*)fopen_utf8(path, mode_str);
            }
            if (!fp)
#endif
            goto error;
         }

         stream->fp  = fp;
      }

      /* Regarding setvbuf:
       *
       * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
       *
       * If the size argument is not zero but buf is NULL,
       * a buffer of the given size will be allocated immediately, and
       * released on close. This is an extension to ANSI C.
       *
       * Since C89 does not support specifying a NULL buffer
       * with a non-zero size, we create and track our own buffer for it.
       */
      /* TODO: this is only useful for a few platforms,
       * find which and add ifdef */
#if defined(_3DS)
      if (stream->scheme != VFS_SCHEME_CDROM)
      {
         stream->buf = (char*)calloc(1, 0x10000);
         if (stream->fp)
            setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000);
      }
#elif defined(WIIU)
      if (stream->scheme != VFS_SCHEME_CDROM)
      {
         const int bufsize = 128 * 1024;
         stream->buf = (char*)memalign(0x40, bufsize);
         if (stream->fp)
            setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);
         stream->buf = (char*)calloc(1, 0x4000);
         if (stream->fp)
            setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
      }
#endif
   }
   else
   {
#if defined(_WIN32) && !defined(_XBOX)
#if defined(LEGACY_WIN32)
      char *path_local    = utf8_to_local_string_alloc(path);
      stream->fd          = open(path_local, flags, 0);
      if (path_local)
         free(path_local);
#else
      wchar_t * path_wide = utf8_to_utf16_string_alloc(path);
      stream->fd          = _wopen(path_wide, flags, 0);
      if (path_wide)
         free(path_wide);
#endif
#else
      stream->fd          = open(path, flags, 0);
#endif

      if (stream->fd == -1)
         goto error;

#ifdef HAVE_MMAP
      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
      {
         stream->mappos  = 0;
         stream->mapped  = NULL;
         stream->mapsize = retro_vfs_file_seek_internal(stream, 0, SEEK_END);

         if (stream->mapsize == (uint64_t)-1)
            goto error;

         retro_vfs_file_seek_internal(stream, 0, SEEK_SET);

         if ((stream->mapped = (uint8_t*)mmap((void*)0,
               stream->mapsize, PROT_READ,  MAP_SHARED, stream->fd, 0)) == MAP_FAILED)
            stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
      }
#endif
   }
#ifdef HAVE_CDROM
   if (stream->scheme == VFS_SCHEME_CDROM)
   {
      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
      retro_vfs_file_seek_cdrom(stream, 0, SEEK_END);

      stream->size = retro_vfs_file_tell_impl(stream);

      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
   }
   else
#endif
   {
      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
      retro_vfs_file_seek_internal(stream, 0, SEEK_END);

      stream->size = retro_vfs_file_tell_impl(stream);

      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
   }
   return stream;

error:
   retro_vfs_file_close_impl(stream);
   return NULL;
}

int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
{
   if (!stream)
      return -1;

#ifdef HAVE_CDROM
   if (stream->scheme == VFS_SCHEME_CDROM)
   {
      retro_vfs_file_close_cdrom(stream);
      goto end;
   }
#endif

   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
   {
      if (stream->fp)
         fclose(stream->fp);
   }
   else
   {
#ifdef HAVE_MMAP
      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
         munmap(stream->mapped, stream->mapsize);
#endif
   }

   if (stream->fd > 0)
      close(stream->fd);
#ifdef HAVE_CDROM
end:
   if (stream->cdrom.cue_buf)
      free(stream->cdrom.cue_buf);
#endif
   if (stream->buf)
      free(stream->buf);

   if (stream->orig_path)
      free(stream->orig_path);

   free(stream);

   return 0;
}

int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
{
#ifdef HAVE_CDROM
   if (stream->scheme == VFS_SCHEME_CDROM)
      return retro_vfs_file_error_cdrom(stream);
#endif
   return ferror(stream->fp);
}

int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
{
   if (stream)
      return stream->size;
   return 0;
}

int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t len)
{
#ifdef _WIN32
   if (stream && _chsize(_fileno(stream->fp), len) == 0)
   {
	   stream->size = len;
	   return 0;
   }
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
   if (stream && ftruncate(fileno(stream->fp), (off_t)len) == 0)
   {
      stream->size = len;
      return 0;
   }
#endif
   return -1;
}

int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
{
   int64_t val;

   if (!stream)
      return -1;

   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
   {
#ifdef HAVE_CDROM
      if (stream->scheme == VFS_SCHEME_CDROM)
         return retro_vfs_file_tell_cdrom(stream);
#endif
#ifdef ATLEAST_VC2005
      /* VC2005 and up have a special 64-bit ftell */
      return _ftelli64(stream->fp);
#elif defined(HAVE_64BIT_OFFSETS)
      return ftello(stream->fp);
#else
      return ftell(stream->fp);
#endif
   }
#ifdef HAVE_MMAP
   /* Need to check stream->mapped because this function
    * is called in filestream_open() */
   if (stream->mapped && stream->hints &
         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
      return stream->mappos;
#endif
   if ((val = lseek(stream->fd, 0, SEEK_CUR)) < 0)
      return -1;

   return val;
}

int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
      int64_t offset, int seek_position)
{
   return retro_vfs_file_seek_internal(stream, offset, seek_position);
}

int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
      void *s, uint64_t len)
{
   if (!stream || !s)
      return -1;

   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
   {
#ifdef HAVE_CDROM
      if (stream->scheme == VFS_SCHEME_CDROM)
         return retro_vfs_file_read_cdrom(stream, s, len);
#endif
      return fread(s, 1, (size_t)len, stream->fp);
   }
#ifdef HAVE_MMAP
   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
   {
      if (stream->mappos > stream->mapsize)
         return -1;

      if (stream->mappos + len > stream->mapsize)
         len = stream->mapsize - stream->mappos;

      memcpy(s, &stream->mapped[stream->mappos], len);
      stream->mappos += len;

      return len;
   }
#endif

   return read(stream->fd, s, (size_t)len);
}

int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
{
   int64_t pos = 0;
   ssize_t ret = -1;

   if (!stream)
      return -1;

   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
   {
      pos = retro_vfs_file_tell_impl(stream);
      ret = fwrite(s, 1, (size_t)len, stream->fp);

      if (ret != -1 && pos + ret > stream->size)
         stream->size = pos + ret;

      return ret;
   }
#ifdef HAVE_MMAP
   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
      return -1;
#endif

   pos = retro_vfs_file_tell_impl(stream);
   ret = write(stream->fd, s, (size_t)len);

   if (ret != -1 && pos + ret > stream->size)
      stream->size = pos + ret;

   return ret;
}

int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
{
   if (stream && fflush(stream->fp) == 0)
      return 0;
   return -1;
}

int retro_vfs_file_remove_impl(const char *path)
{
   if (path && *path)
   {
      int ret          = -1;
#if defined(_WIN32) && !defined(_XBOX)
      /* Win32 (no Xbox) */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
      char *path_local = NULL;
      if ((path_local = utf8_to_local_string_alloc(path)))
      {
         /* We need to check if path is a directory */
         if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
            ret = _rmdir(path_local);
         else
            ret = remove(path_local);
         free(path_local);
      }
#else
      wchar_t *path_wide = NULL;
      if ((path_wide = utf8_to_utf16_string_alloc(path)))
      {
         /* We need to check if path is a directory */
         if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
            ret = _wrmdir(path_wide);
         else
            ret = _wremove(path_wide);
         free(path_wide);
      }
#endif
#else
      ret = remove(path);
#endif
      if (ret == 0)
         return 0;
   }
   return -1;
}

int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
{
#if defined(_WIN32) && !defined(_XBOX)
   /* Win32 (no Xbox) */
   int ret                 = -1;
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
   char *old_path_local    = NULL;
#else
   wchar_t *old_path_wide  = NULL;
#endif

   if (!old_path || !*old_path || !new_path || !*new_path)
      return -1;

#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
   old_path_local = utf8_to_local_string_alloc(old_path);

   if (old_path_local)
   {
      char *new_path_local = utf8_to_local_string_alloc(new_path);

      if (new_path_local)
      {
         if (rename(old_path_local, new_path_local) == 0)
            ret = 0;
         free(new_path_local);
      }

      free(old_path_local);
   }
#else
   old_path_wide = utf8_to_utf16_string_alloc(old_path);

   if (old_path_wide)
   {
      wchar_t *new_path_wide = utf8_to_utf16_string_alloc(new_path);

      if (new_path_wide)
      {
         if (_wrename(old_path_wide, new_path_wide) == 0)
            ret = 0;
         free(new_path_wide);
      }

      free(old_path_wide);
   }
#endif
   return ret;

#else
   /* Every other platform */
   if (!old_path || !*old_path || !new_path || !*new_path)
      return -1;
   return rename(old_path, new_path) == 0 ? 0 : -1;
#endif
}

const char *retro_vfs_file_get_path_impl(
      libretro_vfs_implementation_file *stream)
{
   /* should never happen, do something noisy so caller can be fixed */
   if (!stream)
      abort();
   return stream->orig_path;
}

int retro_vfs_stat_impl(const char *path, int32_t *size)
{
   int ret                   = RETRO_VFS_STAT_IS_VALID;

   if (!path || !*path)
      return 0;
   {
#if defined(VITA)
      /* Vita / PSP */
      SceIoStat stat_buf;
      int dir_ret;
      char *tmp                 = strdup(path);
      size_t _len               = strlen(tmp);
      if (tmp[_len-1] == '/')
          tmp[_len-1]           = '\0';

      dir_ret                   = sceIoGetstat(tmp, &stat_buf);
      free(tmp);
      if (dir_ret < 0)
         return 0;

      if (size)
         *size                  = (int32_t)stat_buf.st_size;

      if (FIO_S_ISDIR(stat_buf.st_mode))
         ret              |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(__PSL1GHT__) || defined(__PS3__)
      /* Lowlevel Lv2 */
      sysFSStat stat_buf;

      if (sysFsStat(path, &stat_buf) < 0)
         return 0;

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)
         ret  |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(_WIN32)
      /* Windows */
      struct _stat stat_buf;
#if defined(LEGACY_WIN32)
      char *path_local          = utf8_to_local_string_alloc(path);
      DWORD file_info           = GetFileAttributes(path_local);

      if (!string_is_empty(path_local))
         _stat(path_local, &stat_buf);

      if (path_local)
         free(path_local);
#else
      wchar_t *path_wide        = utf8_to_utf16_string_alloc(path);
      DWORD file_info           = GetFileAttributesW(path_wide);

      _wstat(path_wide, &stat_buf);

      if (path_wide)
         free(path_wide);
#endif
      if (file_info == INVALID_FILE_ATTRIBUTES)
         return 0;

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if (file_info & FILE_ATTRIBUTE_DIRECTORY)
         ret  |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(GEKKO)
      /* On GEKKO platforms, paths cannot have
       * trailing slashes - we must therefore
       * remove them */
      size_t _len;
      char *path_buf = NULL;
      struct stat stat_buf;

      if (!(path_buf = strdup(path)))
         return 0;

      if ((_len = strlen(path_buf)) > 0)
         if (path_buf[_len - 1] == '/')
             path_buf[_len - 1] = '\0';

      if (stat(path_buf, &stat_buf) < 0)
      {
         free(path_buf);
         return 0;
      }

      free(path_buf);

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if (S_ISDIR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_DIRECTORY;
      if (S_ISCHR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
#else
      /* Every other platform */
      struct stat stat_buf;

      if (stat(path, &stat_buf) < 0)
         return 0;

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if (S_ISDIR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_DIRECTORY;
      if (S_ISCHR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
#endif
   }
   return ret;
}

#if defined(VITA)
#define path_mkdir_err(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
#define path_mkdir_err(ret) ((ret) == -1)
#else
#define path_mkdir_err(ret) ((ret) < 0 && errno == EEXIST)
#endif

int retro_vfs_mkdir_impl(const char *dir)
{
#if defined(_WIN32)
#ifdef LEGACY_WIN32
   int ret        = _mkdir(dir);
#else
   wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);
   int       ret  = -1;

   if (dir_w)
   {
      ret = _wmkdir(dir_w);
      free(dir_w);
   }
#endif
#elif defined(IOS)
   int ret = mkdir(dir, 0755);
#elif defined(VITA)
   int ret = sceIoMkdir(dir, 0777);
#elif defined(__QNX__)
   int ret = mkdir(dir, 0777);
#elif defined(GEKKO) || defined(WIIU)
   /* On GEKKO platforms, mkdir() fails if
    * the path has a trailing slash. We must
    * therefore remove it. */
   int ret = -1;
   if (!string_is_empty(dir))
   {
      char *dir_buf = strdup(dir);

      if (dir_buf)
      {
         size_t _len = strlen(dir_buf);

         if (_len > 0)
            if (dir_buf[_len - 1] == '/')
                dir_buf[_len - 1] = '\0';

         ret = mkdir(dir_buf, 0750);

         free(dir_buf);
      }
   }
#else
   int ret = mkdir(dir, 0750);
#endif

   if (path_mkdir_err(ret))
      return -2;
   return ret < 0 ? -1 : 0;
}

#ifdef VFS_FRONTEND
struct retro_vfs_dir_handle
#else
struct libretro_vfs_implementation_dir
#endif
{
   char* orig_path;
#if defined(_WIN32)
#if defined(LEGACY_WIN32)
   WIN32_FIND_DATA entry;
#else
   WIN32_FIND_DATAW entry;
#endif
   HANDLE directory;
   bool next;
   char path[PATH_MAX_LENGTH];
#elif defined(VITA)
   SceUID directory;
   SceIoDirent entry;
#elif defined(__PSL1GHT__) || defined(__PS3__)
   int error;
   int directory;
   sysFSDirent entry;
#else
   DIR *directory;
   const struct dirent *entry;
#endif
};

static bool dirent_check_err(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
   return (rdir->directory == INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(ORBIS)
   return (rdir->directory < 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   return (rdir->error != FS_SUCCEEDED);
#else
   return !(rdir->directory);
#endif
}

libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
      const char *name, bool include_hidden)
{
#if defined(_WIN32)
   char path_buf[1024];
   size_t _len;
#if defined(LEGACY_WIN32)
   char *path_local   = NULL;
#else
   wchar_t *path_wide = NULL;
#endif
#endif
   libretro_vfs_implementation_dir *rdir;

   /* Reject NULL or empty string paths*/
   if (!name || (*name == 0))
      return NULL;

   /*Allocate RDIR struct. Tidied later with retro_closedir*/
   if (!(rdir = (libretro_vfs_implementation_dir*)
            calloc(1, sizeof(*rdir))))
      return NULL;

   rdir->orig_path       = strdup(name);

#if defined(_WIN32)
   _len = strlcpy(path_buf, name, sizeof(path_buf));
   /* Non-NT platforms don't like extra slashes in the path */
   if (path_buf[_len - 1] != '\\')
      path_buf [_len++]    = '\\';

   path_buf[_len    ]      = '*';
   path_buf[_len + 1]      = '\0';
#if defined(LEGACY_WIN32)
   path_local              = utf8_to_local_string_alloc(path_buf);
   rdir->directory         = FindFirstFile(path_local, &rdir->entry);
   if (path_local)
      free(path_local);
#else
   path_wide               = utf8_to_utf16_string_alloc(path_buf);
   rdir->directory         = FindFirstFileW(path_wide, &rdir->entry);
   if (path_wide)
      free(path_wide);
#endif

#elif defined(VITA)
   rdir->directory       = sceIoDopen(name);
#elif defined(_3DS)
   rdir->directory       = !string_is_empty(name) ? opendir(name) : NULL;
   rdir->entry           = NULL;
#elif defined(__PSL1GHT__) || defined(__PS3__)
   rdir->error           = sysFsOpendir(name, &rdir->directory);
#else
   rdir->directory       = opendir(name);
   rdir->entry           = NULL;
#endif

#ifdef _WIN32
   if (include_hidden)
      rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
   else
      rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
#else
   (void)include_hidden;
#endif

   if (rdir->directory && !dirent_check_err(rdir))
      return rdir;

   retro_vfs_closedir_impl(rdir);
   return NULL;
}

bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
   if (rdir->next)
#if defined(LEGACY_WIN32)
      return (FindNextFile(rdir->directory, &rdir->entry) != 0);
#else
      return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
#endif

   rdir->next = true;
   return (rdir->directory != INVALID_HANDLE_VALUE);
#elif defined(VITA)
   return (sceIoDread(rdir->directory, &rdir->entry) > 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   uint64_t nread;
   rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
   return (nread != 0);
#else
   return ((rdir->entry = readdir(rdir->directory)) != NULL);
#endif
}

const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
#if defined(LEGACY_WIN32)
   char *name       = local_to_utf8_string_alloc(rdir->entry.cFileName);
#else
   char *name       = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
#endif
   memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
   strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
   if (name)
      free(name);
   return (char*)rdir->entry.cFileName;
#elif defined(VITA) || defined(__PSL1GHT__) || defined(__PS3__)
   return rdir->entry.d_name;
#else
   if (!rdir || !rdir->entry)
      return NULL;
   return rdir->entry->d_name;
#endif
}

bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
   const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
   return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
#elif defined(VITA)
   const SceIoDirent *entry     = (const SceIoDirent*)&rdir->entry;
   return SCE_S_ISDIR(entry->d_stat.st_mode);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   sysFSDirent *entry          = (sysFSDirent*)&rdir->entry;
   return (entry->d_type == FS_TYPE_DIR);
#else
   struct stat buf;
   char path[PATH_MAX_LENGTH];
#if defined(DT_DIR)
   const struct dirent *entry = (const struct dirent*)rdir->entry;
   if (entry->d_type == DT_DIR)
      return true;
   /* This can happen on certain file systems. */
   if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
      return false;
#endif
   /* dirent struct doesn't have d_type, do it the slow way ... */
   fill_pathname_join_special(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
   if (stat(path, &buf) < 0)
      return false;
   return S_ISDIR(buf.st_mode);
#endif
}

int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
{
   if (!rdir)
      return -1;

#if defined(_WIN32)
   if (rdir->directory != INVALID_HANDLE_VALUE)
      FindClose(rdir->directory);
#elif defined(VITA)
   sceIoDclose(rdir->directory);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   rdir->error = sysFsClosedir(rdir->directory);
#else
   if (rdir->directory)
      closedir(rdir->directory);
#endif

   if (rdir->orig_path)
      free(rdir->orig_path);
   free(rdir);
   return 0;
}

./include/libretro-common/vfs/vfs_implementation_cdrom.c

/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation_cdrom.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <vfs/vfs_implementation.h>
#include <file/file_path.h>
#include <compat/fopen_utf8.h>
#include <string/stdstring.h>
#include <cdrom/cdrom.h>

#if defined(_WIN32) && !defined(_XBOX)
#include <windows.h>
#endif

/* TODO/FIXME - static global variable */
static cdrom_toc_t vfs_cdrom_toc = {0};

const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
{
   return &vfs_cdrom_toc;
}

int64_t retro_vfs_file_seek_cdrom(
      libretro_vfs_implementation_file *stream,
      int64_t offset, int whence)
{
   const char *ext = path_get_extension(stream->orig_path);

   if (string_is_equal_noncase(ext, "cue"))
   {
      switch (whence)
      {
         case SEEK_SET:
            stream->cdrom.byte_pos = offset;
            break;
         case SEEK_CUR:
            stream->cdrom.byte_pos += offset;
            break;
         case SEEK_END:
            stream->cdrom.byte_pos  = (stream->cdrom.cue_len - 1) + offset;
            break;
      }

#ifdef CDROM_DEBUG
      printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n",
            stream->orig_path,
            offset,
            stream->cdrom.byte_pos);
      fflush(stdout);
#endif
   }
   else if (string_is_equal_noncase(ext, "bin"))
   {
      int lba               = (offset / 2352);
      unsigned char min     = 0;
      unsigned char sec     = 0;
      unsigned char frame   = 0;
#ifdef CDROM_DEBUG
      const char *seek_type = "SEEK_SET";
#endif

      switch (whence)
      {
         case SEEK_CUR:
            {
               unsigned new_lba;
#ifdef CDROM_DEBUG
               seek_type               = "SEEK_CUR";
#endif
               stream->cdrom.byte_pos += offset;
               new_lba                 = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);

               cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
            }
            break;
         case SEEK_END:
            {
               ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio 
                     ? 0 
                     : (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));
               ssize_t lba_len        = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;
#ifdef CDROM_DEBUG
               seek_type              = "SEEK_END";
#endif

               cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);
               stream->cdrom.byte_pos = lba_len * 2352;
            }
            break;
         case SEEK_SET:
         default:
            {
#ifdef CDROM_DEBUG
               seek_type = "SEEK_SET";
#endif
               stream->cdrom.byte_pos = offset;
               cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
            }
            break;
      }

      stream->cdrom.cur_min   = min;
      stream->cdrom.cur_sec   = sec;
      stream->cdrom.cur_frame = frame;
      stream->cdrom.cur_lba   = cdrom_msf_to_lba(min, sec, frame);

#ifdef CDROM_DEBUG
      printf(
            "[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n",
            seek_type,
            stream->orig_path,
            offset,
            stream->cdrom.byte_pos,
            (unsigned)stream->cdrom.cur_min,
            (unsigned)stream->cdrom.cur_sec,
            (unsigned)stream->cdrom.cur_frame,
            stream->cdrom.cur_lba);
      fflush(stdout);
#endif
   }
   else
      return -1;

   return 0;
}

void retro_vfs_file_open_cdrom(
      libretro_vfs_implementation_file *stream,
      const char *path, unsigned mode, unsigned hints)
{
#if defined(__linux__) && !defined(ANDROID)
   char cdrom_path[]       = "/dev/sg1";
   size_t path_len         = strlen(path);
   const char *ext         = path_get_extension(path);

   stream->cdrom.cur_track = 1;

   if (     !string_is_equal_noncase(ext, "cue") 
         && !string_is_equal_noncase(ext, "bin"))
      return;

   if (path_len >= STRLEN_CONST("drive1-track01.bin"))
   {
      if (!memcmp(path, "drive", STRLEN_CONST("drive")))
      {
         if (!memcmp(path + 6, "-track", STRLEN_CONST("-track")))
         {
            if (sscanf(path + 12, "%02u", (unsigned*)&stream->cdrom.cur_track))
            {
#ifdef CDROM_DEBUG
               printf("[CDROM] Opening track %d\n", stream->cdrom.cur_track);
               fflush(stdout);
#endif
            }
         }
      }
   }

   if (path_len >= STRLEN_CONST("drive1.cue"))
   {
      if (!memcmp(path, "drive", STRLEN_CONST("drive")))
      {
         if (path[5] >= '0' && path[5] <= '9')
         {
            cdrom_path[7]       = path[5];
            stream->cdrom.drive = path[5];
            vfs_cdrom_toc.drive = stream->cdrom.drive;
         }
      }
   }

#ifdef CDROM_DEBUG
   printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
   fflush(stdout);
#endif
   stream->fp = (FILE*)fopen_utf8(cdrom_path, "r+b");

   if (!stream->fp)
      return;

   if (string_is_equal_noncase(ext, "cue"))
   {
      if (stream->cdrom.cue_buf)
      {
         free(stream->cdrom.cue_buf);
         stream->cdrom.cue_buf = NULL;
      }

      cdrom_write_cue(stream,
            &stream->cdrom.cue_buf,
            &stream->cdrom.cue_len,
            stream->cdrom.drive,
            &vfs_cdrom_toc.num_tracks,
            &vfs_cdrom_toc);
      cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);

#ifdef CDROM_DEBUG
      if (string_is_empty(stream->cdrom.cue_buf))
      {
         printf("[CDROM] Error writing cue sheet.\n");
         fflush(stdout);
      }
      else
      {
         printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
         fflush(stdout);
      }
#endif
   }
#endif
#if defined(_WIN32) && !defined(_XBOX)
   char cdrom_path[] = "\\\\.\\D:";
   size_t path_len   = strlen(path);
   const char *ext   = path_get_extension(path);

   if (     !string_is_equal_noncase(ext, "cue") 
         && !string_is_equal_noncase(ext, "bin"))
      return;

   if (path_len >= STRLEN_CONST("d:/drive-track01.bin"))
   {
      if (!memcmp(path + 1, ":/drive-track", STRLEN_CONST(":/drive-track")))
      {
         if (sscanf(path + 14, "%02u", (unsigned*)&stream->cdrom.cur_track))
         {
#ifdef CDROM_DEBUG
            printf("[CDROM] Opening track %d\n", stream->cdrom.cur_track);
            fflush(stdout);
#endif
         }
      }
   }

   if (path_len >= STRLEN_CONST("d:/drive.cue"))
   {
      if (!memcmp(path + 1, ":/drive", STRLEN_CONST(":/drive")))
      {
         if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
         {
            cdrom_path[4]       = path[0];
            stream->cdrom.drive = path[0];
            vfs_cdrom_toc.drive = stream->cdrom.drive;
         }
      }
   }

#ifdef CDROM_DEBUG
   printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
   fflush(stdout);
#endif
   stream->fh = CreateFile(cdrom_path,
         GENERIC_READ | GENERIC_WRITE,
         FILE_SHARE_READ | FILE_SHARE_WRITE,
         NULL,
         OPEN_EXISTING,
         FILE_ATTRIBUTE_NORMAL,
         NULL);

   if (stream->fh == INVALID_HANDLE_VALUE)
      return;

   if (string_is_equal_noncase(ext, "cue"))
   {
      if (stream->cdrom.cue_buf)
      {
         free(stream->cdrom.cue_buf);
         stream->cdrom.cue_buf = NULL;
      }

      cdrom_write_cue(stream,
            &stream->cdrom.cue_buf,
            &stream->cdrom.cue_len,
            stream->cdrom.drive,
            &vfs_cdrom_toc.num_tracks,
            &vfs_cdrom_toc);
      cdrom_get_timeouts(stream,
            &vfs_cdrom_toc.timeouts);

#ifdef CDROM_DEBUG
      if (string_is_empty(stream->cdrom.cue_buf))
      {
         printf("[CDROM] Error writing cue sheet.\n");
         fflush(stdout);
      }
      else
      {
         printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
         fflush(stdout);
      }
#endif
   }
#endif
   if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track)
   {
      stream->cdrom.cur_min   = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;
      stream->cdrom.cur_sec   = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;
      stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame;
      stream->cdrom.cur_lba   = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
   }
   else
   {
      stream->cdrom.cur_min   = vfs_cdrom_toc.track[0].min;
      stream->cdrom.cur_sec   = vfs_cdrom_toc.track[0].sec;
      stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;
      stream->cdrom.cur_lba   = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
   }
}

int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream)
{
#ifdef CDROM_DEBUG
   printf("[CDROM] Close: Path %s\n", stream->orig_path);
   fflush(stdout);
#endif

#if defined(_WIN32) && !defined(_XBOX)
   if (!stream->fh || !CloseHandle(stream->fh))
      return -1;
#else
   if (!stream->fp || fclose(stream->fp))
      return -1;
#endif

   return 0;
}

int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
{
   const char *ext = NULL;
   if (!stream)
      return -1;

   ext = path_get_extension(stream->orig_path);

   if (string_is_equal_noncase(ext, "cue"))
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] (cue) Tell: Path %s Position %" PRIu64 "\n", stream->orig_path, stream->cdrom.byte_pos);
      fflush(stdout);
#endif
      return stream->cdrom.byte_pos;
   }
   else if (string_is_equal_noncase(ext, "bin"))
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] (bin) Tell: Path %s Position %" PRId64 "\n", stream->orig_path, stream->cdrom.byte_pos);
      fflush(stdout);
#endif
      return stream->cdrom.byte_pos;
   }

   return -1;
}

int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
      void *s, uint64_t len)
{
   int rv;
   const char *ext = path_get_extension(stream->orig_path);

   if (string_is_equal_noncase(ext, "cue"))
   {
      if ((int64_t)len >= (int64_t)stream->cdrom.cue_len 
            - stream->cdrom.byte_pos)
         len = stream->cdrom.cue_len - stream->cdrom.byte_pos - 1;
#ifdef CDROM_DEBUG
      printf(
            "[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n",
            len,
            stream->cdrom.byte_pos);
      fflush(stdout);
#endif
      memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len);
      stream->cdrom.byte_pos += len;

      return len;
   }
   else if (string_is_equal_noncase(ext, "bin"))
   {
      unsigned char min    = 0;
      unsigned char sec    = 0;
      unsigned char frame  = 0;
      unsigned char rmin   = 0;
      unsigned char rsec   = 0;
      unsigned char rframe = 0;
      size_t skip          = stream->cdrom.byte_pos % 2352;

      if (stream->cdrom.byte_pos >= 
            vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
         return 0;

      if (stream->cdrom.byte_pos + len > 
            vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
         len -= (stream->cdrom.byte_pos + len) 
            - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;

      cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
      cdrom_lba_to_msf(stream->cdrom.cur_lba 
            - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba,
            &rmin, &rsec, &rframe);

#ifdef CDROM_DEBUG
      printf(
            "[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n",
            len,
            stream->orig_path,
            stream->cdrom.byte_pos,
            (unsigned)rmin,
            (unsigned)rsec,
            (unsigned)rframe,
            (unsigned)min,
            (unsigned)sec,
            (unsigned)frame,
            stream->cdrom.cur_lba,
            skip);
      fflush(stdout);
#endif

#if 1
      rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec,
            frame, s, (size_t)len, skip);
#else
      rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s,
            (size_t)len, skip);
#endif

      if (rv)
      {
#ifdef CDROM_DEBUG
         printf("[CDROM] Failed to read %" PRIu64 " bytes from CD.\n", len);
         fflush(stdout);
#endif
         return 0;
      }

      stream->cdrom.byte_pos += len;
      stream->cdrom.cur_lba   = 
         vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba 
         + (stream->cdrom.byte_pos / 2352);

      cdrom_lba_to_msf(stream->cdrom.cur_lba,
            &stream->cdrom.cur_min,
            &stream->cdrom.cur_sec,
            &stream->cdrom.cur_frame);

#ifdef CDROM_DEBUG
      printf(
            "[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n",
            len,
            stream->cdrom.byte_pos,
            (unsigned)stream->cdrom.cur_min,
            (unsigned)stream->cdrom.cur_sec,
            (unsigned)stream->cdrom.cur_frame,
            cdrom_msf_to_lba(
               stream->cdrom.cur_min,
               stream->cdrom.cur_sec,
               stream->cdrom.cur_frame)
            );
      fflush(stdout);
#endif

      return len;
   }

   return 0;
}

int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
{
   return 0;
}

const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(
      const libretro_vfs_implementation_file *stream)
{
   return &stream->cdrom;
}

./include/libretro-common/vfs/vfs_implementation_uwp.cpp

/* Copyright  (C) 2018-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation_uwp.cpp).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <retro_environment.h>

#include <ppl.h>
#include <ppltasks.h>
#include <stdio.h>
#include <wrl.h>
#include <wrl/implements.h>
#include <robuffer.h>
#include <collection.h>
#include <functional>
#include <fileapifromapp.h>
#include <AclAPI.h>
#include <sddl.h>
#include <io.h>
#include <fcntl.h>

#ifdef RARCH_INTERNAL
#ifndef VFS_FRONTEND
#define VFS_FRONTEND
#endif
#endif

#include <vfs/vfs.h>
#include <vfs/vfs_implementation.h>
#include <libretro.h>
#include <encodings/utf.h>
#include <retro_miscellaneous.h>
#include <file/file_path.h>
#include <string/stdstring.h>
#include <retro_environment.h>
#include <uwp/uwp_async.h>
#include <uwp/std_filesystem_compat.h>

namespace
{
   /* UWP deals with paths containing / instead of
    * \ way worse than normal Windows */
   /* and RetroArch may sometimes mix them
    * (e.g. on archive extraction) */
   static void windowsize_path(wchar_t* path)
   {
      if (path)
      {
         while (*path)
         {
            if (*path == '/')
               *path = '\\';
            ++path;
         }
      }
   }
}

#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else
struct libretro_vfs_implementation_file
#endif
{
    int64_t size;
    uint64_t mappos;
    uint64_t mapsize;
    FILE* fp;
    HANDLE fh;
    char* buf;
    char* orig_path;
    uint8_t* mapped;
    int fd;
    unsigned hints;
    enum vfs_scheme scheme;
};

#define RFILE_HINT_UNBUFFERED (1 << 8)

int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
{
    if (!stream)
        return -1;

    if (stream->fp)
        fclose(stream->fp);

    if (stream->buf != NULL)
    {
        free(stream->buf);
        stream->buf = NULL;
    }
    if (stream->orig_path)
        free(stream->orig_path);

    free(stream);

    return 0;
}

int retro_vfs_file_error_impl(libretro_vfs_implementation_file* stream)
{
    return ferror(stream->fp);
}

int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file* stream)
{
    if (stream)
        return stream->size;
    return 0;
}

int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file* stream, int64_t length)
{
   if (stream && _chsize(_fileno(stream->fp), length) == 0)
      return 0;
   return -1;
}

int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
{
    if (!stream)
        return -1;

    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
        return _ftelli64(stream->fp);
    if (lseek(stream->fd, 0, SEEK_CUR) < 0)
        return -1;

    return 0;
}

int64_t retro_vfs_file_seek_internal(
    libretro_vfs_implementation_file* stream,
    int64_t offset, int whence)
{
    if (!stream)
        return -1;

    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
        return _fseeki64(stream->fp, offset, whence);
    if (lseek(stream->fd, (off_t)offset, whence) < 0)
        return -1;

    return 0;
}

int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
    int64_t offset, int seek_position)
{
    return retro_vfs_file_seek_internal(stream, offset, seek_position);
}

int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file* stream,
    void* s, uint64_t len)
{
    if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
      return -1;

   if (stream->fh != INVALID_HANDLE_VALUE)
   {
      DWORD _bytes_read;
      ReadFile(stream->fh, (char*)s, len, &_bytes_read, NULL);
      return (int64_t)_bytes_read;
   }

    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
       return fread(s, 1, (size_t)len, stream->fp);
    return read(stream->fd, s, (size_t)len);
}


int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file* stream, const void* s, uint64_t len)
{
    if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
        return -1;

    if (stream->fh != INVALID_HANDLE_VALUE)
    {
        DWORD bytes_written;
        WriteFile(stream->fh, s, len, &bytes_written, NULL);
        return (int64_t)bytes_written;
    }

    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
        return fwrite(s, 1, (size_t)len, stream->fp);

    return write(stream->fd, s, (size_t)len);
}

int retro_vfs_file_flush_impl(libretro_vfs_implementation_file* stream)
{
    if (stream && fflush(stream->fp) == 0)
       return 0;
    return -1;
}

int retro_vfs_file_remove_impl(const char *path)
{
   BOOL ret;
   wchar_t *path_wide;

   if (!path || !*path)
      return -1;

   path_wide = utf8_to_utf16_string_alloc(path);
   windowsize_path(path_wide);

   /* Try Win32 first, this should work in AppData */
   ret = DeleteFileFromAppW(path_wide);
   free(path_wide);
   if (ret)
      return 0;

   return -1;
}

libretro_vfs_implementation_file* retro_vfs_file_open_impl(
    const char* path, unsigned mode, unsigned hints)
{
    HANDLE file_handle;
    std::wstring path_wstring;
    DWORD desireAccess;
    DWORD creationDisposition;
    wchar_t                       *path_wide = NULL;
    int                                flags = 0;
    const char                     *mode_str = NULL;
    libretro_vfs_implementation_file* stream =
        (libretro_vfs_implementation_file*)
        malloc(sizeof(*stream));

    if (!stream)
        return NULL;

    stream->fd        = 0;
    stream->hints     = hints;
    stream->size      = 0;
    stream->buf       = NULL;
    stream->fp        = NULL;
    stream->fh        = 0;
    stream->orig_path = NULL;
    stream->mappos    = 0;
    stream->mapsize   = 0;
    stream->mapped    = NULL;
    stream->scheme    = VFS_SCHEME_NONE;

#ifdef VFS_FRONTEND
   if (     path
         && path[0] == 'v'
         && path[1] == 'f'
         && path[2] == 's'
         && path[3] == 'o'
         && path[4] == 'n'
         && path[5] == 'l'
         && path[6] == 'y'
         && path[7] == ':'
         && path[8] == '/'
         && path[9] == '/')
         path             += sizeof("vfsonly://")-1;
#endif

    path_wide    = utf8_to_utf16_string_alloc(path);
    windowsize_path(path_wide);
    path_wstring = path_wide;
    free(path_wide);

    for (;;)
    {
       size_t p = path_wstring.find(L"\\\\");
       if (p == std::wstring::npos)
          break;
       path_wstring.replace(p, 2, L"\\");
    }

    path_wstring      = L"\\\\?\\" + path_wstring;
    stream->orig_path = strdup(path);

    stream->hints    &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;

    switch (mode)
    {
       case RETRO_VFS_FILE_ACCESS_READ:
          mode_str = "rb";
          flags    = O_RDONLY | O_BINARY;
          break;

       case RETRO_VFS_FILE_ACCESS_WRITE:
          mode_str = "wb";
          flags    = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
          break;

       case RETRO_VFS_FILE_ACCESS_READ_WRITE:
          mode_str = "w+b";
          flags    = O_RDWR | O_CREAT | O_TRUNC | O_BINARY;
          break;

       case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
       case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
          mode_str = "r+b";
          flags    = O_RDWR | O_BINARY;
          break;

       default:
          goto error;
    }

    switch (mode)
    {
       case RETRO_VFS_FILE_ACCESS_READ_WRITE:
          desireAccess = GENERIC_READ | GENERIC_WRITE;
          break;
       case RETRO_VFS_FILE_ACCESS_WRITE:
          desireAccess = GENERIC_WRITE;
          break;
       case RETRO_VFS_FILE_ACCESS_READ:
          desireAccess = GENERIC_READ;
          break;
    }
    if (mode == RETRO_VFS_FILE_ACCESS_READ)
        creationDisposition = OPEN_EXISTING;
    else
        creationDisposition = (mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING) != 0
           ? OPEN_ALWAYS
           : CREATE_ALWAYS;

    if ((file_handle = CreateFile2FromAppW(path_wstring.data(), desireAccess,
                FILE_SHARE_READ, creationDisposition, NULL)) == INVALID_HANDLE_VALUE)
       goto error;

    stream->fh      = file_handle;
    if ((stream->fd = _open_osfhandle((uint64)stream->fh, flags)) == -1)
        goto error;

    {
        FILE *fp = _fdopen(stream->fd, mode_str);

        if (!fp)
            goto error;
        stream->fp = fp;
    }

    /* Regarding setvbuf:
        *
        * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
        *
        * If the size argument is not zero but buf is NULL,
        * a buffer of the given size will be allocated immediately, and
        * released on close. This is an extension to ANSI C.
        *
        * Since C89 does not support specifying a NULL buffer
        * with a non-zero size, we create and track our own buffer for it.
        */
        /* TODO: this is only useful for a few platforms,
        * find which and add ifdef */
    if (stream->scheme != VFS_SCHEME_CDROM)
    {
        stream->buf = (char*)calloc(1, 0x4000);
        if (stream->fp)
            setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
    }

    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
    retro_vfs_file_seek_internal(stream, 0, SEEK_END);

    stream->size = retro_vfs_file_tell_impl(stream);

    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);

    return stream;

error:
    retro_vfs_file_close_impl(stream);
    return NULL;
}

static int uwp_mkdir_impl(std::experimental::filesystem::path dir)
{
    /*I feel like this should create the directory recursively but the existing implementation does not so this update won't
     *I put in the work but I just commented out the stuff you would need */
    WIN32_FILE_ATTRIBUTE_DATA lpFileInfo;
    bool parent_dir_exists = false;

    if (dir.empty())
        return -1;

    /* Check if file attributes can be gotten successfully  */
    if (GetFileAttributesExFromAppW(dir.parent_path().wstring().c_str(), GetFileExInfoStandard, &lpFileInfo))
    {
        /* Check that the files attributes are not null or empty */
        if (lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES && lpFileInfo.dwFileAttributes != 0)
        {
            if (lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                parent_dir_exists = true;
        }
    }
    if (!parent_dir_exists)
    {
        /* Try to create parent dir */
        int success = uwp_mkdir_impl(dir.parent_path());
        if (success != 0 && success != -2)
            return success;
    }


    /* Try Win32 first, this should work in AppData */
    if (CreateDirectoryFromAppW(dir.wstring().c_str(), NULL))
        return 0;

    if (GetLastError() == ERROR_ALREADY_EXISTS)
        return -2;

    return -1;
}

int retro_vfs_mkdir_impl(const char* dir)
{
    return uwp_mkdir_impl(std::filesystem::path(dir));
}

/* The first run parameter is used to avoid error checking
 * when doing recursion.
 * Unlike the initial implementation, this can move folders
 * even empty ones when you want to move a directory structure.
 *
 * This will fail even if a single file cannot be moved.
 */
static int uwp_move_path(
      std::filesystem::path old_path,
      std::filesystem::path new_path,
      bool firstrun)
{
    if (old_path.empty() || new_path.empty())
        return -1;

    if (firstrun)
    {
        WIN32_FILE_ATTRIBUTE_DATA lpFileInfo, targetfileinfo;
        bool parent_dir_exists = false;

        /* Make sure that parent path exists */
        if (GetFileAttributesExFromAppW(
                 new_path.parent_path().wstring().c_str(),
                 GetFileExInfoStandard, &lpFileInfo))
        {
            /* Check that the files attributes are not null or empty */
            if (     lpFileInfo.dwFileAttributes
                  != INVALID_FILE_ATTRIBUTES
                  && lpFileInfo.dwFileAttributes != 0)
            {
               /* Parent path doesn't exist, so we gotta create it  */
                if (!(lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                    uwp_mkdir_impl(new_path.parent_path());
            }
        }

        /* Make sure that source path exists */
        if (GetFileAttributesExFromAppW(old_path.wstring().c_str(), GetFileExInfoStandard, &lpFileInfo))
        {
            /* Check that the files attributes are not null or empty */
            if (     lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES
                  && lpFileInfo.dwFileAttributes != 0)
            {
                /* Check if source path is a dir */
                if (lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                   int ret;
                   /* create the target dir */
                   CreateDirectoryFromAppW(new_path.wstring().c_str(), NULL);
                   /* Call move function again but with first run disabled in
                    * order to move the folder */
                   if ((ret = uwp_move_path(old_path, new_path, false)) != 0)
                      return ret;
                }
                else
                {
                    /* The file that we want to move exists so we can copy it now
                     * check if target file already exists. */
                   if (GetFileAttributesExFromAppW(
                            new_path.wstring().c_str(),
                            GetFileExInfoStandard,
                            &targetfileinfo))
                    {
                        if (
                                 targetfileinfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES
                              && targetfileinfo.dwFileAttributes != 0
                              && (!(targetfileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
                        {
                            if (DeleteFileFromAppW(new_path.wstring().c_str()))
                                return -1;
                        }
                    }

                    if (!MoveFileFromAppW(old_path.wstring().c_str(),
                             new_path.wstring().c_str()))
                        return -1;
                    /* Set ACL */
                    uwp_set_acl(new_path.wstring().c_str(), L"S-1-15-2-1");
                }
            }
        }

    }
    else
    {
       HANDLE searchResults;
       WIN32_FIND_DATA findDataResult;
       /* We are bypassing error checking and moving a dir.
        * First we have to get a list of files in the dir. */
       wchar_t* filteredPath = wcsdup(old_path.wstring().c_str());
       wcscat_s(filteredPath, sizeof(L"\\*.*"), L"\\*.*");
       searchResults         = FindFirstFileExFromAppW(
             filteredPath, FindExInfoBasic, &findDataResult,
             FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);

       if (searchResults != INVALID_HANDLE_VALUE)
       {
          bool fail = false;
          do
          {
             if (     wcscmp(findDataResult.cFileName, L".")  != 0
                   && wcscmp(findDataResult.cFileName, L"..") != 0)
             {
                std::filesystem::path temp_old = old_path;
                std::filesystem::path temp_new = new_path;
                temp_old /= findDataResult.cFileName;
                temp_new /= findDataResult.cFileName;
                if (    findDataResult.dwFileAttributes
                      & FILE_ATTRIBUTE_DIRECTORY)
                {
                   CreateDirectoryFromAppW(temp_new.wstring().c_str(), NULL);
                   if (uwp_move_path(temp_old, temp_new, false) != 0)
                      fail = true;
                }
                else
                {
                   WIN32_FILE_ATTRIBUTE_DATA targetfileinfo;
                   /* The file that we want to move exists so we can copy
                    * it now.
                    * Check if target file already exists. */
                   if (GetFileAttributesExFromAppW(temp_new.wstring().c_str(),
                            GetFileExInfoStandard, &targetfileinfo))
                   {
                      if (
                               (targetfileinfo.dwFileAttributes !=
                                INVALID_FILE_ATTRIBUTES)
                            && (targetfileinfo.dwFileAttributes != 0)
                            && (!(targetfileinfo.dwFileAttributes
                                  & FILE_ATTRIBUTE_DIRECTORY)))
                      {
                         if (DeleteFileFromAppW(temp_new.wstring().c_str()))
                            fail = true;
                      }
                   }

                   if (!MoveFileFromAppW(temp_old.wstring().c_str(),
                            temp_new.wstring().c_str()))
                      fail = true;
                   /* Set ACL - this step sucks or at least used to
                    * before I made a whole function
                    * Don't know if we actually "need" to set the ACL
                    * though */
                   uwp_set_acl(temp_new.wstring().c_str(), L"S-1-15-2-1");
                }
             }
          } while (FindNextFile(searchResults, &findDataResult));
          FindClose(searchResults);
          if (fail)
             return -1;
       }
       free(filteredPath);
    }
    return 0;
}

/* C doesn't support default arguments so we wrap it up in a shell to enable
 * us to use default arguments.
 * Default arguments mean that we can do better recursion */
int retro_vfs_file_rename_impl(const char* old_path, const char* new_path)
{
    return uwp_move_path(std::filesystem::path(old_path),
          std::filesystem::path(old_path), true);
}

const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream)
{
   /* Should never happen, do something noisy so caller can be fixed */
   if (!stream)
      abort();
   return stream->orig_path;
}

int retro_vfs_stat_impl(const char *path, int32_t *size)
{
   wchar_t *path_wide;
   _WIN32_FILE_ATTRIBUTE_DATA attribdata;

   if (!path || !*path)
      return 0;

   path_wide = utf8_to_utf16_string_alloc(path);
   windowsize_path(path_wide);

   /* Try Win32 first, this should work in AppData */
   if (GetFileAttributesExFromAppW(path_wide,
            GetFileExInfoStandard, &attribdata))
   {
       if (attribdata.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
       {
           if (!(attribdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
           {
               LARGE_INTEGER sz;
               if (size)
               {
                   sz.HighPart = attribdata.nFileSizeHigh;
                   sz.LowPart = attribdata.nFileSizeLow;
                   *size = sz.QuadPart;
               }
           }
           free(path_wide);
           return (attribdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
              ? RETRO_VFS_STAT_IS_VALID | RETRO_VFS_STAT_IS_DIRECTORY
              : RETRO_VFS_STAT_IS_VALID;
       }
   }
   free(path_wide);
   return 0;
}

#ifdef VFS_FRONTEND
struct retro_vfs_dir_handle
#else
struct libretro_vfs_implementation_dir
#endif
{
    char* orig_path;
    WIN32_FIND_DATAW entry;
    HANDLE directory;
    bool next;
    char path[PATH_MAX_LENGTH];
};

libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
    const char* name, bool include_hidden)
{
    size_t _len;
    char path_buf[1024];
    wchar_t* path_wide = NULL;
    libretro_vfs_implementation_dir* rdir;

    /* Reject NULL or empty string paths*/
    if (!name || (*name == 0))
        return NULL;

    /*Allocate RDIR struct. Tidied later with retro_closedir*/
    if (!(rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir))))
        return NULL;

    rdir->orig_path = strdup(name);

    _len = strlcpy(path_buf, name, sizeof(path_buf));

    /* Non-NT platforms don't like extra slashes in the path */
    if (path_buf[_len - 1] != '\\')
        path_buf[_len++]   = '\\';

    path_buf[_len]         = '*';
    path_buf[_len + 1]     = '\0';

    path_wide              = utf8_to_utf16_string_alloc(path_buf);
    rdir->directory        = FindFirstFileExFromAppW(
          path_wide, FindExInfoStandard, &rdir->entry,
          FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);

    if (path_wide)
        free(path_wide);

    if (include_hidden)
        rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
    else
        rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;

    if (rdir->directory && rdir != INVALID_HANDLE_VALUE)
        return rdir;

    retro_vfs_closedir_impl(rdir);
    return NULL;
}

bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
{
    if (rdir->next)
        return (FindNextFileW(rdir->directory, &rdir->entry) != 0);

    rdir->next = true;
    return (rdir->directory != INVALID_HANDLE_VALUE);
}

const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir)
{
    char* name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
    memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
    strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
    if (name)
        free(name);
    return (char*)rdir->entry.cFileName;
}

bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir* rdir)
{
    const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry;
    return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
}

int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
{
    if (!rdir)
        return -1;

    if (rdir->directory != INVALID_HANDLE_VALUE)
        FindClose(rdir->directory);

    if (rdir->orig_path)
        free(rdir->orig_path);
    free(rdir);
    return 0;
}

void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString)
{
    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
    EXPLICIT_ACCESSW ExplicitAccess         = { 0 };
    ACL* AccessControlCurrent               = NULL;
    ACL* AccessControlNew                   = NULL;
    SECURITY_INFORMATION SecurityInfo       = DACL_SECURITY_INFORMATION;
    PSID SecurityIdentifier                 = NULL;
    HANDLE original_file                    = CreateFileFromAppW(path,
          GENERIC_READ    | GENERIC_WRITE | WRITE_DAC,
          FILE_SHARE_READ | FILE_SHARE_WRITE,
          NULL, OPEN_EXISTING, 0, NULL);

    if (original_file != INVALID_HANDLE_VALUE)
    {
       if (
             GetSecurityInfo(
                original_file,
                SE_FILE_OBJECT,
                DACL_SECURITY_INFORMATION,
                NULL,
                NULL,
                &AccessControlCurrent,
                NULL,
                &SecurityDescriptor
                ) == ERROR_SUCCESS
          )
       {
          ConvertStringSidToSidW(AccessString, &SecurityIdentifier);
          if (SecurityIdentifier)
          {
             ExplicitAccess.grfAccessPermissions= GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE;
             ExplicitAccess.grfAccessMode       = SET_ACCESS;
             ExplicitAccess.grfInheritance      = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
             ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
             ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
             ExplicitAccess.Trustee.ptstrName   = reinterpret_cast<wchar_t*>(SecurityIdentifier);

             if (
                   SetEntriesInAclW(
                      1,
                      &ExplicitAccess,
                      AccessControlCurrent,
                      &AccessControlNew
                      ) == ERROR_SUCCESS
                )
                SetSecurityInfo(
                      original_file,
                      SE_FILE_OBJECT,
                      SecurityInfo,
                      NULL,
                      NULL,
                      AccessControlNew,
                      NULL
                      );
          }
       }
       if (SecurityDescriptor)
          LocalFree(reinterpret_cast<HLOCAL>(SecurityDescriptor));
       if (AccessControlNew)
          LocalFree(reinterpret_cast<HLOCAL>(AccessControlNew));
       CloseHandle(original_file);
    }
}

./include/libretro-common/vulkan/vulkan_symbol_wrapper.c

/* This header is autogenerated by vulkan_loader_generator.py */
#include <vulkan/vulkan_symbol_wrapper.h>

PFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;
PFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;
PFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;
PFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;
PFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;
PFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;
PFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;
PFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;
PFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;
PFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;
PFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;
PFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;
PFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;
PFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;
PFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;
PFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;
PFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;
PFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;
PFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;
PFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;
PFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;
PFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;
PFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;
PFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;
PFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;
PFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;
PFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;
PFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;
PFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;
PFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;
PFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;
PFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;
PFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;
PFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;
PFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;
PFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;
PFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;
PFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;
PFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;
PFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;
PFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;
PFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;
PFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;
PFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;
PFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;
PFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;
PFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;
PFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;
PFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;
PFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;
PFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;
PFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;
PFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;
PFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;
PFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;
PFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;
PFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;
PFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;
PFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;
PFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;
PFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;
PFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;
PFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;
PFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;
PFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;
PFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;
PFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;
PFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;
PFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;
PFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;
PFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;
PFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;
PFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;
PFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;
PFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;
PFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;
PFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;
PFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;
PFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;
PFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;
PFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;
PFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;
PFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;
PFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;
PFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;
PFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;
PFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;
PFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;
PFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;
PFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;
PFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;
PFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;
PFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;
PFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;
PFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;
PFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;
PFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;
PFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;
PFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;
PFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;
PFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;
PFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;
PFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;
PFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;
PFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;
PFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;
PFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;
PFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;
PFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;
PFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;
PFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;
PFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;
PFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;
PFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;
PFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;
PFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;
PFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;
PFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;
PFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;
PFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;
PFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;
PFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;
PFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;
PFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;
PFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;
PFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;
PFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;
PFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;
PFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;
PFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;
PFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;
PFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;
PFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;
PFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;
PFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;
PFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;
PFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;
PFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
PFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;
PFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;
PFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;
PFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;
PFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;
PFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;

PFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;
PFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;

static PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
void vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr)
{
    GetInstanceProcAddr = get_instance_proc_addr;
}

PFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void)
{
    return GetInstanceProcAddr;
}

VkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol)
{
    *ppSymbol = GetInstanceProcAddr(instance, name);
    return *ppSymbol != NULL;
}

VkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol)
{
    *ppSymbol = vkGetDeviceProcAddr(device, name);
    return *ppSymbol != NULL;
}

VkBool32 vulkan_symbol_wrapper_load_global_symbols(void)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkCreateInstance", vkCreateInstance)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceExtensionProperties", vkEnumerateInstanceExtensionProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceLayerProperties", vkEnumerateInstanceLayerProperties)) return VK_FALSE;
    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceVersion", vkEnumerateInstanceVersion);
    return VK_TRUE;
}

VkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyInstance", vkDestroyInstance)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumeratePhysicalDevices", vkEnumeratePhysicalDevices)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFeatures", vkGetPhysicalDeviceFeatures)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFormatProperties", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceImageFormatProperties", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceProperties", vkGetPhysicalDeviceProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceQueueFamilyProperties", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceMemoryProperties", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceProcAddr", vkGetDeviceProcAddr)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDevice", vkCreateDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDevice", vkDestroyDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceExtensionProperties", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceLayerProperties", vkEnumerateDeviceLayerProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceQueue", vkGetDeviceQueue)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueSubmit", vkQueueSubmit)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueWaitIdle", vkQueueWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDeviceWaitIdle", vkDeviceWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateMemory", vkAllocateMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeMemory", vkFreeMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkMapMemory", vkMapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkUnmapMemory", vkUnmapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFlushMappedMemoryRanges", vkFlushMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceMemoryCommitment", vkGetDeviceMemoryCommitment)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBindBufferMemory", vkBindBufferMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBindImageMemory", vkBindImageMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetBufferMemoryRequirements", vkGetBufferMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageMemoryRequirements", vkGetImageMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageSparseMemoryRequirements", vkGetImageSparseMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceSparseImageFormatProperties", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueBindSparse", vkQueueBindSparse)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateFence", vkCreateFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyFence", vkDestroyFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetFences", vkResetFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetFenceStatus", vkGetFenceStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkWaitForFences", vkWaitForFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateSemaphore", vkCreateSemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroySemaphore", vkDestroySemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateEvent", vkCreateEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyEvent", vkDestroyEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetEventStatus", vkGetEventStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkSetEvent", vkSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetEvent", vkResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateQueryPool", vkCreateQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyQueryPool", vkDestroyQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetQueryPoolResults", vkGetQueryPoolResults)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateBuffer", vkCreateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyBuffer", vkDestroyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateBufferView", vkCreateBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyBufferView", vkDestroyBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateImage", vkCreateImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyImage", vkDestroyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageSubresourceLayout", vkGetImageSubresourceLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateImageView", vkCreateImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyImageView", vkDestroyImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateShaderModule", vkCreateShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyShaderModule", vkDestroyShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreatePipelineCache", vkCreatePipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipelineCache", vkDestroyPipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPipelineCacheData", vkGetPipelineCacheData)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkMergePipelineCaches", vkMergePipelineCaches)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateGraphicsPipelines", vkCreateGraphicsPipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateComputePipelines", vkCreateComputePipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipeline", vkDestroyPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreatePipelineLayout", vkCreatePipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipelineLayout", vkDestroyPipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateSampler", vkCreateSampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroySampler", vkDestroySampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDescriptorSetLayout", vkCreateDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDescriptorSetLayout", vkDestroyDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDescriptorPool", vkCreateDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDescriptorPool", vkDestroyDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetDescriptorPool", vkResetDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateDescriptorSets", vkAllocateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeDescriptorSets", vkFreeDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkUpdateDescriptorSets", vkUpdateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateFramebuffer", vkCreateFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyFramebuffer", vkDestroyFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateRenderPass", vkCreateRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyRenderPass", vkDestroyRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetRenderAreaGranularity", vkGetRenderAreaGranularity)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateCommandPool", vkCreateCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyCommandPool", vkDestroyCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetCommandPool", vkResetCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateCommandBuffers", vkAllocateCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeCommandBuffers", vkFreeCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBeginCommandBuffer", vkBeginCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEndCommandBuffer", vkEndCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetCommandBuffer", vkResetCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindPipeline", vkCmdBindPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetViewport", vkCmdSetViewport)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetScissor", vkCmdSetScissor)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetLineWidth", vkCmdSetLineWidth)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetDepthBias", vkCmdSetDepthBias)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetBlendConstants", vkCmdSetBlendConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetDepthBounds", vkCmdSetDepthBounds)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilCompareMask", vkCmdSetStencilCompareMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilWriteMask", vkCmdSetStencilWriteMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilReference", vkCmdSetStencilReference)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindDescriptorSets", vkCmdBindDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindIndexBuffer", vkCmdBindIndexBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindVertexBuffers", vkCmdBindVertexBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDraw", vkCmdDraw)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndexed", vkCmdDrawIndexed)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndirect", vkCmdDrawIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndexedIndirect", vkCmdDrawIndexedIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDispatch", vkCmdDispatch)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDispatchIndirect", vkCmdDispatchIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyBuffer", vkCmdCopyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyImage", vkCmdCopyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBlitImage", vkCmdBlitImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyBufferToImage", vkCmdCopyBufferToImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyImageToBuffer", vkCmdCopyImageToBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdUpdateBuffer", vkCmdUpdateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdFillBuffer", vkCmdFillBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearColorImage", vkCmdClearColorImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearDepthStencilImage", vkCmdClearDepthStencilImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearAttachments", vkCmdClearAttachments)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResolveImage", vkCmdResolveImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetEvent", vkCmdSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResetEvent", vkCmdResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdWaitEvents", vkCmdWaitEvents)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdPipelineBarrier", vkCmdPipelineBarrier)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBeginQuery", vkCmdBeginQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdEndQuery", vkCmdEndQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResetQueryPool", vkCmdResetQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdWriteTimestamp", vkCmdWriteTimestamp)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyQueryPoolResults", vkCmdCopyQueryPoolResults)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdPushConstants", vkCmdPushConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBeginRenderPass", vkCmdBeginRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdNextSubpass", vkCmdNextSubpass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdEndRenderPass", vkCmdEndRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdExecuteCommands", vkCmdExecuteCommands)) return VK_FALSE;
    return VK_TRUE;
}

VkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyInstance", vkDestroyInstance)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumeratePhysicalDevices", vkEnumeratePhysicalDevices)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFeatures", vkGetPhysicalDeviceFeatures)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFormatProperties", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceImageFormatProperties", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceProperties", vkGetPhysicalDeviceProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceQueueFamilyProperties", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceMemoryProperties", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceProcAddr", vkGetDeviceProcAddr)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDevice", vkCreateDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceExtensionProperties", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceLayerProperties", vkEnumerateDeviceLayerProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceSparseImageFormatProperties", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;
    return VK_TRUE;
}

VkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDevice", vkDestroyDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetDeviceQueue", vkGetDeviceQueue)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueSubmit", vkQueueSubmit)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueWaitIdle", vkQueueWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDeviceWaitIdle", vkDeviceWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateMemory", vkAllocateMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeMemory", vkFreeMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkMapMemory", vkMapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkUnmapMemory", vkUnmapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFlushMappedMemoryRanges", vkFlushMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetDeviceMemoryCommitment", vkGetDeviceMemoryCommitment)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBindBufferMemory", vkBindBufferMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBindImageMemory", vkBindImageMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetBufferMemoryRequirements", vkGetBufferMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageMemoryRequirements", vkGetImageMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageSparseMemoryRequirements", vkGetImageSparseMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueBindSparse", vkQueueBindSparse)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateFence", vkCreateFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyFence", vkDestroyFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetFences", vkResetFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetFenceStatus", vkGetFenceStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkWaitForFences", vkWaitForFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateSemaphore", vkCreateSemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroySemaphore", vkDestroySemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateEvent", vkCreateEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyEvent", vkDestroyEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetEventStatus", vkGetEventStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkSetEvent", vkSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetEvent", vkResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateQueryPool", vkCreateQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyQueryPool", vkDestroyQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetQueryPoolResults", vkGetQueryPoolResults)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateBuffer", vkCreateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyBuffer", vkDestroyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateBufferView", vkCreateBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyBufferView", vkDestroyBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateImage", vkCreateImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyImage", vkDestroyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageSubresourceLayout", vkGetImageSubresourceLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateImageView", vkCreateImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyImageView", vkDestroyImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateShaderModule", vkCreateShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyShaderModule", vkDestroyShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreatePipelineCache", vkCreatePipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipelineCache", vkDestroyPipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetPipelineCacheData", vkGetPipelineCacheData)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkMergePipelineCaches", vkMergePipelineCaches)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateGraphicsPipelines", vkCreateGraphicsPipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateComputePipelines", vkCreateComputePipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipeline", vkDestroyPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreatePipelineLayout", vkCreatePipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipelineLayout", vkDestroyPipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateSampler", vkCreateSampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroySampler", vkDestroySampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateDescriptorSetLayout", vkCreateDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDescriptorSetLayout", vkDestroyDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateDescriptorPool", vkCreateDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDescriptorPool", vkDestroyDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetDescriptorPool", vkResetDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateDescriptorSets", vkAllocateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeDescriptorSets", vkFreeDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkUpdateDescriptorSets", vkUpdateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateFramebuffer", vkCreateFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyFramebuffer", vkDestroyFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateRenderPass", vkCreateRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyRenderPass", vkDestroyRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetRenderAreaGranularity", vkGetRenderAreaGranularity)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateCommandPool", vkCreateCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyCommandPool", vkDestroyCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetCommandPool", vkResetCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateCommandBuffers", vkAllocateCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeCommandBuffers", vkFreeCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBeginCommandBuffer", vkBeginCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkEndCommandBuffer", vkEndCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetCommandBuffer", vkResetCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindPipeline", vkCmdBindPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetViewport", vkCmdSetViewport)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetScissor", vkCmdSetScissor)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetLineWidth", vkCmdSetLineWidth)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetDepthBias", vkCmdSetDepthBias)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetBlendConstants", vkCmdSetBlendConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetDepthBounds", vkCmdSetDepthBounds)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilCompareMask", vkCmdSetStencilCompareMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilWriteMask", vkCmdSetStencilWriteMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilReference", vkCmdSetStencilReference)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindDescriptorSets", vkCmdBindDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindIndexBuffer", vkCmdBindIndexBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindVertexBuffers", vkCmdBindVertexBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDraw", vkCmdDraw)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndexed", vkCmdDrawIndexed)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndirect", vkCmdDrawIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndexedIndirect", vkCmdDrawIndexedIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDispatch", vkCmdDispatch)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDispatchIndirect", vkCmdDispatchIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyBuffer", vkCmdCopyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyImage", vkCmdCopyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBlitImage", vkCmdBlitImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyBufferToImage", vkCmdCopyBufferToImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyImageToBuffer", vkCmdCopyImageToBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdUpdateBuffer", vkCmdUpdateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdFillBuffer", vkCmdFillBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearColorImage", vkCmdClearColorImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearDepthStencilImage", vkCmdClearDepthStencilImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearAttachments", vkCmdClearAttachments)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResolveImage", vkCmdResolveImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetEvent", vkCmdSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResetEvent", vkCmdResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdWaitEvents", vkCmdWaitEvents)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdPipelineBarrier", vkCmdPipelineBarrier)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBeginQuery", vkCmdBeginQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdEndQuery", vkCmdEndQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResetQueryPool", vkCmdResetQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdWriteTimestamp", vkCmdWriteTimestamp)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyQueryPoolResults", vkCmdCopyQueryPoolResults))
    {
#if 0
       /* Don't return false here. Would cause MESA Intel Ivy Bridge drivers to not work at all. */
       return VK_FALSE;
#endif
    }
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdPushConstants", vkCmdPushConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBeginRenderPass", vkCmdBeginRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdNextSubpass", vkCmdNextSubpass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdEndRenderPass", vkCmdEndRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdExecuteCommands", vkCmdExecuteCommands)) return VK_FALSE;
    return VK_TRUE;
}

./include/libretro.h

#ifndef LIBRETRO_H
#define LIBRETRO_H

#include <stdint.h>
#include <stdbool.h>   // <<-- needed for 'bool'

struct retro_game_geometry {
    unsigned width;
    unsigned height;
    unsigned max_width;
    unsigned max_height;
    float aspect_ratio;
};

typedef bool (*retro_environment_t)(unsigned cmd, void *data);

#endif

./index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>gameboy-perfect-core Mirror</title>
<style>
body { font-family: monospace; background: #f4f4f4; padding: 1rem; }
h2 { margin-top: 2rem; font-size: 1rem; }
pre { background: #2d2d2d; color: #f8f8f2; padding: 0.5rem; overflow-x: auto; white-space: pre-wrap; border-radius: 4px; margin-bottom: 2rem; }
</style>
</head>
<body>
<h1>gameboy-perfect-core Mirror</h1>
<h2>./build/CMakeCache.txt</h2>
<pre># This is the CMakeCache file.
# For build in directory: /home/ubuntu/Desktop/gameboy-perfect-core/build
# It was generated by CMake: /usr/bin/cmake
# You can edit this file to change values found and used by cmake.
# If you do not want to change any of the values, simply exit the editor.
# If you do want to change a value, simply edit, save, and exit the editor.
# The syntax for the file is as follows:
# KEY:TYPE=VALUE
# KEY is the name of a variable in the cache.
# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
# VALUE is the current value for the KEY.

########################
# EXTERNAL cache entries
########################

//Path to a program.
CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line

//Path to a program.
CMAKE_AR:FILEPATH=/usr/bin/ar

//Choose the type of build, options are: None Debug Release RelWithDebInfo
// MinSizeRel ...
CMAKE_BUILD_TYPE:STRING=

//Enable/Disable color output during build.
CMAKE_COLOR_MAKEFILE:BOOL=ON

//C compiler
CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-12

//A wrapper around 'ar' adding the appropriate '--plugin' option
// for the GCC compiler
CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-12

//A wrapper around 'ranlib' adding the appropriate '--plugin' option
// for the GCC compiler
CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-12

//Flags used by the C compiler during all build types.
CMAKE_C_FLAGS:STRING=

//Flags used by the C compiler during DEBUG builds.
CMAKE_C_FLAGS_DEBUG:STRING=-g

//Flags used by the C compiler during MINSIZEREL builds.
CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG

//Flags used by the C compiler during RELEASE builds.
CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG

//Flags used by the C compiler during RELWITHDEBINFO builds.
CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG

//Path to a program.
CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND

//Flags used by the linker during all build types.
CMAKE_EXE_LINKER_FLAGS:STRING=

//Flags used by the linker during DEBUG builds.
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during MINSIZEREL builds.
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during RELEASE builds.
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during RELWITHDEBINFO builds.
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//Enable/Disable output of compile commands during generation.
CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=

//Value Computed by CMake.
CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/pkgRedirects

//Install path prefix, prepended onto install directories.
CMAKE_INSTALL_PREFIX:PATH=/usr/local

//Path to a program.
CMAKE_LINKER:FILEPATH=/usr/bin/ld

//Path to a program.
CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/gmake

//Flags used by the linker during the creation of modules during
// all build types.
CMAKE_MODULE_LINKER_FLAGS:STRING=

//Flags used by the linker during the creation of modules during
// DEBUG builds.
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during the creation of modules during
// MINSIZEREL builds.
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during the creation of modules during
// RELEASE builds.
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during the creation of modules during
// RELWITHDEBINFO builds.
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//Path to a program.
CMAKE_NM:FILEPATH=/usr/bin/nm

//Path to a program.
CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy

//Path to a program.
CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump

//Value Computed by CMake
CMAKE_PROJECT_DESCRIPTION:STATIC=

//Value Computed by CMake
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=

//Value Computed by CMake
CMAKE_PROJECT_NAME:STATIC=gameboy_perfect_core

//Path to a program.
CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib

//Path to a program.
CMAKE_READELF:FILEPATH=/usr/bin/readelf

//Flags used by the linker during the creation of shared libraries
// during all build types.
CMAKE_SHARED_LINKER_FLAGS:STRING=

//Flags used by the linker during the creation of shared libraries
// during DEBUG builds.
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during the creation of shared libraries
// during MINSIZEREL builds.
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during the creation of shared libraries
// during RELEASE builds.
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during the creation of shared libraries
// during RELWITHDEBINFO builds.
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//If set, runtime paths are not added when installing shared libraries,
// but are added when building.
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO

//If set, runtime paths are not added when using shared libraries.
CMAKE_SKIP_RPATH:BOOL=NO

//Flags used by the linker during the creation of static libraries
// during all build types.
CMAKE_STATIC_LINKER_FLAGS:STRING=

//Flags used by the linker during the creation of static libraries
// during DEBUG builds.
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=

//Flags used by the linker during the creation of static libraries
// during MINSIZEREL builds.
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=

//Flags used by the linker during the creation of static libraries
// during RELEASE builds.
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=

//Flags used by the linker during the creation of static libraries
// during RELWITHDEBINFO builds.
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=

//Path to a program.
CMAKE_STRIP:FILEPATH=/usr/bin/strip

//Path to a program.
CMAKE_TAPI:FILEPATH=CMAKE_TAPI-NOTFOUND

//If this value is on, makefiles will be generated without the
// .SILENT directive, and all commands will be echoed to the console
// during the make.  This is useful for debugging only. With Visual
// Studio IDE projects all commands are done without /nologo.
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE

//Value Computed by CMake
gameboy_perfect_core_BINARY_DIR:STATIC=/home/ubuntu/Desktop/gameboy-perfect-core/build

//Value Computed by CMake
gameboy_perfect_core_IS_TOP_LEVEL:STATIC=ON

//Value Computed by CMake
gameboy_perfect_core_SOURCE_DIR:STATIC=/home/ubuntu/Desktop/gameboy-perfect-core


########################
# INTERNAL cache entries
########################

//ADVANCED property for variable: CMAKE_ADDR2LINE
CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_AR
CMAKE_AR-ADVANCED:INTERNAL=1
//This is the directory where this CMakeCache.txt was created
CMAKE_CACHEFILE_DIR:INTERNAL=/home/ubuntu/Desktop/gameboy-perfect-core/build
//Major version of cmake used to create the current loaded cache
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
//Minor version of cmake used to create the current loaded cache
CMAKE_CACHE_MINOR_VERSION:INTERNAL=28
//Patch version of cmake used to create the current loaded cache
CMAKE_CACHE_PATCH_VERSION:INTERNAL=3
//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE
CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1
//Path to CMake executable.
CMAKE_COMMAND:INTERNAL=/usr/bin/cmake
//Path to cpack program executable.
CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack
//Path to ctest program executable.
CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest
//ADVANCED property for variable: CMAKE_C_COMPILER
CMAKE_C_COMPILER-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_COMPILER_AR
CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB
CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS
CMAKE_C_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_DLLTOOL
CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
//Executable file format
CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS
CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1
//Name of external makefile project generator.
CMAKE_EXTRA_GENERATOR:INTERNAL=
//Name of generator.
CMAKE_GENERATOR:INTERNAL=Unix Makefiles
//Generator instance identifier.
CMAKE_GENERATOR_INSTANCE:INTERNAL=
//Name of generator platform.
CMAKE_GENERATOR_PLATFORM:INTERNAL=
//Name of generator toolset.
CMAKE_GENERATOR_TOOLSET:INTERNAL=
//Source directory with the top level CMakeLists.txt file for this
// project
CMAKE_HOME_DIRECTORY:INTERNAL=/home/ubuntu/Desktop/gameboy-perfect-core
//Install .so files without execute permission.
CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1
//ADVANCED property for variable: CMAKE_LINKER
CMAKE_LINKER-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MAKE_PROGRAM
CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_NM
CMAKE_NM-ADVANCED:INTERNAL=1
//number of local generators
CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
//ADVANCED property for variable: CMAKE_OBJCOPY
CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_OBJDUMP
CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
//Platform information initialized
CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
//ADVANCED property for variable: CMAKE_RANLIB
CMAKE_RANLIB-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_READELF
CMAKE_READELF-ADVANCED:INTERNAL=1
//Path to CMake installation.
CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.28
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SKIP_RPATH
CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STRIP
CMAKE_STRIP-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_TAPI
CMAKE_TAPI-ADVANCED:INTERNAL=1
//uname command
CMAKE_UNAME:INTERNAL=/usr/bin/uname
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
//linker supports push/pop state
_CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED:INTERNAL=TRUE</pre>
<h2>./build/CMakeFiles/3.28.3/CMakeCCompiler.cmake</h2>
<pre>set(CMAKE_C_COMPILER "/usr/bin/gcc-12")
set(CMAKE_C_COMPILER_ARG1 "")
set(CMAKE_C_COMPILER_ID "GNU")
set(CMAKE_C_COMPILER_VERSION "12.3.0")
set(CMAKE_C_COMPILER_VERSION_INTERNAL "")
set(CMAKE_C_COMPILER_WRAPPER "")
set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "17")
set(CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT "ON")
set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert;c_std_17;c_std_23")
set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes")
set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros")
set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert")
set(CMAKE_C17_COMPILE_FEATURES "c_std_17")
set(CMAKE_C23_COMPILE_FEATURES "c_std_23")

set(CMAKE_C_PLATFORM_ID "Linux")
set(CMAKE_C_SIMULATE_ID "")
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
set(CMAKE_C_SIMULATE_VERSION "")




set(CMAKE_AR "/usr/bin/ar")
set(CMAKE_C_COMPILER_AR "/usr/bin/gcc-ar-12")
set(CMAKE_RANLIB "/usr/bin/ranlib")
set(CMAKE_C_COMPILER_RANLIB "/usr/bin/gcc-ranlib-12")
set(CMAKE_LINKER "/usr/bin/ld")
set(CMAKE_MT "")
set(CMAKE_TAPI "CMAKE_TAPI-NOTFOUND")
set(CMAKE_COMPILER_IS_GNUCC 1)
set(CMAKE_C_COMPILER_LOADED 1)
set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_C_ABI_COMPILED TRUE)

set(CMAKE_C_COMPILER_ENV_VAR "CC")

set(CMAKE_C_COMPILER_ID_RUN 1)
set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m)
set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
set(CMAKE_C_LINKER_PREFERENCE 10)
set(CMAKE_C_LINKER_DEPFILE_SUPPORTED TRUE)

# Save compiler ABI information.
set(CMAKE_C_SIZEOF_DATA_PTR "8")
set(CMAKE_C_COMPILER_ABI "ELF")
set(CMAKE_C_BYTE_ORDER "LITTLE_ENDIAN")
set(CMAKE_C_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")

if(CMAKE_C_SIZEOF_DATA_PTR)
  set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}")
endif()

if(CMAKE_C_COMPILER_ABI)
  set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}")
endif()

if(CMAKE_C_LIBRARY_ARCHITECTURE)
  set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu")
endif()

set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "")
if(CMAKE_C_CL_SHOWINCLUDES_PREFIX)
  set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}")
endif()





set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/12/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include")
set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "gcc;gcc_s;c;gcc;gcc_s")
set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/12;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib")
set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")</pre>
<h2>./build/CMakeFiles/3.28.3/CMakeDetermineCompilerABI_C.bin</h2>
<pre>ELF&gt;@@7@8
@@@@   TT-== (.&gt;&gt;88800hhhDDStd88800Ptd   ,,QtdRtd-==/lib64/ld-linux-x86-64.so.2 GNUGNU{$$/zcQlGNUemC _ n "__libc_start_main__cxa_finalizelibc.so.6GLIBC_2.2.5GLIBC_2.34_ITM_deregisterTMCloneTable__gmon_start___ITM_registerTMCloneTable"ui	,8= =@@?????HH/HtH5/%/@%/fD1I^HHPTE11H=s/f.H=/H/H9tHV/Ht	H=i/H5b/H)HH?HHHtH%/HtfD=%/u+UH=/HtH=/)d.]wUH}HuEEHHEEHHHEEHHHEEHHEE]HHINFO:sizeof_dptr[08]NIOFb:ty_eroed[rIB_GNEIDNA]INFO:byte_order[LITTLE_ENDIAN]INFO:abi[ELF];,`HzRx`&amp;D$4(FJw?9*3$"\t{EC
r "
==oh
?0	ooooo&gt;@GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0	 p 3I@U=| =@ `   P!&gt; '?=Z  @v  @@ @ @@&amp;@){@ "#Scrt1.o__abi_tagcrtstuff.cderegister_tm_clones__do_global_dtors_auxcompleted.0__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entryCMakeCCompilerABI.cinfo_byte_order_big_endianinfo_byte_order_little_endianinfo_abi__FRAME_END___DYNAMIC__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_start_main@GLIBC_2.34_ITM_deregisterTMCloneTableinfo_sizeof_dptr_edata_fini__data_start__gmon_start____dso_handle_IO_stdin_used_end__bss_startmain__TMC_END___ITM_registerTMCloneTable__cxa_finalize@GLIBC_2.2.5_init.symtab.strtab.shstrtab.interp.note.gnu.property.note.gnu.build-id.note.ABI-tag.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.init.plt.plt.got.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.dynamic.data.bss.comment#8806hh$I Wo$aihhqo~o000  00@@d
     ,  =-=-&gt;.?/@@0@000&amp;80	3)	6</pre>
<h2>./build/CMakeFiles/3.28.3/CMakeSystem.cmake</h2>
<pre>set(CMAKE_HOST_SYSTEM "Linux-6.14.0-29-generic")
set(CMAKE_HOST_SYSTEM_NAME "Linux")
set(CMAKE_HOST_SYSTEM_VERSION "6.14.0-29-generic")
set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64")



set(CMAKE_SYSTEM "Linux-6.14.0-29-generic")
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_VERSION "6.14.0-29-generic")
set(CMAKE_SYSTEM_PROCESSOR "x86_64")

set(CMAKE_CROSSCOMPILING "FALSE")

set(CMAKE_SYSTEM_LOADED 1)</pre>
<h2>./build/CMakeFiles/3.28.3/CompilerIdC/a.out</h2>
<pre>ELF&gt;@@7@8
@@@@hh   -==HP.&gt;&gt;88800hhhDDStd88800Ptd   ,,QtdRtd-==/lib64/ld-linux-x86-64.so.2 GNUGNUV =F&amp;}7GNUemC _ n "__libc_start_main__cxa_finalizelibc.so.6GLIBC_2.2.5GLIBC_2.34_ITM_deregisterTMCloneTable__gmon_start___ITM_registerTMCloneTable"ui	,8= =@@@  @r  @ (@ 0@ ?????HH/HtH5/%/@%/fD1I^HHPTE11H=s/f.H=/H/H9tHV/Ht	H=/H5/H)HH?HHHtH%/HtfD=M/u+UH=/HtH=/)d%/]wUH}HuEH.EHHEH.EHHEH.EHHEEHHEH.EHHEHt.EHHEE]HHINFO:compiler[GNU]INFO:compiler_version[00000012.00000003.00000000]INFO:platform[Linux]INFO:arch[]INFO:standard_default[17]INFO:extensions_default[ON];(T\dtD]zRx(&amp;D$4FJw?9*3$"\tEC
 "
==oh
?08	ooooo&gt;@  r    GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0	 p 3I8@U=| =!&gt; ? B @38@:@@M \@i x@0@@@F@&amp;@8@)8@(@ "+1@ 2&gt; @Scrt1.o__abi_tagcrtstuff.cderegister_tm_clones__do_global_dtors_auxcompleted.0__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entryCMakeCCompilerId.c__FRAME_END___DYNAMIC__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_start_main@GLIBC_2.34_ITM_deregisterTMCloneTable_edata_fini__data_start__gmon_start____dso_handle_IO_stdin_usedinfo_platforminfo_language_extensions_default_endinfo_compiler__bss_startmain__TMC_END__info_language_standard_default_ITM_registerTMCloneTable__cxa_finalize@GLIBC_2.2.5_initinfo_versioninfo_arch.symtab.strtab.shstrtab.interp.note.gnu.property.note.gnu.build-id.note.ABI-tag.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.init.plt.plt.got.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.dynamic.data.bss.comment#8806hh$I Wo$aihhqo~o0008  00@@
     ,  =-=-&gt;.?/@@088@80080&amp;`0	84H6</pre>
<h2>./build/CMakeFiles/3.28.3/CompilerIdC/CMakeCCompilerId.c</h2>
<pre>#ifdef __cplusplus
# error "A C++ compiler has been selected for C."
#endif

#if defined(__18CXX)
# define ID_VOID_MAIN
#endif
#if defined(__CLASSIC_C__)
/* cv-qualifiers did not exist in K&amp;R C */
# define const
# define volatile
#endif

#if !defined(__has_include)
/* If the compiler does not have __has_include, pretend the answer is
   always no.  */
#  define __has_include(x) 0
#endif


/* Version number components: V=Version, R=Revision, P=Patch
   Version date components:   YYYY=Year, MM=Month,   DD=Day  */

#if defined(__INTEL_COMPILER) || defined(__ICC)
# define COMPILER_ID "Intel"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# if defined(__GNUC__)
#  define SIMULATE_ID "GNU"
# endif
  /* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,
     except that a few beta releases use the old format with V=2021.  */
# if __INTEL_COMPILER &lt; 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111
#  define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
#  define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
#  if defined(__INTEL_COMPILER_UPDATE)
#   define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
#  else
#   define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER   % 10)
#  endif
# else
#  define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)
#  define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)
   /* The third version component from --version is an update index,
      but no macro is provided for it.  */
#  define COMPILER_VERSION_PATCH DEC(0)
# endif
# if defined(__INTEL_COMPILER_BUILD_DATE)
   /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
#  define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
# endif
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# if defined(__GNUC__)
#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
# elif defined(__GNUG__)
#  define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
# endif
# if defined(__GNUC_MINOR__)
#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
#  define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif

#elif (defined(__clang__) &amp;&amp; defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)
# define COMPILER_ID "IntelLLVM"
#if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
#endif
#if defined(__GNUC__)
# define SIMULATE_ID "GNU"
#endif
/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
 * later.  Look for 6 digit vs. 8 digit version number to decide encoding.
 * VVVV is no smaller than the current year when a version is released.
 */
#if __INTEL_LLVM_COMPILER &lt; 1000000L
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER    % 10)
#else
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER     % 100)
#endif
#if defined(_MSC_VER)
  /* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
#endif
#if defined(__GNUC__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
#elif defined(__GNUG__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
#endif
#if defined(__GNUC_MINOR__)
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
#endif
#if defined(__GNUC_PATCHLEVEL__)
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
#endif

#elif defined(__PATHCC__)
# define COMPILER_ID "PathScale"
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
# if defined(__PATHCC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
# endif

#elif defined(__BORLANDC__) &amp;&amp; defined(__CODEGEARC_VERSION__)
# define COMPILER_ID "Embarcadero"
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__&gt;&gt;24 &amp; 0x00FF)
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__&gt;&gt;16 &amp; 0x00FF)
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__     &amp; 0xFFFF)

#elif defined(__BORLANDC__)
# define COMPILER_ID "Borland"
  /* __BORLANDC__ = 0xVRR */
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__&gt;&gt;8)
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ &amp; 0xFF)

#elif defined(__WATCOMC__) &amp;&amp; __WATCOMC__ &lt; 1200
# define COMPILER_ID "Watcom"
   /* __WATCOMC__ = VVRR */
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) &gt; 0
#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif

#elif defined(__WATCOMC__)
# define COMPILER_ID "OpenWatcom"
   /* __WATCOMC__ = VVRP + 1100 */
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) &gt; 0
#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif

#elif defined(__SUNPRO_C)
# define COMPILER_ID "SunPro"
# if __SUNPRO_C &gt;= 0x5100
   /* __SUNPRO_C = 0xVRRP */
#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C&gt;&gt;12)
#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_C&gt;&gt;4 &amp; 0xFF)
#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_C    &amp; 0xF)
# else
   /* __SUNPRO_CC = 0xVRP */
#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C&gt;&gt;8)
#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_C&gt;&gt;4 &amp; 0xF)
#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_C    &amp; 0xF)
# endif

#elif defined(__HP_cc)
# define COMPILER_ID "HP"
  /* __HP_cc = VVRRPP */
# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000)
# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__HP_cc     % 100)

#elif defined(__DECC)
# define COMPILER_ID "Compaq"
  /* __DECC_VER = VVRRTPPPP */
# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000)
# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000  % 100)
# define COMPILER_VERSION_PATCH DEC(__DECC_VER         % 10000)

#elif defined(__IBMC__) &amp;&amp; defined(__COMPILER_VER__)
# define COMPILER_ID "zOS"
  /* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)

#elif defined(__open_xl__) &amp;&amp; defined(__clang__)
# define COMPILER_ID "IBMClang"
# define COMPILER_VERSION_MAJOR DEC(__open_xl_version__)
# define COMPILER_VERSION_MINOR DEC(__open_xl_release__)
# define COMPILER_VERSION_PATCH DEC(__open_xl_modification__)
# define COMPILER_VERSION_TWEAK DEC(__open_xl_ptf_fix_level__)


#elif defined(__ibmxl__) &amp;&amp; defined(__clang__)
# define COMPILER_ID "XLClang"
# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)


#elif defined(__IBMC__) &amp;&amp; !defined(__COMPILER_VER__) &amp;&amp; __IBMC__ &gt;= 800
# define COMPILER_ID "XL"
  /* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)

#elif defined(__IBMC__) &amp;&amp; !defined(__COMPILER_VER__) &amp;&amp; __IBMC__ &lt; 800
# define COMPILER_ID "VisualAge"
  /* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)

#elif defined(__NVCOMPILER)
# define COMPILER_ID "NVHPC"
# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
# if defined(__NVCOMPILER_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
# endif

#elif defined(__PGI)
# define COMPILER_ID "PGI"
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
# if defined(__PGIC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
# endif

#elif defined(__clang__) &amp;&amp; defined(__cray__)
# define COMPILER_ID "CrayClang"
# define COMPILER_VERSION_MAJOR DEC(__cray_major__)
# define COMPILER_VERSION_MINOR DEC(__cray_minor__)
# define COMPILER_VERSION_PATCH DEC(__cray_patchlevel__)
# define COMPILER_VERSION_INTERNAL_STR __clang_version__


#elif defined(_CRAYC)
# define COMPILER_ID "Cray"
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)

#elif defined(__TI_COMPILER_VERSION__)
# define COMPILER_ID "TI"
  /* __TI_COMPILER_VERSION__ = VVVRRRPPP */
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000   % 1000)
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__        % 1000)

#elif defined(__CLANG_FUJITSU)
# define COMPILER_ID "FujitsuClang"
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# define COMPILER_VERSION_INTERNAL_STR __clang_version__


#elif defined(__FUJITSU)
# define COMPILER_ID "Fujitsu"
# if defined(__FCC_version__)
#   define COMPILER_VERSION __FCC_version__
# elif defined(__FCC_major__)
#   define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
#   define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
#   define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# endif
# if defined(__fcc_version)
#   define COMPILER_VERSION_INTERNAL DEC(__fcc_version)
# elif defined(__FCC_VERSION)
#   define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)
# endif


#elif defined(__ghs__)
# define COMPILER_ID "GHS"
/* __GHS_VERSION_NUMBER = VVVVRP */
# ifdef __GHS_VERSION_NUMBER
# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER      % 10)
# endif

#elif defined(__TASKING__)
# define COMPILER_ID "Tasking"
  # define COMPILER_VERSION_MAJOR DEC(__VERSION__/1000)
  # define COMPILER_VERSION_MINOR DEC(__VERSION__ % 100)
# define COMPILER_VERSION_INTERNAL DEC(__VERSION__)

#elif defined(__ORANGEC__)
# define COMPILER_ID "OrangeC"
# define COMPILER_VERSION_MAJOR DEC(__ORANGEC_MAJOR__)
# define COMPILER_VERSION_MINOR DEC(__ORANGEC_MINOR__)
# define COMPILER_VERSION_PATCH DEC(__ORANGEC_PATCHLEVEL__)

#elif defined(__TINYC__)
# define COMPILER_ID "TinyCC"

#elif defined(__BCC__)
# define COMPILER_ID "Bruce"

#elif defined(__SCO_VERSION__)
# define COMPILER_ID "SCO"

#elif defined(__ARMCC_VERSION) &amp;&amp; !defined(__clang__)
# define COMPILER_ID "ARMCC"
#if __ARMCC_VERSION &gt;= 1000000
  /* __ARMCC_VERSION = VRRPPPP */
  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION     % 10000)
#else
  /* __ARMCC_VERSION = VRPPPP */
  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION    % 10000)
#endif


#elif defined(__clang__) &amp;&amp; defined(__apple_build_version__)
# define COMPILER_ID "AppleClang"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)

#elif defined(__clang__) &amp;&amp; defined(__ARMCOMPILER_VERSION)
# define COMPILER_ID "ARMClang"
  # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
  # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION/100   % 100)
# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)

#elif defined(__clang__)
# define COMPILER_ID "Clang"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif

#elif defined(__LCC__) &amp;&amp; (defined(__GNUC__) || defined(__GNUG__) || defined(__MCST__))
# define COMPILER_ID "LCC"
# define COMPILER_VERSION_MAJOR DEC(__LCC__ / 100)
# define COMPILER_VERSION_MINOR DEC(__LCC__ % 100)
# if defined(__LCC_MINOR__)
#  define COMPILER_VERSION_PATCH DEC(__LCC_MINOR__)
# endif
# if defined(__GNUC__) &amp;&amp; defined(__GNUC_MINOR__)
#  define SIMULATE_ID "GNU"
#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
#  if defined(__GNUC_PATCHLEVEL__)
#   define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
#  endif
# endif

#elif defined(__GNUC__)
# define COMPILER_ID "GNU"
# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
# if defined(__GNUC_MINOR__)
#  define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif

#elif defined(_MSC_VER)
# define COMPILER_ID "MSVC"
  /* _MSC_VER = VVRR */
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
# if defined(_MSC_FULL_VER)
#  if _MSC_VER &gt;= 1400
    /* _MSC_FULL_VER = VVRRPPPPP */
#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
#  else
    /* _MSC_FULL_VER = VVRRPPPP */
#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
#  endif
# endif
# if defined(_MSC_BUILD)
#  define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
# endif

#elif defined(_ADI_COMPILER)
# define COMPILER_ID "ADSP"
#if defined(__VERSIONNUM__)
  /* __VERSIONNUM__ = 0xVVRRPPTT */
#  define COMPILER_VERSION_MAJOR DEC(__VERSIONNUM__ &gt;&gt; 24 &amp; 0xFF)
#  define COMPILER_VERSION_MINOR DEC(__VERSIONNUM__ &gt;&gt; 16 &amp; 0xFF)
#  define COMPILER_VERSION_PATCH DEC(__VERSIONNUM__ &gt;&gt; 8 &amp; 0xFF)
#  define COMPILER_VERSION_TWEAK DEC(__VERSIONNUM__ &amp; 0xFF)
#endif

#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# define COMPILER_ID "IAR"
# if defined(__VER__) &amp;&amp; defined(__ICCARM__)
#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
#  define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
#  define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# elif defined(__VER__) &amp;&amp; (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
#  define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
#  define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# endif

#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC)
# define COMPILER_ID "SDCC"
# if defined(__SDCC_VERSION_MAJOR)
#  define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR)
#  define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR)
#  define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH)
# else
  /* SDCC = VRP */
#  define COMPILER_VERSION_MAJOR DEC(SDCC/100)
#  define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10)
#  define COMPILER_VERSION_PATCH DEC(SDCC    % 10)
# endif


/* These compilers are either not known or too old to define an
  identification macro.  Try to identify the platform and guess that
  it is the native compiler.  */
#elif defined(__hpux) || defined(__hpua)
# define COMPILER_ID "HP"

#else /* unknown compiler */
# define COMPILER_ID ""
#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
#ifdef SIMULATE_ID
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
#endif

#ifdef __QNXNTO__
char const* qnxnto = "INFO" ":" "qnxnto[]";
#endif

#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
#endif

#define STRINGIFY_HELPER(X) #X
#define STRINGIFY(X) STRINGIFY_HELPER(X)

/* Identify known platforms by name.  */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"

#elif defined(__MSYS__)
# define PLATFORM_ID "MSYS"

#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"

#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"

#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"

#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"

#elif defined(__FreeBSD__) || defined(__FreeBSD)
# define PLATFORM_ID "FreeBSD"

#elif defined(__NetBSD__) || defined(__NetBSD)
# define PLATFORM_ID "NetBSD"

#elif defined(__OpenBSD__) || defined(__OPENBSD)
# define PLATFORM_ID "OpenBSD"

#elif defined(__sun) || defined(sun)
# define PLATFORM_ID "SunOS"

#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
# define PLATFORM_ID "AIX"

#elif defined(__hpux) || defined(__hpux__)
# define PLATFORM_ID "HP-UX"

#elif defined(__HAIKU__)
# define PLATFORM_ID "Haiku"

#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
# define PLATFORM_ID "BeOS"

#elif defined(__QNX__) || defined(__QNXNTO__)
# define PLATFORM_ID "QNX"

#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
# define PLATFORM_ID "Tru64"

#elif defined(__riscos) || defined(__riscos__)
# define PLATFORM_ID "RISCos"

#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
# define PLATFORM_ID "SINIX"

#elif defined(__UNIX_SV__)
# define PLATFORM_ID "UNIX_SV"

#elif defined(__bsdos__)
# define PLATFORM_ID "BSDOS"

#elif defined(_MPRAS) || defined(MPRAS)
# define PLATFORM_ID "MP-RAS"

#elif defined(__osf) || defined(__osf__)
# define PLATFORM_ID "OSF1"

#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
# define PLATFORM_ID "SCO_SV"

#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
# define PLATFORM_ID "ULTRIX"

#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
# define PLATFORM_ID "Xenix"

#elif defined(__WATCOMC__)
# if defined(__LINUX__)
#  define PLATFORM_ID "Linux"

# elif defined(__DOS__)
#  define PLATFORM_ID "DOS"

# elif defined(__OS2__)
#  define PLATFORM_ID "OS2"

# elif defined(__WINDOWS__)
#  define PLATFORM_ID "Windows3x"

# elif defined(__VXWORKS__)
#  define PLATFORM_ID "VxWorks"

# else /* unknown platform */
#  define PLATFORM_ID
# endif

#elif defined(__INTEGRITY)
# if defined(INT_178B)
#  define PLATFORM_ID "Integrity178"

# else /* regular Integrity */
#  define PLATFORM_ID "Integrity"
# endif

# elif defined(_ADI_COMPILER)
#  define PLATFORM_ID "ADSP"

#else /* unknown platform */
# define PLATFORM_ID

#endif

/* For windows compilers MSVC and Intel we can determine
   the architecture of the compiler being used.  This is because
   the compilers do not have flags that can change the architecture,
   but rather depend on which compiler is being used
*/
#if defined(_WIN32) &amp;&amp; defined(_MSC_VER)
# if defined(_M_IA64)
#  define ARCHITECTURE_ID "IA64"

# elif defined(_M_ARM64EC)
#  define ARCHITECTURE_ID "ARM64EC"

# elif defined(_M_X64) || defined(_M_AMD64)
#  define ARCHITECTURE_ID "x64"

# elif defined(_M_IX86)
#  define ARCHITECTURE_ID "X86"

# elif defined(_M_ARM64)
#  define ARCHITECTURE_ID "ARM64"

# elif defined(_M_ARM)
#  if _M_ARM == 4
#   define ARCHITECTURE_ID "ARMV4I"
#  elif _M_ARM == 5
#   define ARCHITECTURE_ID "ARMV5I"
#  else
#   define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
#  endif

# elif defined(_M_MIPS)
#  define ARCHITECTURE_ID "MIPS"

# elif defined(_M_SH)
#  define ARCHITECTURE_ID "SHx"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__WATCOMC__)
# if defined(_M_I86)
#  define ARCHITECTURE_ID "I86"

# elif defined(_M_IX86)
#  define ARCHITECTURE_ID "X86"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# if defined(__ICCARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__ICCRX__)
#  define ARCHITECTURE_ID "RX"

# elif defined(__ICCRH850__)
#  define ARCHITECTURE_ID "RH850"

# elif defined(__ICCRL78__)
#  define ARCHITECTURE_ID "RL78"

# elif defined(__ICCRISCV__)
#  define ARCHITECTURE_ID "RISCV"

# elif defined(__ICCAVR__)
#  define ARCHITECTURE_ID "AVR"

# elif defined(__ICC430__)
#  define ARCHITECTURE_ID "MSP430"

# elif defined(__ICCV850__)
#  define ARCHITECTURE_ID "V850"

# elif defined(__ICC8051__)
#  define ARCHITECTURE_ID "8051"

# elif defined(__ICCSTM8__)
#  define ARCHITECTURE_ID "STM8"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__ghs__)
# if defined(__PPC64__)
#  define ARCHITECTURE_ID "PPC64"

# elif defined(__ppc__)
#  define ARCHITECTURE_ID "PPC"

# elif defined(__ARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__x86_64__)
#  define ARCHITECTURE_ID "x64"

# elif defined(__i386__)
#  define ARCHITECTURE_ID "X86"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__TI_COMPILER_VERSION__)
# if defined(__TI_ARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__MSP430__)
#  define ARCHITECTURE_ID "MSP430"

# elif defined(__TMS320C28XX__)
#  define ARCHITECTURE_ID "TMS320C28x"

# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
#  define ARCHITECTURE_ID "TMS320C6x"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

# elif defined(__ADSPSHARC__)
#  define ARCHITECTURE_ID "SHARC"

# elif defined(__ADSPBLACKFIN__)
#  define ARCHITECTURE_ID "Blackfin"

#elif defined(__TASKING__)

# if defined(__CTC__) || defined(__CPTC__)
#  define ARCHITECTURE_ID "TriCore"

# elif defined(__CMCS__)
#  define ARCHITECTURE_ID "MCS"

# elif defined(__CARM__)
#  define ARCHITECTURE_ID "ARM"

# elif defined(__CARC__)
#  define ARCHITECTURE_ID "ARC"

# elif defined(__C51__)
#  define ARCHITECTURE_ID "8051"

# elif defined(__CPCP__)
#  define ARCHITECTURE_ID "PCP"

# else
#  define ARCHITECTURE_ID ""
# endif

#else
#  define ARCHITECTURE_ID
#endif

/* Convert integer to decimal digit literals.  */
#define DEC(n)                   \
  ('0' + (((n) / 10000000)%10)), \
  ('0' + (((n) / 1000000)%10)),  \
  ('0' + (((n) / 100000)%10)),   \
  ('0' + (((n) / 10000)%10)),    \
  ('0' + (((n) / 1000)%10)),     \
  ('0' + (((n) / 100)%10)),      \
  ('0' + (((n) / 10)%10)),       \
  ('0' +  ((n) % 10))

/* Convert integer to hex digit literals.  */
#define HEX(n)             \
  ('0' + ((n)&gt;&gt;28 &amp; 0xF)), \
  ('0' + ((n)&gt;&gt;24 &amp; 0xF)), \
  ('0' + ((n)&gt;&gt;20 &amp; 0xF)), \
  ('0' + ((n)&gt;&gt;16 &amp; 0xF)), \
  ('0' + ((n)&gt;&gt;12 &amp; 0xF)), \
  ('0' + ((n)&gt;&gt;8  &amp; 0xF)), \
  ('0' + ((n)&gt;&gt;4  &amp; 0xF)), \
  ('0' + ((n)     &amp; 0xF))

/* Construct a string literal encoding the version number. */
#ifdef COMPILER_VERSION
char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";

/* Construct a string literal encoding the version number components. */
#elif defined(COMPILER_VERSION_MAJOR)
char const info_version[] = {
  'I', 'N', 'F', 'O', ':',
  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
  COMPILER_VERSION_MAJOR,
# ifdef COMPILER_VERSION_MINOR
  '.', COMPILER_VERSION_MINOR,
#  ifdef COMPILER_VERSION_PATCH
   '.', COMPILER_VERSION_PATCH,
#   ifdef COMPILER_VERSION_TWEAK
    '.', COMPILER_VERSION_TWEAK,
#   endif
#  endif
# endif
  ']','\0'};
#endif

/* Construct a string literal encoding the internal version number. */
#ifdef COMPILER_VERSION_INTERNAL
char const info_version_internal[] = {
  'I', 'N', 'F', 'O', ':',
  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
  'i','n','t','e','r','n','a','l','[',
  COMPILER_VERSION_INTERNAL,']','\0'};
#elif defined(COMPILER_VERSION_INTERNAL_STR)
char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
#endif

/* Construct a string literal encoding the version number components. */
#ifdef SIMULATE_VERSION_MAJOR
char const info_simulate_version[] = {
  'I', 'N', 'F', 'O', ':',
  's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
  SIMULATE_VERSION_MAJOR,
# ifdef SIMULATE_VERSION_MINOR
  '.', SIMULATE_VERSION_MINOR,
#  ifdef SIMULATE_VERSION_PATCH
   '.', SIMULATE_VERSION_PATCH,
#   ifdef SIMULATE_VERSION_TWEAK
    '.', SIMULATE_VERSION_TWEAK,
#   endif
#  endif
# endif
  ']','\0'};
#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";



#if !defined(__STDC__) &amp;&amp; !defined(__clang__)
# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__)
#  define C_VERSION "90"
# else
#  define C_VERSION
# endif
#elif __STDC_VERSION__ &gt; 201710L
# define C_VERSION "23"
#elif __STDC_VERSION__ &gt;= 201710L
# define C_VERSION "17"
#elif __STDC_VERSION__ &gt;= 201000L
# define C_VERSION "11"
#elif __STDC_VERSION__ &gt;= 199901L
# define C_VERSION "99"
#else
# define C_VERSION "90"
#endif
const char* info_language_standard_default =
  "INFO" ":" "standard_default[" C_VERSION "]";

const char* info_language_extensions_default = "INFO" ":" "extensions_default["
#if (defined(__clang__) || defined(__GNUC__) || defined(__xlC__) ||           \
     defined(__TI_COMPILER_VERSION__)) &amp;&amp;                                     \
  !defined(__STRICT_ANSI__)
  "ON"
#else
  "OFF"
#endif
"]";

/*--------------------------------------------------------------------------*/

#ifdef ID_VOID_MAIN
void main() {}
#else
# if defined(__CLASSIC_C__)
int main(argc, argv) int argc; char *argv[];
# else
int main(int argc, char* argv[])
# endif
{
  int require = 0;
  require += info_compiler[argc];
  require += info_platform[argc];
  require += info_arch[argc];
#ifdef COMPILER_VERSION_MAJOR
  require += info_version[argc];
#endif
#ifdef COMPILER_VERSION_INTERNAL
  require += info_version_internal[argc];
#endif
#ifdef SIMULATE_ID
  require += info_simulate[argc];
#endif
#ifdef SIMULATE_VERSION_MAJOR
  require += info_simulate_version[argc];
#endif
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
  require += info_cray[argc];
#endif
  require += info_language_standard_default[argc];
  require += info_language_extensions_default[argc];
  (void)argv;
  return require;
}
#endif</pre>
<h2>./build/CMakeFiles/cmake.check_cache</h2>
<pre># This file is generated by cmake for dependency checking of the CMakeCache.txt file</pre>
<h2>./build/CMakeFiles/CMakeConfigureLog.yaml</h2>
<pre>
---
events:
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake:233 (message)"
      - "CMakeLists.txt:2 (project)"
    message: |
      The system is: Linux - 6.14.0-29-generic - x86_64
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:17 (message)"
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:64 (__determine_compiler_id_test)"
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCCompiler.cmake:123 (CMAKE_DETERMINE_COMPILER_ID)"
      - "CMakeLists.txt:2 (project)"
    message: |
      Compiling the C compiler identification source file "CMakeCCompilerId.c" succeeded.
      Compiler: /usr/bin/gcc-12 
      Build flags: 
      Id flags:  
      
      The output was:
      0
      
      
      Compilation of the C compiler identification source "CMakeCCompilerId.c" produced "a.out"
      
      The C compiler identification is GNU, found in:
        /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/3.28.3/CompilerIdC/a.out
      
  -
    kind: "try_compile-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:57 (try_compile)"
      - "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
      - "CMakeLists.txt:2 (project)"
    checks:
      - "Detecting C compiler ABI info"
    directories:
      source: "/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau"
      binary: "/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau"
    cmakeVariables:
      CMAKE_C_FLAGS: ""
      CMAKE_C_FLAGS_DEBUG: "-g"
      CMAKE_EXE_LINKER_FLAGS: ""
    buildResult:
      variable: "CMAKE_C_ABI_COMPILED"
      cached: true
      stdout: |
        Change Dir: '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau'
        
        Run Build Command(s): /usr/bin/cmake -E env VERBOSE=1 /usr/bin/gmake -f Makefile cmTC_964bd/fast
        /usr/bin/gmake  -f CMakeFiles/cmTC_964bd.dir/build.make CMakeFiles/cmTC_964bd.dir/build
        gmake[1]: Entering directory '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau'
        Building C object CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o
        /usr/bin/gcc-12   -v -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -c /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c
        Using built-in specs.
        COLLECT_GCC=/usr/bin/gcc-12
        OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
        OFFLOAD_TARGET_DEFAULT=1
        Target: x86_64-linux-gnu
        Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
        Thread model: posix
        Supported LTO compression algorithms: zlib zstd
        gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) 
        COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/'
         /usr/lib/gcc/x86_64-linux-gnu/12/cc1 -quiet -v -imultiarch x86_64-linux-gnu /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c -quiet -dumpdir CMakeFiles/cmTC_964bd.dir/ -dumpbase CMakeCCompilerABI.c.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/cc3SVGrU.s
        GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)
        	compiled by GNU C version 12.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP
        
        GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
        ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
        ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/include-fixed"
        ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include"
        #include "..." search starts here:
        #include &lt;...&gt; search starts here:
         /usr/lib/gcc/x86_64-linux-gnu/12/include
         /usr/local/include
         /usr/include/x86_64-linux-gnu
         /usr/include
        End of search list.
        GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)
        	compiled by GNU C version 12.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP
        
        GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
        Compiler executable checksum: 80b6e71efd51e0718437238f59d9f3d5
        COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/'
         as -v --64 -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o /tmp/cc3SVGrU.s
        GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42
        COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/
        LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/
        COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.'
        Linking C executable cmTC_964bd
        /usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_964bd.dir/link.txt --verbose=1
        /usr/bin/gcc-12  -v CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -o cmTC_964bd 
        Using built-in specs.
        COLLECT_GCC=/usr/bin/gcc-12
        COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper
        OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
        OFFLOAD_TARGET_DEFAULT=1
        Target: x86_64-linux-gnu
        Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
        Thread model: posix
        Supported LTO compression algorithms: zlib zstd
        gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) 
        COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/
        LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/
        COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_964bd' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_964bd.'
         /usr/lib/gcc/x86_64-linux-gnu/12/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/12/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper -plugin-opt=-fresolution=/tmp/ccWyJEFN.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_964bd /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/12 -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/12/../../.. CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o
        COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_964bd' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_964bd.'
        gmake[1]: Leaving directory '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau'
        
      exitCode: 0
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:127 (message)"
      - "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
      - "CMakeLists.txt:2 (project)"
    message: |
      Parsed C implicit include dir info: rv=done
        found start of include info
        found start of implicit include info
          add: [/usr/lib/gcc/x86_64-linux-gnu/12/include]
          add: [/usr/local/include]
          add: [/usr/include/x86_64-linux-gnu]
          add: [/usr/include]
        end of search list found
        collapse include dir [/usr/lib/gcc/x86_64-linux-gnu/12/include] ==&gt; [/usr/lib/gcc/x86_64-linux-gnu/12/include]
        collapse include dir [/usr/local/include] ==&gt; [/usr/local/include]
        collapse include dir [/usr/include/x86_64-linux-gnu] ==&gt; [/usr/include/x86_64-linux-gnu]
        collapse include dir [/usr/include] ==&gt; [/usr/include]
        implicit include dirs: [/usr/lib/gcc/x86_64-linux-gnu/12/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include]
      
      
  -
    kind: "message-v1"
    backtrace:
      - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:159 (message)"
      - "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
      - "CMakeLists.txt:2 (project)"
    message: |
      Parsed C implicit link information:
        link line regex: [^( *|.*[/\\])(ld|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\\]+-)?ld|collect2)[^/\\]*( |$)]
        ignore line: [Change Dir: '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau']
        ignore line: []
        ignore line: [Run Build Command(s): /usr/bin/cmake -E env VERBOSE=1 /usr/bin/gmake -f Makefile cmTC_964bd/fast]
        ignore line: [/usr/bin/gmake  -f CMakeFiles/cmTC_964bd.dir/build.make CMakeFiles/cmTC_964bd.dir/build]
        ignore line: [gmake[1]: Entering directory '/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/CMakeScratch/TryCompile-P3GOau']
        ignore line: [Building C object CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o]
        ignore line: [/usr/bin/gcc-12   -v -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -c /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c]
        ignore line: [Using built-in specs.]
        ignore line: [COLLECT_GCC=/usr/bin/gcc-12]
        ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa]
        ignore line: [OFFLOAD_TARGET_DEFAULT=1]
        ignore line: [Target: x86_64-linux-gnu]
        ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
        ignore line: [Thread model: posix]
        ignore line: [Supported LTO compression algorithms: zlib zstd]
        ignore line: [gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) ]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/']
        ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/12/cc1 -quiet -v -imultiarch x86_64-linux-gnu /usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c -quiet -dumpdir CMakeFiles/cmTC_964bd.dir/ -dumpbase CMakeCCompilerABI.c.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/cc3SVGrU.s]
        ignore line: [GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)]
        ignore line: [	compiled by GNU C version 12.3.0  GMP version 6.3.0  MPFR version 4.2.1  MPC version 1.3.1  isl version isl-0.26-GMP]
        ignore line: []
        ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
        ignore line: [ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"]
        ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/include-fixed"]
        ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include"]
        ignore line: [#include "..." search starts here:]
        ignore line: [#include &lt;...&gt; search starts here:]
        ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/12/include]
        ignore line: [ /usr/local/include]
        ignore line: [ /usr/include/x86_64-linux-gnu]
        ignore line: [ /usr/include]
        ignore line: [End of search list.]
        ignore line: [GNU C17 (Ubuntu 12.3.0-17ubuntu1) version 12.3.0 (x86_64-linux-gnu)]
        ignore line: [	compiled by GNU C version 12.3.0  GMP version 6.3.0  MPFR version 4.2.1  MPC version 1.3.1  isl version isl-0.26-GMP]
        ignore line: []
        ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
        ignore line: [Compiler executable checksum: 80b6e71efd51e0718437238f59d9f3d5]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/']
        ignore line: [ as -v --64 -o CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o /tmp/cc3SVGrU.s]
        ignore line: [GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42]
        ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/]
        ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o' '-c' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.']
        ignore line: [Linking C executable cmTC_964bd]
        ignore line: [/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_964bd.dir/link.txt --verbose=1]
        ignore line: [/usr/bin/gcc-12  -v CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -o cmTC_964bd ]
        ignore line: [Using built-in specs.]
        ignore line: [COLLECT_GCC=/usr/bin/gcc-12]
        ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper]
        ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa]
        ignore line: [OFFLOAD_TARGET_DEFAULT=1]
        ignore line: [Target: x86_64-linux-gnu]
        ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 12.3.0-17ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-12-4qxEZC/gcc-12-12.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu]
        ignore line: [Thread model: posix]
        ignore line: [Supported LTO compression algorithms: zlib zstd]
        ignore line: [gcc version 12.3.0 (Ubuntu 12.3.0-17ubuntu1) ]
        ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/]
        ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/12/../../../:/lib/:/usr/lib/]
        ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_964bd' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_964bd.']
        link line: [ /usr/lib/gcc/x86_64-linux-gnu/12/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/12/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper -plugin-opt=-fresolution=/tmp/ccWyJEFN.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_964bd /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/12 -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/12/../../.. CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/collect2] ==&gt; ignore
          arg [-plugin] ==&gt; ignore
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/liblto_plugin.so] ==&gt; ignore
          arg [-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper] ==&gt; ignore
          arg [-plugin-opt=-fresolution=/tmp/ccWyJEFN.res] ==&gt; ignore
          arg [-plugin-opt=-pass-through=-lgcc] ==&gt; ignore
          arg [-plugin-opt=-pass-through=-lgcc_s] ==&gt; ignore
          arg [-plugin-opt=-pass-through=-lc] ==&gt; ignore
          arg [-plugin-opt=-pass-through=-lgcc] ==&gt; ignore
          arg [-plugin-opt=-pass-through=-lgcc_s] ==&gt; ignore
          arg [--build-id] ==&gt; ignore
          arg [--eh-frame-hdr] ==&gt; ignore
          arg [-m] ==&gt; ignore
          arg [elf_x86_64] ==&gt; ignore
          arg [--hash-style=gnu] ==&gt; ignore
          arg [--as-needed] ==&gt; ignore
          arg [-dynamic-linker] ==&gt; ignore
          arg [/lib64/ld-linux-x86-64.so.2] ==&gt; ignore
          arg [-pie] ==&gt; ignore
          arg [-znow] ==&gt; ignore
          arg [-zrelro] ==&gt; ignore
          arg [-o] ==&gt; ignore
          arg [cmTC_964bd] ==&gt; ignore
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o] ==&gt; obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o] ==&gt; obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o] ==&gt; obj [/usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12] ==&gt; dir [/usr/lib/gcc/x86_64-linux-gnu/12]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu] ==&gt; dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib] ==&gt; dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib]
          arg [-L/lib/x86_64-linux-gnu] ==&gt; dir [/lib/x86_64-linux-gnu]
          arg [-L/lib/../lib] ==&gt; dir [/lib/../lib]
          arg [-L/usr/lib/x86_64-linux-gnu] ==&gt; dir [/usr/lib/x86_64-linux-gnu]
          arg [-L/usr/lib/../lib] ==&gt; dir [/usr/lib/../lib]
          arg [-L/usr/lib/gcc/x86_64-linux-gnu/12/../../..] ==&gt; dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../..]
          arg [CMakeFiles/cmTC_964bd.dir/CMakeCCompilerABI.c.o] ==&gt; ignore
          arg [-lgcc] ==&gt; lib [gcc]
          arg [--push-state] ==&gt; ignore
          arg [--as-needed] ==&gt; ignore
          arg [-lgcc_s] ==&gt; lib [gcc_s]
          arg [--pop-state] ==&gt; ignore
          arg [-lc] ==&gt; lib [c]
          arg [-lgcc] ==&gt; lib [gcc]
          arg [--push-state] ==&gt; ignore
          arg [--as-needed] ==&gt; ignore
          arg [-lgcc_s] ==&gt; lib [gcc_s]
          arg [--pop-state] ==&gt; ignore
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o] ==&gt; obj [/usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o]
          arg [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o] ==&gt; obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o]
        collapse obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o] ==&gt; [/usr/lib/x86_64-linux-gnu/Scrt1.o]
        collapse obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crti.o] ==&gt; [/usr/lib/x86_64-linux-gnu/crti.o]
        collapse obj [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/crtn.o] ==&gt; [/usr/lib/x86_64-linux-gnu/crtn.o]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12] ==&gt; [/usr/lib/gcc/x86_64-linux-gnu/12]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu] ==&gt; [/usr/lib/x86_64-linux-gnu]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../../../lib] ==&gt; [/usr/lib]
        collapse library dir [/lib/x86_64-linux-gnu] ==&gt; [/lib/x86_64-linux-gnu]
        collapse library dir [/lib/../lib] ==&gt; [/lib]
        collapse library dir [/usr/lib/x86_64-linux-gnu] ==&gt; [/usr/lib/x86_64-linux-gnu]
        collapse library dir [/usr/lib/../lib] ==&gt; [/usr/lib]
        collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/12/../../..] ==&gt; [/usr/lib]
        implicit libs: [gcc;gcc_s;c;gcc;gcc_s]
        implicit objs: [/usr/lib/x86_64-linux-gnu/Scrt1.o;/usr/lib/x86_64-linux-gnu/crti.o;/usr/lib/gcc/x86_64-linux-gnu/12/crtbeginS.o;/usr/lib/gcc/x86_64-linux-gnu/12/crtendS.o;/usr/lib/x86_64-linux-gnu/crtn.o]
        implicit dirs: [/usr/lib/gcc/x86_64-linux-gnu/12;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib]
        implicit fwks: []
      
      
...</pre>
<h2>./build/CMakeFiles/CMakeDirectoryInformation.cmake</h2>
<pre># CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Relative path conversion top directories.
set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/ubuntu/Desktop/gameboy-perfect-core")
set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/ubuntu/Desktop/gameboy-perfect-core/build")

# Force unix paths in dependencies.
set(CMAKE_FORCE_UNIX_PATHS 1)


# The C and CXX include file regular expressions for this directory.
set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$")
set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$")
set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})
set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN})</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/build.make</h2>
<pre># CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Delete rule output on recipe failure.
.DELETE_ON_ERROR:

#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:

# Disable VCS-based implicit rules.
% : %,v

# Disable VCS-based implicit rules.
% : RCS/%

# Disable VCS-based implicit rules.
% : RCS/%,v

# Disable VCS-based implicit rules.
% : SCCS/s.%

# Disable VCS-based implicit rules.
% : s.%

.SUFFIXES: .hpux_make_needs_suffix_list

# Command-line flag to silence nested $(MAKE).
$(VERBOSE)MAKESILENT = -s

#Suppress display of executed commands.
$(VERBOSE).SILENT:

# A target that is always out of date.
cmake_force:
.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake

# The command to remove a file.
RM = /usr/bin/cmake -E rm -f

# Escaping for special characters.
EQUALS = =

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/ubuntu/Desktop/gameboy-perfect-core

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/ubuntu/Desktop/gameboy-perfect-core/build

# Include any dependencies generated for this target.
include CMakeFiles/gameboy_perfect_core_libretro.dir/depend.make
# Include any dependencies generated by the compiler for this target.
include CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.make

# Include the progress variables for this target.
include CMakeFiles/gameboy_perfect_core_libretro.dir/progress.make

# Include the compile flags for this target's objects.
include CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_5) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_6) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_7) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o: /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c
CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o: CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_8) "Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o -MF CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o.d -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o -c /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c &gt; CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i

CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s: cmake_force
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s"
	/usr/bin/gcc-12 $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c -o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s

# Object files for target gameboy_perfect_core_libretro
gameboy_perfect_core_libretro_OBJECTS = \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o" \
"CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o"

# External object files for target gameboy_perfect_core_libretro
gameboy_perfect_core_libretro_EXTERNAL_OBJECTS =

gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/build.make
gameboy_perfect_core_libretro.so: CMakeFiles/gameboy_perfect_core_libretro.dir/link.txt
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --bold --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_9) "Linking C shared library gameboy_perfect_core_libretro.so"
	$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/gameboy_perfect_core_libretro.dir/link.txt --verbose=$(VERBOSE)

# Rule to build all files generated by this target.
CMakeFiles/gameboy_perfect_core_libretro.dir/build: gameboy_perfect_core_libretro.so
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/build

CMakeFiles/gameboy_perfect_core_libretro.dir/clean:
	$(CMAKE_COMMAND) -P CMakeFiles/gameboy_perfect_core_libretro.dir/cmake_clean.cmake
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/clean

CMakeFiles/gameboy_perfect_core_libretro.dir/depend:
	cd /home/ubuntu/Desktop/gameboy-perfect-core/build &amp;&amp; $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Desktop/gameboy-perfect-core /home/ubuntu/Desktop/gameboy-perfect-core /home/ubuntu/Desktop/gameboy-perfect-core/build /home/ubuntu/Desktop/gameboy-perfect-core/build /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/gameboy_perfect_core_libretro.dir/DependInfo.cmake "--color=$(COLOR)"
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/depend</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/cmake_clean.cmake</h2>
<pre>file(REMOVE_RECURSE
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o.d"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o"
  "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o.d"
  "gameboy_perfect_core_libretro.pdb"
  "gameboy_perfect_core_libretro.so"
)

# Per-language clean rules from dependency scanning.
foreach(lang C)
  include(CMakeFiles/gameboy_perfect_core_libretro.dir/cmake_clean_${lang}.cmake OPTIONAL)
endforeach()</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.make</h2>
<pre># Empty compiler generated dependencies file for gameboy_perfect_core_libretro.
# This may be replaced when dependencies are built.</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/compiler_depend.ts</h2>
<pre># CMAKE generated file: DO NOT EDIT!
# Timestamp file for compiler generated dependencies management for gameboy_perfect_core_libretro.</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/DependInfo.cmake</h2>
<pre>
# Consider dependencies only in project.
set(CMAKE_DEPENDS_IN_PROJECT_ONLY OFF)

# The set of languages for which implicit dependencies are needed:
set(CMAKE_DEPENDS_LANGUAGES
  )

# The set of dependency files which are needed:
set(CMAKE_DEPENDS_DEPENDENCY_FILES
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_cpu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/gba_mmu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/libretro.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o.d"
  "/home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.c" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o" "gcc" "CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o.d"
  )

# Targets to which this target links which contain Fortran sources.
set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES
  )

# Targets to which this target links which contain Fortran sources.
set(CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES
  )

# Fortran module output directory.
set(CMAKE_Fortran_TARGET_MODULE_DIR "")</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/depend.make</h2>
<pre># Empty dependencies file for gameboy_perfect_core_libretro.
# This may be replaced when dependencies are built.</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/flags.make</h2>
<pre># CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# compile C with /usr/bin/gcc-12
C_DEFINES = -Dgameboy_perfect_core_libretro_EXPORTS

C_INCLUDES = -I/home/ubuntu/Desktop/gameboy-perfect-core/include -I/home/ubuntu/Desktop/gameboy-perfect-core/include/libretro-common/include

C_FLAGS = -std=gnu99 -fPIC</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/link.txt</h2>
<pre>/usr/bin/gcc-12 -fPIC -shared -Wl,-soname,gameboy_perfect_core_libretro.so -o gameboy_perfect_core_libretro.so CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o </pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/progress.make</h2>
<pre>CMAKE_PROGRESS_1 = 1
CMAKE_PROGRESS_2 = 2
CMAKE_PROGRESS_3 = 3
CMAKE_PROGRESS_4 = 4
CMAKE_PROGRESS_5 = 5
CMAKE_PROGRESS_6 = 6
CMAKE_PROGRESS_7 = 7
CMAKE_PROGRESS_8 = 8
CMAKE_PROGRESS_9 = 9</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o</h2>
<pre>ELF&gt;	@@
UHHEHEf(fHn
f/v
UHH}HEHEf1ЃfEHEfE	ЉHEfHEt
]UHHH}HEXHHE@&lt;HEf@8HE@D_UHHH}HEHUHH H}uHEPHEHEPHHEPHHE@D9HEPHHE@D)HEPHfEHEt&gt;HEHXHE@HEH@fHnMMXEHE@t&gt;HEH XHE@ HEH@ fHnMXEHE@tkHEH(XHE@(HEH@(f(fHn
YfZf~fnMXEHE@tHEH8HMXEHEH&lt;YMYEHEE@LHEE@PUHH}HE@L]UHH}HE@P]???&gt;kJn?C|?kJn?-DT!@&gt;GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0GNUzRxIAC
D&lt;eAC
`\OEC
F|EC
VEC
EC
NEC
NIIe %O18EQViapu.csquare_wavenoise_samplefmodgb_apu_initmemsetgb_apu_resetgb_apu_stepsinfgb_apu_sample_leftgb_apu_sample_right#+9C$$,AOW4p&lt; @I`.symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.note.gnu.property.rela.eh_frame @@&amp;^,^1`D90'BR je@h	P	8}	t</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o.d</h2>
<pre>CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdbool.h /usr/include/math.h \
 /usr/include/x86_64-linux-gnu/bits/math-vector.h \
 /usr/include/x86_64-linux-gnu/bits/libm-simd-decl-stubs.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/include/x86_64-linux-gnu/bits/flt-eval-method.h \
 /usr/include/x86_64-linux-gnu/bits/fp-logb.h \
 /usr/include/x86_64-linux-gnu/bits/fp-fast.h \
 /usr/include/x86_64-linux-gnu/bits/mathcalls-helper-functions.h \
 /usr/include/x86_64-linux-gnu/bits/mathcalls.h /usr/include/string.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \
 /usr/include/strings.h</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o</h2>
<pre>ELF&gt;@@UH]UHfUfE]UH]GCC: (Ubuntu 12.3.0-17ubuntu1) 12.3.0GNUzRxEC
B&lt;EC
N\EC
B	!"audio.caudio_initaudio_sampleaudio_update @`".symtab.strtab.shstrtab.text.data.bss.comment.note.GNU-stack.note.gnu.property.rela.eh_frame@-!m'm,0m'5E ]xX@H	0
	.8g</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o.d</h2>
<pre>CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/audio.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o.d</h2>
<pre>CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h /usr/include/stdlib.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/waitflags.h \
 /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/include/x86_64-linux-gnu/sys/types.h \
 /usr/include/x86_64-linux-gnu/bits/types/clock_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/clockid_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/time_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/timer_t.h /usr/include/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endianness.h \
 /usr/include/x86_64-linux-gnu/bits/byteswap.h \
 /usr/include/x86_64-linux-gnu/bits/uintn-identity.h \
 /usr/include/x86_64-linux-gnu/sys/select.h \
 /usr/include/x86_64-linux-gnu/bits/select.h \
 /usr/include/x86_64-linux-gnu/bits/types/sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
 /usr/include/x86_64-linux-gnu/bits/thread-shared-types.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes-arch.h \
 /usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h \
 /usr/include/x86_64-linux-gnu/bits/struct_mutex.h \
 /usr/include/x86_64-linux-gnu/bits/struct_rwlock.h /usr/include/alloca.h \
 /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdbool.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h \
 /usr/include/string.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \
 /usr/include/strings.h</pre>
<h2>./build/CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o.d</h2>
<pre>CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o: \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c \
 /usr/include/stdc-predef.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
 /usr/lib/gcc/x86_64-linux-gnu/12/include/stdbool.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h \
 /usr/include/stdlib.h /usr/lib/gcc/x86_64-linux-gnu/12/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/waitflags.h \
 /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/include/x86_64-linux-gnu/sys/types.h \
 /usr/include/x86_64-linux-gnu/bits/types/clock_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/clockid_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/time_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/timer_t.h /usr/include/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endianness.h \
 /usr/include/x86_64-linux-gnu/bits/byteswap.h \
 /usr/include/x86_64-linux-gnu/bits/uintn-identity.h \
 /usr/include/x86_64-linux-gnu/sys/select.h \
 /usr/include/x86_64-linux-gnu/bits/select.h \
 /usr/include/x86_64-linux-gnu/bits/types/sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
 /usr/include/x86_64-linux-gnu/bits/thread-shared-types.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes-arch.h \
 /usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h \
 /usr/include/x86_64-linux-gnu/bits/struct_mutex.h \
 /usr/include/x86_64-linux-gnu/bits/struct_rwlock.h /usr/include/alloca.h \
 /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/ppu.h \
 /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h \
 /usr/include/string.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \
 /usr/include/strings.h</pre>
<h2>./build/CMakeFiles/Makefile2</h2>
<pre># CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target

#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:

# Disable VCS-based implicit rules.
% : %,v

# Disable VCS-based implicit rules.
% : RCS/%

# Disable VCS-based implicit rules.
% : RCS/%,v

# Disable VCS-based implicit rules.
% : SCCS/s.%

# Disable VCS-based implicit rules.
% : s.%

.SUFFIXES: .hpux_make_needs_suffix_list

# Command-line flag to silence nested $(MAKE).
$(VERBOSE)MAKESILENT = -s

#Suppress display of executed commands.
$(VERBOSE).SILENT:

# A target that is always out of date.
cmake_force:
.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake

# The command to remove a file.
RM = /usr/bin/cmake -E rm -f

# Escaping for special characters.
EQUALS = =

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/ubuntu/Desktop/gameboy-perfect-core

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/ubuntu/Desktop/gameboy-perfect-core/build

#=============================================================================
# Directory level rules for the build root directory

# The main recursive "all" target.
all: CMakeFiles/gameboy_perfect_core_libretro.dir/all
.PHONY : all

# The main recursive "preinstall" target.
preinstall:
.PHONY : preinstall

# The main recursive "clean" target.
clean: CMakeFiles/gameboy_perfect_core_libretro.dir/clean
.PHONY : clean

#=============================================================================
# Target rules for target CMakeFiles/gameboy_perfect_core_libretro.dir

# All Build rule for target.
CMakeFiles/gameboy_perfect_core_libretro.dir/all:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/depend
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/build
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --progress-dir=/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles --progress-num=1,2,3,4,5,6,7,8,9 "Built target gameboy_perfect_core_libretro"
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/all

# Build rule for subdir invocation for target.
CMakeFiles/gameboy_perfect_core_libretro.dir/rule: cmake_check_build_system
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles 9
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 CMakeFiles/gameboy_perfect_core_libretro.dir/all
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles 0
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/rule

# Convenience name for target.
gameboy_perfect_core_libretro: CMakeFiles/gameboy_perfect_core_libretro.dir/rule
.PHONY : gameboy_perfect_core_libretro

# clean rule for target.
CMakeFiles/gameboy_perfect_core_libretro.dir/clean:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/clean
.PHONY : CMakeFiles/gameboy_perfect_core_libretro.dir/clean

#=============================================================================
# Special targets to cleanup operation of make.

# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system</pre>
<h2>./build/CMakeFiles/Makefile.cmake</h2>
<pre># CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# The generator used is:
set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles")

# The top level Makefile was generated from the following files:
set(CMAKE_MAKEFILE_DEPENDS
  "CMakeCache.txt"
  "/home/ubuntu/Desktop/gameboy-perfect-core/CMakeLists.txt"
  "CMakeFiles/3.28.3/CMakeCCompiler.cmake"
  "CMakeFiles/3.28.3/CMakeSystem.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeCCompiler.cmake.in"
  "/usr/share/cmake-3.28/Modules/CMakeCCompilerABI.c"
  "/usr/share/cmake-3.28/Modules/CMakeCInformation.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeCommonLanguageInclude.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeCompilerIdDetection.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompileFeatures.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeFindBinUtils.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeGenericSystem.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeInitializeConfigs.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeLanguageInformation.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeParseImplicitIncludeInfo.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeParseImplicitLinkInfo.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeParseLibraryArchitecture.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeSystem.cmake.in"
  "/usr/share/cmake-3.28/Modules/CMakeSystemSpecificInformation.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeSystemSpecificInitialize.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeTestCCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeTestCompilerCommon.cmake"
  "/usr/share/cmake-3.28/Modules/CMakeUnixFindMake.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/ADSP-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/ARMCC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/ARMClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/AppleClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Borland-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Bruce-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Clang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Compaq-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Cray-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/CrayClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Embarcadero-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Fujitsu-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GHS-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU-C.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU-FindBinUtils.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/GNU.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/HP-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IAR-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IBMClang-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Intel-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/LCC-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/MSVC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/NVHPC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/NVIDIA-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/OrangeC-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/PGI-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/PathScale-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/SCO-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/SDCC-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/SunPro-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/TI-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Tasking-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/Watcom-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/XL-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/XLClang-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Compiler/zOS-C-DetermineCompiler.cmake"
  "/usr/share/cmake-3.28/Modules/Internal/FeatureTesting.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux-GNU-C.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux-GNU.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux-Initialize.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/Linux.cmake"
  "/usr/share/cmake-3.28/Modules/Platform/UnixPaths.cmake"
  )

# The corresponding makefile is:
set(CMAKE_MAKEFILE_OUTPUTS
  "Makefile"
  "CMakeFiles/cmake.check_cache"
  )

# Byproducts of CMake generate step:
set(CMAKE_MAKEFILE_PRODUCTS
  "CMakeFiles/3.28.3/CMakeSystem.cmake"
  "CMakeFiles/3.28.3/CMakeCCompiler.cmake"
  "CMakeFiles/3.28.3/CMakeCCompiler.cmake"
  "CMakeFiles/CMakeDirectoryInformation.cmake"
  )

# Dependency information for all targets:
set(CMAKE_DEPEND_INFO_FILES
  "CMakeFiles/gameboy_perfect_core_libretro.dir/DependInfo.cmake"
  )</pre>
<h2>./build/CMakeFiles/Progress/1</h2>
<pre>empty</pre>
<h2>./build/CMakeFiles/Progress/2</h2>
<pre>empty</pre>
<h2>./build/CMakeFiles/Progress/3</h2>
<pre>empty</pre>
<h2>./build/CMakeFiles/Progress/4</h2>
<pre>empty</pre>
<h2>./build/CMakeFiles/Progress/count.txt</h2>
<pre>9</pre>
<h2>./build/CMakeFiles/progress.marks</h2>
<pre>9</pre>
<h2>./build/CMakeFiles/TargetDirectories.txt</h2>
<pre>/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/gameboy_perfect_core_libretro.dir
/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/edit_cache.dir
/home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles/rebuild_cache.dir</pre>
<h2>./build/cmake_install.cmake</h2>
<pre># Install script for directory: /home/ubuntu/Desktop/gameboy-perfect-core

# Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
  set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")

# Set the install configuration name.
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
  if(BUILD_TYPE)
    string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
           CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
  else()
    set(CMAKE_INSTALL_CONFIG_NAME "")
  endif()
  message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
endif()

# Set the component getting installed.
if(NOT CMAKE_INSTALL_COMPONENT)
  if(COMPONENT)
    message(STATUS "Install component: \"${COMPONENT}\"")
    set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
  else()
    set(CMAKE_INSTALL_COMPONENT)
  endif()
endif()

# Install shared libraries without execute permission?
if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
  set(CMAKE_INSTALL_SO_NO_EXE "1")
endif()

# Is this installation the result of a crosscompile?
if(NOT DEFINED CMAKE_CROSSCOMPILING)
  set(CMAKE_CROSSCOMPILING "FALSE")
endif()

# Set default install directory permissions.
if(NOT DEFINED CMAKE_OBJDUMP)
  set(CMAKE_OBJDUMP "/usr/bin/objdump")
endif()

if(CMAKE_INSTALL_COMPONENT)
  set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
else()
  set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
endif()

string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
       "${CMAKE_INSTALL_MANIFEST_FILES}")
file(WRITE "/home/ubuntu/Desktop/gameboy-perfect-core/build/${CMAKE_INSTALL_MANIFEST}"
     "${CMAKE_INSTALL_MANIFEST_CONTENT}")</pre>
<h2>./build_log.txt</h2>
<pre>[*] Cleaning old build...
[*] Configuring with CMake...
-- The C compiler identification is GNU 12.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/gcc-12 - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /home/ubuntu/Desktop/gameboy-perfect-core/build
[*] Building...
[ 11%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
[ 22%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘-&gt;’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘-&gt;’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:35: error: unknown type name ‘uint8_t’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                   ^~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:1: note: ‘uint8_t’ is defined in header ‘&lt;stdint.h&gt;’; did you forget to ‘#include &lt;stdint.h&gt;’?
  +++ |+#include &lt;stdint.h&gt;
    1 |       |                                                    ^~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘-&gt;’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘-&gt;’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘-&gt;’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘-&gt;’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘-&gt;’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
[ 33%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘-&gt;’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘-&gt;’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:8,
                 from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘-&gt;’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘-&gt;’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘-&gt;’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:2:
/usr/include/string.h:44:22: error: unknown type name ‘size_t’
   44 |                      size_t __n) __THROW __nonnull ((1, 2));
      |                      ^~~~~~
/usr/include/string.h:34:1: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
   33 | #include &lt;stddef.h&gt;
  +++ |+#include &lt;stddef.h&gt;
   34 | 
/usr/include/string.h:47:56: error: unknown type name ‘size_t’
   47 | extern void *memmove (void *__dest, const void *__src, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:47:56: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:55:32: error: unknown type name ‘size_t’
   55 |                       int __c, size_t __n)
      |                                ^~~~~~
/usr/include/string.h:55:32: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:61:42: error: unknown type name ‘size_t’
   61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
      |                                          ^~~~~~
/usr/include/string.h:61:42: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:64:56: error: unknown type name ‘size_t’
   64 | extern int memcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:64:56: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:80:60: error: unknown type name ‘size_t’
   80 | extern int __memcmpeq (const void *__s1, const void *__s2, size_t __n)
      |                                                            ^~~~~~
/usr/include/string.h:80:60: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:107:48: error: unknown type name ‘size_t’
  107 | extern void *memchr (const void *__s, int __c, size_t __n)
      |                                                ^~~~~~
/usr/include/string.h:107:48: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:145:53: error: unknown type name ‘size_t’
  145 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:145:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:153:23: error: unknown type name ‘size_t’
  153 |                       size_t __n) __THROW __nonnull ((1, 2));
      |                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘-&gt;’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:153:23: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:159:57: error: unknown type name ‘size_t’
  159 | extern int strncmp (const char *__s1, const char *__s2, size_t __n)
      |                                                         ^~~~~~
/usr/include/string.h:159:57: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/usr/include/string.h:166:8: error: unknown type name ‘size_t’
  166 | extern size_t strxfrm (char *__restrict __dest,
      |        ^~~~~~
/usr/include/string.h:167:54: error: unknown type name ‘size_t’
  167 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:167:54: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:179:8: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |        ^~~~~~
/usr/include/string.h:179:59: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |                                                           ^~~~~~
/usr/include/string.h:179:59: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:195:45: error: unknown type name ‘size_t’
  195 | extern char *strndup (const char *__string, size_t __n)
      |                                             ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:195:45: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/usr/include/string.h:293:8: error: unknown type name ‘size_t’
  293 | extern size_t strcspn (const char *__s, const char *__reject)
      |        ^~~~~~
/usr/include/string.h:297:8: error: unknown type name ‘size_t’
  297 | extern size_t strspn (const char *__s, const char *__accept)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/usr/include/string.h:389:46: error: unknown type name ‘size_t’
  389 | extern void *memmem (const void *__haystack, size_t __haystacklen,
      |                                              ^~~~~~
/usr/include/string.h:389:46: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:390:44: error: unknown type name ‘size_t’
  390 |                      const void *__needle, size_t __needlelen)
      |                                            ^~~~~~
/usr/include/string.h:390:44: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:398:55: error: unknown type name ‘size_t’
  398 |                         const void *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/usr/include/string.h:398:55: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/usr/include/string.h:401:53: error: unknown type name ‘size_t’
  401 |                       const void *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:401:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:407:8: error: unknown type name ‘size_t’
  407 | extern size_t strlen (const char *__s)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/usr/include/string.h:413:8: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |        ^~~~~~
/usr/include/string.h:413:46: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:413:46: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘-&gt;’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
In file included from /usr/include/features.h:502,
                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
                 from /usr/include/string.h:26:
/usr/include/string.h:432:12: error: unknown type name ‘size_t’
  432 | extern int __REDIRECT_NTH (strerror_r,
      |            ^~~~~~~~~~~~~~
/usr/include/string.h:432:12: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
In file included from /usr/include/string.h:462:
/usr/include/strings.h:34:54: error: unknown type name ‘size_t’
   34 | extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                      ^~~~~~
/usr/include/strings.h:24:1: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
   23 | #include &lt;stddef.h&gt;
  +++ |+#include &lt;stddef.h&gt;
   24 | 
/usr/include/strings.h:38:53: error: unknown type name ‘size_t’
   38 | extern void bcopy (const void *__src, void *__dest, size_t __n)
      |                                                     ^~~~~~
/usr/include/strings.h:38:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/strings.h:42:31: error: unknown type name ‘size_t’
   42 | extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
      |                               ^~~~~~
/usr/include/strings.h:42:31: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/usr/include/strings.h:120:61: error: unknown type name ‘size_t’
  120 | extern int strncasecmp (const char *__s1, const char *__s2, size_t __n)
      |                                                             ^~~~~~
/usr/include/strings.h:120:61: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/strings.h:134:27: error: unknown type name ‘size_t’
  134 |                           size_t __n, locale_t __loc)
      |                           ^~~~~~
/usr/include/strings.h:134:27: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:466:40: error: unknown type name ‘size_t’
  466 | extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1))
      |                                        ^~~~~~
/usr/include/string.h:466:40: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:497:55: error: unknown type name ‘size_t’
  497 |                         const char *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘-&gt;’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/string.h:497:55: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:500:53: error: unknown type name ‘size_t’
  500 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:500:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:506:8: error: unknown type name ‘size_t’
  506 | extern size_t strlcpy (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:507:54: error: unknown type name ‘size_t’
  507 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:507:54: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:512:8: error: unknown type name ‘size_t’
  512 | extern size_t strlcat (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:513:54: error: unknown type name ‘size_t’
  513 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:513:54: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:5:19: error: unknown type name ‘gb_apu_t’
    5 | void gb_apu_reset(gb_apu_t *apu) {
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:11:18: error: unknown type name ‘gb_apu_t’
   11 | void gb_apu_step(gb_apu_t *apu, int cycles) {
      |                  ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:90: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘-&gt;’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘-&gt;’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘-&gt;’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: data definition has no type or storage class
   17 | } core_state_t;
      |   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: type defaults to ‘int’ in declaration of ‘core_state_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:19:1: error: unknown type name ‘core_state_t’
   19 | core_state_t* gb_core_create(void);
      | ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:20:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   20 | void gb_core_destroy(core_state_t* state);
      |                      ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_init(core_state_t* state, const uint8_t* rom_data, size_t rom_size);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:22:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   22 | void gb_core_step(core_state_t* state);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:23:25: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   23 | int gb_core_frame_ready(core_state_t* state);
      |                         ^~~~~~~~~~~~
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:4:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘-&gt;’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘-&gt;’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: error: redefinition of ‘val’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘-&gt;’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘-&gt;’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘-&gt;’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘-&gt;’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘-&gt;’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘-&gt;’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘-&gt;’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:5:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: data definition has no type or storage class
   25 | } gb_mmu_t;
      |   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: type defaults to ‘int’ in declaration of ‘gb_mmu_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:28:19: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   28 | void gb_mmu_reset(gb_mmu_t *mmu);
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:31:26: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   31 | uint8_t gb_mmu_read_byte(gb_mmu_t *mmu, uint16_t addr);
      |                          ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:34:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   34 | void gb_mmu_write_byte(gb_mmu_t *mmu, uint16_t addr, uint8_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:37:27: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   37 | uint16_t gb_mmu_read_word(gb_mmu_t *mmu, uint16_t addr);
      |                           ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:40:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   40 | void gb_mmu_write_word(gb_mmu_t *mmu, uint16_t addr, uint16_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:9:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
    9 | void gb_core_init(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_step(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:28:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   28 | void gb_core_destroy(core_state_t *state) {
      |                      ^~~~~~~~~~~~
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:104: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/gameboy_perfect_core_libretro.dir/all] Error 2
make: *** [Makefile:91: all] Error 2</pre>
<h2>./build/Makefile</h2>
<pre># CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.28

# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target

# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:

#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:

# Disable VCS-based implicit rules.
% : %,v

# Disable VCS-based implicit rules.
% : RCS/%

# Disable VCS-based implicit rules.
% : RCS/%,v

# Disable VCS-based implicit rules.
% : SCCS/s.%

# Disable VCS-based implicit rules.
% : s.%

.SUFFIXES: .hpux_make_needs_suffix_list

# Command-line flag to silence nested $(MAKE).
$(VERBOSE)MAKESILENT = -s

#Suppress display of executed commands.
$(VERBOSE).SILENT:

# A target that is always out of date.
cmake_force:
.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake

# The command to remove a file.
RM = /usr/bin/cmake -E rm -f

# Escaping for special characters.
EQUALS = =

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/ubuntu/Desktop/gameboy-perfect-core

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/ubuntu/Desktop/gameboy-perfect-core/build

#=============================================================================
# Targets provided globally by CMake.

# Special rule for the target edit_cache
edit_cache:
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "No interactive CMake dialog available..."
	/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
.PHONY : edit_cache

# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast

# Special rule for the target rebuild_cache
rebuild_cache:
	@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..."
	/usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache

# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast

# The main all target
all: cmake_check_build_system
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles /home/ubuntu/Desktop/gameboy-perfect-core/build//CMakeFiles/progress.marks
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all
	$(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Desktop/gameboy-perfect-core/build/CMakeFiles 0
.PHONY : all

# The main clean target
clean:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean
.PHONY : clean

# The main clean target
clean/fast: clean
.PHONY : clean/fast

# Prepare targets for installation.
preinstall: all
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall

# Prepare targets for installation.
preinstall/fast:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall/fast

# clear depends
depend:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
.PHONY : depend

#=============================================================================
# Target rules for targets named gameboy_perfect_core_libretro

# Build rule for target.
gameboy_perfect_core_libretro: cmake_check_build_system
	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 gameboy_perfect_core_libretro
.PHONY : gameboy_perfect_core_libretro

# fast build rule for target.
gameboy_perfect_core_libretro/fast:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/build
.PHONY : gameboy_perfect_core_libretro/fast

src/common/apu.o: src/common/apu.c.o
.PHONY : src/common/apu.o

# target to build an object file
src/common/apu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
.PHONY : src/common/apu.c.o

src/common/apu.i: src/common/apu.c.i
.PHONY : src/common/apu.i

# target to preprocess a source file
src/common/apu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.i
.PHONY : src/common/apu.c.i

src/common/apu.s: src/common/apu.c.s
.PHONY : src/common/apu.s

# target to generate assembly for a file
src/common/apu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.s
.PHONY : src/common/apu.c.s

src/common/audio.o: src/common/audio.c.o
.PHONY : src/common/audio.o

# target to build an object file
src/common/audio.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
.PHONY : src/common/audio.c.o

src/common/audio.i: src/common/audio.c.i
.PHONY : src/common/audio.i

# target to preprocess a source file
src/common/audio.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.i
.PHONY : src/common/audio.c.i

src/common/audio.s: src/common/audio.c.s
.PHONY : src/common/audio.s

# target to generate assembly for a file
src/common/audio.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.s
.PHONY : src/common/audio.c.s

src/common/core_state.o: src/common/core_state.c.o
.PHONY : src/common/core_state.o

# target to build an object file
src/common/core_state.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
.PHONY : src/common/core_state.c.o

src/common/core_state.i: src/common/core_state.c.i
.PHONY : src/common/core_state.i

# target to preprocess a source file
src/common/core_state.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.i
.PHONY : src/common/core_state.c.i

src/common/core_state.s: src/common/core_state.c.s
.PHONY : src/common/core_state.s

# target to generate assembly for a file
src/common/core_state.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.s
.PHONY : src/common/core_state.c.s

src/common/cpu.o: src/common/cpu.c.o
.PHONY : src/common/cpu.o

# target to build an object file
src/common/cpu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.o
.PHONY : src/common/cpu.c.o

src/common/cpu.i: src/common/cpu.c.i
.PHONY : src/common/cpu.i

# target to preprocess a source file
src/common/cpu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.i
.PHONY : src/common/cpu.c.i

src/common/cpu.s: src/common/cpu.c.s
.PHONY : src/common/cpu.s

# target to generate assembly for a file
src/common/cpu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/cpu.c.s
.PHONY : src/common/cpu.c.s

src/common/gba_cpu.o: src/common/gba_cpu.c.o
.PHONY : src/common/gba_cpu.o

# target to build an object file
src/common/gba_cpu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.o
.PHONY : src/common/gba_cpu.c.o

src/common/gba_cpu.i: src/common/gba_cpu.c.i
.PHONY : src/common/gba_cpu.i

# target to preprocess a source file
src/common/gba_cpu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.i
.PHONY : src/common/gba_cpu.c.i

src/common/gba_cpu.s: src/common/gba_cpu.c.s
.PHONY : src/common/gba_cpu.s

# target to generate assembly for a file
src/common/gba_cpu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_cpu.c.s
.PHONY : src/common/gba_cpu.c.s

src/common/gba_mmu.o: src/common/gba_mmu.c.o
.PHONY : src/common/gba_mmu.o

# target to build an object file
src/common/gba_mmu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.o
.PHONY : src/common/gba_mmu.c.o

src/common/gba_mmu.i: src/common/gba_mmu.c.i
.PHONY : src/common/gba_mmu.i

# target to preprocess a source file
src/common/gba_mmu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.i
.PHONY : src/common/gba_mmu.c.i

src/common/gba_mmu.s: src/common/gba_mmu.c.s
.PHONY : src/common/gba_mmu.s

# target to generate assembly for a file
src/common/gba_mmu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/gba_mmu.c.s
.PHONY : src/common/gba_mmu.c.s

src/common/libretro.o: src/common/libretro.c.o
.PHONY : src/common/libretro.o

# target to build an object file
src/common/libretro.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.o
.PHONY : src/common/libretro.c.o

src/common/libretro.i: src/common/libretro.c.i
.PHONY : src/common/libretro.i

# target to preprocess a source file
src/common/libretro.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.i
.PHONY : src/common/libretro.c.i

src/common/libretro.s: src/common/libretro.c.s
.PHONY : src/common/libretro.s

# target to generate assembly for a file
src/common/libretro.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/libretro.c.s
.PHONY : src/common/libretro.c.s

src/common/ppu.o: src/common/ppu.c.o
.PHONY : src/common/ppu.o

# target to build an object file
src/common/ppu.c.o:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.o
.PHONY : src/common/ppu.c.o

src/common/ppu.i: src/common/ppu.c.i
.PHONY : src/common/ppu.i

# target to preprocess a source file
src/common/ppu.c.i:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.i
.PHONY : src/common/ppu.c.i

src/common/ppu.s: src/common/ppu.c.s
.PHONY : src/common/ppu.s

# target to generate assembly for a file
src/common/ppu.c.s:
	$(MAKE) $(MAKESILENT) -f CMakeFiles/gameboy_perfect_core_libretro.dir/build.make CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/ppu.c.s
.PHONY : src/common/ppu.c.s

# Help Target
help:
	@echo "The following are some of the valid targets for this Makefile:"
	@echo "... all (the default if no target is provided)"
	@echo "... clean"
	@echo "... depend"
	@echo "... edit_cache"
	@echo "... rebuild_cache"
	@echo "... gameboy_perfect_core_libretro"
	@echo "... src/common/apu.o"
	@echo "... src/common/apu.i"
	@echo "... src/common/apu.s"
	@echo "... src/common/audio.o"
	@echo "... src/common/audio.i"
	@echo "... src/common/audio.s"
	@echo "... src/common/core_state.o"
	@echo "... src/common/core_state.i"
	@echo "... src/common/core_state.s"
	@echo "... src/common/cpu.o"
	@echo "... src/common/cpu.i"
	@echo "... src/common/cpu.s"
	@echo "... src/common/gba_cpu.o"
	@echo "... src/common/gba_cpu.i"
	@echo "... src/common/gba_cpu.s"
	@echo "... src/common/gba_mmu.o"
	@echo "... src/common/gba_mmu.i"
	@echo "... src/common/gba_mmu.s"
	@echo "... src/common/libretro.o"
	@echo "... src/common/libretro.i"
	@echo "... src/common/libretro.s"
	@echo "... src/common/ppu.o"
	@echo "... src/common/ppu.i"
	@echo "... src/common/ppu.s"
.PHONY : help



#=============================================================================
# Special targets to cleanup operation of make.

# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system</pre>
<h2>./build.sh</h2>
<pre>#!/bin/bash
set -e

echo "[*] Cleaning old build..."
rm -rf build
mkdir -p build
cd build

echo "[*] Configuring with CMake..."
cmake ..

echo "[*] Building..."
make -j$(nproc)

echo "[*] Done!"
echo "Output core: $(realpath gameboy_perfect_core_libretro.so)"</pre>
<h2>./CMakeLists.txt</h2>
<pre>cmake_minimum_required(VERSION 3.10)
project(gameboy_perfect_core C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

set(SRC
    src/common/audio.c
    src/common/apu.c
    src/common/core_state.c
    src/common/cpu.c
    src/common/gba_cpu.c
    src/common/gba_mmu.c
    src/common/libretro.c
    src/common/ppu.c
)

include_directories(
    include
    include/libretro-common/include
)

add_library(gameboy_perfect_core_libretro SHARED ${SRC})

set_target_properties(gameboy_perfect_core_libretro PROPERTIES
    PREFIX ""
    OUTPUT_NAME "gameboy_perfect_core_libretro"
)</pre>
<h2>./errors_only.txt</h2>
<pre>-- Build files have been written to: /home/ubuntu/Desktop/gameboy-perfect-core/build
[*] Building...
[ 11%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o
[ 22%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/audio.c.o
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘-&gt;’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘-&gt;’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:35: error: unknown type name ‘uint8_t’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                   ^~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:1: note: ‘uint8_t’ is defined in header ‘&lt;stdint.h&gt;’; did you forget to ‘#include &lt;stdint.h&gt;’?
  +++ |+#include &lt;stdint.h&gt;
    1 |       |                                                    ^~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘-&gt;’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: redefinition of ‘val’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘int’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘-&gt;’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘-&gt;’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘-&gt;’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘-&gt;’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
[ 33%] Building C object CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘-&gt;’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘-&gt;’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:8,
                 from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:1:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘-&gt;’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘-&gt;’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:47: warning: implicit declaration of function ‘gb_mmu_read_byte’ [-Wimplicit-function-declaration]
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                               ^~~~~~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:64: error: ‘state’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                ^~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:75: error: ‘hl’ undeclared here (not in a function)
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                           ^~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘-&gt;’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:2:
/usr/include/string.h:44:22: error: unknown type name ‘size_t’
   44 |                      size_t __n) __THROW __nonnull ((1, 2));
      |                      ^~~~~~
/usr/include/string.h:34:1: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
   33 | #include &lt;stddef.h&gt;
  +++ |+#include &lt;stddef.h&gt;
   34 | 
/usr/include/string.h:47:56: error: unknown type name ‘size_t’
   47 | extern void *memmove (void *__dest, const void *__src, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:47:56: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:55:32: error: unknown type name ‘size_t’
   55 |                       int __c, size_t __n)
      |                                ^~~~~~
/usr/include/string.h:55:32: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:61:42: error: unknown type name ‘size_t’
   61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
      |                                          ^~~~~~
/usr/include/string.h:61:42: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:64:56: error: unknown type name ‘size_t’
   64 | extern int memcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                        ^~~~~~
/usr/include/string.h:64:56: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:80:60: error: unknown type name ‘size_t’
   80 | extern int __memcmpeq (const void *__s1, const void *__s2, size_t __n)
      |                                                            ^~~~~~
/usr/include/string.h:80:60: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:107:48: error: unknown type name ‘size_t’
  107 | extern void *memchr (const void *__s, int __c, size_t __n)
      |                                                ^~~~~~
/usr/include/string.h:107:48: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:145:53: error: unknown type name ‘size_t’
  145 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:145:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:153:23: error: unknown type name ‘size_t’
  153 |                       size_t __n) __THROW __nonnull ((1, 2));
      |                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘-&gt;’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:153:23: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:159:57: error: unknown type name ‘size_t’
  159 | extern int strncmp (const char *__s1, const char *__s2, size_t __n)
      |                                                         ^~~~~~
/usr/include/string.h:159:57: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/usr/include/string.h:166:8: error: unknown type name ‘size_t’
  166 | extern size_t strxfrm (char *__restrict __dest,
      |        ^~~~~~
/usr/include/string.h:167:54: error: unknown type name ‘size_t’
  167 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:167:54: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:179:8: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |        ^~~~~~
/usr/include/string.h:179:59: error: unknown type name ‘size_t’
  179 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
      |                                                           ^~~~~~
/usr/include/string.h:179:59: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:195:45: error: unknown type name ‘size_t’
  195 | extern char *strndup (const char *__string, size_t __n)
      |                                             ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:195:45: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/usr/include/string.h:293:8: error: unknown type name ‘size_t’
  293 | extern size_t strcspn (const char *__s, const char *__reject)
      |        ^~~~~~
/usr/include/string.h:297:8: error: unknown type name ‘size_t’
  297 | extern size_t strspn (const char *__s, const char *__accept)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/usr/include/string.h:389:46: error: unknown type name ‘size_t’
  389 | extern void *memmem (const void *__haystack, size_t __haystacklen,
      |                                              ^~~~~~
/usr/include/string.h:389:46: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:390:44: error: unknown type name ‘size_t’
  390 |                      const void *__needle, size_t __needlelen)
      |                                            ^~~~~~
/usr/include/string.h:390:44: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:398:55: error: unknown type name ‘size_t’
  398 |                         const void *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/usr/include/string.h:398:55: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/usr/include/string.h:401:53: error: unknown type name ‘size_t’
  401 |                       const void *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:401:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:407:8: error: unknown type name ‘size_t’
  407 | extern size_t strlen (const char *__s)
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/usr/include/string.h:413:8: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |        ^~~~~~
/usr/include/string.h:413:46: error: unknown type name ‘size_t’
  413 | extern size_t strnlen (const char *__string, size_t __maxlen)
      |                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:413:46: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘-&gt;’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
In file included from /usr/include/features.h:502,
                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
                 from /usr/include/string.h:26:
/usr/include/string.h:432:12: error: unknown type name ‘size_t’
  432 | extern int __REDIRECT_NTH (strerror_r,
      |            ^~~~~~~~~~~~~~
/usr/include/string.h:432:12: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
In file included from /usr/include/string.h:462:
/usr/include/strings.h:34:54: error: unknown type name ‘size_t’
   34 | extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      |                                                      ^~~~~~
/usr/include/strings.h:24:1: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
   23 | #include &lt;stddef.h&gt;
  +++ |+#include &lt;stddef.h&gt;
   24 | 
/usr/include/strings.h:38:53: error: unknown type name ‘size_t’
   38 | extern void bcopy (const void *__src, void *__dest, size_t __n)
      |                                                     ^~~~~~
/usr/include/strings.h:38:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/strings.h:42:31: error: unknown type name ‘size_t’
   42 | extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
      |                               ^~~~~~
/usr/include/strings.h:42:31: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/usr/include/strings.h:120:61: error: unknown type name ‘size_t’
  120 | extern int strncasecmp (const char *__s1, const char *__s2, size_t __n)
      |                                                             ^~~~~~
/usr/include/strings.h:120:61: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/strings.h:134:27: error: unknown type name ‘size_t’
  134 |                           size_t __n, locale_t __loc)
      |                           ^~~~~~
/usr/include/strings.h:134:27: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:466:40: error: unknown type name ‘size_t’
  466 | extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1))
      |                                        ^~~~~~
/usr/include/string.h:466:40: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/usr/include/string.h:497:55: error: unknown type name ‘size_t’
  497 |                         const char *__restrict __src, size_t __n)
      |                                                       ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘-&gt;’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/usr/include/string.h:497:55: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:500:53: error: unknown type name ‘size_t’
  500 |                       const char *__restrict __src, size_t __n)
      |                                                     ^~~~~~
/usr/include/string.h:500:53: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/usr/include/string.h:506:8: error: unknown type name ‘size_t’
  506 | extern size_t strlcpy (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/usr/include/string.h:507:54: error: unknown type name ‘size_t’
  507 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:507:54: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/usr/include/string.h:512:8: error: unknown type name ‘size_t’
  512 | extern size_t strlcat (char *__restrict __dest,
      |        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/usr/include/string.h:513:54: error: unknown type name ‘size_t’
  513 |                        const char *__restrict __src, size_t __n)
      |                                                      ^~~~~~
/usr/include/string.h:513:54: note: ‘size_t’ is defined in header ‘&lt;stddef.h&gt;’; did you forget to ‘#include &lt;stddef.h&gt;’?
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:5:19: error: unknown type name ‘gb_apu_t’
    5 | void gb_apu_reset(gb_apu_t *apu) {
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.c:11:18: error: unknown type name ‘gb_apu_t’
   11 | void gb_apu_step(gb_apu_t *apu, int cycles) {
      |                  ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:90: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/apu.c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘-&gt;’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘-&gt;’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘-&gt;’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: data definition has no type or storage class
   17 | } core_state_t;
      |   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:17:3: warning: type defaults to ‘int’ in declaration of ‘core_state_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:19:1: error: unknown type name ‘core_state_t’
   19 | core_state_t* gb_core_create(void);
      | ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:20:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   20 | void gb_core_destroy(core_state_t* state);
      |                      ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_init(core_state_t* state, const uint8_t* rom_data, size_t rom_size);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:22:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   22 | void gb_core_step(core_state_t* state);
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.h:23:25: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   23 | int gb_core_frame_ready(core_state_t* state);
      |                         ^~~~~~~~~~~~
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:4:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
    1 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
    3 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
    5 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
    6 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
    8 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘-&gt;’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
    9 |   107 |         case 0x05: cpu-&gt;l=(cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
   10 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
   12 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
   14 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘-&gt;’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
   15 |   107 | (cpu-&gt;l&lt;&lt;1)|(cpu-&gt;l&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
   16 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
   19 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
   21 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
   22 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
   24 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
   25 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
   26 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
   29 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
   31 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
   32 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
   34 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:107:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
   35 |   107 | _FLAG(cpu,FLAG_Z,cpu-&gt;l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;l&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token
   36 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:75: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:105: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:118: error: universal character \u2019 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:138: error: unknown type name ‘has’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                          ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                 ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:145: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2018 is not valid in an identifier
   38 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:80: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                              ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:38:158: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: error: redefinition of ‘val’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: data definition has no type or storage class
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:80: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:84: error: initializer element is not constant
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:126: error: expected ‘)’ before ‘-&gt;’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                              ^~
      |                                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:167: error: expected ‘)’ before ‘==’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                       ^~
      |                                                                                                                                                                       )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:194: error: expected ‘)’ before ‘|’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                  ^
      |                                                                                                                                                                                                  )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:227: error: expected ‘)’ before ‘(’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                   ^
      |                                                                                                                                                                                                                                   )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:243: error: expected identifier or ‘(’ before ‘return’
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                   ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:253: error: expected identifier or ‘(’ before ‘}’ token
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                                                                             ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:40:7: error: expected identifier or ‘(’ before ‘|’ token
   40 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                            ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:76: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:106: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:119: error: universal character \u2019 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:139: error: unknown type name ‘has’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                  ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:146: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2018 is not valid in an identifier
   42 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:137: error: \u2018core_state_t\u2019 {aka \u2018struct core_state_s\u2019} has no member named \u2018mmu\u2019
      |                                                                                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:42:159: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: data definition has no type or storage class
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                       ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: warning: type defaults to ‘int’ in declaration of ‘val’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:23: error: conflicting types for ‘val’; have ‘int’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:39:43: note: previous definition of ‘val’ with type ‘uint8_t’ {aka ‘unsigned char’}
   39 |   108 |  uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                           ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:27: error: initializer element is not constant
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                           ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:69: error: expected ‘)’ before ‘-&gt;’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                     ^~
      |                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:110: error: expected ‘)’ before ‘==’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                              ^~
      |                                                                                                              )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:137: error: expected ‘)’ before ‘|’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                         ^
      |                                                                                                                                         )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:170: error: expected ‘)’ before ‘(’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                          ^
      |                                                                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:186: error: expected identifier or ‘(’ before ‘return’
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                          ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:43:196: error: expected identifier or ‘(’ before ‘}’ token
   43 |   108 | ate-&gt;mmu,hl); val=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:44:7: error: expected identifier or ‘(’ before ‘|’ token
   44 |       |                                                             ^~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:100: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:113: error: universal character \u2019 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:129: error: unknown type name ‘has’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2018 is not valid in an identifier
   46 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:46:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:47:9: error: stray ‘#’ in program
   47 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2018 is not valid in an identifier
   49 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:49:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:50:9: error: stray ‘#’ in program
   50 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2018 is not valid in an identifier
   52 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:52:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:54: error: expected ‘)’ before ‘-&gt;’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:95: error: expected ‘)’ before ‘==’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:122: error: expected ‘)’ before ‘|’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:155: error: expected ‘)’ before ‘(’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:171: error: expected identifier or ‘(’ before ‘return’
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:53:181: error: expected identifier or ‘(’ before ‘}’ token
   53 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:54:7: error: expected identifier or ‘(’ before ‘|’ token
   54 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:100: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:113: error: universal character \u2019 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:129: error: unknown type name ‘has’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2018 is not valid in an identifier
   56 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:56:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:57:9: error: stray ‘#’ in program
   57 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2018 is not valid in an identifier
   59 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:59:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:60:9: error: stray ‘#’ in program
   60 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2018 is not valid in an identifier
   62 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:152: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:62:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:54: error: expected ‘)’ before ‘-&gt;’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                      ^~
      |                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:95: error: expected ‘)’ before ‘==’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                               ^~
      |                                                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:122: error: expected ‘)’ before ‘|’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                          ^
      |                                                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:155: error: expected ‘)’ before ‘(’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                           ^
      |                                                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:171: error: expected identifier or ‘(’ before ‘return’
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:63:181: error: expected identifier or ‘(’ before ‘}’ token
   63 |   108 | al=(val&lt;&lt;1)|(val&gt;&gt;7); gb_mmu_write_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:64:7: error: expected identifier or ‘(’ before ‘|’ token
   64 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:100: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:113: error: universal character \u2019 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:129: error: unknown type name ‘has’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2018 is not valid in an identifier
   66 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:66:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:67:9: error: stray ‘#’ in program
   67 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2018 is not valid in an identifier
   69 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:184: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:69:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:63: error: expected ‘)’ before ‘==’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                               ^~
      |                                                               )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:90: error: expected ‘)’ before ‘|’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:123: error: expected ‘)’ before ‘(’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:139: error: expected identifier or ‘(’ before ‘return’
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                           ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:70:149: error: expected identifier or ‘(’ before ‘}’ token
   70 |   108 | te_byte(state-&gt;mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:71:7: error: expected identifier or ‘(’ before ‘|’ token
   71 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:100: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:113: error: universal character \u2019 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:129: error: unknown type name ‘has’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2018 is not valid in an identifier
   73 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:73:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:74:9: error: stray ‘#’ in program
   74 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2018 is not valid in an identifier
   76 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:76:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:77:9: error: stray ‘#’ in program
   77 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2018 is not valid in an identifier
   79 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:79:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:59: error: expected ‘)’ before ‘|’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:92: error: expected ‘)’ before ‘(’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:108: error: expected identifier or ‘(’ before ‘return’
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:80:118: error: expected identifier or ‘(’ before ‘}’ token
   80 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:81:7: error: expected identifier or ‘(’ before ‘|’ token
   81 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:100: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:113: error: universal character \u2019 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:129: error: unknown type name ‘has’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2018 is not valid in an identifier
   83 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:83:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:84:9: error: stray ‘#’ in program
   84 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2018 is not valid in an identifier
   86 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:86:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:87:9: error: stray ‘#’ in program
   87 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2018 is not valid in an identifier
   89 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:108:215: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:89:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:59: error: expected ‘)’ before ‘|’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:92: error: expected ‘)’ before ‘(’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:108: error: expected identifier or ‘(’ before ‘return’
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                            ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:90:118: error: expected identifier or ‘(’ before ‘}’ token
   90 |   108 | ATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&amp;0x80)!=0); return 16;}
      |                                                                                                                      ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:91:7: error: expected identifier or ‘(’ before ‘|’ token
   91 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:100: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:113: error: universal character \u2019 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:129: error: unknown type name ‘has’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2018 is not valid in an identifier
   93 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:93:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:94:9: error: stray ‘#’ in program
   94 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2018 is not valid in an identifier
   96 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:96:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:97:9: error: stray ‘#’ in program
   97 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2018 is not valid in an identifier
   99 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:99:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:86: error: expected ‘)’ before ‘-&gt;’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:116: error: expected ‘)’ before ‘|’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:149: error: expected ‘)’ before ‘(’ token
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:100:168: error: expected identifier or ‘(’ before ‘return’
  100 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:101:7: error: expected identifier or ‘(’ before ‘|’ token
  101 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:100: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:113: error: universal character \u2019 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:129: error: unknown type name ‘has’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2018 is not valid in an identifier
  102 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:102:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:103:9: error: stray ‘#’ in program
  103 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2018 is not valid in an identifier
  105 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:105:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:106:9: error: stray ‘#’ in program
  106 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2018 is not valid in an identifier
  108 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:52: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:108:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:86: error: expected ‘)’ before ‘-&gt;’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                      ^~
      |                                                                                      )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:116: error: expected ‘)’ before ‘|’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                    ^
      |                                                                                                                    )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:149: error: expected ‘)’ before ‘(’ token
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                     ^
      |                                                                                                                                                     )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:109:168: error: expected identifier or ‘(’ before ‘return’
  109 |   109 |         case 0x07: cpu-&gt;a=(cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:110:7: error: expected identifier or ‘(’ before ‘|’ token
  110 |       |                                                    ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:100: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:113: error: universal character \u2019 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:129: error: unknown type name ‘has’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2018 is not valid in an identifier
  111 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:111:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:112:9: error: stray ‘#’ in program
  112 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2018 is not valid in an identifier
  114 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:87: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                                ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:114:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:60: error: expected ‘)’ before ‘-&gt;’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                            ^~
      |                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:90: error: expected ‘)’ before ‘|’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                          ^
      |                                                                                          )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:123: error: expected ‘)’ before ‘(’ token
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                           ^
      |                                                                                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:115:142: error: expected identifier or ‘(’ before ‘return’
  115 |   109 | (cpu-&gt;a&lt;&lt;1)|(cpu-&gt;a&gt;&gt;7); UPDATE_FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                                                              ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:116:7: error: expected identifier or ‘(’ before ‘|’ token
  116 |       |                                                             ^~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:100: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:113: error: universal character \u2019 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:129: error: unknown type name ‘has’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2018 is not valid in an identifier
  118 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:118:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:119:9: error: stray ‘#’ in program
  119 |    15 | #define SET_FLAG(cpu,f) ((cpu)-&gt;freg|=(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2018 is not valid in an identifier
  121 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:41: note: in expansion of macro \u2018SET_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:121:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:122:9: error: stray ‘#’ in program
  122 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2018 is not valid in an identifier
  124 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:124:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:59: error: expected ‘)’ before ‘|’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:92: error: expected ‘)’ before ‘(’ token
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:125:111: error: expected identifier or ‘(’ before ‘return’
  125 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:126:7: error: expected identifier or ‘(’ before ‘|’ token
  126 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                          ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:100: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                    ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:113: error: universal character \u2019 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:129: error: unknown type name ‘has’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                 ^~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                        ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2018 is not valid in an identifier
  128 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
      |                                                                                                                                                     ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:128:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:129:9: error: stray ‘#’ in program
  129 |    16 | #define CLEAR_FLAG(cpu,f) ((cpu)-&gt;freg&amp;=~(f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2018 is not valid in an identifier
  131 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:17:57: note: in expansion of macro \u2018CLEAR_FLAG\u2019
      |                                                                                               ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:131:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:132:9: error: stray ‘#’ in program
  132 |    17 | #define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))
      |         ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2018 is not valid in an identifier
  134 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:109:118: note: in expansion of macro \u2018UPDATE_FLAG\u2019
      |                                                                                                 ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:134:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:59: error: expected ‘)’ before ‘|’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                           ^
      |                                                           )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:92: error: expected ‘)’ before ‘(’ token
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                            ^
      |                                                                                            )
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:135:111: error: expected identifier or ‘(’ before ‘return’
  135 |   109 | _FLAG(cpu,FLAG_Z,cpu-&gt;a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu-&gt;a&amp;0x80)!=0); return 8;
      |                                                                                                               ^~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:136:7: error: expected identifier or ‘(’ before ‘|’ token
  136 |       |                                                             ^~~~~~~~~~~
      |       ^
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:141:7: error: stray ‘@’ in program
  141 | ubuntu@ubuntu:~/Desktop/gameboy-perfect-core$
      |       ^
In file included from /home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:5:
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: data definition has no type or storage class
   25 | } gb_mmu_t;
      |   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:25:3: warning: type defaults to ‘int’ in declaration of ‘gb_mmu_t’ [-Wimplicit-int]
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:28:19: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   28 | void gb_mmu_reset(gb_mmu_t *mmu);
      |                   ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:31:26: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   31 | uint8_t gb_mmu_read_byte(gb_mmu_t *mmu, uint16_t addr);
      |                          ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:34:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   34 | void gb_mmu_write_byte(gb_mmu_t *mmu, uint16_t addr, uint8_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:37:27: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   37 | uint16_t gb_mmu_read_word(gb_mmu_t *mmu, uint16_t addr);
      |                           ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/mmu.h:40:24: error: expected declaration specifiers or ‘...’ before ‘gb_mmu_t’
   40 | void gb_mmu_write_word(gb_mmu_t *mmu, uint16_t addr, uint16_t val);
      |                        ^~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:9:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
    9 | void gb_core_init(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:21:19: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   21 | void gb_core_step(core_state_t *state) {
      |                   ^~~~~~~~~~~~
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/core_state.c:28:22: error: expected declaration specifiers or ‘...’ before ‘core_state_t’
   28 | void gb_core_destroy(core_state_t *state) {
      |                      ^~~~~~~~~~~~
make[2]: *** [CMakeFiles/gameboy_perfect_core_libretro.dir/build.make:104: CMakeFiles/gameboy_perfect_core_libretro.dir/src/common/core_state.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/gameboy_perfect_core_libretro.dir/all] Error 2
make: *** [Makefile:91: all] Error 2</pre>
<h2>./gameboy_perfect_core_libretro.info</h2>
<pre>display_name = "Game Boy Perfect"
authors = "CanC-Code"
supported_extensions = "gb|gbc|gba"
corename = "Game Boy Perfect Core"
manufacturer = "Nintendo"
categories = "Emulator"
systemname = "Game Boy / Color / Advance"
license = "GPLv3"
permissions = ""
display_version = "0.1.0"
library_name = "Game Boy Perfect"
library_version = "0.1.0"
datasource = "libretro"
supports_no_game = "false"
firmware_count = "0"</pre>
<h2>./.gitignore</h2>
<pre># Build artifacts
/build/
/bin/
/obj/
/*.o
/*.so
*.apk
*.log

# IDE files
*.idea/
*.vscode/
*.iml</pre>
<h2>./.gitmodules</h2>
<pre>[submodule "include/libretro-common"]
	path = include/libretro-common
	url = https://github.com/libretro/libretro-common.git</pre>
<h2>./include/libretro-common/audio/audio_mix.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mix.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;memalign.h&gt;

#include &lt;retro_environment.h&gt;

#if defined(__SSE2__)
#include &lt;emmintrin.h&gt;
#elif defined(__ALTIVEC__)
#include &lt;altivec.h&gt;
#endif

#include &lt;retro_miscellaneous.h&gt;
#include &lt;audio/audio_mix.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;audio/conversion/float_to_s16.h&gt;
#include &lt;audio/conversion/s16_to_float.h&gt;

void audio_mix_volume_C(float *s, const float *in, float vol, size_t len)
{
   size_t i;
   for (i = 0; i &lt; len; i++)
      s[i] += in[i] * vol;
}

#ifdef __SSE2__
void audio_mix_volume_SSE2(float *s, const float *in, float vol, size_t len)
{
   size_t i, remaining_samples;
   __m128 volume = _mm_set1_ps(vol);

   for (i = 0; i + 16 &lt;= len; i += 16, s += 16, in += 16)
   {
      unsigned j;
      __m128 input[4];
      __m128 additive[4];

      input[0]    = _mm_loadu_ps(s +  0);
      input[1]    = _mm_loadu_ps(s +  4);
      input[2]    = _mm_loadu_ps(s +  8);
      input[3]    = _mm_loadu_ps(s + 12);

      additive[0] = _mm_mul_ps(volume, _mm_loadu_ps(in +  0));
      additive[1] = _mm_mul_ps(volume, _mm_loadu_ps(in +  4));
      additive[2] = _mm_mul_ps(volume, _mm_loadu_ps(in +  8));
      additive[3] = _mm_mul_ps(volume, _mm_loadu_ps(in + 12));

      for (j = 0; j &lt; 4; j++)
         _mm_storeu_ps(s + 4 * j, _mm_add_ps(input[j], additive[j]));
   }

   remaining_samples = len - i;

   for (i = 0; i &lt; remaining_samples; i++)
      s[i] += in[i] * vol;
}
#endif

void audio_mix_free_chunk(audio_chunk_t *chunk)
{
   if (!chunk)
      return;

#ifdef HAVE_RWAV
   if (chunk-&gt;rwav &amp;&amp; chunk-&gt;rwav-&gt;samples)
   {
      /* rwav_free only frees the samples */
      rwav_free(chunk-&gt;rwav);
      free(chunk-&gt;rwav);
   }
#endif

   if (chunk-&gt;buf)
      free(chunk-&gt;buf);

   if (chunk-&gt;upsample_buf)
      memalign_free(chunk-&gt;upsample_buf);

   if (chunk-&gt;float_buf)
      memalign_free(chunk-&gt;float_buf);

   if (chunk-&gt;float_resample_buf)
      memalign_free(chunk-&gt;float_resample_buf);

   if (chunk-&gt;resample_buf)
      memalign_free(chunk-&gt;resample_buf);

   if (chunk-&gt;resampler &amp;&amp; chunk-&gt;resampler_data)
      chunk-&gt;resampler-&gt;free(chunk-&gt;resampler_data);

   free(chunk);
}

audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,
      const char *resampler_ident, enum resampler_quality quality)
{
#ifdef HAVE_RWAV
   int sample_size;
   int64_t len                = 0;
   void *buf                  = NULL;
   audio_chunk_t *chunk       = (audio_chunk_t*)malloc(sizeof(*chunk));

   if (!chunk)
      return NULL;

   chunk-&gt;buf                 = NULL;
   chunk-&gt;upsample_buf        = NULL;
   chunk-&gt;float_buf           = NULL;
   chunk-&gt;float_resample_buf  = NULL;
   chunk-&gt;resample_buf        = NULL;
   chunk-&gt;len                 = 0;
   chunk-&gt;resample_len        = 0;
   chunk-&gt;sample_rate         = sample_rate;
   chunk-&gt;resample            = false;
   chunk-&gt;resampler           = NULL;
   chunk-&gt;resampler_data      = NULL;
   chunk-&gt;ratio               = 0.00f;
   chunk-&gt;rwav                = (rwav_t*)malloc(sizeof(rwav_t));

   if (!chunk-&gt;rwav)
      goto error;

   chunk-&gt;rwav-&gt;bitspersample = 0;
   chunk-&gt;rwav-&gt;numchannels   = 0;
   chunk-&gt;rwav-&gt;samplerate    = 0;
   chunk-&gt;rwav-&gt;numsamples    = 0;
   chunk-&gt;rwav-&gt;subchunk2size = 0;
   chunk-&gt;rwav-&gt;samples       = NULL;

   if (!filestream_read_file(path, &amp;buf, &amp;len))
      goto error;

   chunk-&gt;buf                 = buf;
   chunk-&gt;len                 = len;

   if (rwav_load(chunk-&gt;rwav, chunk-&gt;buf, chunk-&gt;len) == RWAV_ITERATE_ERROR)
      goto error;

   /* numsamples does not know or care about
    * multiple channels, but we need space for 2 */
   chunk-&gt;upsample_buf        = (int16_t*)memalign_alloc(128,
         chunk-&gt;rwav-&gt;numsamples * 2 * sizeof(int16_t));

   sample_size                = chunk-&gt;rwav-&gt;bitspersample / 8;

   if (sample_size == 1)
   {
      unsigned i;

      if (chunk-&gt;rwav-&gt;numchannels == 1)
      {
         for (i = 0; i &lt; chunk-&gt;rwav-&gt;numsamples; i++)
         {
            uint8_t *sample                  = (
                  (uint8_t*)chunk-&gt;rwav-&gt;samples) + i;

            chunk-&gt;upsample_buf[i * 2]       =
               (int16_t)((sample[0] - 128) &lt;&lt; 8);
            chunk-&gt;upsample_buf[(i * 2) + 1] =
               (int16_t)((sample[0] - 128) &lt;&lt; 8);
         }
      }
      else if (chunk-&gt;rwav-&gt;numchannels == 2)
      {
         for (i = 0; i &lt; chunk-&gt;rwav-&gt;numsamples; i++)
         {
            uint8_t *sample                  = (
                  (uint8_t*)chunk-&gt;rwav-&gt;samples) +
               (i * 2);

            chunk-&gt;upsample_buf[i * 2]       =
               (int16_t)((sample[0] - 128) &lt;&lt; 8);
            chunk-&gt;upsample_buf[(i * 2) + 1] =
               (int16_t)((sample[1] - 128) &lt;&lt; 8);
         }
      }
   }
   else if (sample_size == 2)
   {
      if (chunk-&gt;rwav-&gt;numchannels == 1)
      {
         unsigned i;

         for (i = 0; i &lt; chunk-&gt;rwav-&gt;numsamples; i++)
         {
            int16_t sample                   = ((int16_t*)
                  chunk-&gt;rwav-&gt;samples)[i];

            chunk-&gt;upsample_buf[i * 2]       = sample;
            chunk-&gt;upsample_buf[(i * 2) + 1] = sample;
         }
      }
      else if (chunk-&gt;rwav-&gt;numchannels == 2)
         memcpy(chunk-&gt;upsample_buf, chunk-&gt;rwav-&gt;samples,
               chunk-&gt;rwav-&gt;subchunk2size);
   }
   else if (sample_size != 2)
   {
      /* we don't support any other sample size besides 8 and 16-bit yet */
      goto error;
   }

   if (sample_rate != (int)chunk-&gt;rwav-&gt;samplerate)
   {
      chunk-&gt;resample = true;
      chunk-&gt;ratio    = (double)sample_rate / chunk-&gt;rwav-&gt;samplerate;

      retro_resampler_realloc(&amp;chunk-&gt;resampler_data,
            &amp;chunk-&gt;resampler,
            resampler_ident,
            quality,
            chunk-&gt;ratio);

      if (chunk-&gt;resampler &amp;&amp; chunk-&gt;resampler_data)
      {
         struct resampler_data info;

         chunk-&gt;float_buf          = (float*)memalign_alloc(128,
               chunk-&gt;rwav-&gt;numsamples * 2 *
               chunk-&gt;ratio * sizeof(float));

         /* why is *3 needed instead of just *2? Does the
          * sinc driver require more space than we know about? */
         chunk-&gt;float_resample_buf = (float*)memalign_alloc(128,
               chunk-&gt;rwav-&gt;numsamples * 3 *
               chunk-&gt;ratio * sizeof(float));

         convert_s16_to_float(chunk-&gt;float_buf,
               chunk-&gt;upsample_buf, chunk-&gt;rwav-&gt;numsamples * 2, 1.0);

         info.data_in       = (const float*)chunk-&gt;float_buf;
         info.data_out      = chunk-&gt;float_resample_buf;
         /* a 'frame' consists of two channels, so we set this
          * to the number of samples irrespective of channel count */
         info.input_frames  = chunk-&gt;rwav-&gt;numsamples;
         info.output_frames = 0;
         info.ratio         = chunk-&gt;ratio;

         chunk-&gt;resampler-&gt;process(chunk-&gt;resampler_data, &amp;info);

         /* number of output_frames does not increase with
          * multiple channels, but assume we need space for 2 */
         chunk-&gt;resample_buf = (int16_t*)memalign_alloc(128,
               info.output_frames * 2 * sizeof(int16_t));
         chunk-&gt;resample_len = info.output_frames;
         convert_float_to_s16(chunk-&gt;resample_buf,
               chunk-&gt;float_resample_buf, info.output_frames * 2);
      }
   }

   return chunk;

error:
   audio_mix_free_chunk(chunk);
#endif
   return NULL;
}

size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk-&gt;rwav)
   {
      if (chunk-&gt;resample)
         return chunk-&gt;resample_len;
      return chunk-&gt;rwav-&gt;numsamples;
   }
#endif

   /* no other filetypes supported yet */
   return 0;
}

/**
 * audio_mix_get_chunk_sample:
 * @chunk              : audio chunk instance
 * @channel            : channel of the sample (0=left, 1=right)
 * @index              : index of the sample
 *
 * Get a sample from an audio chunk.
 *
 * Returns: A signed 16-bit audio sample.
 **/
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk,
      unsigned channel, size_t index)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk-&gt;rwav)
   {
      int sample_size    = chunk-&gt;rwav-&gt;bitspersample / 8;
      int16_t sample_out = 0;

      /* 0 is the first/left channel */
      uint8_t *sample    = NULL;

      if (chunk-&gt;resample)
         sample = (uint8_t*)chunk-&gt;resample_buf +
            (sample_size * index * chunk-&gt;rwav-&gt;numchannels)
            + (channel * sample_size);
      else
         sample = (uint8_t*)chunk-&gt;upsample_buf +
            (sample_size * index * chunk-&gt;rwav-&gt;numchannels)
            + (channel * sample_size);

      sample_out = (int16_t)*sample;

      return sample_out;
   }
#endif

   /* no other filetypes supported yet */
   return 0;
}

int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk-&gt;rwav)
   {
      int16_t *sample;

      if (chunk-&gt;resample)
         sample = chunk-&gt;resample_buf;
      else
         sample = chunk-&gt;upsample_buf;

      return sample;
   }
#endif

   return NULL;
}

int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk)
{
   if (!chunk)
      return 0;

#ifdef HAVE_RWAV
   if (chunk-&gt;rwav)
      return chunk-&gt;rwav-&gt;numchannels;
#endif

   /* don't support other formats yet */
   return 0;
}</pre>
<h2>./include/libretro-common/audio/audio_mixer.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mixer.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif

#include &lt;audio/audio_mixer.h&gt;
#include &lt;audio/audio_resampler.h&gt;

#ifdef HAVE_RWAV
#include &lt;formats/rwav.h&gt;
#endif
#include &lt;memalign.h&gt;

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;math.h&gt;

#ifdef HAVE_STB_VORBIS
#define STB_VORBIS_NO_PUSHDATA_API
#define STB_VORBIS_NO_STDIO
#define STB_VORBIS_NO_CRT

#include &lt;stb/stb_vorbis.h&gt;
#endif

#ifdef HAVE_DR_FLAC
#include &lt;retro_inline.h&gt;
#define DR_FLAC_IMPLEMENTATION
#define DRFLAC_API static INLINE
#include &lt;dr/dr_flac.h&gt;
#endif

#ifdef HAVE_DR_MP3
#define DR_MP3_IMPLEMENTATION
#include &lt;retro_assert.h&gt;
#define DRMP3_ASSERT(expression) retro_assert(expression)
#include &lt;dr/dr_mp3.h&gt;
#endif

#ifdef HAVE_IBXM
#include &lt;ibxm/ibxm.h&gt;
#endif

#ifdef HAVE_THREADS
#include &lt;rthreads/rthreads.h&gt;
#define AUDIO_MIXER_LOCK(voice)   slock_lock(voice-&gt;lock)
#define AUDIO_MIXER_UNLOCK(voice) slock_unlock(voice-&gt;lock)
#else
#define AUDIO_MIXER_LOCK(voice)   do {} while(0)
#define AUDIO_MIXER_UNLOCK(voice) do {} while(0)
#endif

#define AUDIO_MIXER_MAX_VOICES      8
#define AUDIO_MIXER_TEMP_BUFFER 8192

struct audio_mixer_sound
{
   enum audio_mixer_type type;
   void* user_data;

   union
   {
      struct
      {
         /* wav */
         const float* pcm;
         unsigned frames;
      } wav;

#ifdef HAVE_STB_VORBIS
      struct
      {
         /* ogg */
         const void* data;
         unsigned size;
      } ogg;
#endif

#ifdef HAVE_DR_FLAC
      struct
      {
          /* flac */
         const void* data;
         unsigned size;
      } flac;
#endif

#ifdef HAVE_DR_MP3
      struct
      {
          /* mp */
         const void* data;
         unsigned size;
      } mp3;
#endif

#ifdef HAVE_IBXM
      struct
      {
         /* mod/s3m/xm */
         const void* data;
         unsigned size;
      } mod;
#endif
   } types;
};

struct audio_mixer_voice
{
   struct
   {
      struct
      {
         unsigned position;
      } wav;

#ifdef HAVE_STB_VORBIS
      struct
      {
         stb_vorbis *stream;
         void       *resampler_data;
         const retro_resampler_t *resampler;
         float      *buffer;
         unsigned    position;
         unsigned    samples;
         unsigned    buf_samples;
         float       ratio;
      } ogg;
#endif

#ifdef HAVE_DR_FLAC
      struct
      {
         float*      buffer;
         drflac      *stream;
         void        *resampler_data;
         const retro_resampler_t *resampler;
         unsigned    position;
         unsigned    samples;
         unsigned    buf_samples;
         float       ratio;
      } flac;
#endif

#ifdef HAVE_DR_MP3
      struct
      {
         drmp3       stream;
         void        *resampler_data;
         const retro_resampler_t *resampler;
         float*      buffer;
         unsigned    position;
         unsigned    samples;
         unsigned    buf_samples;
         float       ratio;
      } mp3;
#endif

#ifdef HAVE_IBXM
      struct
      {
         int*              buffer;
         struct replay*    stream;
         struct module*    module;
         unsigned          position;
         unsigned          samples;
         unsigned          buf_samples;
      } mod;
#endif
   } types;
   audio_mixer_sound_t *sound;
   audio_mixer_stop_cb_t stop_cb;
   unsigned type;
   float    volume;
   bool     repeat;
#ifdef HAVE_THREADS
   slock_t *lock;
#endif
};

/* TODO/FIXME - static globals */
static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0};
static unsigned s_rate = 0;

static void audio_mixer_release(audio_mixer_voice_t* voice);

#ifdef HAVE_RWAV
static bool wav_to_float(const rwav_t* wav, float** pcm, size_t len)
{
   size_t i;
   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
   float *f           = (float*)memalign_alloc(16,
         ((len + 15) &amp; ~15) * sizeof(float));

   if (!f)
      return false;

   *pcm = f;

   if (wav-&gt;bitspersample == 8)
   {
      float sample      = 0.0f;
      const uint8_t *u8 = (const uint8_t*)wav-&gt;samples;

      if (wav-&gt;numchannels == 1)
      {
         for (i = wav-&gt;numsamples; i != 0; i--)
         {
            sample = (float)*u8++ / 255.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            *f++   = sample;
         }
      }
      else if (wav-&gt;numchannels == 2)
      {
         for (i = wav-&gt;numsamples; i != 0; i--)
         {
            sample = (float)*u8++ / 255.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            sample = (float)*u8++ / 255.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
         }
      }
   }
   else
   {
      /* TODO/FIXME note to leiradel - can we use audio/conversion/s16_to_float
       * functions here? */

      float sample       = 0.0f;
      const int16_t *s16 = (const int16_t*)wav-&gt;samples;

      if (wav-&gt;numchannels == 1)
      {
         for (i = wav-&gt;numsamples; i != 0; i--)
         {
            sample = (float)((int)*s16++ + 32768) / 65535.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            *f++   = sample;
         }
      }
      else if (wav-&gt;numchannels == 2)
      {
         for (i = wav-&gt;numsamples; i != 0; i--)
         {
            sample = (float)((int)*s16++ + 32768) / 65535.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
            sample = (float)((int)*s16++ + 32768) / 65535.0f;
            sample = sample * 2.0f - 1.0f;
            *f++   = sample;
         }
      }
   }

   return true;
}

static bool one_shot_resample(const float* in, size_t samples_in,
      unsigned rate, const char *resampler_ident, enum resampler_quality quality,
      float** out, size_t* samples_out)
{
   struct resampler_data info;
   void* data                         = NULL;
   const retro_resampler_t* resampler = NULL;
   float ratio                        = (double)s_rate / (double)rate;

   if (!retro_resampler_realloc(&amp;data, &amp;resampler,
         resampler_ident, quality, ratio))
      return false;

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler-&gt;process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   *samples_out                       = (size_t)(samples_in * ratio);
   *out                               = (float*)memalign_alloc(16,
         (((*samples_out + 16) + 15) &amp; ~15) * sizeof(float));

   if (*out == NULL)
      return false;

   info.data_in                       = in;
   info.data_out                      = *out;
   info.input_frames                  = samples_in / 2;
   info.output_frames                 = 0;
   info.ratio                         = ratio;

   resampler-&gt;process(data, &amp;info);
   resampler-&gt;free(data);
   return true;
}
#endif

void audio_mixer_init(unsigned rate)
{
   unsigned i;

   s_rate = rate;

   for (i = 0; i &lt; AUDIO_MIXER_MAX_VOICES; i++)
   {
      audio_mixer_voice_t *voice = &amp;s_voices[i];

      voice-&gt;type = AUDIO_MIXER_TYPE_NONE;
#ifdef HAVE_THREADS
      if (!voice-&gt;lock)
         voice-&gt;lock = slock_new();
#endif
   }
}

void audio_mixer_done(void)
{
   unsigned i;

   for (i = 0; i &lt; AUDIO_MIXER_MAX_VOICES; i++)
   {
      audio_mixer_voice_t *voice = &amp;s_voices[i];

      AUDIO_MIXER_LOCK(voice);
      audio_mixer_release(voice);
      AUDIO_MIXER_UNLOCK(voice);
#ifdef HAVE_THREADS
      slock_free(voice-&gt;lock);
      voice-&gt;lock = NULL;
#endif
   }
}

audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,
      const char *resampler_ident, enum resampler_quality quality)
{
#ifdef HAVE_RWAV
   /* WAV data */
   rwav_t wav;
   /* WAV samples converted to float */
   float* pcm                 = NULL;
   size_t samples             = 0;
   /* Result */
   audio_mixer_sound_t* sound = NULL;

   wav.bitspersample          = 0;
   wav.numchannels            = 0;
   wav.samplerate             = 0;
   wav.numsamples             = 0;
   wav.subchunk2size          = 0;
   wav.samples                = NULL;

   if ((rwav_load(&amp;wav, buffer, size)) != RWAV_ITERATE_DONE)
      return NULL;

   samples       = wav.numsamples * 2;

   if (!wav_to_float(&amp;wav, &amp;pcm, samples))
      return NULL;

   if (wav.samplerate != s_rate)
   {
      float* resampled           = NULL;

      if (!one_shot_resample(pcm, samples, wav.samplerate,
            resampler_ident, quality,
            &amp;resampled, &amp;samples))
         return NULL;

      memalign_free((void*)pcm);
      pcm = resampled;
   }

   sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
   {
      memalign_free((void*)pcm);
      return NULL;
   }

   sound-&gt;type             = AUDIO_MIXER_TYPE_WAV;
   sound-&gt;types.wav.frames = (unsigned)(samples / 2);
   sound-&gt;types.wav.pcm    = pcm;

   rwav_free(&amp;wav);

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size)
{
#ifdef HAVE_STB_VORBIS
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound-&gt;type           = AUDIO_MIXER_TYPE_OGG;
   sound-&gt;types.ogg.size = size;
   sound-&gt;types.ogg.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size)
{
#ifdef HAVE_DR_FLAC
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound-&gt;type           = AUDIO_MIXER_TYPE_FLAC;
   sound-&gt;types.flac.size = size;
   sound-&gt;types.flac.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size)
{
#ifdef HAVE_DR_MP3
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound-&gt;type           = AUDIO_MIXER_TYPE_MP3;
   sound-&gt;types.mp3.size = size;
   sound-&gt;types.mp3.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size)
{
#ifdef HAVE_IBXM
   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));

   if (!sound)
      return NULL;

   sound-&gt;type           = AUDIO_MIXER_TYPE_MOD;
   sound-&gt;types.mod.size = size;
   sound-&gt;types.mod.data = buffer;

   return sound;
#else
   return NULL;
#endif
}

void audio_mixer_destroy(audio_mixer_sound_t* sound)
{
   void *handle = NULL;
   if (!sound)
      return;

   switch (sound-&gt;type)
   {
      case AUDIO_MIXER_TYPE_WAV:
         handle = (void*)sound-&gt;types.wav.pcm;
         if (handle)
            memalign_free(handle);
         break;
      case AUDIO_MIXER_TYPE_OGG:
#ifdef HAVE_STB_VORBIS
         handle = (void*)sound-&gt;types.ogg.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_MOD:
#ifdef HAVE_IBXM
         handle = (void*)sound-&gt;types.mod.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_FLAC:
#ifdef HAVE_DR_FLAC
         handle = (void*)sound-&gt;types.flac.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_MP3:
#ifdef HAVE_DR_MP3
         handle = (void*)sound-&gt;types.mp3.data;
         if (handle)
            free(handle);
#endif
         break;
      case AUDIO_MIXER_TYPE_NONE:
         break;
   }

   free(sound);
}

static bool audio_mixer_play_wav(audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice, bool repeat, float volume,
      audio_mixer_stop_cb_t stop_cb)
{
   voice-&gt;types.wav.position = 0;
   return true;
}

#ifdef HAVE_STB_VORBIS
static bool audio_mixer_play_ogg(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   stb_vorbis_info info;
   int res                         = 0;
   float ratio                     = 1.0f;
   unsigned samples                = 0;
   void *ogg_buffer                = NULL;
   void *resampler_data            = NULL;
   const retro_resampler_t* resamp = NULL;
   stb_vorbis *stb_vorbis          = stb_vorbis_open_memory(
         (const unsigned char*)sound-&gt;types.ogg.data,
         sound-&gt;types.ogg.size, &amp;res, NULL);

   if (!stb_vorbis)
      return false;

   info                    = stb_vorbis_get_info(stb_vorbis);

   if (info.sample_rate != s_rate)
   {
      ratio = (double)s_rate / (double)info.sample_rate;

      if (!retro_resampler_realloc(&amp;resampler_data,
               &amp;resamp, resampler_ident, quality,
               ratio))
         goto error;
   }

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler-&gt;process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
   ogg_buffer                      = (float*)memalign_alloc(16,
         (((samples + 16) + 15) &amp; ~15) * sizeof(float));

   if (!ogg_buffer)
   {
      if (resamp &amp;&amp; resampler_data)
         resamp-&gt;free(resampler_data);
      goto error;
   }

   voice-&gt;types.ogg.resampler      = resamp;
   voice-&gt;types.ogg.resampler_data = resampler_data;
   voice-&gt;types.ogg.buffer         = (float*)ogg_buffer;
   voice-&gt;types.ogg.buf_samples    = samples;
   voice-&gt;types.ogg.ratio          = ratio;
   voice-&gt;types.ogg.stream         = stb_vorbis;
   voice-&gt;types.ogg.position       = 0;
   voice-&gt;types.ogg.samples        = 0;

   return true;

error:
   stb_vorbis_close(stb_vorbis);
   return false;
}

static void audio_mixer_release_ogg(audio_mixer_voice_t* voice)
{
   if (voice-&gt;types.ogg.stream)
      stb_vorbis_close(voice-&gt;types.ogg.stream);
   if (voice-&gt;types.ogg.resampler &amp;&amp; voice-&gt;types.ogg.resampler_data)
      voice-&gt;types.ogg.resampler-&gt;free(voice-&gt;types.ogg.resampler_data);
   if (voice-&gt;types.ogg.buffer)
      memalign_free(voice-&gt;types.ogg.buffer);
}

#endif

#ifdef HAVE_IBXM
static bool audio_mixer_play_mod(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      audio_mixer_stop_cb_t stop_cb)
{
   struct data data;
   char message[64];
   int buf_samples               = 0;
   int samples                   = 0;
   void *mod_buffer              = NULL;
   struct module* module         = NULL;
   struct replay* replay         = NULL;

   data.buffer                   = (char*)sound-&gt;types.mod.data;
   data.length                   = sound-&gt;types.mod.size;
   module                        = module_load(&amp;data, message);

   if (!module)
   {
      printf("audio_mixer_play_mod module_load() failed with error: %s\n", message);
      goto error;
   }

   if (voice-&gt;types.mod.module)
      dispose_module(voice-&gt;types.mod.module);

   voice-&gt;types.mod.module = module;

   replay = new_replay(module, s_rate, 1);

   if (!replay)
   {
      printf("audio_mixer_play_mod new_replay() failed\n");
      goto error;
   }

   buf_samples = calculate_mix_buf_len(s_rate);
   mod_buffer  = memalign_alloc(16, ((buf_samples + 15) &amp; ~15) * sizeof(int));

   if (!mod_buffer)
   {
      printf("audio_mixer_play_mod cannot allocate mod_buffer !\n");
      goto error;
   }

   samples = replay_calculate_duration(replay);

   if (!samples)
   {
      printf("audio_mixer_play_mod cannot retrieve duration !\n");
      goto error;
   }

   voice-&gt;types.mod.buffer         = (int*)mod_buffer;
   voice-&gt;types.mod.buf_samples    = buf_samples;
   voice-&gt;types.mod.stream         = replay;
   voice-&gt;types.mod.position       = 0;
   voice-&gt;types.mod.samples        = 0; /* samples; */

   return true;

error:
   if (mod_buffer)
      memalign_free(mod_buffer);
   if (module)
      dispose_module(module);
   return false;

}

static void audio_mixer_release_mod(audio_mixer_voice_t* voice)
{
   if (voice-&gt;types.mod.stream)
      dispose_replay(voice-&gt;types.mod.stream);
   if (voice-&gt;types.mod.buffer)
      memalign_free(voice-&gt;types.mod.buffer);
}
#endif

#ifdef HAVE_DR_FLAC
static bool audio_mixer_play_flac(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   float ratio                     = 1.0f;
   unsigned samples                = 0;
   void *flac_buffer                = NULL;
   void *resampler_data            = NULL;
   const retro_resampler_t* resamp = NULL;
   drflac *dr_flac          = drflac_open_memory((const unsigned char*)sound-&gt;types.flac.data, sound-&gt;types.flac.size, NULL);

   if (!dr_flac)
      return false;
   if (dr_flac-&gt;sampleRate != s_rate)
   {
      ratio = (double)s_rate / (double)(dr_flac-&gt;sampleRate);

      if (!retro_resampler_realloc(&amp;resampler_data,
               &amp;resamp, resampler_ident, quality,
               ratio))
         goto error;
   }

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler-&gt;process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
   flac_buffer                     = (float*)memalign_alloc(16,
         (((samples + 16) + 15) &amp; ~15) * sizeof(float));

   if (!flac_buffer)
   {
      if (resamp &amp;&amp; resamp-&gt;free)
         resamp-&gt;free(resampler_data);
      goto error;
   }

   voice-&gt;types.flac.resampler      = resamp;
   voice-&gt;types.flac.resampler_data = resampler_data;
   voice-&gt;types.flac.buffer         = (float*)flac_buffer;
   voice-&gt;types.flac.buf_samples    = samples;
   voice-&gt;types.flac.ratio          = ratio;
   voice-&gt;types.flac.stream         = dr_flac;
   voice-&gt;types.flac.position       = 0;
   voice-&gt;types.flac.samples        = 0;

   return true;

error:
   drflac_close(dr_flac);
   return false;
}

static void audio_mixer_release_flac(audio_mixer_voice_t* voice)
{
   if (voice-&gt;types.flac.stream)
      drflac_close(voice-&gt;types.flac.stream);
   if (voice-&gt;types.flac.resampler &amp;&amp; voice-&gt;types.flac.resampler_data)
      voice-&gt;types.flac.resampler-&gt;free(voice-&gt;types.flac.resampler_data);
   if (voice-&gt;types.flac.buffer)
      memalign_free(voice-&gt;types.flac.buffer);
}
#endif

#ifdef HAVE_DR_MP3
static bool audio_mixer_play_mp3(
      audio_mixer_sound_t* sound,
      audio_mixer_voice_t* voice,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   float ratio                     = 1.0f;
   unsigned samples                = 0;
   void *mp3_buffer                = NULL;
   void *resampler_data            = NULL;
   const retro_resampler_t* resamp = NULL;
   bool res;

   res = drmp3_init_memory(&amp;voice-&gt;types.mp3.stream, (const unsigned char*)sound-&gt;types.mp3.data, sound-&gt;types.mp3.size, NULL);

   if (!res)
      return false;

   if (voice-&gt;types.mp3.stream.sampleRate != s_rate)
   {
      ratio = (double)s_rate / (double)(voice-&gt;types.mp3.stream.sampleRate);

      if (!retro_resampler_realloc(&amp;resampler_data,
               &amp;resamp, resampler_ident, quality,
               ratio))
         goto error;
   }

   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
    * add 16 more samples in the formula below just as safeguard, because
    * resampler-&gt;process sometimes reports more output samples than the
    * formula below calculates. Ideally, audio resamplers should have a
    * function to return the number of samples they will output given a
    * count of input samples. */
   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
   mp3_buffer                      = (float*)memalign_alloc(16,
         (((samples + 16) + 15) &amp; ~15) * sizeof(float));

   if (!mp3_buffer)
   {
      if (resamp &amp;&amp; resampler_data)
         resamp-&gt;free(resampler_data);
      goto error;
   }

   voice-&gt;types.mp3.resampler      = resamp;
   voice-&gt;types.mp3.resampler_data = resampler_data;
   voice-&gt;types.mp3.buffer         = (float*)mp3_buffer;
   voice-&gt;types.mp3.buf_samples    = samples;
   voice-&gt;types.mp3.ratio          = ratio;
   voice-&gt;types.mp3.position       = 0;
   voice-&gt;types.mp3.samples        = 0;

   return true;

error:
   drmp3_uninit(&amp;voice-&gt;types.mp3.stream);
   return false;
}

static void audio_mixer_release_mp3(audio_mixer_voice_t* voice)
{
   if (voice-&gt;types.mp3.resampler &amp;&amp; voice-&gt;types.mp3.resampler_data)
      voice-&gt;types.mp3.resampler-&gt;free(voice-&gt;types.mp3.resampler_data);
   if (voice-&gt;types.mp3.buffer)
      memalign_free(voice-&gt;types.mp3.buffer);
   if (voice-&gt;types.mp3.stream.pData)
      drmp3_uninit(&amp;voice-&gt;types.mp3.stream);
}

#endif

audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb)
{
   unsigned i;
   bool res                   = false;
   audio_mixer_voice_t* voice = s_voices;

   if (!sound)
      return NULL;

   for (i = 0; i &lt; AUDIO_MIXER_MAX_VOICES; i++, voice++)
   {
      if (voice-&gt;type != AUDIO_MIXER_TYPE_NONE)
         continue;

      AUDIO_MIXER_LOCK(voice);

      if (voice-&gt;type != AUDIO_MIXER_TYPE_NONE)
      {
         AUDIO_MIXER_UNLOCK(voice);
         continue;
      }

      /* claim the voice, also helps with cleanup on error */
      voice-&gt;type = sound-&gt;type;

      switch (sound-&gt;type)
      {
         case AUDIO_MIXER_TYPE_WAV:
            res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb);
            break;
         case AUDIO_MIXER_TYPE_OGG:
#ifdef HAVE_STB_VORBIS
            res = audio_mixer_play_ogg(sound, voice, repeat, volume,
                  resampler_ident, quality, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_MOD:
#ifdef HAVE_IBXM
            res = audio_mixer_play_mod(sound, voice, repeat, volume, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_FLAC:
#ifdef HAVE_DR_FLAC
            res = audio_mixer_play_flac(sound, voice, repeat, volume,
                  resampler_ident, quality, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_MP3:
#ifdef HAVE_DR_MP3
            res = audio_mixer_play_mp3(sound, voice, repeat, volume,
                  resampler_ident, quality, stop_cb);
#endif
            break;
         case AUDIO_MIXER_TYPE_NONE:
            break;
      }

      break;
   }

   if (res)
   {
      voice-&gt;repeat   = repeat;
      voice-&gt;volume   = volume;
      voice-&gt;sound    = sound;
      voice-&gt;stop_cb  = stop_cb;
      AUDIO_MIXER_UNLOCK(voice);
   }
   else
   {
      if (i &lt; AUDIO_MIXER_MAX_VOICES)
      {
         audio_mixer_release(voice);
         AUDIO_MIXER_UNLOCK(voice);
      }
      voice = NULL;
   }

   return voice;
}

/* Need to hold lock for voice.  */
static void audio_mixer_release(audio_mixer_voice_t* voice)
{
   if (!voice)
      return;

   switch (voice-&gt;type)
   {
#ifdef HAVE_STB_VORBIS
      case AUDIO_MIXER_TYPE_OGG:
         audio_mixer_release_ogg(voice);
         break;
#endif
#ifdef HAVE_IBXM
      case AUDIO_MIXER_TYPE_MOD:
         audio_mixer_release_mod(voice);
         break;
#endif
#ifdef HAVE_DR_FLAC
      case AUDIO_MIXER_TYPE_FLAC:
         audio_mixer_release_flac(voice);
         break;
#endif
#ifdef HAVE_DR_MP3
      case AUDIO_MIXER_TYPE_MP3:
         audio_mixer_release_mp3(voice);
         break;
#endif
      default:
         break;
   }

   memset(&amp;voice-&gt;types, 0, sizeof(voice-&gt;types));
   voice-&gt;type = AUDIO_MIXER_TYPE_NONE;
}

void audio_mixer_stop(audio_mixer_voice_t* voice)
{
   audio_mixer_stop_cb_t stop_cb = NULL;
   audio_mixer_sound_t* sound    = NULL;

   if (voice)
   {
      AUDIO_MIXER_LOCK(voice);
      stop_cb     = voice-&gt;stop_cb;
      sound       = voice-&gt;sound;

      audio_mixer_release(voice);

      AUDIO_MIXER_UNLOCK(voice);

      if (stop_cb)
         stop_cb(sound, AUDIO_MIXER_SOUND_STOPPED);
   }
}

static void audio_mixer_mix_wav(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   unsigned buf_free                = (unsigned)(num_frames * 2);
   const audio_mixer_sound_t* sound = voice-&gt;sound;
   unsigned pcm_available           = sound-&gt;types.wav.frames
      * 2 - voice-&gt;types.wav.position;
   const float* pcm                 = sound-&gt;types.wav.pcm +
      voice-&gt;types.wav.position;

again:
   if (pcm_available &lt; buf_free)
   {
      for (i = pcm_available; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      if (voice-&gt;repeat)
      {
         if (voice-&gt;stop_cb)
            voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_REPEATED);

         buf_free                  -= pcm_available;
         pcm_available              = sound-&gt;types.wav.frames * 2;
         pcm                        = sound-&gt;types.wav.pcm;
         voice-&gt;types.wav.position  = 0;
         goto again;
      }

      if (voice-&gt;stop_cb)
         voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_FINISHED);

      audio_mixer_release(voice);
   }
   else
   {
      for (i = buf_free; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      voice-&gt;types.wav.position += buf_free;
   }
}

#ifdef HAVE_STB_VORBIS
static void audio_mixer_mix_ogg(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   float* temp_buffer = NULL;
   unsigned buf_free                = (unsigned)(num_frames * 2);
   unsigned temp_samples            = 0;
   float* pcm                       = NULL;

   if (!voice-&gt;types.ogg.stream)
      return;

   if (voice-&gt;types.ogg.position == voice-&gt;types.ogg.samples)
   {
again:
      if (temp_buffer == NULL)
         temp_buffer = (float*)malloc(AUDIO_MIXER_TEMP_BUFFER * sizeof(float));

      temp_samples = stb_vorbis_get_samples_float_interleaved(
            voice-&gt;types.ogg.stream, 2, temp_buffer,
            AUDIO_MIXER_TEMP_BUFFER) * 2;

      if (temp_samples == 0)
      {
         if (voice-&gt;repeat)
         {
            if (voice-&gt;stop_cb)
               voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_REPEATED);

            stb_vorbis_seek_start(voice-&gt;types.ogg.stream);
            goto again;
         }

         if (voice-&gt;stop_cb)
            voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         goto cleanup;
      }

      if (voice-&gt;types.ogg.resampler)
      {
         struct resampler_data info;
         info.data_in = temp_buffer;
         info.data_out = voice-&gt;types.ogg.buffer;
         info.input_frames = temp_samples / 2;
         info.output_frames = 0;
         info.ratio = voice-&gt;types.ogg.ratio;

         voice-&gt;types.ogg.resampler-&gt;process(
               voice-&gt;types.ogg.resampler_data, &amp;info);
      }
      else
         memcpy(voice-&gt;types.ogg.buffer, temp_buffer,
               temp_samples * sizeof(float));

      voice-&gt;types.ogg.position = 0;
      voice-&gt;types.ogg.samples  = voice-&gt;types.ogg.buf_samples;
   }

   pcm = voice-&gt;types.ogg.buffer + voice-&gt;types.ogg.position;

   if (voice-&gt;types.ogg.samples &lt; buf_free)
   {
      for (i = voice-&gt;types.ogg.samples; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      buf_free -= voice-&gt;types.ogg.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
      *buffer++ += *pcm++ * volume;

   voice-&gt;types.ogg.position += buf_free;
   voice-&gt;types.ogg.samples  -= buf_free;

cleanup:
   if (temp_buffer != NULL)
      free(temp_buffer);
}
#endif

#ifdef HAVE_IBXM
static void audio_mixer_mix_mod(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   float samplef                    = 0.0f;
   unsigned temp_samples            = 0;
   unsigned buf_free                = (unsigned)(num_frames * 2);
   int* pcm                         = NULL;

   if (voice-&gt;types.mod.samples == 0)
   {
again:
      temp_samples = replay_get_audio(
            voice-&gt;types.mod.stream, voice-&gt;types.mod.buffer, 0 ) * 2;

      if (temp_samples == 0)
      {
         if (voice-&gt;repeat)
         {
            if (voice-&gt;stop_cb)
               voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_REPEATED);

            replay_seek( voice-&gt;types.mod.stream, 0);
            goto again;
         }

         if (voice-&gt;stop_cb)
            voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         return;
      }

      voice-&gt;types.mod.position = 0;
      voice-&gt;types.mod.samples  = temp_samples;
   }
   pcm = voice-&gt;types.mod.buffer + voice-&gt;types.mod.position;

   if (voice-&gt;types.mod.samples &lt; buf_free)
   {
      for (i = voice-&gt;types.mod.samples; i != 0; i--)
      {
         samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;
         samplef     = samplef * 2.0f - 1.0f;
         *buffer++  += samplef * volume;
      }

      buf_free -= voice-&gt;types.mod.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
   {
      samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;
      samplef     = samplef * 2.0f - 1.0f;
      *buffer++  += samplef * volume;
   }

   voice-&gt;types.mod.position += buf_free;
   voice-&gt;types.mod.samples  -= buf_free;
}
#endif

#ifdef HAVE_DR_FLAC
static void audio_mixer_mix_flac(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   struct resampler_data info;
   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
   unsigned buf_free                = (unsigned)(num_frames * 2);
   unsigned temp_samples            = 0;
   float *pcm                       = NULL;

   if (voice-&gt;types.flac.position == voice-&gt;types.flac.samples)
   {
again:
      temp_samples = (unsigned)drflac_read_pcm_frames_f32( voice-&gt;types.flac.stream, AUDIO_MIXER_TEMP_BUFFER, temp_buffer);
      if (temp_samples == 0)
      {
         if (voice-&gt;repeat)
         {
            if (voice-&gt;stop_cb)
               voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_REPEATED);

            drflac_seek_to_pcm_frame(voice-&gt;types.flac.stream,0);
            goto again;
         }

         if (voice-&gt;stop_cb)
            voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         return;
      }

      info.data_in              = temp_buffer;
      info.data_out             = voice-&gt;types.flac.buffer;
      info.input_frames         = temp_samples / 2;
      info.output_frames        = 0;
      info.ratio                = voice-&gt;types.flac.ratio;

      if (voice-&gt;types.flac.resampler)
         voice-&gt;types.flac.resampler-&gt;process(
               voice-&gt;types.flac.resampler_data, &amp;info);
      else
         memcpy(voice-&gt;types.flac.buffer, temp_buffer, temp_samples * sizeof(float));
      voice-&gt;types.flac.position = 0;
      voice-&gt;types.flac.samples  = voice-&gt;types.flac.buf_samples;
   }

   pcm = voice-&gt;types.flac.buffer + voice-&gt;types.flac.position;

   if (voice-&gt;types.flac.samples &lt; buf_free)
   {
      for (i = voice-&gt;types.flac.samples; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      buf_free -= voice-&gt;types.flac.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
      *buffer++ += *pcm++ * volume;

   voice-&gt;types.flac.position += buf_free;
   voice-&gt;types.flac.samples  -= buf_free;
}
#endif

#ifdef HAVE_DR_MP3
static void audio_mixer_mix_mp3(float* buffer, size_t num_frames,
      audio_mixer_voice_t* voice,
      float volume)
{
   int i;
   struct resampler_data info;
   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
   unsigned buf_free                = (unsigned)(num_frames * 2);
   unsigned temp_samples            = 0;
   float* pcm                       = NULL;

   if (voice-&gt;types.mp3.position == voice-&gt;types.mp3.samples)
   {
again:
      temp_samples = (unsigned)drmp3_read_f32(
            &amp;voice-&gt;types.mp3.stream,
            AUDIO_MIXER_TEMP_BUFFER / 2, temp_buffer) * 2;

      if (temp_samples == 0)
      {
         if (voice-&gt;repeat)
         {
            if (voice-&gt;stop_cb)
               voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_REPEATED);

            drmp3_seek_to_frame(&amp;voice-&gt;types.mp3.stream,0);
            goto again;
         }

         if (voice-&gt;stop_cb)
            voice-&gt;stop_cb(voice-&gt;sound, AUDIO_MIXER_SOUND_FINISHED);

         audio_mixer_release(voice);
         return;
      }

      info.data_in              = temp_buffer;
      info.data_out             = voice-&gt;types.mp3.buffer;
      info.input_frames         = temp_samples / 2;
      info.output_frames        = 0;
      info.ratio                = voice-&gt;types.mp3.ratio;

      if (voice-&gt;types.mp3.resampler)
         voice-&gt;types.mp3.resampler-&gt;process(
               voice-&gt;types.mp3.resampler_data, &amp;info);
      else
         memcpy(voice-&gt;types.mp3.buffer, temp_buffer,
               temp_samples * sizeof(float));
      voice-&gt;types.mp3.position = 0;
      voice-&gt;types.mp3.samples  = voice-&gt;types.mp3.buf_samples;
   }

   pcm = voice-&gt;types.mp3.buffer + voice-&gt;types.mp3.position;

   if (voice-&gt;types.mp3.samples &lt; buf_free)
   {
      for (i = voice-&gt;types.mp3.samples; i != 0; i--)
         *buffer++ += *pcm++ * volume;

      buf_free -= voice-&gt;types.mp3.samples;
      goto again;
   }

   for (i = buf_free; i != 0; --i )
      *buffer++ += *pcm++ * volume;

   voice-&gt;types.mp3.position += buf_free;
   voice-&gt;types.mp3.samples  -= buf_free;
}
#endif

void audio_mixer_mix(float* buffer, size_t num_frames,
      float volume_override, bool override)
{
   unsigned i;
   size_t j                   = 0;
   float* sample              = NULL;
   audio_mixer_voice_t* voice = s_voices;

   for (i = 0; i &lt; AUDIO_MIXER_MAX_VOICES; i++, voice++)
   {
      float volume;

      AUDIO_MIXER_LOCK(voice);

      volume = (override) ? volume_override : voice-&gt;volume;

      switch (voice-&gt;type)
      {
         case AUDIO_MIXER_TYPE_WAV:
            audio_mixer_mix_wav(buffer, num_frames, voice, volume);
            break;
         case AUDIO_MIXER_TYPE_OGG:
#ifdef HAVE_STB_VORBIS
            audio_mixer_mix_ogg(buffer, num_frames, voice, volume);
#endif
            break;
         case AUDIO_MIXER_TYPE_MOD:
#ifdef HAVE_IBXM
            audio_mixer_mix_mod(buffer, num_frames, voice, volume);
#endif
            break;
         case AUDIO_MIXER_TYPE_FLAC:
#ifdef HAVE_DR_FLAC
            audio_mixer_mix_flac(buffer, num_frames, voice, volume);
#endif
            break;
            case AUDIO_MIXER_TYPE_MP3:
#ifdef HAVE_DR_MP3
            audio_mixer_mix_mp3(buffer, num_frames, voice, volume);
#endif
            break;
         case AUDIO_MIXER_TYPE_NONE:
            break;
      }

      AUDIO_MIXER_UNLOCK(voice);
   }

   for (j = 0, sample = buffer; j &lt; num_frames * 2; j++, sample++)
   {
      if (*sample &lt; -1.0f)
         *sample = -1.0f;
      else if (*sample &gt; 1.0f)
         *sample = 1.0f;
   }
}

float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice)
{
   if (!voice)
      return 0.0f;

   return voice-&gt;volume;
}

void audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val)
{
   if (!voice)
      return;

   AUDIO_MIXER_LOCK(voice);
   voice-&gt;volume = val;
   AUDIO_MIXER_UNLOCK(voice);
}</pre>
<h2>./include/libretro-common/audio/conversion/float_to_s16.c</h2>
<pre>/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#if defined(__SSE2__)
#include &lt;emmintrin.h&gt;
#elif defined(__ALTIVEC__)
#include &lt;altivec.h&gt;
#endif

#include &lt;features/features_cpu.h&gt;
#include &lt;audio/conversion/float_to_s16.h&gt;

#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
static bool float_to_s16_neon_enabled = false;
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
void convert_float_s16_asm(int16_t *s, const float *in, size_t len);
#else
#include &lt;arm_neon.h&gt;
#endif

void convert_float_to_s16(int16_t *s, const float *in, size_t len)
{
   size_t i           = 0;
   if (float_to_s16_neon_enabled)
   {
      float        gf = (1&lt;&lt;15);
      float32x4_t vgf = {gf, gf, gf, gf};
      while (len &gt;= 8)
      {
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
         size_t aligned_samples = len &amp; ~7;
         if (aligned_samples)
            convert_float_s16_asm(s, in, aligned_samples);

         s        += aligned_samples;
         in       += aligned_samples;
         samples  -= aligned_samples;
         i         = 0;
#else
         int16x4x2_t oreg;
         int32x4x2_t creg;
         float32x4x2_t inreg = vld2q_f32(in);
         creg.val[0]         = vcvtq_s32_f32(vmulq_f32(inreg.val[0], vgf));
         creg.val[1]         = vcvtq_s32_f32(vmulq_f32(inreg.val[1], vgf));
         oreg.val[0]         = vqmovn_s32(creg.val[0]);
         oreg.val[1]         = vqmovn_s32(creg.val[1]);
         vst2_s16(s, oreg);
         in      += 8;
         s       += 8;
         len     -= 8;
#endif
      }
   }

   for (; i &lt; len; i++)
   {
      int32_t val = (int32_t)(in[i] * 0x8000);
      s[i]        = (val &gt; 0x7FFF) ? 0x7FFF :
         (val &lt; -0x8000 ? -0x8000 : (int16_t)val);
   }
}

void convert_float_to_s16_init_simd(void)
{
   uint64_t cpu = cpu_features_get();

   if (cpu &amp; RETRO_SIMD_NEON)
      float_to_s16_neon_enabled = true;
}
#else
void convert_float_to_s16(int16_t *s, const float *in, size_t len)
{
   size_t i          = 0;
#if defined(__SSE2__)
   __m128 factor     = _mm_set1_ps((float)0x8000);
   /* Initialize a 4D vector with 32768.0 for its elements */

   for (i = 0; i + 8 &lt;= len; i += 8, in += 8, s += 8)
   { /* Skip forward 8 samples at a time... */
      __m128 input_a = _mm_loadu_ps(in + 0); /* Create a 4-float vector from the next four samples... */
      __m128 input_b = _mm_loadu_ps(in + 4); /* ...and another from the *next* next four. */
      __m128 res_a   = _mm_mul_ps(input_a, factor);
      __m128 res_b   = _mm_mul_ps(input_b, factor); /* Multiply these samples by 32768 */
      __m128i ints_a = _mm_cvtps_epi32(res_a);
      __m128i ints_b = _mm_cvtps_epi32(res_b); /* Convert the samples to 32-bit integers */
      __m128i packed = _mm_packs_epi32(ints_a, ints_b); /* Then convert them to 16-bit ints, clamping to [-32768, 32767] */

      _mm_storeu_si128((__m128i *)s, packed); /* Then put the result in the output array */
   }

   len               = len - i;
   i                 = 0;
   /* If there are any stray samples at the end, we need to convert them
    * (maybe the original array didn't contain a multiple of 8 samples) */
#elif defined(__ALTIVEC__)
   int samples_in    = len;

   /* Unaligned loads/store is a bit expensive,
    * so we optimize for the good path (very likely). */
   if (((uintptr_t)s &amp; 15) + ((uintptr_t)in &amp; 15) == 0)
   {
      size_t i;
      for (i = 0; i + 8 &lt;= len; i += 8, in += 8, s += 8)
      {
         vector float       input0 = vec_ld( 0, in);
         vector float       input1 = vec_ld(16, in);
         vector signed int result0 = vec_cts(input0, 15);
         vector signed int result1 = vec_cts(input1, 15);
         vec_st(vec_packs(result0, result1), 0, s);
      }

      samples_in    -= i;
   }

   len               = samples_in;
   i                 = 0;
#elif defined(_MIPS_ARCH_ALLEGREX)
#ifdef DEBUG
   /* Make sure the buffers are 16 byte aligned, this should be
    * the default behaviour of malloc in the PSPSDK.
    * Assume alignment. */
   retro_assert(((uintptr_t)in  &amp; 0xf) == 0);
   retro_assert(((uintptr_t)s &amp; 0xf) == 0);
#endif

   for (i = 0; i + 8 &lt;= len; i += 8)
   {
      __asm__ (
            ".set    push                 \n"
            ".set    noreorder            \n"

            "lv.q    c100,  0(%0)         \n"
            "lv.q    c110,  16(%0)        \n"

            "vf2in.q c100, c100, 31       \n"
            "vf2in.q c110, c110, 31       \n"
            "vi2s.q  c100, c100           \n"
            "vi2s.q  c102, c110           \n"

            "sv.q    c100,  0(%1)         \n"

            ".set    pop                  \n"
            :: "r"(in + i), "r"(s + i));
   }
#endif

   /* This loop converts stray samples to the right format,
    * but it's also a fallback in case no SIMD instructions are available. */
   for (; i &lt; len; i++)
   {
      int32_t val    = (int32_t)(in[i] * 0x8000);
      s[i]           = (val &gt; 0x7FFF)
         ? 0x7FFF
         : (val &lt; -0x8000 ? -0x8000 : (int16_t)val);
   }
}

void convert_float_to_s16_init_simd(void) { }
#endif</pre>
<h2>./include/libretro-common/audio/conversion/float_to_s16_neon.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) &amp;&amp; defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#if defined(__thumb__)
#define DECL_ARMMODE(x) "  .align 2\n" "  .global " x "\n" "  .thumb\n" "  .thumb_func\n" "  .type " x ", %function\n" x ":\n"
#else
#define DECL_ARMMODE(x) "  .align 4\n" "  .global " x "\n" "  .arm\n" x ":\n"
#endif

asm(
    DECL_ARMMODE("convert_float_s16_asm")
    DECL_ARMMODE("_convert_float_s16_asm")
    "# convert_float_s16_asm(int16_t *s, const float *in, size_t len)\n"
    "   # Hacky way to get a constant of 2^15.\n"
    "   # ((2^4)^2)^2 * 0.5 = 2^15\n"
    "   vmov.f32 q8, #16.0\n"
    "   vmov.f32 q9, #0.5\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q9\n"
    "\n"
    "1:\n"
    "   # Preload here?\n"
    "   vld1.f32 {q0-q1}, [r1]!\n"
    "\n"
    "   vmul.f32 q0, q0, q8\n"
    "   vmul.f32 q1, q1, q8\n"
    "\n"
    "   vcvt.s32.f32 q0, q0\n"
    "   vcvt.s32.f32 q1, q1\n"
    "\n"
    "   vqmovn.s32 d4, q0\n"
    "   vqmovn.s32 d5, q1\n"
    "\n"
    "   vst1.f32 {d4-d5}, [r0]!\n"
    "\n"
    "   # Guaranteed to get samples in multiples of 8.\n"
    "   subs r2, r2, #8\n"
    "   bne 1b\n"
    "\n"
    "   bx lr\n"
    "\n"
    );
#endif</pre>
<h2>./include/libretro-common/audio/conversion/float_to_s16_neon.S</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) &amp;&amp; defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#ifndef __MACH__
.arm
#endif

.align 4
.globl convert_float_s16_asm
#ifndef __MACH__
.type convert_float_s16_asm, %function
#endif
.globl _convert_float_s16_asm
#ifndef __MACH__
.type _convert_float_s16_asm, %function
#endif
# convert_float_s16_asm(int16_t *out, const float *in, size_t samples)
convert_float_s16_asm:
_convert_float_s16_asm:
   # Hacky way to get a constant of 2^15.
   # ((2^4)^2)^2 * 0.5 = 2^15
   vmov.f32 q8, #16.0
   vmov.f32 q9, #0.5
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q9

1:
   # Preload here?
   vld1.f32 {q0-q1}, [r1]!

   vmul.f32 q0, q0, q8
   vmul.f32 q1, q1, q8

   vcvt.s32.f32 q0, q0
   vcvt.s32.f32 q1, q1

   vqmovn.s32 d4, q0
   vqmovn.s32 d5, q1

   vst1.f32 {d4-d5}, [r0]!

   # Guaranteed to get samples in multiples of 8.
   subs r2, r2, #8
   bne 1b

   bx lr

#endif</pre>
<h2>./include/libretro-common/audio/conversion/mono_to_stereo_float.c</h2>
<pre>/* Copyright  (C) 2010-2023 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (mono_to_stereo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;audio/conversion/dual_mono.h&gt;

/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */
void convert_to_dual_mono_float(float *s, const float *in, size_t len)
{
   unsigned i = 0;

   if (!s || !in || !len)
      return;

   for (; i &lt; len; i++)
   {
      s[i * 2]     = in[i];
      s[i * 2 + 1] = in[i];
   }
}

/* Why is there no equivalent for int16_t samples?
 * No inherent reason, I just didn't need one.
 * If you do, open a pull request. */</pre>
<h2>./include/libretro-common/audio/conversion/s16_to_float.c</h2>
<pre>/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__SSE2__)
#include &lt;emmintrin.h&gt;
#elif defined(__ALTIVEC__)
#include &lt;altivec.h&gt;
#endif

#include &lt;boolean.h&gt;
#include &lt;features/features_cpu.h&gt;
#include &lt;audio/conversion/s16_to_float.h&gt;

#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
static bool s16_to_float_neon_enabled = false;

#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
/* Avoid potential hard-float/soft-float ABI issues. */
void convert_s16_float_asm(float *s, const int16_t *in,
      size_t len, const float *gain);
#else
#include &lt;arm_neon.h&gt;
#endif

void convert_s16_to_float(float *s,
      const int16_t *in, size_t len, float gain)
{
   unsigned i      = 0;

   if (s16_to_float_neon_enabled)
   {
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
      size_t aligned_samples = len &amp; ~7;
      if (aligned_samples)
         convert_s16_float_asm(s, in, aligned_samples, &amp;gain);

      /* Could do all conversion in ASM, but keep it simple for now. */
      s                 += aligned_samples;
      in                += aligned_samples;
      len               -= aligned_samples;
      i                  = 0;
#else
      float        gf    = gain / (1 &lt;&lt; 15);
      float32x4_t vgf    = {gf, gf, gf, gf};
      while (len &gt;= 8)
      {
         float32x4x2_t oreg;
         int16x4x2_t inreg   = vld2_s16(in);
         int32x4_t      p1   = vmovl_s16(inreg.val[0]);
         int32x4_t      p2   = vmovl_s16(inreg.val[1]);
         oreg.val[0]         = vmulq_f32(vcvtq_f32_s32(p1), vgf);
         oreg.val[1]         = vmulq_f32(vcvtq_f32_s32(p2), vgf);
         vst2q_f32(s, oreg);
         in                 += 8;
         s                  += 8;
         len                -= 8;
      }
#endif
   }

   gain /= 0x8000;

   for (; i &lt; len; i++)
      s[i] = (float)in[i] * gain;
}

void convert_s16_to_float_init_simd(void)
{
   uint64_t cpu = cpu_features_get();

   if (cpu &amp; RETRO_SIMD_NEON)
      s16_to_float_neon_enabled = true;
}
#else
void convert_s16_to_float(float *s,
      const int16_t *in, size_t len, float gain)
{
   unsigned i      = 0;

#if defined(__SSE2__)
   float fgain   = gain / UINT32_C(0x80000000);
   __m128 factor = _mm_set1_ps(fgain);

   for (i = 0; i + 8 &lt;= len; i += 8, in += 8, s += 8)
   {
      __m128i input    = _mm_loadu_si128((const __m128i *)in);
      __m128i regs_l   = _mm_unpacklo_epi16(_mm_setzero_si128(), input);
      __m128i regs_r   = _mm_unpackhi_epi16(_mm_setzero_si128(), input);
      __m128 output_l  = _mm_mul_ps(_mm_cvtepi32_ps(regs_l), factor);
      __m128 output_r  = _mm_mul_ps(_mm_cvtepi32_ps(regs_r), factor);

      _mm_storeu_ps(s + 0, output_l);
      _mm_storeu_ps(s + 4, output_r);
   }

   len     = len - i;
   i       = 0;
#elif defined(__ALTIVEC__)
   size_t samples_in = len;

   /* Unaligned loads/store is a bit expensive, so we
    * optimize for the good path (very likely). */
   if (((uintptr_t)s &amp; 15) + ((uintptr_t)in &amp; 15) == 0)
   {
      const vector float gain_vec = { gain, gain , gain, gain };
      const vector float zero_vec = { 0.0f, 0.0f, 0.0f, 0.0f};

      for (i = 0; i + 8 &lt;= len; i += 8, in += 8, s += 8)
      {
         vector signed short input = vec_ld(0, in);
         vector signed int hi      = vec_unpackh(input);
         vector signed int lo      = vec_unpackl(input);
         vector float out_hi       = vec_madd(vec_ctf(hi, 15), gain_vec, zero_vec);
         vector float out_lo       = vec_madd(vec_ctf(lo, 15), gain_vec, zero_vec);

         vec_st(out_hi,  0, s);
         vec_st(out_lo, 16, s);
      }

      samples_in -= i;
   }

   len     = samples_in;
   i       = 0;
#endif

   gain   /= 0x8000;

#if defined(_MIPS_ARCH_ALLEGREX)
#ifdef DEBUG
   /* Make sure the buffer is 16 byte aligned, this should be the
    * default behaviour of malloc in the PSPSDK.
    * Only the output buffer can be assumed to be 16-byte aligned. */
   retro_assert(((uintptr_t)s &amp; 0xf) == 0);
#endif

   __asm__ (
         ".set    push                    \n"
         ".set    noreorder               \n"
         "mtv     %0, s200                \n"
         ".set    pop                     \n"
         ::"r"(gain));

   for (i = 0; i + 16 &lt;= len; i += 16)
   {
      __asm__ (
            ".set    push                 \n"
            ".set    noreorder            \n"

            "lv.s    s100,  0(%0)         \n"
            "lv.s    s101,  4(%0)         \n"
            "lv.s    s110,  8(%0)         \n"
            "lv.s    s111, 12(%0)         \n"
            "lv.s    s120, 16(%0)         \n"
            "lv.s    s121, 20(%0)         \n"
            "lv.s    s130, 24(%0)         \n"
            "lv.s    s131, 28(%0)         \n"

            "vs2i.p  c100, c100           \n"
            "vs2i.p  c110, c110           \n"
            "vs2i.p  c120, c120           \n"
            "vs2i.p  c130, c130           \n"

            "vi2f.q  c100, c100, 16       \n"
            "vi2f.q  c110, c110, 16       \n"
            "vi2f.q  c120, c120, 16       \n"
            "vi2f.q  c130, c130, 16       \n"

            "vmscl.q e100, e100, s200     \n"

            "sv.q    c100,  0(%1)         \n"
            "sv.q    c110, 16(%1)         \n"
            "sv.q    c120, 32(%1)         \n"
            "sv.q    c130, 48(%1)         \n"

            ".set    pop                  \n"
            :: "r"(in + i), "r"(s + i));
   }
#endif

   for (; i &lt; len; i++)
      s[i] = (float)in[i] * gain;
}

void convert_s16_to_float_init_simd(void) { }
#endif</pre>
<h2>./include/libretro-common/audio/conversion/s16_to_float_neon.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) &amp;&amp; defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#if defined(__thumb__)
#define DECL_ARMMODE(x) "  .align 2\n" "  .global " x "\n" "  .thumb\n" "  .thumb_func\n" "  .type " x ", %function\n" x ":\n"
#else
#define DECL_ARMMODE(x) "  .align 4\n" "  .global " x "\n" "  .arm\n" x ":\n"
#endif

asm(
    DECL_ARMMODE("convert_s16_float_asm")
    DECL_ARMMODE("_convert_s16_float_asm")
    "# convert_s16_float_asm(float *s, const int16_t *in, size_t len, const float *gain)\n"
    "   # Hacky way to get a constant of 2^-15.\n"
    "   # Might be faster to just load a constant from memory.\n"
    "   # It's just done once however ...\n"
    "   vmov.f32 q8, #0.25\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vmul.f32 q8, q8, q8\n"
    "   vadd.f32 q8, q8, q8\n"
    "\n"
    "   # Apply gain\n"
    "   vld1.f32 {d6[0]}, [r3]\n"
    "   vmul.f32 q8, q8, d6[0]\n"
    "\n"
    "1:\n"
    "   # Preload here?\n"
    "   vld1.s16 {q0}, [r1]!\n"
    "\n"
    "   # Widen to 32-bit\n"
    "   vmovl.s16 q1, d0\n"
    "   vmovl.s16 q2, d1\n"
    "\n"
    "   # Convert to float\n"
    "   vcvt.f32.s32 q1, q1\n"
    "   vcvt.f32.s32 q2, q2\n"
    "\n"
    "   vmul.f32 q1, q1, q8\n"
    "   vmul.f32 q2, q2, q8\n"
    "\n"
    "   vst1.f32 {q1-q2}, [r0]!\n"
    "\n"
    "   # Guaranteed to get samples in multiples of 8.\n"
    "   subs r2, r2, #8\n"
    "   bne 1b\n"
    "\n"
    "   bx lr\n"
    "\n"
    );
#endif</pre>
<h2>./include/libretro-common/audio/conversion/s16_to_float_neon.S</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#if defined(__ARM_NEON__) &amp;&amp; defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#ifndef __MACH__
.arm
#endif

.align 4
.globl convert_s16_float_asm
#ifndef __MACH__
.type convert_s16_float_asm, %function
#endif
.globl _convert_s16_float_asm
#ifndef __MACH__
.type _convert_s16_float_asm, %function
#endif
# convert_s16_float_asm(float *out, const int16_t *in, size_t samples, const float *gain)
convert_s16_float_asm:
_convert_s16_float_asm:
   # Hacky way to get a constant of 2^-15.
   # Might be faster to just load a constant from memory.
   # It's just done once however ...
   vmov.f32 q8, #0.25
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q8
   vmul.f32 q8, q8, q8
   vadd.f32 q8, q8, q8

   # Apply gain
   vld1.f32 {d6[0]}, [r3]
   vmul.f32 q8, q8, d6[0]

1:
   # Preload here?
   vld1.s16 {q0}, [r1]!

   # Widen to 32-bit
   vmovl.s16 q1, d0
   vmovl.s16 q2, d1

   # Convert to float
   vcvt.f32.s32 q1, q1
   vcvt.f32.s32 q2, q2

   vmul.f32 q1, q1, q8
   vmul.f32 q2, q2, q8

   vst1.f32 {q1-q2}, [r0]!

   # Guaranteed to get samples in multiples of 8.
   subs r2, r2, #8
   bne 1b

   bx lr

#endif</pre>
<h2>./include/libretro-common/audio/conversion/stereo_to_mono_float.c</h2>
<pre>/* Copyright  (C) 2010-2023 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (mono_to_stereo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;audio/conversion/dual_mono.h&gt;

/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */
void convert_to_mono_float_left(float *out, const float *in, size_t frames)
{
   unsigned i = 0;

   if (!out || !in || !frames)
      return;

   for (; i &lt; frames; i++)
   {
      out[i] = in[i * 2];
   }
}

/* Why is there no equivalent for int16_t samples?
 * No inherent reason, I just didn't need one.
 * If you do, open a pull request.
 * Same goes for the lack of a convert_to_mono_float_right;
 * I didn't need one, so I didn't write one. */</pre>
<h2>./include/libretro-common/audio/dsp_filter.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dsp_filter.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;

#include &lt;retro_miscellaneous.h&gt;

#include &lt;compat/posix_string.h&gt;
#include &lt;dynamic/dylib.h&gt;

#include &lt;file/file_path.h&gt;
#include &lt;file/config_file_userdata.h&gt;
#include &lt;features/features_cpu.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;libretro_dspfilter.h&gt;

#include &lt;audio/dsp_filter.h&gt;

struct retro_dsp_plug
{
#ifdef HAVE_DYLIB
   dylib_t lib;
#endif
   const struct dspfilter_implementation *impl;
};

struct retro_dsp_instance
{
   const struct dspfilter_implementation *impl;
   void *impl_data;
};

struct retro_dsp_filter
{
   config_file_t *conf;

   struct retro_dsp_plug *plugs;
   unsigned num_plugs;

   struct retro_dsp_instance *instances;
   unsigned num_instances;
};

static const struct dspfilter_implementation *find_implementation(
      retro_dsp_filter_t *dsp, const char *ident)
{
   unsigned i;
   for (i = 0; i &lt; dsp-&gt;num_plugs; i++)
   {
      if (string_is_equal(dsp-&gt;plugs[i].impl-&gt;short_ident, ident))
         return dsp-&gt;plugs[i].impl;
   }

   return NULL;
}

static const struct dspfilter_config dspfilter_config = {
   config_userdata_get_float,
   config_userdata_get_int,
   config_userdata_get_float_array,
   config_userdata_get_int_array,
   config_userdata_get_string,
   config_userdata_free,
};

static bool create_filter_graph(retro_dsp_filter_t *dsp, float sample_rate)
{
   unsigned i;
   struct retro_dsp_instance *instances = NULL;
   unsigned filters                     = 0;

   if (!config_get_uint(dsp-&gt;conf, "filters", &amp;filters))
      return false;

   instances = (struct retro_dsp_instance*)calloc(filters, sizeof(*instances));
   if (!instances)
      return false;

   dsp-&gt;instances     = instances;
   dsp-&gt;num_instances = filters;

   for (i = 0; i &lt; filters; i++)
   {
      struct config_file_userdata userdata;
      struct dspfilter_info info;
      char key[64];
      char name[64];

      key[0] = name[0] = '\0';

      info.input_rate  = sample_rate;

      snprintf(key, sizeof(key), "filter%u", i);

      if (!config_get_array(dsp-&gt;conf, key, name, sizeof(name)))
         return false;

      dsp-&gt;instances[i].impl = find_implementation(dsp, name);
      if (!dsp-&gt;instances[i].impl)
         return false;

      userdata.conf = dsp-&gt;conf;
      /* Index-specific configs take priority over ident-specific. */
      userdata.prefix[0] = key;
      userdata.prefix[1] = dsp-&gt;instances[i].impl-&gt;short_ident;

      dsp-&gt;instances[i].impl_data = dsp-&gt;instances[i].impl-&gt;init(&amp;info,
            &amp;dspfilter_config, &amp;userdata);
      if (!dsp-&gt;instances[i].impl_data)
         return false;
   }

   return true;
}

#if defined(HAVE_FILTERS_BUILTIN)
extern const struct dspfilter_implementation *chorus_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *delta_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *echo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *eq_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *iir_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *panning_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *phaser_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *reverb_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *tremolo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *vibrato_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
extern const struct dspfilter_implementation *wahwah_dspfilter_get_implementation(dspfilter_simd_mask_t mask);

static const dspfilter_get_implementation_t dsp_plugs_builtin[] = {
   chorus_dspfilter_get_implementation,
   delta_dspfilter_get_implementation,
   echo_dspfilter_get_implementation,
   eq_dspfilter_get_implementation,
   iir_dspfilter_get_implementation,
   panning_dspfilter_get_implementation,
   phaser_dspfilter_get_implementation,
   reverb_dspfilter_get_implementation,
   tremolo_dspfilter_get_implementation,
   vibrato_dspfilter_get_implementation,
   wahwah_dspfilter_get_implementation,
};

static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
{
   unsigned i;
   dspfilter_simd_mask_t mask   = (dspfilter_simd_mask_t)cpu_features_get();
   struct retro_dsp_plug *plugs = (struct retro_dsp_plug*)
      calloc(ARRAY_SIZE(dsp_plugs_builtin), sizeof(*plugs));

   if (!plugs)
      return false;

   dsp-&gt;plugs     = plugs;
   dsp-&gt;num_plugs = ARRAY_SIZE(dsp_plugs_builtin);

   for (i = 0; i &lt; ARRAY_SIZE(dsp_plugs_builtin); i++)
   {
      dsp-&gt;plugs[i].impl = dsp_plugs_builtin[i](mask);
      if (!dsp-&gt;plugs[i].impl)
         return false;
   }

   return true;
}
#elif defined(HAVE_DYLIB)
static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
{
   unsigned i;
   dspfilter_simd_mask_t mask = (dspfilter_simd_mask_t)cpu_features_get();
   unsigned list_size         = list ? (unsigned)list-&gt;size : 0;

   for (i = 0; i &lt; list_size; i++)
   {
      dspfilter_get_implementation_t cb;
      const struct dspfilter_implementation *impl = NULL;
      struct retro_dsp_plug *new_plugs            = NULL;
      dylib_t lib                                 =
         dylib_load(list-&gt;elems[i].data);

      if (!lib)
         continue;

      cb = (dspfilter_get_implementation_t)dylib_proc(lib, "dspfilter_get_implementation");
      if (!cb)
      {
         dylib_close(lib);
         continue;
      }

      impl = cb(mask);
      if (!impl)
      {
         dylib_close(lib);
         continue;
      }

      if (impl-&gt;api_version != DSPFILTER_API_VERSION)
      {
         dylib_close(lib);
         continue;
      }

      new_plugs = (struct retro_dsp_plug*)
         realloc(dsp-&gt;plugs, sizeof(*dsp-&gt;plugs) * (dsp-&gt;num_plugs + 1));
      if (!new_plugs)
      {
         dylib_close(lib);
         return false;
      }

      /* Found plug. */

      dsp-&gt;plugs = new_plugs;
      dsp-&gt;plugs[dsp-&gt;num_plugs].lib = lib;
      dsp-&gt;plugs[dsp-&gt;num_plugs].impl = impl;
      dsp-&gt;num_plugs++;
   }

   return true;
}
#endif

retro_dsp_filter_t *retro_dsp_filter_new(
      const char *filter_config,
      void *string_data,
      float sample_rate)
{
   config_file_t *conf           = NULL;
   struct string_list *plugs     = NULL;
   retro_dsp_filter_t *dsp       = (retro_dsp_filter_t*)calloc(1, sizeof(*dsp));

   if (!dsp)
      return NULL;

   if (!(conf = config_file_new_from_path_to_string(filter_config)))
      goto error;

   dsp-&gt;conf = conf;

   if (string_data)
      plugs = (struct string_list*)string_data;

#if defined(HAVE_DYLIB) || defined(HAVE_FILTERS_BUILTIN)
   if (!append_plugs(dsp, plugs))
      goto error;
#endif

   if (plugs)
      string_list_free(plugs);
   plugs = NULL;

   if (!create_filter_graph(dsp, sample_rate))
      goto error;

   return dsp;

error:
   if (plugs)
      string_list_free(plugs);
   retro_dsp_filter_free(dsp);
   return NULL;
}

void retro_dsp_filter_free(retro_dsp_filter_t *dsp)
{
   unsigned i;
   if (!dsp)
      return;

   for (i = 0; i &lt; dsp-&gt;num_instances; i++)
   {
      if (dsp-&gt;instances[i].impl_data &amp;&amp; dsp-&gt;instances[i].impl)
         dsp-&gt;instances[i].impl-&gt;free(dsp-&gt;instances[i].impl_data);
   }
   free(dsp-&gt;instances);

#ifdef HAVE_DYLIB
   for (i = 0; i &lt; dsp-&gt;num_plugs; i++)
   {
      if (dsp-&gt;plugs[i].lib)
         dylib_close(dsp-&gt;plugs[i].lib);
   }
   free(dsp-&gt;plugs);
#endif

   if (dsp-&gt;conf)
      config_file_free(dsp-&gt;conf);

   free(dsp);
}

void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
      struct retro_dsp_data *data)
{
   unsigned i;
   struct dspfilter_output output = {0};
   struct dspfilter_input input   = {0};

   output.samples = data-&gt;input;
   output.frames  = data-&gt;input_frames;

   for (i = 0; i &lt; dsp-&gt;num_instances; i++)
   {
      input.samples = output.samples;
      input.frames  = output.frames;
      dsp-&gt;instances[i].impl-&gt;process(
            dsp-&gt;instances[i].impl_data, &amp;output, &amp;input);
   }

   data-&gt;output        = output.samples;
   data-&gt;output_frames = output.frames;
}</pre>
<h2>./include/libretro-common/audio/dsp_filters/BassBoost.dsp</h2>
<pre>filters = 2
filter0 = iir
filter1 = panning

iir_gain = 10.0
iir_type = BBOOST
iir_frequency = 200.0

# Avoids clipping.
panning_left_mix = "0.3 0.0"
panning_right_mix = "0.0 0.3"</pre>
<h2>./include/libretro-common/audio/dsp_filters/ChipTuneEnhance.dsp</h2>
<pre>filters = 4
filter0 = eq
filter1 = reverb
filter2 = iir
filter3 = panning

eq_frequencies = "32 64 125 250 500 1000 2000 4000 8000 16000 20000"
eq_gains = "6 9 12 7 6 5 7 9 11 6 0"

# Reverb - slight reverb
 reverb_drytime = 0.5
 reverb_wettime = 0.15
 reverb_damping = 0.8
 reverb_roomwidth = 0.25
 reverb_roomsize = 0.25

# IIR - filters out some harsh sounds on the upper end
iir_type = RIAA_CD

# Panning - cut the volume a bit
panning_left_mix = "0.75 0.0"
panning_right_mix = "0.0 0.75"</pre>
<h2>./include/libretro-common/audio/dsp_filters/ChipTune-Lowpass.dsp</h2>
<pre>filters = 1
filter0 = iir

iir_frequency = 8600.0
iir_quality = 0.707
iir_gain = 6.0
iir_type = LPF</pre>
<h2>./include/libretro-common/audio/dsp_filters/chorus.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (chorus.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;

#define CHORUS_MAX_DELAY 4096
#define CHORUS_DELAY_MASK (CHORUS_MAX_DELAY - 1)

struct chorus_data
{
   float old[2][CHORUS_MAX_DELAY];
   float delay;
   float depth;
   float input_rate;
   float mix_dry;
   float mix_wet;
   unsigned old_ptr;
   unsigned lfo_ptr;
   unsigned lfo_period;
};

static void chorus_free(void *data)
{
   if (data)
      free(data);
}

static void chorus_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out             = NULL;
   struct chorus_data *ch = (struct chorus_data*)data;

   output-&gt;samples        = input-&gt;samples;
   output-&gt;frames         = input-&gt;frames;
   out                    = output-&gt;samples;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      unsigned delay_int;
      float delay_frac, l_a, l_b, r_a, r_b;
      float chorus_l, chorus_r;
      float in[2]             = { out[0], out[1] };
      float delay             = ch-&gt;delay + ch-&gt;depth * sin((2.0 * M_PI * ch-&gt;lfo_ptr++) / ch-&gt;lfo_period);

      delay                  *= ch-&gt;input_rate;
      if (ch-&gt;lfo_ptr &gt;= ch-&gt;lfo_period)
         ch-&gt;lfo_ptr          = 0;

      delay_int               = (unsigned)delay;

      if (delay_int &gt;= CHORUS_MAX_DELAY - 1)
         delay_int            = CHORUS_MAX_DELAY - 2;

      delay_frac              = delay - delay_int;

      ch-&gt;old[0][ch-&gt;old_ptr] = in[0];
      ch-&gt;old[1][ch-&gt;old_ptr] = in[1];

      l_a                     = ch-&gt;old[0][(ch-&gt;old_ptr - delay_int - 0) &amp; CHORUS_DELAY_MASK];
      l_b                     = ch-&gt;old[0][(ch-&gt;old_ptr - delay_int - 1) &amp; CHORUS_DELAY_MASK];
      r_a                     = ch-&gt;old[1][(ch-&gt;old_ptr - delay_int - 0) &amp; CHORUS_DELAY_MASK];
      r_b                     = ch-&gt;old[1][(ch-&gt;old_ptr - delay_int - 1) &amp; CHORUS_DELAY_MASK];

      /* Lerp introduces aliasing of the chorus component,
       * but doing full polyphase here is probably overkill. */
      chorus_l                = l_a * (1.0f - delay_frac) + l_b * delay_frac;
      chorus_r                = r_a * (1.0f - delay_frac) + r_b * delay_frac;

      out[0]                  = ch-&gt;mix_dry * in[0] + ch-&gt;mix_wet * chorus_l;
      out[1]                  = ch-&gt;mix_dry * in[1] + ch-&gt;mix_wet * chorus_r;

      ch-&gt;old_ptr             = (ch-&gt;old_ptr + 1) &amp; CHORUS_DELAY_MASK;
   }
}

static void *chorus_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float delay, depth, lfo_freq, drywet;
   struct chorus_data *ch = (struct chorus_data*)calloc(1, sizeof(*ch));
   if (!ch)
      return NULL;

   config-&gt;get_float(userdata, "delay_ms", &amp;delay, 25.0f);
   config-&gt;get_float(userdata, "depth_ms", &amp;depth, 1.0f);
   config-&gt;get_float(userdata, "lfo_freq", &amp;lfo_freq, 0.5f);
   config-&gt;get_float(userdata, "drywet", &amp;drywet, 0.8f);

   delay            /= 1000.0f;
   depth            /= 1000.0f;

   if (depth &gt; delay)
      depth          = delay;

   if (drywet &lt; 0.0f)
      drywet         = 0.0f;
   else if (drywet &gt; 1.0f)
      drywet         = 1.0f;

   ch-&gt;mix_dry       = 1.0f - 0.5f * drywet;
   ch-&gt;mix_wet       = 0.5f * drywet;

   ch-&gt;delay         = delay;
   ch-&gt;depth         = depth;
   ch-&gt;lfo_period    = (1.0f / lfo_freq) * info-&gt;input_rate;
   ch-&gt;input_rate    = info-&gt;input_rate;
   if (!ch-&gt;lfo_period)
      ch-&gt;lfo_period = 1;
   return ch;
}

static const struct dspfilter_implementation chorus_plug = {
   chorus_init,
   chorus_process,
   chorus_free,

   DSPFILTER_API_VERSION,
   "Chorus",
   "chorus",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation chorus_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *
dspfilter_get_implementation(dspfilter_simd_mask_t mask) { return &amp;chorus_plug; }

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Chorus.dsp</h2>
<pre>filters = 1
filter0 = chorus

# Controls the base delay of the chorus (milliseconds).
# chorus_delay_ms = 25.0
#
# Controls the depth of the delay. The delay will vary between delay_ms +/- depth_ms.
# chorus_depth_ms = 1.0
#
# Frequency of LFO which controls delay.
# chorus_lfo_freq = 0.5
#
# Controls dry/wet-ness of effect. 1.0 = full chorus, 0.0 = no chorus.
# chorus_drywet = 0.8</pre>
<h2>./include/libretro-common/audio/dsp_filters/configure</h2>
<pre>#!/bin/sh

PACKAGE_NAME=retroarch-filters-audio</pre>
<h2>./include/libretro-common/audio/dsp_filters/crystalizer.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (echo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;

struct delta_data
{
   float intensity;
   float old[2];
};

static void delta_free(void *data)
{
   free(data);
}

static void delta_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i, c;
   struct delta_data *d   = (struct delta_data*)data;
   float *out             = output-&gt;samples;
   output-&gt;samples        = input-&gt;samples;
   output-&gt;frames         = input-&gt;frames;

   for (i = 0; i &lt; input-&gt;frames; i++)
   {
      for (c = 0; c &lt; 2; c++)
      {
           float current  = *out;
           *out++         = current + (current - d-&gt;old[c]) * d-&gt;intensity;
           d-&gt;old[c]      = current;
      }
   }
}

static void *delta_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   struct delta_data *d = (struct delta_data*)calloc(1, sizeof(*d));
   if (!d)
      return NULL;
   config-&gt;get_float(userdata, "intensity", &amp;d-&gt;intensity, 5.0f);
   return d;
}

static const struct dspfilter_implementation delta_plug = {
   delta_init,
   delta_process,
   delta_free,
   DSPFILTER_API_VERSION,
   "Delta Sharpening",
   "crystalizer",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation delta_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;delta_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Crystalizer.dsp</h2>
<pre>filters = 1
filter0 = crystalizer
# Controls dry/wet-ness of effect. 0.0 = none, 10.0 = max.
crystalizer_intensity = 5.0</pre>
<h2>./include/libretro-common/audio/dsp_filters/echo.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (echo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;

struct echo_channel
{
   float *buffer;
   unsigned ptr;
   unsigned frames;
   float feedback;
};

struct echo_data
{
   struct echo_channel *channels;
   unsigned num_channels;
   float amp;
};

static void echo_free(void *data)
{
   unsigned i;
   struct echo_data *echo = (struct echo_data*)data;

   for (i = 0; i &lt; echo-&gt;num_channels; i++)
      free(echo-&gt;channels[i].buffer);
   free(echo-&gt;channels);
   free(echo);
}

static void echo_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i, c;
   float *out             = NULL;
   struct echo_data *echo = (struct echo_data*)data;

   output-&gt;samples        = input-&gt;samples;
   output-&gt;frames         = input-&gt;frames;

   out                    = output-&gt;samples;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float left, right;
      float echo_left  = 0.0f;
      float echo_right = 0.0f;

      for (c = 0; c &lt; echo-&gt;num_channels; c++)
      {
         echo_left  += echo-&gt;channels[c].buffer[(echo-&gt;channels[c].ptr &lt;&lt; 1) + 0];
         echo_right += echo-&gt;channels[c].buffer[(echo-&gt;channels[c].ptr &lt;&lt; 1) + 1];
      }

      echo_left     *= echo-&gt;amp;
      echo_right    *= echo-&gt;amp;

      left           = out[0] + echo_left;
      right          = out[1] + echo_right;

      for (c = 0; c &lt; echo-&gt;num_channels; c++)
      {
         float feedback_left  = out[0] + echo-&gt;channels[c].feedback * echo_left;
         float feedback_right = out[1] + echo-&gt;channels[c].feedback * echo_right;

         echo-&gt;channels[c].buffer[(echo-&gt;channels[c].ptr &lt;&lt; 1) + 0] = feedback_left;
         echo-&gt;channels[c].buffer[(echo-&gt;channels[c].ptr &lt;&lt; 1) + 1] = feedback_right;

         echo-&gt;channels[c].ptr = (echo-&gt;channels[c].ptr + 1) % echo-&gt;channels[c].frames;
      }

      out[0] = left;
      out[1] = right;
   }
}

static void *echo_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   unsigned i, channels;
   struct echo_channel *echo_channels    = NULL;
   float *delay                          = NULL;
   float *feedback                       = NULL;
   unsigned num_delay                    = 0;
   unsigned num_feedback                 = 0;

   static const float default_delay[]    = { 200.0f };
   static const float default_feedback[] = { 0.5f };
   struct echo_data *echo                = (struct echo_data*)
      calloc(1, sizeof(*echo));

   if (!echo)
      return NULL;

   config-&gt;get_float_array(userdata, "delay", &amp;delay,
         &amp;num_delay, default_delay, 1);
   config-&gt;get_float_array(userdata, "feedback", &amp;feedback,
         &amp;num_feedback, default_feedback, 1);
   config-&gt;get_float(userdata, "amp", &amp;echo-&gt;amp, 0.2f);

   channels            = num_feedback = num_delay = MIN(num_delay, num_feedback);

   if (!(echo_channels = (struct echo_channel*)calloc(channels,
         sizeof(*echo_channels))))
      goto error;

   echo-&gt;channels      = echo_channels;
   echo-&gt;num_channels  = channels;

   for (i = 0; i &lt; channels; i++)
   {
      unsigned frames  = (unsigned)(delay[i] * info-&gt;input_rate / 1000.0f + 0.5f);
      if (!frames)
         goto error;

      if (!(echo-&gt;channels[i].buffer = (float*)calloc(frames, 2 * sizeof(float))))
         goto error;

      echo-&gt;channels[i].frames   = frames;
      echo-&gt;channels[i].feedback = feedback[i];
   }

   config-&gt;free(delay);
   config-&gt;free(feedback);
   return echo;

error:
   config-&gt;free(delay);
   config-&gt;free(feedback);
   echo_free(echo);
   return NULL;
}

static const struct dspfilter_implementation echo_plug = {
   echo_init,
   echo_process,
   echo_free,

   DSPFILTER_API_VERSION,
   "Multi-Echo",
   "echo",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation echo_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;echo_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Echo.dsp</h2>
<pre>filters = 1
filter0 = echo

# Somewhat fancy Echo filter. Can take any number of echo channels with varying delays (ms) and feedback factors.
# Echo output from all channels can be fed back into each other to create a somewhat reverb-like effect if desired.

# Defaults, 200 ms delay echo with feedback:
# Delay in ms. Takes an array with multiple channels.
# echo_delay = "200"
# Feedback factor for echo.
# echo_feedback = "0.5"
# Overall echo amplification. If too high, the echo becomes unstable due to feedback.
# echo_amp = "0.2"

# Reverby preset.
# echo_delay    = " 60  80 120 172 200 320 380"
# echo_feedback = "0.5 0.5 0.4 0.3 0.5 0.3 0.2"

# echo_amp = "0.12"</pre>
<h2>./include/libretro-common/audio/dsp_filters/EchoReverb.dsp</h2>
<pre>filters = 2
filter0 = echo
filter1 = reverb

echo_delay = "200"
echo_feedback = "0.6"
echo_amp = "0.25"

reverb_roomwidth = 0.75
reverb_roomsize = 0.75
reverb_damping = 1.0
reverb_wettime = 0.3</pre>
<h2>./include/libretro-common/audio/dsp_filters/eq.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (eq.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;filters.h&gt;
#include &lt;libretro_dspfilter.h&gt;

#include "fft/fft.c"

struct eq_data
{
   fft_t *fft;
   float *save;
   float *block;
   fft_complex_t *filter;
   fft_complex_t *fftblock;
   float buffer[8 * 1024];
   unsigned block_size;
   unsigned block_ptr;
};

struct eq_gain
{
   float freq;
   float gain; /* Linear. */
};

static void eq_free(void *data)
{
   struct eq_data *eq = (struct eq_data*)data;
   if (!eq)
      return;

   fft_free(eq-&gt;fft);
   free(eq-&gt;save);
   free(eq-&gt;block);
   free(eq-&gt;fftblock);
   free(eq-&gt;filter);
   free(eq);
}

static void eq_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   float *out;
   const float *in;
   unsigned input_frames;
   struct eq_data *eq = (struct eq_data*)data;

   output-&gt;samples    = eq-&gt;buffer;
   output-&gt;frames     = 0;

   out                = eq-&gt;buffer;
   in                 = input-&gt;samples;
   input_frames       = input-&gt;frames;

   while (input_frames)
   {
      unsigned write_avail = eq-&gt;block_size - eq-&gt;block_ptr;

      if (input_frames &lt; write_avail)
         write_avail = input_frames;

      memcpy(eq-&gt;block + eq-&gt;block_ptr * 2, in, write_avail * 2 * sizeof(float));

      in            += write_avail * 2;
      input_frames  -= write_avail;
      eq-&gt;block_ptr += write_avail;

      /* Convolve a new block. */
      if (eq-&gt;block_ptr == eq-&gt;block_size)
      {
         unsigned i, c;

         for (c = 0; c &lt; 2; c++)
         {
            fft_process_forward(eq-&gt;fft, eq-&gt;fftblock, eq-&gt;block + c, 2);
            for (i = 0; i &lt; 2 * eq-&gt;block_size; i++)
               eq-&gt;fftblock[i] = fft_complex_mul(eq-&gt;fftblock[i], eq-&gt;filter[i]);
            fft_process_inverse(eq-&gt;fft, out + c, eq-&gt;fftblock, 2);
         }

         /* Overlap add method, so add in saved block now. */
         for (i = 0; i &lt; 2 * eq-&gt;block_size; i++)
            out[i]      += eq-&gt;save[i];

         /* Save block for later. */
         memcpy(eq-&gt;save, out + 2 * eq-&gt;block_size, 2 * eq-&gt;block_size * sizeof(float));

         out            += eq-&gt;block_size * 2;
         output-&gt;frames += eq-&gt;block_size;
         eq-&gt;block_ptr   = 0;
      }
   }
}

static int gains_cmp(const void *a_, const void *b_)
{
   const struct eq_gain *a = (const struct eq_gain*)a_;
   const struct eq_gain *b = (const struct eq_gain*)b_;
   if (a-&gt;freq &lt; b-&gt;freq)
      return -1;
   if (a-&gt;freq &gt; b-&gt;freq)
      return 1;
   return 0;
}

static void generate_response(fft_complex_t *response,
      const struct eq_gain *gains, unsigned num_gains, unsigned samples)
{
   unsigned i;

   float start_freq = 0.0f;
   float start_gain = 1.0f;

   float end_freq   = 1.0f;
   float end_gain   = 1.0f;

   if (num_gains)
   {
      end_freq = gains-&gt;freq;
      end_gain = gains-&gt;gain;
      num_gains--;
      gains++;
   }

   /* Create a response by linear interpolation between
    * known frequency sample points. */
   for (i = 0; i &lt;= samples; i++)
   {
      float gain;
      float lerp = 0.5f;
      float freq = (float)i / samples;

      while (freq &gt;= end_freq)
      {
         if (num_gains)
         {
            start_freq = end_freq;
            start_gain = end_gain;
            end_freq = gains-&gt;freq;
            end_gain = gains-&gt;gain;

            gains++;
            num_gains--;
         }
         else
         {
            start_freq = end_freq;
            start_gain = end_gain;
            end_freq = 1.0f;
            end_gain = 1.0f;
            break;
         }
      }

      /* Edge case where i == samples. */
      if (end_freq &gt; start_freq)
         lerp = (freq - start_freq) / (end_freq - start_freq);
      gain = (1.0f - lerp) * start_gain + lerp * end_gain;

      response[i].real               = gain;
      response[i].imag               = 0.0f;
      response[2 * samples - i].real = gain;
      response[2 * samples - i].imag = 0.0f;
   }
}

static void create_filter(struct eq_data *eq, unsigned size_log2,
      struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)
{
   int i;
   int half_block_size = eq-&gt;block_size &gt;&gt; 1;
   double window_mod   = 1.0 / kaiser_window_function(0.0, beta);
   fft_t *fft          = fft_new(size_log2);
   float *time_filter  = (float*)calloc(eq-&gt;block_size * 2 + 1, sizeof(*time_filter));
   if (!fft || !time_filter)
      goto end;

   /* Make sure bands are in correct order. */
   qsort(gains, num_gains, sizeof(*gains), gains_cmp);

   /* Compute desired filter response. */
   generate_response(eq-&gt;filter, gains, num_gains, half_block_size);

   /* Get equivalent time-domain filter. */
   fft_process_inverse(fft, time_filter, eq-&gt;filter, 1);

   /* ifftshift() to create the correct linear phase filter.
    * The filter response was designed with zero phase, which
    * won't work unless we compensate
    * for the repeating property of the FFT here
    * by flipping left and right blocks. */
   for (i = 0; i &lt; half_block_size; i++)
   {
      float tmp = time_filter[i + half_block_size];
      time_filter[i + half_block_size] = time_filter[i];
      time_filter[i] = tmp;
   }

   /* Apply a window to smooth out the frequency response. */
   for (i = 0; i &lt; (int)eq-&gt;block_size; i++)
   {
      /* Kaiser window. */
      double phase    = (double)i / eq-&gt;block_size;
      phase           = 2.0 * (phase - 0.5);
      time_filter[i] *= window_mod * kaiser_window_function(phase, beta);
   }

#ifdef DEBUG
   /* Debugging. */
   if (filter_path)
   {
      FILE *file = fopen(filter_path, "w");
      if (file)
      {
         for (i = 0; i &lt; (int)eq-&gt;block_size - 1; i++)
            fprintf(file, "%.8f\n", time_filter[i + 1]);
         fclose(file);
      }
   }
#endif

   /* Padded FFT to create our FFT filter.
    * Make our even-length filter odd by discarding the first coefficient.
    * For some interesting reason, this allows us to design an odd-length linear phase filter.
    */
   fft_process_forward(eq-&gt;fft, eq-&gt;filter, time_filter + 1, 1);

end:
   fft_free(fft);
   free(time_filter);
}

static void *eq_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   int size_log2;
   float beta;
   float *frequencies, *gain;
   unsigned num_freq, num_gain, i, size;
   struct eq_gain *gains      = NULL;
   char *filter_path          = NULL;
   const float default_freq[] = { 0.0f, info-&gt;input_rate };
   const float default_gain[] = { 0.0f, 0.0f };
   struct eq_data *eq         = (struct eq_data*)calloc(1, sizeof(*eq));
   if (!eq)
      return NULL;

   config-&gt;get_float(userdata, "window_beta", &amp;beta, 4.0f);

   config-&gt;get_int(userdata, "block_size_log2", &amp;size_log2, 8);
   size = 1 &lt;&lt; size_log2;

   config-&gt;get_float_array(userdata, "frequencies", &amp;frequencies, &amp;num_freq, default_freq, 2);
   config-&gt;get_float_array(userdata, "gains", &amp;gain, &amp;num_gain, default_gain, 2);

   if (!config-&gt;get_string(userdata, "impulse_response_output", &amp;filter_path, ""))
   {
      config-&gt;free(filter_path);
      filter_path = NULL;
   }

   num_gain = num_freq = MIN(num_gain, num_freq);

   if (!(gains = (struct eq_gain*)calloc(num_gain, sizeof(*gains))))
      goto error;

   for (i = 0; i &lt; num_gain; i++)
   {
      gains[i].freq = frequencies[i] / (0.5f * info-&gt;input_rate);
      gains[i].gain = pow(10.0, gain[i] / 20.0);
   }
   config-&gt;free(frequencies);
   config-&gt;free(gain);

   eq-&gt;block_size = size;

   eq-&gt;save       = (float*)calloc(    size, 2 * sizeof(*eq-&gt;save));
   eq-&gt;block      = (float*)calloc(2 * size, 2 * sizeof(*eq-&gt;block));
   eq-&gt;fftblock   = (fft_complex_t*)calloc(2 * size, sizeof(*eq-&gt;fftblock));
   eq-&gt;filter     = (fft_complex_t*)calloc(2 * size, sizeof(*eq-&gt;filter));

   /* Use an FFT which is twice the block size with zero-padding
    * to make circular convolution =&gt; proper convolution.
    */
   eq-&gt;fft        = fft_new(size_log2 + 1);

   if (!eq-&gt;fft || !eq-&gt;fftblock || !eq-&gt;save || !eq-&gt;block || !eq-&gt;filter)
      goto error;

   create_filter(eq, size_log2, gains, num_gain, beta, filter_path);
   config-&gt;free(filter_path);
   filter_path = NULL;

   free(gains);
   return eq;

error:
   free(gains);
   eq_free(eq);
   return NULL;
}

static const struct dspfilter_implementation eq_plug = {
   eq_init,
   eq_process,
   eq_free,

   DSPFILTER_API_VERSION,
   "Linear-Phase FFT Equalizer",
   "eq",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation eq_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;eq_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/EQ.dsp</h2>
<pre>filters = 1
filter0 = eq

# Defaults

# Beta factor for Kaiser window.
# Lower values will allow better frequency resolution, but more ripple.
# eq_window_beta = 4.0

# The block size on which FFT is done.
# Too high value requires more processing as well as longer latency but
# allows finer-grained control over the spectrum.
# eq_block_size_log2 = 8

# An array of which frequencies to control.
# You can create an arbitrary amount of these sampling points.
# The EQ will try to create a frequency response which fits well to these points.
# The filter response is linearly interpolated between sampling points here.
#
# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
#
# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
# eq_frequencies = "500 1000 2000"
# eq_gains = "0 3 0"
# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.

# By default, this filter has a flat frequency response.

# Dumps the impulse response generated by the EQ as a plain-text file
# with one coefficient per line.
# eq_impulse_response_output = "eq_impulse.txt"
#
# Using GNU Octave or Matlab, you can plot the response with:
#
# f = fopen('/path/to/eq_impulse.txt');
# l = textscan(f, '%f');
# res = l{1};
# freqz(res, 1, 4096, 48000);
#
# It will give the response in Hz; 48000 is the default Output Rate of RetroArch</pre>
<h2>./include/libretro-common/audio/dsp_filters/fft/fft.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fft.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;

#include "fft.h"

#include &lt;retro_miscellaneous.h&gt;

struct fft
{
   fft_complex_t *interleave_buffer;
   fft_complex_t *phase_lut;
   unsigned *bitinverse_buffer;
   unsigned size;
};

static unsigned bitswap(unsigned x, unsigned size_log2)
{
   unsigned i;
   unsigned ret = 0;
   for (i = 0; i &lt; size_log2; i++)
      ret |= ((x &gt;&gt; i) &amp; 1) &lt;&lt; (size_log2 - i - 1);
   return ret;
}

static void build_bitinverse(unsigned *bitinverse, unsigned size_log2)
{
   unsigned i;
   unsigned size = 1 &lt;&lt; size_log2;
   for (i = 0; i &lt; size; i++)
      bitinverse[i] = bitswap(i, size_log2);
}

static fft_complex_t exp_imag(double phase)
{
   fft_complex_t out = { cos(phase), sin(phase) };
   return out;
}

static void build_phase_lut(fft_complex_t *out, int size)
{
   int i;
   out += size;
   for (i = -size; i &lt;= size; i++)
      out[i] = exp_imag((M_PI * i) / size);
}

static void interleave_complex(const unsigned *bitinverse,
      fft_complex_t *out, const fft_complex_t *in,
      unsigned samples, unsigned step)
{
   unsigned i;
   for (i = 0; i &lt; samples; i++, in += step)
      out[bitinverse[i]] = *in;
}

static void interleave_float(const unsigned *bitinverse,
      fft_complex_t *out, const float *in,
      unsigned samples, unsigned step)
{
   unsigned i;
   for (i = 0; i &lt; samples; i++, in += step)
   {
      unsigned inv_i = bitinverse[i];
      out[inv_i].real = *in;
      out[inv_i].imag = 0.0f;
   }
}

static void resolve_float(float *out, const fft_complex_t *in, unsigned samples,
      float gain, unsigned step)
{
   unsigned i;
   for (i = 0; i &lt; samples; i++, in++, out += step)
      *out = gain * in-&gt;real;
}

fft_t *fft_new(unsigned block_size_log2)
{
   unsigned size;
   fft_t *fft = (fft_t*)calloc(1, sizeof(*fft));
   if (!fft)
      return NULL;

   size                   = 1 &lt;&lt; block_size_log2;
   fft-&gt;interleave_buffer = (fft_complex_t*)calloc(size, sizeof(*fft-&gt;interleave_buffer));
   fft-&gt;bitinverse_buffer = (unsigned*)calloc(size, sizeof(*fft-&gt;bitinverse_buffer));
   fft-&gt;phase_lut         = (fft_complex_t*)calloc(2 * size + 1, sizeof(*fft-&gt;phase_lut));

   if (!fft-&gt;interleave_buffer || !fft-&gt;bitinverse_buffer || !fft-&gt;phase_lut)
      goto error;

   fft-&gt;size = size;

   build_bitinverse(fft-&gt;bitinverse_buffer, block_size_log2);
   build_phase_lut(fft-&gt;phase_lut, size);
   return fft;

error:
   fft_free(fft);
   return NULL;
}

void fft_free(fft_t *fft)
{
   if (!fft)
      return;

   free(fft-&gt;interleave_buffer);
   free(fft-&gt;bitinverse_buffer);
   free(fft-&gt;phase_lut);
   free(fft);
}

static void butterfly(fft_complex_t *a, fft_complex_t *b, fft_complex_t mod)
{
   mod = fft_complex_mul(mod, *b);
   *b  = fft_complex_sub(*a, mod);
   *a  = fft_complex_add(*a, mod);
}

static void butterflies(fft_complex_t *butterfly_buf,
      const fft_complex_t *phase_lut,
      int phase_dir, unsigned step_size, unsigned samples)
{
   unsigned i, j;
   for (i = 0; i &lt; samples; i += step_size &lt;&lt; 1)
   {
      int phase_step = (int)samples * phase_dir / (int)step_size;
      for (j = i; j &lt; i + step_size; j++)
         butterfly(&amp;butterfly_buf[j], &amp;butterfly_buf[j + step_size],
               phase_lut[phase_step * (int)(j - i)]);
   }
}

void fft_process_forward_complex(fft_t *fft,
      fft_complex_t *out, const fft_complex_t *in, unsigned step)
{
   unsigned step_size;
   unsigned samples = fft-&gt;size;
   interleave_complex(fft-&gt;bitinverse_buffer, out, in, samples, step);

   for (step_size = 1; step_size &lt; samples; step_size &lt;&lt;= 1)
   {
      butterflies(out,
            fft-&gt;phase_lut + samples,
            -1, step_size, samples);
   }
}

void fft_process_forward(fft_t *fft,
      fft_complex_t *out, const float *in, unsigned step)
{
   unsigned step_size;
   unsigned samples = fft-&gt;size;
   interleave_float(fft-&gt;bitinverse_buffer, out, in, samples, step);

   for (step_size = 1; step_size &lt; fft-&gt;size; step_size &lt;&lt;= 1)
   {
      butterflies(out,
            fft-&gt;phase_lut + samples,
            -1, step_size, samples);
   }
}

void fft_process_inverse(fft_t *fft,
      float *out, const fft_complex_t *in, unsigned step)
{
   unsigned step_size;
   unsigned samples = fft-&gt;size;

   interleave_complex(fft-&gt;bitinverse_buffer, fft-&gt;interleave_buffer,
         in, samples, 1);

   for (step_size = 1; step_size &lt; samples; step_size &lt;&lt;= 1)
   {
      butterflies(fft-&gt;interleave_buffer,
            fft-&gt;phase_lut + samples,
            1, step_size, samples);
   }

   resolve_float(out, fft-&gt;interleave_buffer, samples, 1.0f / samples, step);
}</pre>
<h2>./include/libretro-common/audio/dsp_filters/fft/fft.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fft.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RARCH_FFT_H__
#define RARCH_FFT_H__

#include &lt;retro_inline.h&gt;
#include &lt;math/complex.h&gt;

typedef struct fft fft_t;

fft_t *fft_new(unsigned block_size_log2);

void fft_free(fft_t *fft);

void fft_process_forward_complex(fft_t *fft,
      fft_complex_t *out, const fft_complex_t *in, unsigned step);

void fft_process_forward(fft_t *fft,
      fft_complex_t *out, const float *in, unsigned step);

void fft_process_inverse(fft_t *fft,
      float *out, const fft_complex_t *in, unsigned step);

#endif</pre>
<h2>./include/libretro-common/audio/dsp_filters/HighShelfDampen.dsp</h2>
<pre>filters = 1
filter0 = iir

iir_gain = -12.0
iir_type = HSH
iir_frequency = 8000.0</pre>
<h2>./include/libretro-common/audio/dsp_filters/iir.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (iir.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;
#include &lt;string/stdstring.h&gt;

#define sqr(a) ((a) * (a))

/* filter types */
enum IIRFilter
{
   LPF,        /* low pass filter */
   HPF,        /* High pass filter */
   BPCSGF,     /* band pass filter 1 */
   BPZPGF,     /* band pass filter 2 */
   APF,        /* Allpass filter*/
   NOTCH,      /* Notch Filter */
   RIAA_phono, /* RIAA record/tape deemphasis */
   PEQ,        /* Peaking band EQ filter */
   BBOOST,     /* Bassboost filter */
   LSH,        /* Low shelf filter */
   HSH,        /* High shelf filter */
   RIAA_CD     /* CD de-emphasis */
};

struct iir_data
{
   float b0, b1, b2;
   float a0, a1, a2;

   struct
   {
      float xn1, xn2;
      float yn1, yn2;
   } l, r;
};

static void iir_free(void *data)
{
   free(data);
}

static void iir_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   struct iir_data *iir = (struct iir_data*)data;
   float *out           = output-&gt;samples;

   float b0             = iir-&gt;b0;
   float b1             = iir-&gt;b1;
   float b2             = iir-&gt;b2;
   float a0             = iir-&gt;a0;
   float a1             = iir-&gt;a1;
   float a2             = iir-&gt;a2;

   float xn1_l          = iir-&gt;l.xn1;
   float xn2_l          = iir-&gt;l.xn2;
   float yn1_l          = iir-&gt;l.yn1;
   float yn2_l          = iir-&gt;l.yn2;

   float xn1_r          = iir-&gt;r.xn1;
   float xn2_r          = iir-&gt;r.xn2;
   float yn1_r          = iir-&gt;r.yn1;
   float yn2_r          = iir-&gt;r.yn2;

   output-&gt;samples      = input-&gt;samples;
   output-&gt;frames       = input-&gt;frames;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float in_l = out[0];
      float in_r = out[1];

      float l    = (b0 * in_l + b1 * xn1_l + b2 * xn2_l - a1 * yn1_l - a2 * yn2_l) / a0;
      float r    = (b0 * in_r + b1 * xn1_r + b2 * xn2_r - a1 * yn1_r - a2 * yn2_r) / a0;

      xn2_l      = xn1_l;
      xn1_l      = in_l;
      yn2_l      = yn1_l;
      yn1_l      = l;

      xn2_r      = xn1_r;
      xn1_r      = in_r;
      yn2_r      = yn1_r;
      yn1_r      = r;

      out[0]     = l;
      out[1]     = r;
   }

   iir-&gt;l.xn1 = xn1_l;
   iir-&gt;l.xn2 = xn2_l;
   iir-&gt;l.yn1 = yn1_l;
   iir-&gt;l.yn2 = yn2_l;

   iir-&gt;r.xn1 = xn1_r;
   iir-&gt;r.xn2 = xn2_r;
   iir-&gt;r.yn1 = yn1_r;
   iir-&gt;r.yn2 = yn2_r;
}

#define CHECK(x) if (string_is_equal(str, #x)) return x
static enum IIRFilter str_to_type(const char *str)
{
   CHECK(LPF);
   CHECK(HPF);
   CHECK(BPCSGF);
   CHECK(BPZPGF);
   CHECK(APF);
   CHECK(NOTCH);
   CHECK(RIAA_phono);
   CHECK(PEQ);
   CHECK(BBOOST);
   CHECK(LSH);
   CHECK(HSH);
   CHECK(RIAA_CD);

   return LPF; /* Fallback. */
}
#undef CHECK

static void make_poly_from_roots(
      const double *roots, unsigned num_roots, float *poly)
{
   unsigned i, j;

   poly[0] = 1;
   poly[1] = -roots[0];
   memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));

   for (i = 1; i &lt; num_roots; i++)
      for (j = num_roots; j &gt; 0; j--)
         poly[j] -= poly[j - 1] * roots[i];
}

static void iir_filter_init(struct iir_data *iir,
      float sample_rate, float freq, float qual, float gain, enum IIRFilter filter_type)
{
	double omega = 2.0 * M_PI * freq / sample_rate;
   double cs    = cos(omega);
   double sn    = sin(omega);
   double a1pha = sn / (2.0 * qual);
   double A     = exp(log(10.0) * gain / 40.0);
   double beta  = sqrt(A + A);

   float b0     = 0.0, b1 = 0.0, b2 = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0;

   /* Set up filter coefficients according to type */
   switch (filter_type)
   {
      case LPF:
         b0 =  (1.0 - cs) / 2.0;
         b1 =   1.0 - cs ;
         b2 =  (1.0 - cs) / 2.0;
         a0 =   1.0 + a1pha;
         a1 =  -2.0 * cs;
         a2 =   1.0 - a1pha;
         break;
      case HPF:
         b0 =  (1.0 + cs) / 2.0;
         b1 = -(1.0 + cs);
         b2 =  (1.0 + cs) / 2.0;
         a0 =   1.0 + a1pha;
         a1 =  -2.0 * cs;
         a2 =   1.0 - a1pha;
         break;
      case APF:
         b0 =  1.0 - a1pha;
         b1 = -2.0 * cs;
         b2 =  1.0 + a1pha;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case BPZPGF:
         b0 =  a1pha;
         b1 =  0.0;
         b2 = -a1pha;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case BPCSGF:
         b0 =  sn / 2.0;
         b1 =  0.0;
         b2 = -sn / 2.0;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case NOTCH:
         b0 =  1.0;
         b1 = -2.0 * cs;
         b2 =  1.0;
         a0 =  1.0 + a1pha;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha;
         break;
      case RIAA_phono: /* http://www.dsprelated.com/showmessage/73300/3.php */
      {
         double y, b_re, a_re, b_im, a_im, g;
         float b[3] = {0.0f};
         float a[3] = {0.0f};

         if ((int)sample_rate == 44100)
         {
            static const double zeros[] = {-0.2014898, 0.9233820};
            static const double poles[] = {0.7083149, 0.9924091};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }
         else if ((int)sample_rate == 48000)
         {
            static const double zeros[] = {-0.1766069, 0.9321590};
            static const double poles[] = {0.7396325, 0.9931330};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }
         else if ((int)sample_rate == 88200)
         {
            static const double zeros[] = {-0.1168735, 0.9648312};
            static const double poles[] = {0.8590646, 0.9964002};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }
         else if ((int)sample_rate == 96000)
         {
            static const double zeros[] = {-0.1141486, 0.9676817};
            static const double poles[] = {0.8699137, 0.9966946};
            make_poly_from_roots(zeros, 2, b);
            make_poly_from_roots(poles, 2, a);
         }

         b0    = b[0];
         b1    = b[1];
         b2    = b[2];
         a0    = a[0];
         a1    = a[1];
         a2    = a[2];

         /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */
         y     = 2.0 * M_PI * 1000.0 / sample_rate;
         b_re  = b0 + b1 * cos(-y) + b2 * cos(-2.0 * y);
         a_re  = a0 + a1 * cos(-y) + a2 * cos(-2.0 * y);
         b_im  = b1 * sin(-y) + b2 * sin(-2.0 * y);
         a_im  = a1 * sin(-y) + a2 * sin(-2.0 * y);
         g     = 1.0 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));
         b0   *= g; b1 *= g; b2 *= g;
         break;
      }
      case PEQ:
         b0 =  1.0 + a1pha * A;
         b1 = -2.0 * cs;
         b2 =  1.0 - a1pha * A;
         a0 =  1.0 + a1pha / A;
         a1 = -2.0 * cs;
         a2 =  1.0 - a1pha / A;
         break;
      case BBOOST:
         beta = sqrt((A * A + 1) / 1.0 - (pow((A - 1), 2)));
         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
         b1 = 2 * A * ((A - 1) - (A + 1) * cs);
         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
         a0 = ((A + 1) + (A - 1) * cs + beta * sn);
         a1 = -2 * ((A - 1) + (A + 1) * cs);
         a2 = (A + 1) + (A - 1) * cs - beta * sn;
         break;
      case LSH:
         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
         b1 = 2 * A * ((A - 1) - (A + 1) * cs);
         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
         a0 = (A + 1) + (A - 1) * cs + beta * sn;
         a1 = -2 * ((A - 1) + (A + 1) * cs);
         a2 = (A + 1) + (A - 1) * cs - beta * sn;
         break;
      case RIAA_CD:
         omega = 2.0 * M_PI * 5283.0 / sample_rate;
         cs = cos(omega);
         sn = sin(omega);
         a1pha = sn / (2.0 * 0.4845);
         A = exp(log(10.0) * -9.477 / 40.0);
         beta = sqrt(A + A);
         (void)a1pha;
      case HSH:
         b0 = A * ((A + 1.0) + (A - 1.0) * cs + beta * sn);
         b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * cs);
         b2 = A * ((A + 1.0) + (A - 1.0) * cs - beta * sn);
         a0 = (A + 1.0) - (A - 1.0) * cs + beta * sn;
         a1 = 2.0 * ((A - 1.0) - (A + 1.0) * cs);
         a2 = (A + 1.0) - (A - 1.0) * cs - beta * sn;
         break;
      default:
         break;
   }

   iir-&gt;b0 = b0;
   iir-&gt;b1 = b1;
   iir-&gt;b2 = b2;
   iir-&gt;a0 = a0;
   iir-&gt;a1 = a1;
   iir-&gt;a2 = a2;
}

static void *iir_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float freq, qual, gain;
   enum IIRFilter filter  = LPF;
   char           *type   = NULL;
   struct iir_data *iir   = (struct iir_data*)calloc(1, sizeof(*iir));
   if (!iir)
      return NULL;

   config-&gt;get_float(userdata, "frequency", &amp;freq, 1024.0f);
   config-&gt;get_float(userdata, "quality", &amp;qual, 0.707f);
   config-&gt;get_float(userdata, "gain", &amp;gain, 0.0f);

   config-&gt;get_string(userdata, "type", &amp;type, "LPF");

   filter = str_to_type(type);
   config-&gt;free(type);

   iir_filter_init(iir, info-&gt;input_rate, freq, qual, gain, filter);
   return iir;
}

static const struct dspfilter_implementation iir_plug = {
   iir_init,
   iir_process,
   iir_free,

   DSPFILTER_API_VERSION,
   "IIR",
   "iir",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation iir_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;iir_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/IIR.dsp</h2>
<pre>filters = 1
filter0 = iir

# Defaults.
#iir_frequency = 1024.0
#iir_quality = 0.707
#iir_gain = 0.0
#iir_type = LPF

# Filter types:
# LPF: Low-pass
# HPF: High-pass
# BPCSGF: Band-pass #1
# BPZPGF: Band-pass #2
# APF: Allpass
# NOTCH: Notch filter
# RIAA_phono: RIAA record/tape deemphasis
# PEQ: peaking band EQ
# BBOOST: Bassboost
# LSH: Low-shelf
# HSH: High-shelf
# RIAA_CD: CD de-emphasis</pre>
<h2>./include/libretro-common/audio/dsp_filters/link.T</h2>
<pre>{
  global: dspfilter_get_implementation;
  local: *;
};</pre>
<h2>./include/libretro-common/audio/dsp_filters/LowPassCPS.dsp</h2>
<pre>filters = 1
filter0 = eq

eq_frequencies = "8000 10000 12500 16000 20000"
eq_gains = "0 -30 -30 -30 -30"

# Low pass filter for the QSound chip from CPS-1/2.
# Some games have aliasing due low quality samples, so you can hear some annoying noisy near 11 kHz

# Defaults

# Beta factor for Kaiser window.
# Lower values will allow better frequency resolution, but more ripple.
# eq_window_beta = 4.0

# The block size on which FFT is done.
# Too high value requires more processing as well as longer latency but
# allows finer-grained control over the spectrum.
# eq_block_size_log2 = 8

# An array of which frequencies to control.
# You can create an arbitrary amount of these sampling points.
# The EQ will try to create a frequency response which fits well to these points.
# The filter response is linearly interpolated between sampling points here.
#
# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
#
# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
# eq_frequencies = "500 1000 2000"
# eq_gains = "0 3 0"
# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.

# By default, this filter has a low pass response with cuttof frequency at ~8600 Hz.

# Dumps the impulse response generated by the EQ as a plain-text file
# with one coefficient per line.
# eq_impulse_response_output = "eq_impulse.txt"
#
# Using GNU Octave or Matlab, you can plot the response with:
#
# f = fopen('/path/to/eq_impulse.txt');
# l = textscan(f, '%f');
# res = l{1};
# freqz(res, 1, 4096, 48000);
#
# It will give the response in Hz; 48000 is the default Output Rate of RetroArch</pre>
<h2>./include/libretro-common/audio/dsp_filters/Makefile</h2>
<pre>compiler    := gcc
extra_flags :=
use_neon    := 0
build       = release
DYLIB	      := so
PREFIX      := /usr
INSTALLDIR  := $(PREFIX)/lib/retroarch/filters/audio

ifeq ($(platform),)
   platform = unix
   ifeq ($(shell uname -s),)
      platform = win
   else ifneq ($(findstring Darwin,$(shell uname -s)),)
      platform = osx
      arch     = intel
      ifeq ($(shell uname -p),powerpc)
         arch = ppc
      endif
   else ifneq ($(findstring MINGW,$(shell uname -s)),)
      platform = win
   endif
endif

ifeq ($(platform),gcc)
   extra_rules_gcc := $(shell $(compiler) -dumpmachine)
endif

ifneq (,$(findstring armv7,$(extra_rules_gcc)))
   extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon
   use_neon := 1
endif

ifneq (,$(findstring hardfloat,$(extra_rules_gcc)))
   extra_flags += -mfloat-abi=hard
endif

ifeq (release,$(build))
   extra_flags += -O2
endif

ifeq (debug,$(build))
   extra_flags += -O0 -g
endif

ldflags := $(LDFLAGS) -shared -lm -Wl,--version-script=link.T

ifeq ($(platform), unix)
   DYLIB = so
else ifeq ($(platform), osx)
   compiler := $(CC)
   DYLIB = dylib
   ldflags := -dynamiclib
   ARCHFLAGS=
   MINVERFLAGS=
   ifeq ($(shell uname -p),arm)
      MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)
   else ifeq ($(HAVE_METAL),1)
      MINVERFLAGS = -mmacosx-version-min=10.13 -stdlib=libc++  # macOS  (Metal, x86 64bit)
   else ifeq ($(shell uname -p),powerpc)
      MINVERFLAGS = -mmacosx-version-min=10.5  # macOSX (PowerPC 32-bit)
   else ifeq ($(shell uname -m),i386)
      MINVERFLAGS = -mmacosx-version-min=10.6  # macOSX (OpenGL, x86 32bit)
   else
      MINVERFLAGS = -mmacosx-version-min=10.7 -stdlib=libc++ # macOSX (OpenGL, x86 64bit)
   endif

	# Build for a specific architecture when ARCH is defined as a switch
   ifeq ($(ARCH),arm64)
      MINVERFLAGS  = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)
      ARCHFLAGS    = -arch arm64
   else ifeq ($(ARCH),x86_64)
      ifeq ($(HAVE_METAL),1)
         MINVERFLAGS  = -mmacosx-version-min=10.13 -stdlib=libc++
      else
         MINVERFLAGS  = -mmacosx-version-min=10.7  -stdlib=libc++
      endif
      ARCHFLAGS       = -arch x86_64
   else ifeq ($(ARCH),x86)
      MINVERFLAGS     = -mmacosx-version-min=10.6
      ARCHFLAGS       = -arch x86
   else ifeq ($(ARCH),ppc)
      MINVERFLAGS     = -mmacosx-version-min=10.5
      ARCHFLAGS       = -arch ppc
   endif
   ifeq ($(BUILDBOT),1)
      ARCHFLAGS       = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT)
   endif
	extraflags += $(MINVERFLAGS) $(ARCHFLAGS)
	ldflags += $(MINVERFLAGS) $(ARCHFLAGS)
else
   extra_flags += -static-libgcc -static-libstdc++
   DYLIB = dll
endif

CC      := $(compiler) -Wall
CXX     := $(subst CC,++,$(compiler)) -std=gnu++0x -Wall
flags   := $(CPPFLAGS) $(CFLAGS) -fPIC $(extra_flags) -I../../include
asflags := $(ASFLAGS) -fPIC  $(extra_flags)
objects :=

ifeq (1,$(use_neon))
   ASMFLAGS := -INEON/asm
   asflags += -mfpu=neon
endif

plugs := $(wildcard *.c)
objects := $(plugs:.c=.o)
targets := $(objects:.o=.$(DYLIB))

all: build;

%.o: %.S
	$(CC) -c -o $@ $(asflags)  $(ASMFLAGS)  $&lt;

%.o: %.c
	$(CC) -c -o $@ $(flags) $&lt;

%.$(DYLIB): %.o
	$(CC) -o $@ $(ldflags) $(flags) $^

build: $(targets)

clean:
	rm -f *.o
	rm -f *.$(DYLIB)

strip:
	strip -s *.$(DYLIB)

install:
	mkdir -p $(DESTDIR)$(INSTALLDIR)
	cp -t $(DESTDIR)$(INSTALLDIR) $(targets) *.dsp

test-install:
	DESTDIR=/tmp/build $(MAKE) install</pre>
<h2>./include/libretro-common/audio/dsp_filters/Mono.dsp</h2>
<pre>filters = 1
filter0 = panning

# Gains are linear.

# Stereo Mono:
 panning_left_mix = "0.5 0.5"
 panning_right_mix = "0.5 0.5"

# Mono on one speaker:
# panning_left_mix = "0.5 0.5"
# panning_right_mix = "0.0 0.0"</pre>
<h2>./include/libretro-common/audio/dsp_filters/panning.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (panning.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;libretro_dspfilter.h&gt;

struct panning_data
{
   float left[2];
   float right[2];
};

static void panning_free(void *data)
{
   free(data);
}

static void panning_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   struct panning_data *pan = (struct panning_data*)data;
   float *out               = output-&gt;samples;

   output-&gt;samples          = input-&gt;samples;
   output-&gt;frames           = input-&gt;frames;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float left  = out[0];
      float right = out[1];
      out[0]      = left * pan-&gt;left[0]  + right * pan-&gt;left[1];
      out[1]      = left * pan-&gt;right[0] + right * pan-&gt;right[1];
   }
}

static void *panning_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   static const float default_left[]  = { 1.0f, 0.0f };
   static const float default_right[] = { 0.0f, 1.0f };
   float *left                        = NULL;
   float *right                       = NULL;
   unsigned num_left                  = 0;
   unsigned num_right                 = 0;
   struct panning_data *pan           = (struct panning_data*)
      calloc(1, sizeof(*pan));

   if (!pan)
      return NULL;

   config-&gt;get_float_array(userdata, "left_mix",
         &amp;left, &amp;num_left, default_left, 2);
   config-&gt;get_float_array(userdata, "right_mix",
         &amp;right, &amp;num_right, default_right, 2);

   memcpy(pan-&gt;left,  (num_left  == 2) ?
         left :  default_left,  sizeof(pan-&gt;left));
   memcpy(pan-&gt;right, (num_right == 2) ?
         right : default_right, sizeof(pan-&gt;right));

   config-&gt;free(left);
   config-&gt;free(right);

   return pan;
}

static const struct dspfilter_implementation panning = {
   panning_init,
   panning_process,
   panning_free,

   DSPFILTER_API_VERSION,
   "Panning",
   "panning",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation panning_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *
dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;panning;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Panning.dsp</h2>
<pre>filters = 1
filter0 = panning

# Gains are linear.

# The default. Left and right channels map to each other.
panning_left_mix = "1.0 0.0"
panning_right_mix = "0.0 1.0"

# Some examples:
#
# Mono:
# panning_left_mix = "0.5 0.5"
# panning_right_mix = "0.5 0.5"

# Swap left and right channels:
# panning_left_mix = "0.0 1.0"
# panning_right_mix = "1.0 0.0"
#
# Mono on one speaker:
# panning_left_mix = "0.5 0.5"
# panning_right_mix = "0.0 0.0"</pre>
<h2>./include/libretro-common/audio/dsp_filters/phaser.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (phaser.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;

#define PHASER_LFO_SHAPE 4.0
#define PHASER_LFO_SKIP_SAMPLES 20

struct phaser_data
{
   float freq;
   float startphase;
   float fb;
   float depth;
   float drywet;
   float old[2][24];
   float gain;
   float fbout[2];
   float lfoskip;
   float phase;

   int stages;
   unsigned long skipcount;
};

static void phaser_free(void *data)
{
   free(data);
}

static void phaser_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i, c;
   int s;
   float m[2], tmp[2];
   struct phaser_data *ph = (struct phaser_data*)data;
   float *out             = output-&gt;samples;

   output-&gt;samples        = input-&gt;samples;
   output-&gt;frames         = input-&gt;frames;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float in[2] = { out[0], out[1] };

      for (c = 0; c &lt; 2; c++)
         m[c] = in[c] + ph-&gt;fbout[c] * ph-&gt;fb * 0.01f;

      if ((ph-&gt;skipcount++ % PHASER_LFO_SKIP_SAMPLES) == 0)
      {
         ph-&gt;gain = 0.5 * (1.0 + cos(ph-&gt;skipcount * ph-&gt;lfoskip + ph-&gt;phase));
         ph-&gt;gain = (exp(ph-&gt;gain * PHASER_LFO_SHAPE) - 1.0) / (exp(PHASER_LFO_SHAPE) - 1);
         ph-&gt;gain = 1.0 - ph-&gt;gain * ph-&gt;depth;
      }

      for (s = 0; s &lt; ph-&gt;stages; s++)
      {
         for (c = 0; c &lt; 2; c++)
         {
            tmp[c] = ph-&gt;old[c][s];
            ph-&gt;old[c][s] = ph-&gt;gain * tmp[c] + m[c];
            m[c] = tmp[c] - ph-&gt;gain * ph-&gt;old[c][s];
         }
      }

      for (c = 0; c &lt; 2; c++)
      {
         ph-&gt;fbout[c] = m[c];
         out[c] = m[c] * ph-&gt;drywet + in[c] * (1.0f - ph-&gt;drywet);
      }
   }
}

static void *phaser_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float lfo_freq, lfo_start_phase;
   struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));
   if (!ph)
      return NULL;

   config-&gt;get_float(userdata, "lfo_freq", &amp;lfo_freq, 0.4f);
   config-&gt;get_float(userdata, "lfo_start_phase", &amp;lfo_start_phase, 0.0f);
   config-&gt;get_float(userdata, "feedback", &amp;ph-&gt;fb, 0.0f);
   config-&gt;get_float(userdata, "depth", &amp;ph-&gt;depth, 0.4f);
   config-&gt;get_float(userdata, "dry_wet", &amp;ph-&gt;drywet, 0.5f);
   config-&gt;get_int(userdata, "stages", &amp;ph-&gt;stages, 2);

   if (ph-&gt;stages &lt; 1)
      ph-&gt;stages = 1;
   else if (ph-&gt;stages &gt; 24)
      ph-&gt;stages = 24;

   ph-&gt;lfoskip = lfo_freq * 2.0 * M_PI / info-&gt;input_rate;
   ph-&gt;phase   = lfo_start_phase * M_PI / 180.0;

   return ph;
}

static const struct dspfilter_implementation phaser_plug = {
   phaser_init,
   phaser_process,
   phaser_free,

   DSPFILTER_API_VERSION,
   "Phaser",
   "phaser",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation phaser_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;phaser_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Phaser.dsp</h2>
<pre>filters = 1
filter0 = phaser

# Defaults.
# phaser_lfo_freq = 0.4
# phaser_lfo_start_phase = 0.0
# phaser_feedback = 0.0
# phaser_depth = 0.4
# phaser_dry_wet = 0.5
# phaser_stages = 2</pre>
<h2>./include/libretro-common/audio/dsp_filters/reverb.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (reverb.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;libretro_dspfilter.h&gt;

struct comb
{
   float *buffer;
   unsigned bufsize;
   unsigned bufidx;

   float feedback;
   float filterstore;
   float damp1, damp2;
};

struct allpass
{
   float *buffer;
   float feedback;
   unsigned bufsize;
   unsigned bufidx;
};

static INLINE float comb_process(struct comb *c, float input)
{
   float output         = c-&gt;buffer[c-&gt;bufidx];
   c-&gt;filterstore       = (output * c-&gt;damp2) + (c-&gt;filterstore * c-&gt;damp1);

   c-&gt;buffer[c-&gt;bufidx] = input + (c-&gt;filterstore * c-&gt;feedback);

   c-&gt;bufidx++;
   if (c-&gt;bufidx &gt;= c-&gt;bufsize)
      c-&gt;bufidx = 0;

   return output;
}

static INLINE float allpass_process(struct allpass *a, float input)
{
   float bufout         = a-&gt;buffer[a-&gt;bufidx];
   float output         = -input + bufout;
   a-&gt;buffer[a-&gt;bufidx] = input + bufout * a-&gt;feedback;

   a-&gt;bufidx++;
   if (a-&gt;bufidx &gt;= a-&gt;bufsize)
      a-&gt;bufidx = 0;

   return output;
}

#define numcombs 8
#define numallpasses 4
static const float muted = 0;
static const float fixedgain = 0.015f;
static const float scalewet = 3;
static const float scaledry = 2;
static const float scaledamp = 0.4f;
static const float scaleroom = 0.28f;
static const float offsetroom = 0.7f;
static const float initialroom = 0.5f;
static const float initialdamp = 0.5f;
static const float initialwet = 1.0f / 3.0f;
static const float initialdry = 0;
static const float initialwidth = 1;
static const float initialmode = 0;
static const float freezemode = 0.5f;

struct revmodel
{
   struct comb combL[numcombs];
   struct allpass allpassL[numallpasses];

   float *bufcomb[numcombs];
   float *bufallpass[numallpasses];

   float gain;
   float roomsize, roomsize1;
   float damp, damp1;
   float wet, wet1, wet2;
   float dry;
   float width;
   float mode;
};

static float revmodel_process(struct revmodel *rev, float in)
{
   int i;
   float mono_out = 0.0f;
   float mono_in  = in;
   float input    = mono_in * rev-&gt;gain;

   for (i = 0; i &lt; numcombs; i++)
      mono_out += comb_process(&amp;rev-&gt;combL[i], input);

   for (i = 0; i &lt; numallpasses; i++)
      mono_out = allpass_process(&amp;rev-&gt;allpassL[i], mono_out);

   return mono_in * rev-&gt;dry + mono_out * rev-&gt;wet1;
}

static void revmodel_update(struct revmodel *rev)
{
   int i;
   rev-&gt;wet1 = rev-&gt;wet * (rev-&gt;width / 2.0f + 0.5f);

   if (rev-&gt;mode &gt;= freezemode)
   {
      rev-&gt;roomsize1 = 1.0f;
      rev-&gt;damp1 = 0.0f;
      rev-&gt;gain = muted;
   }
   else
   {
      rev-&gt;roomsize1 = rev-&gt;roomsize;
      rev-&gt;damp1 = rev-&gt;damp;
      rev-&gt;gain = fixedgain;
   }

   for (i = 0; i &lt; numcombs; i++)
   {
      rev-&gt;combL[i].feedback = rev-&gt;roomsize1;
      rev-&gt;combL[i].damp1 = rev-&gt;damp1;
      rev-&gt;combL[i].damp2 = 1.0f - rev-&gt;damp1;
   }
}

static void revmodel_setroomsize(struct revmodel *rev, float value)
{
   rev-&gt;roomsize = value * scaleroom + offsetroom;
   revmodel_update(rev);
}

static void revmodel_setdamp(struct revmodel *rev, float value)
{
   rev-&gt;damp = value * scaledamp;
   revmodel_update(rev);
}

static void revmodel_setwet(struct revmodel *rev, float value)
{
   rev-&gt;wet = value * scalewet;
   revmodel_update(rev);
}

static void revmodel_setdry(struct revmodel *rev, float value)
{
   rev-&gt;dry = value * scaledry;
   revmodel_update(rev);
}

static void revmodel_setwidth(struct revmodel *rev, float value)
{
   rev-&gt;width = value;
   revmodel_update(rev);
}

static void revmodel_setmode(struct revmodel *rev, float value)
{
   rev-&gt;mode = value;
   revmodel_update(rev);
}

static void revmodel_init(struct revmodel *rev,int srate)
{

  static const int comb_lengths[8] = { 1116,1188,1277,1356,1422,1491,1557,1617 };
  static const int allpass_lengths[4] = { 225,341,441,556 };
  double r = srate * (1 / 44100.0);
  unsigned c;

   for (c = 0; c &lt; numcombs; ++c)
   {
	   rev-&gt;bufcomb[c] = malloc(r*comb_lengths[c]*sizeof(float));
	   rev-&gt;combL[c].buffer  =  rev-&gt;bufcomb[c];
         memset(rev-&gt;combL[c].buffer,0,r*comb_lengths[c]*sizeof(float));
         rev-&gt;combL[c].bufsize=r*comb_lengths[c];
  }

   for (c = 0; c &lt; numallpasses; ++c)
   {
	   rev-&gt;bufallpass[c] = malloc(r*allpass_lengths[c]*sizeof(float));
	   rev-&gt;allpassL[c].buffer  =  rev-&gt;bufallpass[c];
         memset(rev-&gt;allpassL[c].buffer,0,r*allpass_lengths[c]*sizeof(float));
         rev-&gt;allpassL[c].bufsize=r*allpass_lengths[c];
         rev-&gt;allpassL[c].feedback = 0.5f;
  }

   revmodel_setwet(rev, initialwet);
   revmodel_setroomsize(rev, initialroom);
   revmodel_setdry(rev, initialdry);
   revmodel_setdamp(rev, initialdamp);
   revmodel_setwidth(rev, initialwidth);
   revmodel_setmode(rev, initialmode);
}

struct reverb_data
{
   struct revmodel left, right;
};

static void reverb_free(void *data)
{
   unsigned i;
   struct reverb_data *rev = (struct reverb_data*)data;

   for (i = 0; i &lt; numcombs; i++)
   {
      free(rev-&gt;left.bufcomb[i]);
      free(rev-&gt;right.bufcomb[i]);
   }

   for (i = 0; i &lt; numallpasses; i++)
   {
      free(rev-&gt;left.bufallpass[i]);
      free(rev-&gt;right.bufallpass[i]);
   }
   free(data);
}

static void reverb_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out;
   struct reverb_data *rev = (struct reverb_data*)data;

   output-&gt;samples         = input-&gt;samples;
   output-&gt;frames          = input-&gt;frames;
   out                     = output-&gt;samples;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float in[2] = { out[0], out[1] };

      out[0] = revmodel_process(&amp;rev-&gt;left, in[0]);
      out[1] = revmodel_process(&amp;rev-&gt;right, in[1]);
   }
}

static void *reverb_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float drytime, wettime, damping, roomwidth, roomsize;
   struct reverb_data *rev = (struct reverb_data*)
      calloc(1, sizeof(*rev));
   if (!rev)
      return NULL;

   config-&gt;get_float(userdata, "drytime", &amp;drytime, 0.43f);
   config-&gt;get_float(userdata, "wettime", &amp;wettime, 0.4f);
   config-&gt;get_float(userdata, "damping", &amp;damping, 0.8f);
   config-&gt;get_float(userdata, "roomwidth", &amp;roomwidth, 0.56f);
   config-&gt;get_float(userdata, "roomsize", &amp;roomsize, 0.56f);

   revmodel_init(&amp;rev-&gt;left,info-&gt;input_rate);
   revmodel_init(&amp;rev-&gt;right,info-&gt;input_rate);

   revmodel_setdamp(&amp;rev-&gt;left, damping);
   revmodel_setdry(&amp;rev-&gt;left, drytime);
   revmodel_setwet(&amp;rev-&gt;left, wettime);
   revmodel_setwidth(&amp;rev-&gt;left, roomwidth);
   revmodel_setroomsize(&amp;rev-&gt;left, roomsize);

   revmodel_setdamp(&amp;rev-&gt;right, damping);
   revmodel_setdry(&amp;rev-&gt;right, drytime);
   revmodel_setwet(&amp;rev-&gt;right, wettime);
   revmodel_setwidth(&amp;rev-&gt;right, roomwidth);
   revmodel_setroomsize(&amp;rev-&gt;right, roomsize);

   return rev;
}

static const struct dspfilter_implementation reverb_plug = {
   reverb_init,
   reverb_process,
   reverb_free,

   DSPFILTER_API_VERSION,
   "Reverb",
   "reverb",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation reverb_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;reverb_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Reverb.dsp</h2>
<pre>filters = 1
filter0 = reverb

# Defaults.
# reverb_drytime = 0.43
# reverb_wettime = 0.4
# reverb_damping = 0.8
# reverb_roomwidth = 0.56
# reverb_roomsize = 0.56</pre>
<h2>./include/libretro-common/audio/dsp_filters/tremolo.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (tremolo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;
#include &lt;string/stdstring.h&gt;

#define sqr(a) ((a) * (a))

struct tremolo_core
{
   float *wavetable;
   float freq;
   float depth;
   unsigned index;
   unsigned maxindex;
};

struct tremolo
{
   struct tremolo_core left, right;
};

static void tremolo_free(void *data)
{
   struct tremolo *tre = (struct tremolo*)data;
   free(tre-&gt;left.wavetable);
   free(tre-&gt;right.wavetable);
   free(data);
}

static void tremolocore_init(struct tremolo_core *core,float depth,int samplerate,float freq)
{
   double env;
   unsigned i;
   const double offset = 1. - depth / 2.;
   core-&gt;index     = 0;
   core-&gt;maxindex  = samplerate / freq;
   core-&gt;wavetable = malloc(core-&gt;maxindex   * sizeof(float));
   memset(core-&gt;wavetable, 0, core-&gt;maxindex * sizeof(float));
   for (i = 0; i &lt; core-&gt;maxindex; i++)
   {
      env                = freq * i / samplerate;
      env                = sin((M_PI*2) * fmod(env + 0.25, 1.0));
      core-&gt;wavetable[i] = env * (1 - fabs(offset)) + offset;
   }
}

float tremolocore_core(struct tremolo_core *core,float in)
{
   core-&gt;index = core-&gt;index % core-&gt;maxindex;
   return in * core-&gt;wavetable[core-&gt;index++];
}

static void tremolo_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out;
   struct tremolo *tre = (struct tremolo*)data;

   output-&gt;samples     = input-&gt;samples;
   output-&gt;frames      = input-&gt;frames;
   out                 = output-&gt;samples;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float in[2]      = { out[0], out[1] };
      out[0]           = tremolocore_core(&amp;tre-&gt;left, in[0]);
      out[1]           = tremolocore_core(&amp;tre-&gt;right, in[1]);
   }
}

static void *tremolo_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float freq, depth;
   struct tremolo *tre = (struct tremolo*)calloc(1, sizeof(*tre));
   if (!tre)
      return NULL;

   config-&gt;get_float(userdata, "freq", &amp;freq,4.0f);
   config-&gt;get_float(userdata, "depth", &amp;depth, 0.9f);
   tremolocore_init(&amp;tre-&gt;left,depth,info-&gt;input_rate,freq);
   tremolocore_init(&amp;tre-&gt;right,depth,info-&gt;input_rate,freq);
   return tre;
}

static const struct dspfilter_implementation tremolo_plug = {
   tremolo_init,
   tremolo_process,
   tremolo_free,

   DSPFILTER_API_VERSION,
   "Tremolo",
   "tremolo",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation tremolo_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;tremolo_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Tremolo.dsp</h2>
<pre>filters = 1
filter0 = tremolo

# Defaults.
#tremolo_frequency = 4.0
#tremolo_depth = 0.9</pre>
<h2>./include/libretro-common/audio/dsp_filters/vibrato.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vibrato.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;
#include &lt;string/stdstring.h&gt;

#define sqr(a) ((a) * (a))

#define VIBRATO_BASE_DELAY_SEC 0.002f /* 2 ms */
#define VIBRATO_FREQUENCY_DEFAULT_HZ 2.0f
#define VIBRATO_FREQUENCY_MAX_HZ 14.0f
#define VIBRATO_DEPTH_DEFAULT_PERCENT 50.0f
#define VIBRATO_ADD_DELAY 3

static float hermite_interp(float x, float *y)
{
   float c0 = y[1];
   float c1 = (1.0f / 2.0f) * (y[2] - y[0]);
   float c2 = (y[0] - (5.0f / 2.0f) * y[1]) + (2.0f * y[2] - (1.0f / 2.0f) * y[3]);
   float c3 = (1.0f / 2.0f) * (y[3] - y[0]) + (3.0f / 2.0f) * (y[1] - y[2]);
   return ((c3 * x + c2) * x + c1) * x + c0;
}

struct vibrato_core
{
   float* buffer;
   float freq;
   float samplerate;
   float depth;
   int phase;
   int writeindex;
   int size;
};

struct vibrato
{
   struct vibrato_core left, right;
};

static void vibrato_free(void *data)
{
   struct vibrato *vib = (struct vibrato*)data;
   free(vib-&gt;left.buffer);
   free(vib-&gt;right.buffer);
   free(data);
}

static void vibratocore_init(struct vibrato_core *core,float depth,int samplerate,float freq)
{
	core-&gt;size       = VIBRATO_BASE_DELAY_SEC * samplerate * 2;
	core-&gt;buffer     = malloc((core-&gt;size + VIBRATO_ADD_DELAY) * sizeof(float));
	memset(core-&gt;buffer, 0, (core-&gt;size   + VIBRATO_ADD_DELAY) * sizeof(float));
	core-&gt;samplerate = samplerate;
	core-&gt;freq       = freq;
	core-&gt;depth      = depth;
	core-&gt;phase      = 0;
	core-&gt;writeindex = 0;
}

float vibratocore_core(struct vibrato_core *core,float in)
{
   int ipart;
   float delay, readindex, fpart, value;
   float M                        = core-&gt;freq / core-&gt;samplerate;
   int maxphase                   = core-&gt;samplerate / core-&gt;freq;
   float lfo                      = sin(M * 2. * M_PI * core-&gt;phase++);
   int maxdelay                   = VIBRATO_BASE_DELAY_SEC * core-&gt;samplerate;
   core-&gt;phase                    = core-&gt;phase % maxphase;
   lfo                            = (lfo + 1) * 1.; /* Transform from [-1; 1] to [0; 1] */
   delay                          =  lfo * core-&gt;depth * maxdelay;
   delay                         += VIBRATO_ADD_DELAY;
   readindex                      = core-&gt;writeindex - 1 - delay;
   while (readindex &lt; 0)
      readindex                  += core-&gt;size;
   while (readindex &gt;= core-&gt;size)
      readindex                  -= core-&gt;size;
   ipart                          = (int)readindex;    /* Integer part of the delay */
   fpart                          = readindex - ipart; /* fractional part of the delay */
   value                          = hermite_interp(fpart, &amp;(core-&gt;buffer[ipart]));
   core-&gt;buffer[core-&gt;writeindex] = in;
   if (core-&gt;writeindex &lt; VIBRATO_ADD_DELAY)
      core-&gt;buffer[core-&gt;size + core-&gt;writeindex] = in;
   core-&gt;writeindex++;
   if (core-&gt;writeindex == core-&gt;size)
      core-&gt;writeindex = 0;
   return value;
}

static void vibrato_process(void *data,
      struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   float *out;
   struct vibrato *vib = (struct vibrato*)data;

   output-&gt;samples     = input-&gt;samples;
   output-&gt;frames      = input-&gt;frames;
   out                 = output-&gt;samples;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float in[2] = { out[0], out[1] };
      out[0]      = vibratocore_core(&amp;vib-&gt;left, in[0]);
      out[1]      = vibratocore_core(&amp;vib-&gt;right, in[1]);
   }
}

static void *vibrato_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   float freq, depth;
   struct vibrato *vib = (struct vibrato*)calloc(1, sizeof(*vib));
   if (!vib)
      return NULL;

   config-&gt;get_float(userdata, "freq", &amp;freq,5.0f);
   config-&gt;get_float(userdata, "depth", &amp;depth, 0.5f);
   vibratocore_init(&amp;vib-&gt;left,depth,info-&gt;input_rate,freq);
   vibratocore_init(&amp;vib-&gt;right,depth,info-&gt;input_rate,freq);
   return vib;
}

static const struct dspfilter_implementation vibrato_plug = {
   vibrato_init,
   vibrato_process,
   vibrato_free,

   DSPFILTER_API_VERSION,
   "Vibrato",
   "vibrato",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation vibrato_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   return &amp;vibrato_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/Vibrato.dsp</h2>
<pre>filters = 1
filter0 = vibrato

# Defaults.
#vibrato_frequency = 5.0
#vibrato_depth = 0.5</pre>
<h2>./include/libretro-common/audio/dsp_filters/wahwah.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (wahwah.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;math.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;libretro_dspfilter.h&gt;

#define WAHWAH_LFO_SKIP_SAMPLES 30

struct wahwah_data
{
   float phase;
   float lfoskip;
   float b0, b1, b2, a0, a1, a2;
   float freq, startphase;
   float depth, freqofs, res;
   unsigned long skipcount;

   struct
   {
      float xn1, xn2, yn1, yn2;
   } l, r;
};

static void wahwah_free(void *data)
{
   if (data)
      free(data);
}

static void wahwah_process(void *data, struct dspfilter_output *output,
      const struct dspfilter_input *input)
{
   unsigned i;
   struct wahwah_data *wah = (struct wahwah_data*)data;
   float *out              = output-&gt;samples;

   output-&gt;samples         = input-&gt;samples;
   output-&gt;frames          = input-&gt;frames;

   for (i = 0; i &lt; input-&gt;frames; i++, out += 2)
   {
      float out_l, out_r;
      float in[2] = { out[0], out[1] };

      if ((wah-&gt;skipcount++ % WAHWAH_LFO_SKIP_SAMPLES) == 0)
      {
         float omega, sn, cs, alpha;
         float frequency = (1.0f + cos(wah-&gt;skipcount * wah-&gt;lfoskip + wah-&gt;phase)) / 2.0f;

         frequency       = frequency * wah-&gt;depth * (1.0f - wah-&gt;freqofs) + wah-&gt;freqofs;
         frequency       = exp((frequency - 1.0f) * 6.0f);

         omega           = M_PI * frequency;
         sn              = sin(omega);
         cs              = cos(omega);
         alpha           = sn / (2.0f * wah-&gt;res);

         wah-&gt;b0         = (1.0f - cs) / 2.0f;
         wah-&gt;b1         = 1.0f  - cs;
         wah-&gt;b2         = (1.0f - cs) / 2.0f;
         wah-&gt;a0         = 1.0f + alpha;
         wah-&gt;a1         = -2.0f * cs;
         wah-&gt;a2         = 1.0f - alpha;
      }

      out_l              = (wah-&gt;b0 * in[0] + wah-&gt;b1 * wah-&gt;l.xn1 + wah-&gt;b2 * wah-&gt;l.xn2 - wah-&gt;a1 * wah-&gt;l.yn1 - wah-&gt;a2 * wah-&gt;l.yn2) / wah-&gt;a0;
      out_r              = (wah-&gt;b0 * in[1] + wah-&gt;b1 * wah-&gt;r.xn1 + wah-&gt;b2 * wah-&gt;r.xn2 - wah-&gt;a1 * wah-&gt;r.yn1 - wah-&gt;a2 * wah-&gt;r.yn2) / wah-&gt;a0;

      wah-&gt;l.xn2         = wah-&gt;l.xn1;
      wah-&gt;l.xn1         = in[0];
      wah-&gt;l.yn2         = wah-&gt;l.yn1;
      wah-&gt;l.yn1         = out_l;

      wah-&gt;r.xn2         = wah-&gt;r.xn1;
      wah-&gt;r.xn1         = in[1];
      wah-&gt;r.yn2         = wah-&gt;r.yn1;
      wah-&gt;r.yn1         = out_r;

      out[0]             = out_l;
      out[1]             = out_r;
   }
}

static void *wahwah_init(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata)
{
   struct wahwah_data *wah = (struct wahwah_data*)calloc(1, sizeof(*wah));
   if (!wah)
      return NULL;

   config-&gt;get_float(userdata, "lfo_freq", &amp;wah-&gt;freq, 1.5f);
   config-&gt;get_float(userdata, "lfo_start_phase", &amp;wah-&gt;startphase, 0.0f);
   config-&gt;get_float(userdata, "freq_offset", &amp;wah-&gt;freqofs, 0.3f);
   config-&gt;get_float(userdata, "depth", &amp;wah-&gt;depth, 0.7f);
   config-&gt;get_float(userdata, "resonance", &amp;wah-&gt;res, 2.5f);

   wah-&gt;lfoskip = wah-&gt;freq * 2.0f * M_PI / info-&gt;input_rate;
   wah-&gt;phase   = wah-&gt;startphase * M_PI / 180.0f;

   return wah;
}

static const struct dspfilter_implementation wahwah_plug = {
   wahwah_init,
   wahwah_process,
   wahwah_free,

   DSPFILTER_API_VERSION,
   "Wah-Wah",
   "wahwah",
};

#ifdef HAVE_FILTERS_BUILTIN
#define dspfilter_get_implementation wahwah_dspfilter_get_implementation
#endif

const struct dspfilter_implementation *
dspfilter_get_implementation(dspfilter_simd_mask_t mask)
{
   (void)mask;
   return &amp;wahwah_plug;
}

#undef dspfilter_get_implementation</pre>
<h2>./include/libretro-common/audio/dsp_filters/WahWah.dsp</h2>
<pre>filters = 1
filter0 = wahwah

# Defaults.
# wahwah_lfo_freq = 1.5
# wahwah_lfo_start_phase = 0.0
# wahwah_freq_offset = 0.3
# wahwah_depth = 0.7
# wahwah_resonance = 2.5</pre>
<h2>./include/libretro-common/audio/resampler/audio_resampler.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_resampler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;string.h&gt;

#include &lt;string/stdstring.h&gt;
#include &lt;features/features_cpu.h&gt;
#include &lt;file/config_file_userdata.h&gt;

#include &lt;audio/audio_resampler.h&gt;

static void resampler_null_process(void *a, struct resampler_data *b) { }
static void resampler_null_free(void *a) { }
static void *resampler_null_init(const struct resampler_config *a, double b,
      enum resampler_quality c, resampler_simd_mask_t d) { return (void*)0; }

retro_resampler_t null_resampler = {
   resampler_null_init,
   resampler_null_process,
   resampler_null_free,
   RESAMPLER_API_VERSION,
   "null",
   "null"
};

static const retro_resampler_t *resampler_drivers[] = {
   &amp;sinc_resampler,
#ifdef HAVE_CC_RESAMPLER
   &amp;CC_resampler,
#endif
#ifdef HAVE_NEAREST_RESAMPLER
   &amp;nearest_resampler,
#endif
   &amp;null_resampler,
   NULL,
};

static const struct resampler_config resampler_config = {
   config_userdata_get_float,
   config_userdata_get_int,
   config_userdata_get_float_array,
   config_userdata_get_int_array,
   config_userdata_get_string,
   config_userdata_free,
};

/**
 * find_resampler_driver_index:
 * @ident                      : Identifier of resampler driver to find.
 *
 * Finds resampler driver index by @ident name.
 *
 * Returns: resampler driver index if resampler driver was found, otherwise
 * -1.
 **/
static int find_resampler_driver_index(const char *ident)
{
   unsigned i;

   for (i = 0; resampler_drivers[i]; i++)
      if (string_is_equal_noncase(ident, resampler_drivers[i]-&gt;ident))
         return i;
   return -1;
}

/**
 * find_resampler_driver:
 * @ident                      : Identifier of resampler driver to find.
 *
 * Finds resampler by @ident name.
 *
 * Returns: resampler driver if resampler driver was found, otherwise
 * NULL.
 **/
static const retro_resampler_t *find_resampler_driver(const char *ident)
{
   int i = find_resampler_driver_index(ident);

   if (i &gt;= 0)
      return resampler_drivers[i];

   return resampler_drivers[0];
}

/**
 * resampler_append_plugs:
 * @re                         : Resampler handle
 * @backend                    : Resampler backend that is about to be set.
 * @bw_ratio                   : Bandwidth ratio.
 *
 * Initializes resampler driver based on queried CPU features.
 *
 * Returns: true (1) if successfully initialized, otherwise false (0).
 **/
static bool resampler_append_plugs(void **re,
      const retro_resampler_t **backend,
      enum resampler_quality quality,
      double bw_ratio)
{
   resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get();

   if (*backend)
      *re = (*backend)-&gt;init(&amp;resampler_config, bw_ratio, quality, mask);

   if (!*re)
      return false;
   return true;
}


/**
 * audio_resampler_driver_find_handle:
 * @idx                : index of driver to get handle to.
 *
 * Returns: handle to audio resampler driver at index. Can be NULL
 * if nothing found.
 **/
const void *audio_resampler_driver_find_handle(int idx)
{
   const void *drv = resampler_drivers[idx];
   if (!drv)
      return NULL;
   return drv;
}

/**
 * audio_resampler_driver_find_ident:
 * @idx                : index of driver to get handle to.
 *
 * Returns: Human-readable identifier of audio resampler driver at index.
 * Can be NULL if nothing found.
 **/
const char *audio_resampler_driver_find_ident(int idx)
{
   const retro_resampler_t *drv = resampler_drivers[idx];
   if (!drv)
      return NULL;
   return drv-&gt;ident;
}

/**
 * retro_resampler_realloc:
 * @re                         : Resampler handle
 * @backend                    : Resampler backend that is about to be set.
 * @ident                      : Identifier name for resampler we want.
 * @bw_ratio                   : Bandwidth ratio.
 *
 * Reallocates resampler. Will free previous handle before
 * allocating a new one. If ident is NULL, first resampler will be used.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
      const char *ident, enum resampler_quality quality, double bw_ratio)
{
   if (*re &amp;&amp; *backend)
      (*backend)-&gt;free(*re);

   *re      = NULL;
   *backend = find_resampler_driver(ident);

   if (!resampler_append_plugs(re, backend, quality, bw_ratio))
   {
      if (!*re)
         *backend = NULL;
      return false;
   }

   return true;
}</pre>
<h2>./include/libretro-common/audio/resampler/drivers/nearest_resampler.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nearest_resampler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;math.h&gt;

#include &lt;audio/audio_resampler.h&gt;

typedef struct rarch_nearest_resampler
{
   float fraction;
} rarch_nearest_resampler_t;

static void resampler_nearest_process(
      void *re_, struct resampler_data *data)
{
   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
   audio_frame_float_t  *inp     = (audio_frame_float_t*)data-&gt;data_in;
   audio_frame_float_t  *inp_max = (audio_frame_float_t*)inp + data-&gt;input_frames;
   audio_frame_float_t  *outp    = (audio_frame_float_t*)data-&gt;data_out;
   float                   ratio = 1.0 / data-&gt;ratio;

   while (inp != inp_max)
   {
      while (re-&gt;fraction &gt; 1)
      {
         *outp++       = *inp;
         re-&gt;fraction -= ratio;
      }
      re-&gt;fraction++;
      inp++;
   }

   data-&gt;output_frames = (outp - (audio_frame_float_t*)data-&gt;data_out);
}

static void resampler_nearest_free(void *re_)
{
   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
   if (re)
      free(re);
}

static void *resampler_nearest_init(const struct resampler_config *config,
      double bandwidth_mod,
      enum resampler_quality quality,
      resampler_simd_mask_t mask)
{
   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)
      calloc(1, sizeof(rarch_nearest_resampler_t));
   if (!re)
      return NULL;
   re-&gt;fraction = 0;
   return re;
}

retro_resampler_t nearest_resampler = {
   resampler_nearest_init,
   resampler_nearest_process,
   resampler_nearest_free,
   RESAMPLER_API_VERSION,
   "nearest",
   "nearest"
};</pre>
<h2>./include/libretro-common/audio/resampler/drivers/sinc_resampler.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (sinc_resampler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Bog-standard windowed SINC implementation. */

#if defined(__GNUC__) &amp;&amp; defined(__OPTIMIZE__) &amp;&amp; !defined(__clang__)
#pragma GCC push_options
#pragma GCC optimize ("fast-math")
#endif

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;math.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_environment.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;filters.h&gt;
#include &lt;memalign.h&gt;

#include &lt;audio/audio_resampler.h&gt;
#include &lt;filters.h&gt;

#ifdef __SSE__
#include &lt;xmmintrin.h&gt;
#endif

#if defined(__AVX__)
#include &lt;immintrin.h&gt;
#endif

/* Rough SNR values for upsampling:
 * LOWEST: 40 dB
 * LOWER: 55 dB
 * NORMAL: 70 dB
 * HIGHER: 110 dB
 * HIGHEST: 140 dB
 */

/* TODO, make all this more configurable. */

enum sinc_window
{
   SINC_WINDOW_NONE   = 0,
   SINC_WINDOW_KAISER,
   SINC_WINDOW_LANCZOS
};

/* For the little amount of taps we're using,
 * SSE1 is faster than AVX for some reason.
 * AVX code is kept here though as by increasing number
 * of sinc taps, the AVX code is clearly faster than SSE1.
 */

typedef struct rarch_sinc_resampler
{
   /* A buffer for phase_table, buffer_l and buffer_r
    * are created in a single calloc().
    * Ensure that we get as good cache locality as we can hope for. */
   float *main_buffer;
   float *phase_table;
   float *buffer_l;
   float *buffer_r;
   unsigned phase_bits;
   unsigned subphase_bits;
   unsigned subphase_mask;
   unsigned taps;
   unsigned ptr;
   uint32_t time;
   float subphase_mod;
   float kaiser_beta;
} rarch_sinc_resampler_t;

#if (defined(__ARM_NEON__) || defined(HAVE_NEON))

#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
void process_sinc_neon_asm(float *out, const float *left,
      const float *right, const float *coeff, unsigned taps);
#else
#include &lt;arm_neon.h&gt;

/* Assumes that taps &gt;= 8, and that taps is a multiple of 8.
 * Not bothering to reimplement this one for the external .S
 */
static void resampler_sinc_process_neon_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);
   uint32_t ratio                 = phases / data-&gt;ratio;
   const float *input             = data-&gt;data_in;
   float *output                  = data-&gt;data_out;
   size_t frames                  = data-&gt;input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_l[resamp-&gt;ptr]     = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_r[resamp-&gt;ptr]     = *input++;

         resamp-&gt;time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r    = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            int i;
            unsigned phase           = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            const float *phase_table = resamp-&gt;phase_table + phase * taps * 2;
            const float *delta_table = phase_table + taps;
            float32x4_t delta        = vdupq_n_f32((resamp-&gt;time &amp; resamp-&gt;subphase_mask) * resamp-&gt;subphase_mod);
            float32x4_t p1 = {0, 0, 0, 0}, p2 = {0, 0, 0, 0};
            float32x2_t p3, p4;

            for (i = 0; i &lt; (int)taps; i += 8)
            {
               float32x4x2_t coeff8  = vld2q_f32(&amp;phase_table[i]);
               float32x4x2_t delta8  = vld2q_f32(&amp;delta_table[i]);
               float32x4x2_t left8   = vld2q_f32(&amp;buffer_l[i]);
               float32x4x2_t right8  = vld2q_f32(&amp;buffer_r[i]);

               coeff8.val[0] = vmlaq_f32(coeff8.val[0], delta8.val[0], delta);
               coeff8.val[1] = vmlaq_f32(coeff8.val[1], delta8.val[1], delta);

               p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);
               p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);
               p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);
               p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);
            }

            p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));
            p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));
            vst1_f32(output, vpadd_f32(p3, p4));
            output                 += 2;
            out_frames++;
            resamp-&gt;time           += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}
#endif

/* Assumes that taps &gt;= 8, and that taps is a multiple of 8. */
static void resampler_sinc_process_neon(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);
   uint32_t ratio                 = phases / data-&gt;ratio;
   const float *input             = data-&gt;data_in;
   float *output                  = data-&gt;data_out;
   size_t frames                  = data-&gt;input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_l[resamp-&gt;ptr]     = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_r[resamp-&gt;ptr]     = *input++;

         resamp-&gt;time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r    = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            unsigned phase           = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            const float *phase_table = resamp-&gt;phase_table + phase * taps;
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
            process_sinc_neon_asm(output, buffer_l, buffer_r, phase_table, taps);
#else
            int i;
            float32x4_t p1 = {0, 0, 0, 0}, p2 = {0, 0, 0, 0};
            float32x2_t p3, p4;

            for (i = 0; i &lt; (int)taps; i += 8)
            {
               float32x4x2_t coeff8  = vld2q_f32(&amp;phase_table[i]);
               float32x4x2_t left8   = vld2q_f32(&amp;buffer_l[i]);
               float32x4x2_t right8  = vld2q_f32(&amp;buffer_r[i]);

               p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);
               p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);
               p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);
               p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);
            }

            p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));
            p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));
            vst1_f32(output, vpadd_f32(p3, p4));
#endif
            output                 += 2;
            out_frames++;
            resamp-&gt;time           += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}
#endif

#if defined(__AVX__)
static void resampler_sinc_process_avx_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);

   uint32_t ratio                 = phases / data-&gt;ratio;
   const float *input             = data-&gt;data_in;
   float *output                  = data-&gt;data_out;
   size_t frames                  = data-&gt;input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_l[resamp-&gt;ptr]     = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_r[resamp-&gt;ptr]     = *input++;

         resamp-&gt;time                                -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r    = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            int i;
            __m256 res_l, res_r;
            unsigned phase           = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            float *phase_table       = resamp-&gt;phase_table + phase * taps * 2;
            float *delta_table       = phase_table + taps;
            __m256 delta             = _mm256_set1_ps((float)
                  (resamp-&gt;time &amp; resamp-&gt;subphase_mask) * resamp-&gt;subphase_mod);
            __m256 sum_l             = _mm256_setzero_ps();
            __m256 sum_r             = _mm256_setzero_ps();

            for (i = 0; i &lt; (int)taps; i += 8)
            {
               __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);
               __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);
               __m256 deltas = _mm256_load_ps(delta_table + i);
               __m256 sinc   = _mm256_add_ps(_mm256_load_ps((const float*)phase_table + i),
                     _mm256_mul_ps(deltas, delta));

               sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
               sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
            }

            /* hadd on AVX is weird, and acts on low-lanes
             * and high-lanes separately. */
            res_l = _mm256_hadd_ps(sum_l, sum_l);
            res_r = _mm256_hadd_ps(sum_r, sum_r);
            res_l = _mm256_hadd_ps(res_l, res_l);
            res_r = _mm256_hadd_ps(res_r, res_r);
            res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
            res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);

            /* This is optimized to mov %xmmN, [mem].
             * There doesn't seem to be any _mm256_store_ss intrinsic. */
            _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
            _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));

            output += 2;
            out_frames++;
            resamp-&gt;time += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}

static void resampler_sinc_process_avx(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases    = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);

   uint32_t ratio     = phases / data-&gt;ratio;
   const float *input = data-&gt;data_in;
   float *output      = data-&gt;data_out;
   size_t frames      = data-&gt;input_frames;
   size_t out_frames  = 0;
   unsigned taps      = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_l[resamp-&gt;ptr]     = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_r[resamp-&gt;ptr]     = *input++;

         resamp-&gt;time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r    = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            int i;
            __m256 delta, res_l, res_r;
            unsigned phase           = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            float *phase_table       = resamp-&gt;phase_table + phase * taps;

            __m256 sum_l             = _mm256_setzero_ps();
            __m256 sum_r             = _mm256_setzero_ps();

            for (i = 0; i &lt; (int)taps; i += 8)
            {
               __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);
               __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);
               __m256 sinc   = _mm256_load_ps((const float*)phase_table + i);

               sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
               sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
            }

            /* hadd on AVX is weird, and acts on low-lanes
             * and high-lanes separately. */
            res_l = _mm256_hadd_ps(sum_l, sum_l);
            res_r = _mm256_hadd_ps(sum_r, sum_r);
            res_l = _mm256_hadd_ps(res_l, res_l);
            res_r = _mm256_hadd_ps(res_r, res_r);
            res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
            res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);

            /* This is optimized to mov %xmmN, [mem].
             * There doesn't seem to be any _mm256_store_ss intrinsic. */
            _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
            _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));

            output += 2;
            out_frames++;
            resamp-&gt;time += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}
#endif

#if defined(__SSE__)
static void resampler_sinc_process_sse_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);

   uint32_t ratio                 = phases / data-&gt;ratio;
   const float *input             = data-&gt;data_in;
   float *output                  = data-&gt;data_out;
   size_t frames                  = data-&gt;input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_l[resamp-&gt;ptr]     = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_r[resamp-&gt;ptr]     = *input++;

         resamp-&gt;time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r    = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            int i;
            __m128 sum;
            unsigned phase           = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            float *phase_table       = resamp-&gt;phase_table + phase * taps * 2;
            float *delta_table       = phase_table + taps;
            __m128 delta             = _mm_set1_ps((float)
                  (resamp-&gt;time &amp; resamp-&gt;subphase_mask) * resamp-&gt;subphase_mod);

            __m128 sum_l             = _mm_setzero_ps();
            __m128 sum_r             = _mm_setzero_ps();

            for (i = 0; i &lt; (int)taps; i += 4)
            {
               __m128 buf_l = _mm_loadu_ps(buffer_l + i);
               __m128 buf_r = _mm_loadu_ps(buffer_r + i);
               __m128 deltas = _mm_load_ps(delta_table + i);
               __m128 _sinc  = _mm_add_ps(_mm_load_ps((const float*)phase_table + i),
                     _mm_mul_ps(deltas, delta));
               sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
               sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
            }

            /* Them annoying shuffles.
             * sum_l = { l3, l2, l1, l0 }
             * sum_r = { r3, r2, r1, r0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
                     _MM_SHUFFLE(1, 0, 1, 0)),
                  _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));

            /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
             * sum   = { R1, R0, L1, L0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);

            /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
             * sum   = { X,  R,  X,  L }
             */

            /* Store L */
            _mm_store_ss(output + 0, sum);

            /* movehl { X, R, X, L } == { X, R, X, R } */
            _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));

            output += 2;
            out_frames++;
            resamp-&gt;time += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}

static void resampler_sinc_process_sse(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);

   uint32_t ratio                 = phases / data-&gt;ratio;
   const float *input             = data-&gt;data_in;
   float *output                  = data-&gt;data_out;
   size_t frames                  = data-&gt;input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_l[resamp-&gt;ptr]     = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps] =
            resamp-&gt;buffer_r[resamp-&gt;ptr]     = *input++;

         resamp-&gt;time                        -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r    = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            int i;
            __m128 sum;
            unsigned phase           = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            float *phase_table       = resamp-&gt;phase_table + phase * taps;

            __m128 sum_l             = _mm_setzero_ps();
            __m128 sum_r             = _mm_setzero_ps();

            for (i = 0; i &lt; (int)taps; i += 4)
            {
               __m128 buf_l = _mm_loadu_ps(buffer_l + i);
               __m128 buf_r = _mm_loadu_ps(buffer_r + i);
               __m128 _sinc = _mm_load_ps((const float*)phase_table + i);
               sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
               sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
            }

            /* Them annoying shuffles.
             * sum_l = { l3, l2, l1, l0 }
             * sum_r = { r3, r2, r1, r0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
                     _MM_SHUFFLE(1, 0, 1, 0)),
                  _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));

            /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
             * sum   = { R1, R0, L1, L0 }
             */

            sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);

            /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
             * sum   = { X,  R,  X,  L }
             */

            /* Store L */
            _mm_store_ss(output + 0, sum);

            /* movehl { X, R, X, L } == { X, R, X, R } */
            _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));

            output += 2;
            out_frames++;
            resamp-&gt;time += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}
#endif

static void resampler_sinc_process_c_kaiser(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);

   uint32_t ratio                 = phases / data-&gt;ratio;
   const float *input             = data-&gt;data_in;
   float *output                  = data-&gt;data_out;
   size_t frames                  = data-&gt;input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps]    =
            resamp-&gt;buffer_l[resamp-&gt;ptr]        = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps]    =
            resamp-&gt;buffer_r[resamp-&gt;ptr]        = *input++;

         resamp-&gt;time                           -= phases;
         frames--;
      }

      {
         const float *buffer_l = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            int i;
            float sum_l        = 0.0f;
            float sum_r        = 0.0f;
            unsigned phase     = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            float *phase_table = resamp-&gt;phase_table + phase * taps * 2;
            float *delta_table = phase_table + taps;
            float delta        = (float)
               (resamp-&gt;time &amp; resamp-&gt;subphase_mask) * resamp-&gt;subphase_mod;

            for (i = 0; i &lt; (int)taps; i++)
            {
               float sinc_val  = phase_table[i] + delta_table[i] * delta;

               sum_l          += buffer_l[i] * sinc_val;
               sum_r          += buffer_r[i] * sinc_val;
            }

            output[0]          = sum_l;
            output[1]          = sum_r;

            output            += 2;
            out_frames++;
            resamp-&gt;time      += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}

static void resampler_sinc_process_c(void *re_, struct resampler_data *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
   unsigned phases                = 1 &lt;&lt; (resamp-&gt;phase_bits + resamp-&gt;subphase_bits);

   uint32_t ratio                 = phases / data-&gt;ratio;
   const float *input             = data-&gt;data_in;
   float *output                  = data-&gt;data_out;
   size_t frames                  = data-&gt;input_frames;
   size_t out_frames              = 0;
   unsigned taps                  = resamp-&gt;taps;

   while (frames)
   {
      while (frames &amp;&amp; resamp-&gt;time &gt;= phases)
      {
         /* Push in reverse to make filter more obvious. */
         if (!resamp-&gt;ptr)
            resamp-&gt;ptr = taps;
         resamp-&gt;ptr--;

         resamp-&gt;buffer_l[resamp-&gt;ptr + taps]    =
            resamp-&gt;buffer_l[resamp-&gt;ptr]        = *input++;

         resamp-&gt;buffer_r[resamp-&gt;ptr + taps]    =
            resamp-&gt;buffer_r[resamp-&gt;ptr]        = *input++;

         resamp-&gt;time                           -= phases;
         frames--;
      }

      {
         const float *buffer_l    = resamp-&gt;buffer_l + resamp-&gt;ptr;
         const float *buffer_r    = resamp-&gt;buffer_r + resamp-&gt;ptr;
         while (resamp-&gt;time &lt; phases)
         {
            int i;
            float sum_l           = 0.0f;
            float sum_r           = 0.0f;
            unsigned phase        = resamp-&gt;time &gt;&gt; resamp-&gt;subphase_bits;
            float *phase_table    = resamp-&gt;phase_table + phase * taps;

            for (i = 0; i &lt; (int)taps; i++)
            {
               float sinc_val     = phase_table[i];

               sum_l             += buffer_l[i] * sinc_val;
               sum_r             += buffer_r[i] * sinc_val;
            }

            output[0]             = sum_l;
            output[1]             = sum_r;

            output               += 2;
            out_frames++;
            resamp-&gt;time         += ratio;
         }
      }
   }

   data-&gt;output_frames = out_frames;
}

static void resampler_sinc_free(void *data)
{
   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)data;
   if (resamp)
      memalign_free(resamp-&gt;main_buffer);
   free(resamp);
}

static void sinc_init_table_kaiser(rarch_sinc_resampler_t *resamp,
      double cutoff,
      float *phase_table, int phases, int taps, bool calculate_delta)
{
   int i, j;
   /* Kaiser window function - need to normalize w(0) to 1.0f */
   float kaiser_beta = resamp-&gt;kaiser_beta;
   double window_mod = besseli0(kaiser_beta);
   int stride        = calculate_delta ? 2 : 1;
   double sidelobes  = taps / 2.0;

   for (i = 0; i &lt; phases; i++)
   {
      for (j = 0; j &lt; taps; j++)
      {
         float val;
         double sinc_phase;
         int               n = j * phases + i;
         double window_phase = (double)n / (phases * taps); /* [0, 1). */
         window_phase        = 2.0 * window_phase - 1.0; /* [-1, 1) */
         sinc_phase          = sidelobes * window_phase;
         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
              besseli0(kaiser_beta * sqrtf(1 - window_phase * window_phase))
            / window_mod;
         phase_table[i * stride * taps + j] = val;
      }
   }

   if (calculate_delta)
   {
      int phase;
      int p;
      for (p = 0; p &lt; phases - 1; p++)
      {
         for (j = 0; j &lt; taps; j++)
         {
            float delta = phase_table[(p + 1) * stride * taps + j] -
               phase_table[p * stride * taps + j];
            phase_table[(p * stride + 1) * taps + j] = delta;
         }
      }

      phase = phases - 1;
      for (j = 0; j &lt; taps; j++)
      {
         float val, delta;
         double sinc_phase;
         int n               = j * phases + (phase + 1);
         double window_phase = (double)n / (phases * taps); /* (0, 1]. */
         window_phase        = 2.0 * window_phase - 1.0; /* (-1, 1] */
         sinc_phase          = sidelobes * window_phase;

         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
              besseli0(resamp-&gt;kaiser_beta * sqrtf(1 - window_phase *
window_phase)) / window_mod;
         delta = (val - phase_table[phase * stride * taps + j]);
         phase_table[(phase * stride + 1) * taps + j] = delta;
      }
   }
}

static void sinc_init_table_lanczos(
      rarch_sinc_resampler_t *resamp, double cutoff,
      float *phase_table, int phases, int taps, bool calculate_delta)
{
   int i, j;
   /* Lanczos window function - need to normalize w(0) to 1.0f */
   double window_mod = 1.0;
   int stride        = calculate_delta ? 2 : 1;
   double sidelobes  = taps / 2.0;

   for (i = 0; i &lt; phases; i++)
   {
      for (j = 0; j &lt; taps; j++)
      {
         double sinc_phase;
         float val;
         int               n = j * phases + i;
         double window_phase = (double)n / (phases * taps); /* [0, 1). */
         window_phase        = 2.0 * window_phase - 1.0; /* [-1, 1) */
         sinc_phase          = sidelobes * window_phase;
         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
            sinc(M_PI * window_phase) / window_mod;
         phase_table[i * stride * taps + j] = val;
      }
   }

   if (calculate_delta)
   {
      int p;
      int phase;

      for (p = 0; p &lt; phases - 1; p++)
      {
         for (j = 0; j &lt; taps; j++)
         {
            float delta = phase_table[(p + 1) * stride * taps + j] -
               phase_table[p * stride * taps + j];
            phase_table[(p * stride + 1) * taps + j] = delta;
         }
      }

      phase = phases - 1;
      for (j = 0; j &lt; taps; j++)
      {
         float val, delta;
         double sinc_phase;
         int n               = j * phases + (phase + 1);
         double window_phase = (double)n / (phases * taps); /* (0, 1]. */
         window_phase        = 2.0 * window_phase - 1.0; /* (-1, 1] */
         sinc_phase          = sidelobes * window_phase;

         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
            sinc(M_PI * window_phase) / window_mod;
         delta = (val - phase_table[phase * stride * taps + j]);
         phase_table[(phase * stride + 1) * taps + j] = delta;
      }
   }
}

static void *resampler_sinc_new(const struct resampler_config *config,
      double bandwidth_mod, enum resampler_quality quality,
      resampler_simd_mask_t mask)
{
   double cutoff                  = 0.0;
   size_t phase_elems             = 0;
   size_t elems                   = 0;
   unsigned enable_avx            = 0;
   unsigned sidelobes             = 0;
   enum sinc_window window_type   = SINC_WINDOW_NONE;
   rarch_sinc_resampler_t *re     = (rarch_sinc_resampler_t*)
      calloc(1, sizeof(*re));

   if (!re)
      return NULL;

   switch (quality)
   {
      case RESAMPLER_QUALITY_LOWEST:
         cutoff            = 0.98;
         sidelobes         = 2;
         re-&gt;phase_bits    = 12;
         re-&gt;subphase_bits = 10;
         window_type       = SINC_WINDOW_LANCZOS;
         break;
      case RESAMPLER_QUALITY_LOWER:
         cutoff            = 0.98;
         sidelobes         = 4;
         re-&gt;phase_bits    = 12;
         re-&gt;subphase_bits = 10;
         window_type       = SINC_WINDOW_LANCZOS;
         break;
      case RESAMPLER_QUALITY_HIGHER:
         cutoff            = 0.90;
         sidelobes         = 32;
         re-&gt;phase_bits    = 10;
         re-&gt;subphase_bits = 14;
         window_type       = SINC_WINDOW_KAISER;
         re-&gt;kaiser_beta   = 10.5;
         enable_avx        = 1;
         break;
      case RESAMPLER_QUALITY_HIGHEST:
         cutoff            = 0.962;
         sidelobes         = 128;
         re-&gt;phase_bits    = 10;
         re-&gt;subphase_bits = 14;
         window_type       = SINC_WINDOW_KAISER;
         re-&gt;kaiser_beta   = 14.5;
         enable_avx        = 1;
         break;
      case RESAMPLER_QUALITY_NORMAL:
      case RESAMPLER_QUALITY_DONTCARE:
         cutoff            = 0.825;
         sidelobes         = 8;
         re-&gt;phase_bits    = 8;
         re-&gt;subphase_bits = 16;
         window_type       = SINC_WINDOW_KAISER;
         re-&gt;kaiser_beta   = 5.5;
         break;
   }

   re-&gt;subphase_mask = (1 &lt;&lt; re-&gt;subphase_bits) - 1;
   re-&gt;subphase_mod  = 1.0f / (1 &lt;&lt; re-&gt;subphase_bits);
   re-&gt;taps          = sidelobes * 2;

   /* Downsampling, must lower cutoff, and extend number of
    * taps accordingly to keep same stopband attenuation. */
   if (bandwidth_mod &lt; 1.0)
   {
      cutoff  *= bandwidth_mod;
      re-&gt;taps = (unsigned)ceil(re-&gt;taps / bandwidth_mod);
   }

   /* Be SIMD-friendly. */
#if defined(__AVX__)
   if (enable_avx)
      re-&gt;taps = (re-&gt;taps + 7) &amp; ~7;
   else
#endif
   {
#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
      re-&gt;taps = (re-&gt;taps + 7) &amp; ~7;
#else
      re-&gt;taps = (re-&gt;taps + 3) &amp; ~3;
#endif
   }

   phase_elems = ((1 &lt;&lt; re-&gt;phase_bits) * re-&gt;taps);
   if (window_type == SINC_WINDOW_KAISER)
      phase_elems  = phase_elems * 2;
   elems       = phase_elems + 4 * re-&gt;taps;

   re-&gt;main_buffer = (float*)memalign_alloc(128, sizeof(float) * elems);
   if (!re-&gt;main_buffer)
      goto error;

   memset(re-&gt;main_buffer, 0, sizeof(float) * elems);

   re-&gt;phase_table = re-&gt;main_buffer;
   re-&gt;buffer_l    = re-&gt;main_buffer + phase_elems;
   re-&gt;buffer_r    = re-&gt;buffer_l + 2 * re-&gt;taps;

   switch (window_type)
   {
      case SINC_WINDOW_LANCZOS:
         sinc_init_table_lanczos(re, cutoff, re-&gt;phase_table,
               1 &lt;&lt; re-&gt;phase_bits, re-&gt;taps, false);
         break;
      case SINC_WINDOW_KAISER:
         sinc_init_table_kaiser(re, cutoff, re-&gt;phase_table,
               1 &lt;&lt; re-&gt;phase_bits, re-&gt;taps, true);
         break;
      case SINC_WINDOW_NONE:
         goto error;
   }

   sinc_resampler.process = resampler_sinc_process_c;
   if (window_type == SINC_WINDOW_KAISER)
      sinc_resampler.process    = resampler_sinc_process_c_kaiser;

   if (mask &amp; RESAMPLER_SIMD_AVX &amp;&amp; enable_avx)
   {
#if defined(__AVX__)
      sinc_resampler.process    = resampler_sinc_process_avx;
      if (window_type == SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_avx_kaiser;
#endif
   }
   else if (mask &amp; RESAMPLER_SIMD_SSE)
   {
#if defined(__SSE__)
      sinc_resampler.process = resampler_sinc_process_sse;
      if (window_type == SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_sse_kaiser;
#endif
   }
   else if (mask &amp; RESAMPLER_SIMD_NEON)
   {
#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
      if (window_type != SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_neon;
#else
      sinc_resampler.process = resampler_sinc_process_neon;
      if (window_type == SINC_WINDOW_KAISER)
         sinc_resampler.process = resampler_sinc_process_neon_kaiser;
#endif
#endif
   }

   return re;

error:
   resampler_sinc_free(re);
   return NULL;
}

retro_resampler_t sinc_resampler = {
   resampler_sinc_new,
   resampler_sinc_process_c,
   resampler_sinc_free,
   RESAMPLER_API_VERSION,
   "sinc",
   "sinc"
};

#if defined(__GNUC__) &amp;&amp; defined(__OPTIMIZE__) &amp;&amp; !defined(__clang__)
#pragma GCC pop_options
#endif</pre>
<h2>./include/libretro-common/audio/resampler/drivers/sinc_resampler_neon.S</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (sinc_resampler_neon.S).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if defined(__ARM_NEON__) &amp;&amp; defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)

#ifndef __MACH__
.arm
#endif
.align 4
.globl process_sinc_neon_asm
#ifndef __MACH__
.type process_sinc_neon_asm, %function
#endif
.globl _process_sinc_neon_asm
#ifndef __MACH__
.type _process_sinc_neon_asm, %function
#endif
# void process_sinc_neon(float *out, const float *left, const float *right, const float *coeff, unsigned taps)
# Assumes taps is &gt;= 8, and a multiple of 8.
process_sinc_neon_asm:
_process_sinc_neon_asm:

   push {r4, lr}
   vmov.f32 q0, #0.0
   vmov.f32 q8, #0.0

   # Taps argument (r4) goes on stack in armeabi.
   ldr r4, [sp, #8]

1:
   # Left
   vld1.f32 {q2-q3}, [r1]!
   # Right
   vld1.f32 {q10-q11}, [r2]!
   # Coeff
   vld1.f32 {q12-q13}, [r3, :128]!

   # Left / Right
   vmla.f32 q0, q2, q12
   vmla.f32 q8, q10, q12
   vmla.f32 q0, q3, q13
   vmla.f32 q8, q11, q13

   subs r4, r4, #8
   bne 1b

   # Add everything together
   vadd.f32 d0, d0, d1
   vadd.f32 d16, d16, d17
   vpadd.f32 d0, d0, d16
   vst1.f32 d0, [r0]

   pop {r4, pc}

#endif</pre>
<h2>./include/libretro-common/cdrom/cdrom.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (cdrom.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include &lt;cdrom/cdrom.h&gt;
#include &lt;libretro.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;compat/strcasestr.h&gt;
#include &lt;retro_math.h&gt;
#include &lt;retro_timers.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;retro_endianness.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;vfs/vfs_implementation.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;lists/dir_list.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;memalign.h&gt;

#include &lt;math.h&gt;
#ifdef _WIN32
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt;
#endif

#if defined(__linux__) &amp;&amp; !defined(ANDROID)
#include &lt;sys/ioctl.h&gt;
#include &lt;scsi/sg.h&gt;
#endif

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#include &lt;windows.h&gt;
#include &lt;winioctl.h&gt;
#include &lt;ntddscsi.h&gt;
#endif

#define CDROM_CUE_TRACK_BYTES 107
#define CDROM_MAX_SENSE_BYTES 16
#define CDROM_MAX_RETRIES 10
#define CDROM_MIN_BUFSIZE 9

typedef enum
{
   DIRECTION_NONE,
   DIRECTION_IN,
   DIRECTION_OUT
} CDROM_CMD_Direction;

void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame)
{
   if (!min || !sec || !frame)
      return;

   *frame  = lba % 75;
   lba    /= 75;
   *sec    = lba % 60;
   lba    /= 60;
   *min    = lba;
}

unsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame)
{
   return (min * 60 + sec) * 75 + frame;
}

void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
{
   if (!min || !sec || !frame)
      return;

   *min   = (*frame == 74) ? (*sec &lt; 59 ? *min : *min + 1) : *min;
   *sec   = (*frame == 74) ? (*sec &lt; 59 ? (*sec + 1) : 0) : *sec;
   *frame = (*frame  &lt; 74) ? (*frame + 1) : 0;
}

#ifdef CDROM_DEBUG
static void cdrom_print_sense_data(const unsigned char *s, size_t len)
{
   unsigned i;
   const char *sense_key_text = NULL;
   unsigned char key;
   unsigned char asc;
   unsigned char ascq;

   if (len &lt; 16)
   {
      printf("[CDROM] Sense data buffer length too small.\n");
      fflush(stdout);
      return;
   }

   key  = s[2] &amp; 0xF;
   asc  = s[12];
   ascq = s[13];

   printf("[CDROM] Sense Data: ");

   for (i = 0; i &lt; MIN(len, 16); i++)
      printf("%02X ", s[i]);

   printf("\n");

   if (s[0] == 0x70)
      printf("[CDROM] CURRENT ERROR:\n");
   if (s[0] == 0x71)
      printf("[CDROM] DEFERRED ERROR:\n");

   switch (key)
   {
      case 0:
         sense_key_text = "NO SENSE";
         break;
      case 1:
         sense_key_text = "RECOVERED ERROR";
         break;
      case 2:
         sense_key_text = "NOT READY";
         break;
      case 3:
         sense_key_text = "MEDIUM ERROR";
         break;
      case 4:
         sense_key_text = "HARDWARE ERROR";
         break;
      case 5:
         sense_key_text = "ILLEGAL REQUEST";
         break;
      case 6:
         sense_key_text = "UNIT ATTENTION";
         break;
      case 7:
         sense_key_text = "DATA PROTECT";
         break;
      case 8:
         sense_key_text = "BLANK CHECK";
         break;
      case 9:
         sense_key_text = "VENDOR SPECIFIC";
         break;
      case 10:
         sense_key_text = "COPY ABORTED";
         break;
      case 11:
         sense_key_text = "ABORTED COMMAND";
         break;
      case 13:
         sense_key_text = "VOLUME OVERFLOW";
         break;
      case 14:
         sense_key_text = "MISCOMPARE";
         break;
   }

   printf("[CDROM] Sense Key: %02X (%s)\n", key, sense_key_text ? sense_key_text : "null");
   printf("[CDROM] ASC: %02X\n", asc);
   printf("[CDROM] ASCQ: %02X\n", ascq);

   switch (key)
   {
      case 2:
      {
         switch (asc)
         {
            case 4:
            {
               switch (ascq)
               {
                  case 1:
                     printf("[CDROM] Description: LOGICAL UNIT IS IN PROCESS OF BECOMING READY\n");
                     break;
                  default:
                     break;
               }

               break;
            }
            case 0x3a:
            {
               switch (ascq)
               {
                  case 0:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT\n");
                     break;
                  case 3:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT - LOADABLE\n");
                     break;
                  case 1:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT - TRAY CLOSED\n");
                     break;
                  case 2:
                     printf("[CDROM] Description: MEDIUM NOT PRESENT - TRAY OPEN\n");
                     break;
                  default:
                     break;
               }

               break;
            }
            default:
               break;
         }
      }
      case 3:
      {
         if (asc == 0x11 &amp;&amp; ascq == 0x5)
            printf("[CDROM] Description: L-EC UNCORRECTABLE ERROR\n");
         break;
      }
      case 5:
      {
         if (asc == 0x20 &amp;&amp; ascq == 0)
            printf("[CDROM] Description: INVALID COMMAND OPERATION CODE\n");
         else if (asc == 0x24 &amp;&amp; ascq == 0)
            printf("[CDROM] Description: INVALID FIELD IN CDB\n");
         else if (asc == 0x26 &amp;&amp; ascq == 0)
            printf("[CDROM] Description: INVALID FIELD IN PARAMETER LIST\n");
         break;
      }
      case 6:
      {
         if (asc == 0x28 &amp;&amp; ascq == 0)
            printf("[CDROM] Description: NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED\n");
         break;
      }
      default:
         break;
   }

   fflush(stdout);
}
#endif

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
{
   DWORD ioctl_bytes;
   BOOL ioctl_rv;
#ifdef CDROM_DEBUG
   clock_t t                       = clock();
   const char *extra               = " ";
   static unsigned char last_min   = 0;
   static unsigned char last_sec   = 0;
   static unsigned char last_frame = 0;

   unsigned lba_cur = cdrom_msf_to_lba(last_min, last_sec, last_frame);
   unsigned lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);
#endif
   struct sptd_with_sense
   {
     SCSI_PASS_THROUGH_DIRECT s;
     UCHAR sense[128];
   } sptd;

   memset(&amp;sptd, 0, sizeof(sptd));

   sptd.s.Length    = sizeof(sptd.s);
   sptd.s.CdbLength = cmd_len;

   switch (dir)
   {
      case DIRECTION_IN:
         sptd.s.DataIn = SCSI_IOCTL_DATA_IN;
         break;
      case DIRECTION_OUT:
         sptd.s.DataIn = SCSI_IOCTL_DATA_OUT;
         break;
      case DIRECTION_NONE:
      default:
         sptd.s.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
         break;
   }

   sptd.s.TimeOutValue       = 5;
   sptd.s.DataBuffer         = buf;
   sptd.s.DataTransferLength = len;
   sptd.s.SenseInfoLength    = sizeof(sptd.sense);
   sptd.s.SenseInfoOffset    = offsetof(struct sptd_with_sense, sense);

   memcpy(sptd.s.Cdb, cmd, cmd_len);

   ioctl_rv = DeviceIoControl(stream-&gt;fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &amp;sptd,
      sizeof(sptd), &amp;sptd, sizeof(sptd), &amp;ioctl_bytes, NULL);

#ifdef CDROM_DEBUG
   if (lba_req &lt; lba_cur)
      extra = " BACKWARDS SECTOR READ";
   else if (lba_req &gt; lba_cur)
      extra = " SKIPPED SECTOR READ";

   if (cmd[0] == 0xB9)
   {
      double time_taken = (double)(((clock() - t) * 1000) / CLOCKS_PER_SEC);
      printf("time taken %f ms for DT received length %ld of %" PRId64 " for %02d:%02d:%02d to %02d:%02d:%02d%s req %d cur %d cur_lba %d\n", time_taken, sptd.s.DataTransferLength, len, cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], extra, lba_req, lba_cur, stream-&gt;cdrom.cur_lba);
      fflush(stdout);
   }

   last_min   = cmd[3];
   last_sec   = cmd[4];
   last_frame = cmd[5];
   increment_msf(&amp;last_min, &amp;last_sec, &amp;last_frame);
#endif

   if (!ioctl_rv || sptd.s.ScsiStatus != 0)
      return 1;

   return 0;
}
#endif

#if defined(__linux__) &amp;&amp; !defined(ANDROID)
static int cdrom_send_command_linux(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
{
   int rv;
   sg_io_hdr_t sgio = {0};

   switch (dir)
   {
      case DIRECTION_IN:
         sgio.dxfer_direction = SG_DXFER_FROM_DEV;
         break;
      case DIRECTION_OUT:
         sgio.dxfer_direction = SG_DXFER_TO_DEV;
         break;
      case DIRECTION_NONE:
      default:
         sgio.dxfer_direction = SG_DXFER_NONE;
         break;
   }

   sgio.interface_id = 'S';
   sgio.cmd_len      = cmd_len;
   sgio.cmdp         = cmd;
   sgio.dxferp       = buf;
   sgio.dxfer_len    = len;
   sgio.sbp          = sense;
   sgio.mx_sb_len    = sense_len;
   sgio.timeout      = 5000;

   rv = ioctl(fileno(stream-&gt;fp), SG_IO, &amp;sgio);

   if (rv == -1 || sgio.info &amp; SG_INFO_CHECK)
      return 1;

   return 0;
}
#endif

static int cdrom_send_command(libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir,
      void *s, size_t len, unsigned char *cmd, size_t cmd_len, size_t skip)
{
   int i, rv = 0;
   int frames = 1;
   unsigned char *xfer_buf     = NULL;
   unsigned char *xfer_buf_pos = xfer_buf;
   unsigned char sense[CDROM_MAX_SENSE_BYTES] = {0};
   unsigned char retries_left  = CDROM_MAX_RETRIES;
   size_t padded_req_bytes;
   size_t copied_bytes         = 0;
   bool read_cd                = false;

   if (!cmd || cmd_len == 0 || cmd_len &lt; CDROM_MIN_BUFSIZE)
      return 1;

   if (cmd[0] == 0xBE || cmd[0] == 0xB9)
   {
      frames = ceil((len + skip) / 2352.0);
      padded_req_bytes = 2352 * frames;
      read_cd = true;
      /* these will be incremented below */
      cmd[6] = cmd[3];
      cmd[7] = cmd[4];
      cmd[8] = cmd[5];
   }
   else
   {
      padded_req_bytes = len + skip;
   }

   xfer_buf     = (unsigned char*)memalign_alloc(4096, padded_req_bytes);
   xfer_buf_pos = xfer_buf;

   if (!xfer_buf)
      return 1;

   memset(xfer_buf, 0, padded_req_bytes);
#ifdef CDROM_DEBUG
   printf("Number of frames to read: %d\n", frames);
   fflush(stdout);
#endif
   for (i = 0; i &lt; frames; i++)
   {
      size_t request_len = padded_req_bytes;
      size_t copy_len = request_len;
      bool cached_read = false;

      if (read_cd)
      {
         unsigned lba_req = 0;

         request_len = 2352;
         copy_len = request_len;

         increment_msf(&amp;cmd[6], &amp;cmd[7], &amp;cmd[8]);

         if (i &gt; 0)
         {
            skip = 0;
            increment_msf(&amp;cmd[3], &amp;cmd[4], &amp;cmd[5]);
         }
         else
         {
            if (skip)
               copy_len -= skip;
         }

         if (i == frames - 1)
         {
            copy_len = len - copied_bytes;
         }

         lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);

         if (stream-&gt;cdrom.last_frame_valid &amp;&amp; lba_req == stream-&gt;cdrom.last_frame_lba)
         {
            /* use cached frame */
            cached_read = true;
#ifdef CDROM_DEBUG
            printf("[CDROM] Using cached frame\n");
            fflush(stdout);
#endif
            /* assumes request_len is always equal to the size of last_frame */
            memcpy(xfer_buf_pos, stream-&gt;cdrom.last_frame, sizeof(stream-&gt;cdrom.last_frame));
         }

      }

#ifdef CDROM_DEBUG
      if (!cached_read)
      {
         unsigned j;

         printf("[CDROM] Send Command: ");

         for (j = 0; j &lt; cmd_len / sizeof(*cmd); j++)
         {
            printf("%02X ", cmd[j]);
         }

         if (len)
            printf("(buffer of size %" PRId64 " with skip bytes %" PRId64 " padded to %" PRId64 "), frame %d\n", len, skip, padded_req_bytes, i);
         else
            printf("\n");

         fflush(stdout);
      }
#endif

retry:
#if defined(__linux__) &amp;&amp; !defined(ANDROID)
      if (cached_read || !cdrom_send_command_linux(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))
#else
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
      if (cached_read || !cdrom_send_command_win32(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))
#endif
#endif
      {
         rv = 0;

         if (s)
         {
#if 0
            printf("offsetting %" PRId64 " from buf, copying at xfer_buf offset %" PRId64 ", copying %" PRId64 " bytes\n", copied_bytes, (xfer_buf_pos + skip) - xfer_buf, copy_len);
            fflush(stdout);
#endif
            memcpy((char*)s + copied_bytes, xfer_buf_pos + skip, copy_len);
            copied_bytes += copy_len;

            if (read_cd &amp;&amp; !cached_read &amp;&amp; request_len &gt;= 2352)
            {
               unsigned frame_end = cdrom_msf_to_lba(cmd[6], cmd[7], cmd[8]);

               /* cache the last received frame */
               memcpy(stream-&gt;cdrom.last_frame, xfer_buf_pos, sizeof(stream-&gt;cdrom.last_frame));
               stream-&gt;cdrom.last_frame_valid = true;
               /* the ending frame is never actually read, so what we really just read is the one right before that */
               stream-&gt;cdrom.last_frame_lba = frame_end - 1;
            }
            else
               stream-&gt;cdrom.last_frame_valid = false;

#if 0
            printf("Frame %d, adding %" PRId64 " to buf_pos, is now %" PRId64 ". skip is %" PRId64 "\n", i, request_len, (xfer_buf_pos + request_len) - xfer_buf, skip);
            fflush(stdout);
#endif
            xfer_buf_pos += request_len;
         }
      }
      else
      {
#ifdef CDROM_DEBUG
         cdrom_print_sense_data(sense, sizeof(sense));
#endif

         /* INQUIRY/TEST/SENSE should never fail, don't retry. */
         /* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */
         if (cmd[0] != 0x0 &amp;&amp; cmd[0] != 0x12 &amp;&amp; cmd[0] != 0x5A &amp;&amp; !(cmd[0] == 0x43 &amp;&amp; cmd[2] == 0x4))
         {
            unsigned char key = sense[2] &amp; 0xF;

            switch (key)
            {
               case 0:
               case 2:
               case 3:
               case 4:
               case 6:
                  if (retries_left)
                  {
   #ifdef CDROM_DEBUG
                     printf("[CDROM] Read Retry...\n");
                     fflush(stdout);
   #endif
                     retries_left--;
                      retro_sleep(1000);
                     goto retry;
                  }
                  else
                  {
                     rv = 1;
   #ifdef CDROM_DEBUG
                     printf("[CDROM] Read retries failed, giving up.\n");
                     fflush(stdout);
   #endif
                  }

                  break;
               default:
                  break;
            }
         }

         rv = 1;
      }
   }

   if (xfer_buf)
      memalign_free(xfer_buf);
   return rv;
}

static const char *cdrom_get_profile(unsigned short profile)
{
   switch (profile)
   {
      case 2:
         return "Removable disk";
      case 8:
         return "CD-ROM";
      case 9:
         return "CD-R";
      case 0xA:
         return "CD-RW";
      case 0x10:
         return "DVD-ROM";
      case 0x11:
         return "DVD-R Sequential Recording";
      case 0x12:
         return "DVD-RAM";
      case 0x13:
         return "DVD-RW Restricted Overwrite";
      case 0x14:
         return "DVD-RW Sequential recording";
      case 0x15:
         return "DVD-R Dual Layer Sequential Recording";
      case 0x16:
         return "DVD-R Dual Layer Jump Recording";
      case 0x17:
         return "DVD-RW Dual Layer";
      case 0x1A:
         return "DVD+RW";
      case 0x1B:
         return "DVD+R";
      case 0x2A:
         return "DVD+RW Dual Layer";
      case 0x2B:
         return "DVD+R Dual Layer";
      case 0x40:
         return "BD-ROM";
      case 0x41:
         return "BD-R SRM";
      case 0x42:
         return "BD-R RRM";
      case 0x43:
         return "BD-RE";
      case 0x50:
         return "HD DVD-ROM";
      case 0x51:
         return "HD DVD-R";
      case 0x52:
         return "HD DVD-RAM";
      case 0x53:
         return "HD DVD-RW";
      case 0x58:
         return "HD DVD-R Dual Layer";
      case 0x5A:
         return "HD DVD-RW Dual Layer";
      default:
         break;
   }

   return "Unknown";
}

/* TODO/FIXME - sense never used here? */
int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len)
{
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x3, 0, 0, 0, 0xFC, 0};
   unsigned char buf[0xFC] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] get sense data status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

#ifdef CDROM_DEBUG
   cdrom_print_sense_data(buf, sizeof(buf));
#endif

   return 0;
}

void cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x10, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[0x14] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config random readable status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i &lt; 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] Random Readable Feature Descriptor: ");

   for (i = 0; i &lt; 12; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   printf("[CDROM] Supported commands: READ CAPACITY, READ (10)\n");
}

void cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x1D, 0, 0, 0, 0, 0xC, 0};
   unsigned char buf[0xC] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config multi-read status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i &lt; 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] Multi-Read Feature Descriptor: ");

   for (i = 0; i &lt; 4; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   printf("[CDROM] Supported commands: READ (10), READ CD, READ DISC INFORMATION, READ TRACK INFORMATION\n");
}

void cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x1E, 0, 0, 0, 0, 0x10, 0};
   unsigned char buf[0x10] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config cd read status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i &lt; 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] CD Read Feature Descriptor: ");

   for (i = 0; i &lt; 8; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   if (buf[8 + 2] &amp; 1)
      printf("(current)\n");

   printf("[CDROM] Supported commands: READ CD, READ CD MSF, READ TOC/PMA/ATIP\n");
}

void cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x0, 0, 0, 0, 0xFF, 0xFA, 0};
   unsigned char buf[0xFFFA] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;

   printf("[CDROM] get current config profiles status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i &lt; 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   printf("[CDROM] Profile List Descriptor: ");

   for (i = 0; i &lt; 4; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   printf("[CDROM] Number of profiles: %u\n", buf[8 + 3] / 4);

   for (i = 0; i &lt; buf[8 + 3] / 4; i++)
   {
      unsigned short profile = (buf[8 + (4 * (i + 1))] &lt;&lt; 8) | buf[8 + (4 * (i + 1)) + 1];

      printf("[CDROM] Profile Number: %04X (%s) ", profile, cdrom_get_profile(profile));

      if (buf[8 + (4 * (i + 1)) + 2] &amp; 1)
         printf("(current)\n");
      else
         printf("\n");
   }
}

void cdrom_get_current_config_core(libretro_vfs_implementation_file *stream)
{
   unsigned char cdb[] = {0x46, 0x2, 0, 0x1, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[20] = {0};
   unsigned intf_std = 0;
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   int i;
   const char *intf_std_name = "Unknown";

   printf("[CDROM] get current config core status code %d\n", rv);

   if (rv)
      return;

   printf("[CDROM] Feature Header: ");

   for (i = 0; i &lt; 8; i++)
   {
      printf("%02X ", buf[i]);
   }

   printf("\n");

   if (buf[6] == 0 &amp;&amp; buf[7] == 8)
      printf("[CDROM] Current Profile: CD-ROM\n");
   else
      printf("[CDROM] Current Profile: %02X%02X\n", buf[6], buf[7]);

   printf("[CDROM] Core Feature Descriptor: ");

   for (i = 0; i &lt; 12; i++)
   {
      printf("%02X ", buf[8 + i]);
   }

   printf("\n");

   intf_std = buf[8 + 4] &lt;&lt; 24 | buf[8 + 5] &lt;&lt; 16 | buf[8 + 6] &lt;&lt; 8 | buf[8 + 7];

   switch (intf_std)
   {
      case 0:
         intf_std_name = "Unspecified";
         break;
      case 1:
         intf_std_name = "SCSI Family";
         break;
      case 2:
         intf_std_name = "ATAPI";
         break;
      case 7:
         intf_std_name = "Serial ATAPI";
         break;
      case 8:
         intf_std_name = "USB";
         break;
      default:
         break;
   }

   printf("[CDROM] Physical Interface Standard: %u (%s)\n", intf_std, intf_std_name);
}

int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *s, size_t len)
{
   /* MMC Command: READ TOC/PMA/ATIP */
   unsigned char cdb[] = {0x43, 0x2, 0x2, 0, 0, 0, 0x1, 0x9, 0x30, 0};
#ifdef CDROM_DEBUG
   unsigned short data_len = 0;
   unsigned char first_session = 0;
   unsigned char last_session = 0;
   int i;
#endif
   int rv;

   if (!s)
      return 1;

   rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), 0);

   if (rv)
     return 1;

#ifdef CDROM_DEBUG
   data_len      = s[0] &lt;&lt; 8 | s[1];
   first_session = s[2];
   last_session  = s[3];

   printf("[CDROM] Data Length: %d\n", data_len);
   printf("[CDROM] First Session: %d\n", first_session);
   printf("[CDROM] Last Session: %d\n", last_session);

   for (i = 0; i &lt; (data_len - 2) / 11; i++)
   {
      unsigned char session_num = s[4 + (i * 11) + 0];
      unsigned char adr         = (s[4 + (i * 11) + 1] &gt;&gt; 4) &amp; 0xF;
#if 0
      unsigned char control     = s[4 + (i * 11) + 1] &amp; 0xF;
#endif
      unsigned char tno         = s[4 + (i * 11) + 2];
      unsigned char point       = s[4 + (i * 11) + 3];
      unsigned char pmin        = s[4 + (i * 11) + 8];
      unsigned char psec        = s[4 + (i * 11) + 9];
      unsigned char pframe      = s[4 + (i * 11) + 10];

      /*printf("i %d control %d adr %d tno %d point %d: ", i, control, adr, tno, point);*/
      /* why is control always 0? */

      if (/*(control == 4 || control == 6) &amp;&amp; */adr == 1 &amp;&amp; tno == 0 &amp;&amp; point &gt;= 1 &amp;&amp; point &lt;= 99)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("Track start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
      }
      else if (/*(control == 4 || control == 6) &amp;&amp; */adr == 1 &amp;&amp; tno == 0 &amp;&amp; point == 0xA0)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("First Track Number: %d ", pmin);
         printf("Disc Type: %d ", psec);
      }
      else if (/*(control == 4 || control == 6) &amp;&amp; */adr == 1 &amp;&amp; tno == 0 &amp;&amp; point == 0xA1)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("Last Track Number: %d ", pmin);
      }
      else if (/*(control == 4 || control == 6) &amp;&amp; */adr == 1 &amp;&amp; tno == 0 &amp;&amp; point == 0xA2)
      {
         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
         printf("Lead-out start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
      }

      printf("\n");
   }

   fflush(stdout);
#endif
   return 0;
}

static int cdrom_read_track_info(libretro_vfs_implementation_file *stream, unsigned char track, cdrom_toc_t *toc)
{
   /* MMC Command: READ TRACK INFORMATION */
   unsigned char cdb[] = {0x52, 0x1, 0, 0, 0, 0, 0, 0x1, 0x80, 0};
   unsigned char buf[384] = {0};
   unsigned lba = 0;
   unsigned track_size = 0;
   int rv;
   ssize_t pregap_lba_len;

   cdb[5] = track;

   if ((rv = cdrom_send_command(stream, DIRECTION_IN, buf,
         sizeof(buf), cdb, sizeof(cdb), 0)))
     return 1;

   memcpy(&amp;lba, buf + 8, 4);
   memcpy(&amp;track_size, buf + 24, 4);

   lba = swap_if_little32(lba);
   track_size = swap_if_little32(track_size);

   /* lba_start may be earlier than the MSF start times seen in read_subq */
   toc-&gt;track[track - 1].lba_start = lba;
   toc-&gt;track[track - 1].track_size = track_size;

   pregap_lba_len = (toc-&gt;track[track - 1].audio ? 0 : (toc-&gt;track[track - 1].lba - toc-&gt;track[track - 1].lba_start));

   toc-&gt;track[track - 1].track_bytes = (track_size - pregap_lba_len) * 2352;
   toc-&gt;track[track - 1].mode = buf[6] &amp; 0xF;

#ifdef CDROM_DEBUG
   printf("[CDROM] Track %d Info: ", track);
   printf("Copy: %d ", (buf[5] &amp; 0x10) &gt; 0);
   printf("Data Mode: %d ", toc-&gt;track[track - 1].mode);
   printf("LBA Start: %d (%d) ", lba, toc-&gt;track[track - 1].lba);
   printf("Track Size: %d\n", track_size);
   fflush(stdout);
#endif

   return 0;
}

int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed)
{
   /* MMC Command: SET CD SPEED */
   unsigned char cmd[] = {0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

   cmd[2] = (speed &gt;&gt; 24) &amp; 0xFF;
   cmd[3] = (speed &gt;&gt; 16) &amp; 0xFF;
   cmd[4] = (speed &gt;&gt; 8) &amp; 0xFF;
   cmd[5] = speed &amp; 0xFF;

   return cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cmd, sizeof(cmd), 0);
}

int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc)
{
   int i;
   unsigned char buf[2352] = {0};
   unsigned short data_len = 0;
   size_t _len = 0, pos = 0;
   int rv = 0;

   if (!out_buf || !out_len || !num_tracks || !toc)
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] Invalid buffer/length pointer for CDROM cue sheet\n");
      fflush(stdout);
#endif
      return 1;
   }

   cdrom_set_read_speed(stream, 0xFFFFFFFF);

   rv = cdrom_read_subq(stream, buf, sizeof(buf));

   if (rv)
      return rv;

   data_len = buf[0] &lt;&lt; 8 | buf[1];

   for (i = 0; i &lt; (data_len - 2) / 11; i++)
   {
      unsigned char adr = (buf[4 + (i * 11) + 1] &gt;&gt; 4) &amp; 0xF;
      unsigned char tno = buf[4 + (i * 11) + 2];
      unsigned char point = buf[4 + (i * 11) + 3];
      unsigned char pmin = buf[4 + (i * 11) + 8];

      if (/*(control == 4 || control == 6) &amp;&amp; */adr == 1 &amp;&amp; tno == 0 &amp;&amp; point == 0xA1)
      {
         *num_tracks = pmin;
#ifdef CDROM_DEBUG
         printf("[CDROM] Number of CDROM tracks: %d\n", *num_tracks);
         fflush(stdout);
#endif
         break;
      }
   }

   if (!*num_tracks || *num_tracks &gt; 99)
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] Invalid number of CDROM tracks: %d\n", *num_tracks);
      fflush(stdout);
#endif
      return 1;
   }

   _len            = CDROM_CUE_TRACK_BYTES * (*num_tracks);
   toc-&gt;num_tracks = *num_tracks;
   *out_buf        = (char*)calloc(1, _len);
   *out_len        = _len;

   for (i = 0; i &lt; (data_len - 2) / 11; i++)
   {
      /*unsigned char session_num = buf[4 + (i * 11) + 0];*/
      unsigned char adr = (buf[4 + (i * 11) + 1] &gt;&gt; 4) &amp; 0xF;
      unsigned char control = buf[4 + (i * 11) + 1] &amp; 0xF;
      unsigned char tno = buf[4 + (i * 11) + 2];
      unsigned char point = buf[4 + (i * 11) + 3];
      /*unsigned char amin = buf[4 + (i * 11) + 4];
      unsigned char asec = buf[4 + (i * 11) + 5];
      unsigned char aframe = buf[4 + (i * 11) + 6];*/
      unsigned char pmin = buf[4 + (i * 11) + 8];
      unsigned char psec = buf[4 + (i * 11) + 9];
      unsigned char pframe = buf[4 + (i * 11) + 10];
      unsigned lba = cdrom_msf_to_lba(pmin, psec, pframe);

      /*printf("i %d control %d adr %d tno %d point %d: amin %d asec %d aframe %d pmin %d psec %d pframe %d\n", i, control, adr, tno, point, amin, asec, aframe, pmin, psec, pframe);*/
      /* why is control always 0? */

      if (/*(control == 4 || control == 6) &amp;&amp; */adr == 1 &amp;&amp; tno == 0 &amp;&amp; point &gt;= 1 &amp;&amp; point &lt;= 99)
      {
         bool audio = false;
         const char *track_type = "MODE1/2352";

         audio = (!(control &amp; 0x4) &amp;&amp; !(control &amp; 0x5));

#ifdef CDROM_DEBUG
         printf("[CDROM] Track %02d CONTROL %01X ADR %01X AUDIO? %d\n", point, control, adr, audio);
         fflush(stdout);
#endif

         toc-&gt;track[point - 1].track_num = point;
         toc-&gt;track[point - 1].min = pmin;
         toc-&gt;track[point - 1].sec = psec;
         toc-&gt;track[point - 1].frame = pframe;
         toc-&gt;track[point - 1].lba = lba;
         toc-&gt;track[point - 1].audio = audio;

         cdrom_read_track_info(stream, point, toc);

         if (audio)
            track_type = "AUDIO";
         else if (toc-&gt;track[point - 1].mode == 1)
            track_type = "MODE1/2352";
         else if (toc-&gt;track[point - 1].mode == 2)
            track_type = "MODE2/2352";

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
         pos += snprintf(*out_buf + pos, _len - pos, "FILE \"cdrom://%c:/drive-track%02d.bin\" BINARY\n", cdrom_drive, point);
#else
         pos += snprintf(*out_buf + pos, _len - pos, "FILE \"cdrom://drive%c-track%02d.bin\" BINARY\n", cdrom_drive, point);
#endif
         pos += snprintf(*out_buf + pos, _len - pos, "  TRACK %02d %s\n", point, track_type);

         {
            unsigned pregap_lba_len = toc-&gt;track[point - 1].lba - toc-&gt;track[point - 1].lba_start;

            if (toc-&gt;track[point - 1].audio &amp;&amp; pregap_lba_len &gt; 0)
            {
               unsigned char min = 0;
               unsigned char sec = 0;
               unsigned char frame = 0;

               cdrom_lba_to_msf(pregap_lba_len, &amp;min, &amp;sec, &amp;frame);

               pos += snprintf(*out_buf + pos, _len - pos, "    INDEX 00 00:00:00\n");
               pos += snprintf(*out_buf + pos, _len - pos, "    INDEX 01 %02u:%02u:%02u\n", (unsigned)min, (unsigned)sec, (unsigned)frame);
            }
            else
               pos += snprintf(*out_buf + pos, _len - pos, "    INDEX 01 00:00:00\n");
         }
      }
   }

   return 0;
}

/* needs 32 bytes for full vendor, product and version */
int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *s, size_t len, bool *is_cdrom)
{
   /* MMC Command: INQUIRY */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x12, 0, 0, 0, 0xff, 0};
   unsigned char buf[256] = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
   bool cdrom = false;

   if (rv)
      return 1;

   if (s &amp;&amp; len &gt;= 32)
   {
      memset(s, 0, len);
      /* vendor */
      memcpy(s, buf + 8, 8);
      s[8] = ' ';
      /* product */
      memcpy(s + 9, buf + 16, 16);
      s[25] = ' ';
      /* version */
      memcpy(s + 26, buf + 32, 4);
   }

   cdrom = (buf[0] == 5);

   if (is_cdrom &amp;&amp; cdrom)
      *is_cdrom = true;

#ifdef CDROM_DEBUG
   printf("[CDROM] Device Model: %s (is CD-ROM? %s)\n", s, (cdrom ? "yes" : "no"));
#endif
   return 0;
}

int cdrom_read(libretro_vfs_implementation_file *stream,
      cdrom_group_timeouts_t *timeouts, unsigned char min,
      unsigned char sec, unsigned char frame, void *s,
      size_t len, size_t skip)
{
   /* MMC Command: READ CD MSF */
   unsigned char cdb[] = {0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0xF8, 0, 0};
   int rv;
   double frames = ceil((len + skip) / 2352.0);
   unsigned frame_end = cdrom_msf_to_lba(min, sec, frame) + frames;

   cdb[3] = min;
   cdb[4] = sec;
   cdb[5] = frame;

   if (frames &lt;= 1)
   {
      cdrom_lba_to_msf(frame_end, &amp;cdb[6], &amp;cdb[7], &amp;cdb[8]);
#ifdef CDROM_DEBUG
      printf("[CDROM] single-frame read: %d %d %d skip %" PRId64 "\n", cdb[3], cdb[4], cdb[5], skip);
      fflush(stdout);
#endif
   }
   else
   {
      cdrom_lba_to_msf(frame_end, &amp;cdb[6], &amp;cdb[7], &amp;cdb[8]);

#ifdef CDROM_DEBUG
      printf("[CDROM] multi-frame read: %d sectors starting from %02d:%02d:%02d skip %" PRId64 "\n", (int)frames, cdb[3], cdb[4], cdb[5], skip);
      fflush(stdout);
#endif
   }

   /* regardless of the length specified here, a new buffer will be allocated and padded to a sector multiple inside cdrom_send_command */
   rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), skip);

#ifdef CDROM_DEBUG
   printf("[CDROM] read msf status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
   {
      stream-&gt;cdrom.last_frame_valid = false;
      return 1;
   }

   return 0;
}

int cdrom_stop(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: START STOP UNIT */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x0, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] stop status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

int cdrom_unlock(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: PREVENT ALLOW MEDIUM REMOVAL */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1E, 0, 0, 0, 0x2, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] persistent prevent clear status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   cdb[4] = 0x0;

   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] prevent clear status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

int cdrom_open_tray(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: START STOP UNIT */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x2, 0};
   int rv;

   cdrom_unlock(stream);
   cdrom_stop(stream);

   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] open tray status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

int cdrom_close_tray(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: START STOP UNIT */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x3, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] close tray status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return 1;

   return 0;
}

struct string_list* cdrom_get_available_drives(void)
{
   struct string_list *list = string_list_new();
#if defined(__linux__) &amp;&amp; !defined(ANDROID)
   struct string_list *dir_list = dir_list_new("/dev", NULL, false, false, false, false);
   int i;
   bool found = false;

   if (!dir_list)
      return list;

   for (i = 0; i &lt; (int)dir_list-&gt;size; i++)
   {
      if (string_starts_with_size(dir_list-&gt;elems[i].data, "/dev/sg",
               STRLEN_CONST("/dev/sg")))
      {
         char drive_string[33];
         libretro_vfs_implementation_file *stream;
         char drive_model[32]             = {0};
         union string_list_elem_attr attr = {0};
         int dev_index                    = 0;
         RFILE *file                      = filestream_open(
               dir_list-&gt;elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
         bool is_cdrom                    = false;

         found = true;

         if (!file)
         {
#ifdef CDROM_DEBUG
            printf("[CDROM] Could not open %s, please check permissions.\n", dir_list-&gt;elems[i].data);
            fflush(stdout);
#endif
            continue;
         }

         stream = filestream_get_vfs_handle(file);
         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &amp;is_cdrom);
         filestream_close(file);

         if (!is_cdrom)
            continue;

         sscanf(dir_list-&gt;elems[i].data + STRLEN_CONST("/dev/sg"),
               "%d", &amp;dev_index);

         dev_index = '0' + dev_index;
         attr.i    = dev_index;

         if (!string_is_empty(drive_model))
            strlcpy(drive_string, drive_model, sizeof(drive_string));
         else
            strlcpy(drive_string, "Unknown Drive", sizeof(drive_string));

         string_list_append(list, drive_string, attr);
      }
   }

   if (!found)
   {
      char *buf   = NULL;
      int64_t len = 0;

      if (filestream_read_file("/proc/modules", (void**)&amp;buf, &amp;len))
      {
#ifdef CDROM_DEBUG
         bool found              = false;
#endif
         struct string_list mods = {0};

         string_list_initialize(&amp;mods);

         if (string_split_noalloc(&amp;mods, buf, "\n"))
         {
            for (i = 0; i &lt; (int)mods.size; i++)
            {
               if (strcasestr(mods.elems[i].data, "sg "))
               {
#ifdef CDROM_DEBUG
                  found = true;
#endif
                  break;
               }
            }
         }
         string_list_deinitialize(&amp;mods);
         free(buf);

#ifdef CDROM_DEBUG
         if (found)
         {
            printf("[CDROM] No sg devices found but kernel module is loaded.\n");
            fflush(stdout);
         }
         else
         {
            printf("[CDROM] No sg devices found and sg kernel module is not loaded.\n");
            fflush(stdout);
         }
#endif
      }
#ifdef CDROM_DEBUG
      else
      {
         printf("[CDROM] No sg devices found, could not check if sg kernel module is loaded.\n");
         fflush(stdout);
      }
#endif
   }

   string_list_free(dir_list);
#endif
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
   DWORD drive_mask = GetLogicalDrives();
   int i;

   for (i = 0; i &lt; (int)(sizeof(DWORD) * 8); i++)
   {
      char path[]       = {"a:\\"};
      char cdrom_path[] = {"cdrom://a:/drive-track01.bin"};

      path[0]          += i;
      cdrom_path[8]    += i;

      /* this drive letter doesn't exist */
      if (!(drive_mask &amp; (1 &lt;&lt; i)))
         continue;

      if (GetDriveType(path) != DRIVE_CDROM)
         continue;

      {
         char drive_string[33];
         libretro_vfs_implementation_file *stream;
         bool is_cdrom                    = false;
         char drive_model[32]             = {0};
         union string_list_elem_attr attr = {0};
         RFILE *file = filestream_open(cdrom_path, RETRO_VFS_FILE_ACCESS_READ, 0);
         if (!file)
            continue;

         stream = filestream_get_vfs_handle(file);
         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &amp;is_cdrom);
         filestream_close(file);

         if (!is_cdrom)
            continue;

         attr.i = path[0];

         if (!string_is_empty(drive_model))
            strlcpy(drive_string, drive_model, sizeof(drive_string));
         else
            strlcpy(drive_string, "Unknown Drive", sizeof(drive_string));

         string_list_append(list, drive_string, attr);
      }
   }
#endif
   return list;
}

bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: TEST UNIT READY */
   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x00, 0, 0, 0, 0, 0};
   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] media inserted status code %d\n", rv);
   fflush(stdout);
#endif

   /* Will also return false if the drive is simply not ready yet (tray open, disc spinning back up after tray closed etc).
    * Command will not block or wait for media to become ready. */
   if (rv)
      return false;

   return true;
}

bool cdrom_drive_has_media(const char drive)
{
   RFILE *file;
   char cdrom_path_bin[256] = {0};

   cdrom_device_fillpath(cdrom_path_bin, sizeof(cdrom_path_bin), drive, 1, false);

   file = filestream_open(cdrom_path_bin, RETRO_VFS_FILE_ACCESS_READ, 0);

   if (file)
   {
      libretro_vfs_implementation_file *stream = filestream_get_vfs_handle(file);
      bool has_media = cdrom_is_media_inserted(stream);

      filestream_close(file);

      return has_media;
   }

   return false;
}

bool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled)
{
   int i;
   /* MMC Command: MODE SENSE (10) and MODE SELECT (10) */
   unsigned char cdb_sense_changeable[] = {0x5A, 0, 0x48, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char cdb_sense[]            = {0x5A, 0, 0x8, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char cdb_select[]           = {0x55, 0x10, 0, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[20]                = {0};
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf),
         cdb_sense_changeable, sizeof(cdb_sense_changeable), 0);

#ifdef CDROM_DEBUG
   printf("[CDROM] mode sense changeable status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

   if (!(buf[10] &amp; 0x1))
   {
      /* RCD (read cache disable) bit is not changeable */
#ifdef CDROM_DEBUG
      printf("[CDROM] RCD (read cache disable) bit is not changeable.\n");
      fflush(stdout);
#endif
      return false;
   }

   memset(buf, 0, sizeof(buf));

   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb_sense, sizeof(cdb_sense), 0);

#ifdef CDROM_DEBUG
   printf("mode sense status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

#ifdef CDROM_DEBUG
   printf("Mode sense data for caching mode page: ");

   for (i = 0; i &lt; (int)sizeof(buf); i++)
      printf("%02X ", buf[i]);

   printf("\n");
   fflush(stdout);
#endif

   /* "When transferred during execution of the MODE SELECT (10) command, Mode Data Length is reserved." */
   for (i = 0; i &lt; 8; i++)
      buf[i] = 0;

   if (enabled)
      buf[10] &amp;= ~1;
   else
      buf[10] |=  1;

   rv = cdrom_send_command(stream, DIRECTION_OUT, buf, sizeof(buf), cdb_select, sizeof(cdb_select), 0);

#ifdef CDROM_DEBUG
   printf("mode select status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

   return true;
}

bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts)
{
   /* MMC Command: MODE SENSE (10) */
   int rv;
   unsigned char cdb[]   = {0x5A, 0, 0x1D, 0, 0, 0, 0, 0, 0x14, 0};
   unsigned char buf[20] = {0};
   unsigned short g1     = 0;
   unsigned short g2     = 0;
   unsigned short g3     = 0;

   if (!timeouts)
      return false;

   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);

#ifdef CDROM_DEBUG
   printf("get timeouts status code %d\n", rv);
   fflush(stdout);
#endif

   if (rv)
      return false;

   g1 = buf[14] &lt;&lt; 8 | buf[15];
   g2 = buf[16] &lt;&lt; 8 | buf[17];
   g3 = buf[18] &lt;&lt; 8 | buf[19];

#ifdef CDROM_DEBUG
   {
      int i;

      printf("Mode sense data for timeout groups: ");

      for (i = 0; i &lt; (int)sizeof(buf); i++)
         printf("%02X ", buf[i]);

      printf("\n");

      printf("Group 1 Timeout: %d\n", g1);
      printf("Group 2 Timeout: %d\n", g2);
      printf("Group 3 Timeout: %d\n", g3);

      fflush(stdout);
   }
#endif

   timeouts-&gt;g1_timeout = g1;
   timeouts-&gt;g2_timeout = g2;
   timeouts-&gt;g3_timeout = g3;

   return true;
}

bool cdrom_has_atip(libretro_vfs_implementation_file *stream)
{
   /* MMC Command: READ TOC/PMA/ATIP */
   unsigned char cdb[]     = {0x43, 0x2, 0x4, 0, 0, 0, 0, 0x9, 0x30, 0};
   unsigned char buf[32]   = {0};
   unsigned short atip_len = 0;
   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);

   if (rv)
     return false;

   atip_len = buf[0] &lt;&lt; 8 | buf[1];

#ifdef CDROM_DEBUG
   printf("ATIP Length %d, Disc Type %d, Disc Sub-Type %d\n",
         atip_len,
         (buf[6]  &gt;&gt; 6) &amp; 0x1,
         ((buf[6] &gt;&gt; 5) &amp; 0x1) &lt;&lt; 2 | ((buf[6] &gt;&gt; 4) &amp; 0x1) &lt;&lt; 1 | ((buf[6] &gt;&gt; 3) &amp; 0x1) &lt;&lt; 0);
#endif

   if (atip_len &lt; 5)
      return false;

   return true;
}

size_t cdrom_device_fillpath(char *s, size_t len, char drive, unsigned char track, bool is_cue)
{
   if (s &amp;&amp; len &gt; 0)
   {
      if (is_cue)
      {
#ifdef _WIN32
         size_t _len = strlcpy(s, "cdrom://", len);
         if (len &gt; _len)
            s[_len++] = drive;
         _len += strlcpy(s + _len, ":/drive.cue", len - _len);
         return _len;
#else
#ifdef __linux__
         size_t _len = strlcpy(s, "cdrom://drive", len);
         if (len &gt; _len + 1)
         {
            s[_len++] = drive;
            s[_len]   = '\0';
         }
         _len += strlcpy(s + _len, ".cue", len - _len);
         return _len;
#endif
#endif
      }
      else
      {
#ifdef _WIN32
         size_t _len = strlcpy(s, "cdrom://", len);
         if (len &gt; _len + 1)
         {
            s[_len++] = drive;
            s[_len]   = '\0';
         }
         _len += snprintf(s + _len, len - _len, ":/drive-track%02d.bin", track);
         return _len;
#else
#ifdef __linux__
         size_t _len = strlcpy(s, "cdrom://drive", len);
         if (len &gt; _len)
            s[_len++] = drive;
         _len += snprintf(s + _len, len - _len, "-track%02d.bin", track);
         return _len;
#endif
#endif
      }
   }
   return 0;
}</pre>
<h2>./include/libretro-common/compat/compat_fnmatch.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_fnmatch.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stddef.h&gt;

#include &lt;compat/fnmatch.h&gt;

/* Implementation of fnmatch(3) so it can be
 * distributed to non *nix platforms.
 *
 * No flags are implemented ATM.
 * We don't use them. Add flags as needed. */

int rl_fnmatch(const char *pattern, const char *string, int flags)
{
   int rv;
   const char *c = NULL;
   int charmatch = 0;

   for (c = pattern; *c != '\0'; c++)
   {
      /* String ended before pattern */
      if ((*c != '*') &amp;&amp; (*string == '\0'))
         return FNM_NOMATCH;

      switch (*c)
      {
         /* Match any number of unknown chars */
         case '*':
            /* Find next node in the pattern
             * ignoring multiple asterixes
             */
            do {
               c++;
               if (*c == '\0')
                  return 0;
            } while (*c == '*');

            /* Match the remaining pattern
             * ignoring more and more characters. */
            do {
               /* We reached the end of the string without a
                * match. There is a way to optimize this by
                * calculating the minimum chars needed to
                * match the remaining pattern but I don't
                * think it is worth the work ATM.
                */
               if (*string == '\0')
                  return FNM_NOMATCH;

               rv = rl_fnmatch(c, string, flags);
               string++;
            } while (rv != 0);

            return 0;
            /* Match char from list */
         case '[':
            charmatch = 0;
            for (c++; *c != ']'; c++)
            {
               /* Bad format */
               if (*c == '\0')
                  return FNM_NOMATCH;

               /* Match already found */
               if (charmatch)
                  continue;

               if (*c == *string)
                  charmatch = 1;
            }

            /* No match in list */
            if (!charmatch)
               return FNM_NOMATCH;

            string++;
            break;
            /* Has any character */
         case '?':
            string++;
            break;
            /* Match following character verbatim */
         case '\\':
            c++;
            /* Dangling escape at end of pattern.
             * FIXME: Was c == '\0' (makes no sense).
             * Not sure if c == NULL or *c == '\0'
             * is intended. Assuming *c due to c++ right before. */
            if (*c == '\0')
               return FNM_NOMATCH;
         default:
            if (*c != *string)
               return FNM_NOMATCH;
            string++;
      }
   }

   /* End of string and end of pattend */
   if (*string == '\0')
      return 0;
   return FNM_NOMATCH;
}</pre>
<h2>./include/libretro-common/compat/compat_getopt.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_getopt.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;ctype.h&gt;

#include &lt;string.h&gt;
#include &lt;boolean.h&gt;
#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;retro_miscellaneous.h&gt;

#include &lt;compat/getopt.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;compat/strcasestr.h&gt;
#include &lt;compat/posix_string.h&gt;

char *optarg;
int optind, opterr, optopt;

static bool is_short_option(const char *str)
{
   return str[0] == '-' &amp;&amp; str[1] != '-';
}

static bool is_long_option(const char *str)
{
   return str[0] == '-' &amp;&amp; str[1] == '-';
}

static int find_short_index(char * const *argv)
{
   int idx;
   for (idx = 0; argv[idx]; idx++)
   {
      if (is_short_option(argv[idx]))
         return idx;
   }

   return -1;
}

static int find_long_index(char * const *argv)
{
   int idx;
   for (idx = 0; argv[idx]; idx++)
   {
      if (is_long_option(argv[idx]))
         return idx;
   }

   return -1;
}

static int parse_short(const char *optstring, char * const *argv)
{
   bool extra_opt, takes_arg, embedded_arg;
   const char *opt = NULL;
   char        arg = argv[0][1];

   if (arg == ':')
      return '?';

   opt = strchr(optstring, arg);
   if (!opt)
      return '?';

   extra_opt = argv[0][2];
   takes_arg = opt[1] == ':';

   /* If we take an argument, and we see additional characters,
    * this is in fact the argument (i.e. -cfoo is same as -c foo). */
   embedded_arg = extra_opt &amp;&amp; takes_arg;

   if (takes_arg)
   {
      if (embedded_arg)
      {
         optarg = argv[0] + 2;
         optind++;
      }
      else
      {
         optarg = argv[1];
         optind += 2;
      }

      return optarg ? opt[0] : '?';
   }

   if (embedded_arg)
   {
      /* If we see additional characters,
       * and they don't take arguments, this
       * means we have multiple flags in one. */
      memmove(&amp;argv[0][1], &amp;argv[0][2], strlen(&amp;argv[0][2]) + 1);
      return opt[0];
   }

   optind++;
   return opt[0];
}

static int parse_long(const struct option *longopts, char * const *argv)
{
   size_t i;
   char *save  = NULL;
   char *argv0 = strdup(&amp;argv[0][2]);
   char *token = strtok_r(argv0, "=", &amp;save);
   const struct option *opt = NULL;

   for (i = 0; longopts[i].name; i++)
   {
      if (token &amp;&amp; !strcmp(longopts[i].name, token))
      {
         opt = &amp;longopts[i];
         break;
      }
   }

   free(argv0);
   argv0 = NULL;

   if (!opt)
      return '?';

   /* Handle args with '=' instead of space */
   if (opt-&gt;has_arg)
   {
      char *special_arg = strchr(argv[0], '=');
      if (special_arg)
      {
         optarg = ++special_arg;
         optind++;
         return opt-&gt;val;
      }
   }

   /* getopt_long has an "optional" arg, but we don't bother with that. */
   if (opt-&gt;has_arg &amp;&amp; !argv[1])
      return '?';

   if (opt-&gt;has_arg)
   {
      optarg = argv[1];
      optind += 2;
   }
   else
      optind++;

   if (opt-&gt;flag)
   {
      *opt-&gt;flag = opt-&gt;val;
      return 0;
   }

   return opt-&gt;val;
}

static void shuffle_block(char **begin, char **last, char **end)
{
   ptrdiff_t    len = last - begin;
   const char **tmp = (const char**)calloc(len, sizeof(const char*));

   memcpy((void*)tmp, begin, len * sizeof(const char*));
   memmove(begin, last, (end - last) * sizeof(const char*));
   memcpy(end - len, tmp, len * sizeof(const char*));

   free((void*)tmp);
}

int getopt_long(int argc, char *argv[],
      const char *optstring, const struct option *longopts, int *longindex)
{
   int short_index, long_index;

   if (optind == 0)
      optind = 1;

   if (argc &lt; 2)
      return -1;

   short_index = find_short_index(&amp;argv[optind]);
   long_index  = find_long_index(&amp;argv[optind]);

   /* We're done here. */
   if (short_index == -1 &amp;&amp; long_index == -1)
      return -1;

   /* Reorder argv so that non-options come last.
    * Non-POSIXy, but that's what getopt does by default. */
   if ((short_index &gt; 0) &amp;&amp; ((short_index &lt; long_index) || (long_index == -1)))
   {
      shuffle_block(&amp;argv[optind], &amp;argv[optind + short_index], &amp;argv[argc]);
      short_index = 0;
   }
   else if ((long_index &gt; 0) &amp;&amp; ((long_index &lt; short_index)
            || (short_index == -1)))
   {
      shuffle_block(&amp;argv[optind], &amp;argv[optind + long_index], &amp;argv[argc]);
      long_index = 0;
   }

   if (short_index == 0)
      return parse_short(optstring, &amp;argv[optind]);
   if (long_index == 0)
      return parse_long(longopts, &amp;argv[optind]);

   return '?';
}</pre>
<h2>./include/libretro-common/compat/compat_ifaddrs.c</h2>
<pre>/*
Copyright (c) 2013, Kenneth MacKay
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include &lt;compat/ifaddrs.h&gt;

#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;
#include &lt;errno.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;netpacket/packet.h&gt;
#include &lt;net/if_arp.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;linux/netlink.h&gt;
#include &lt;linux/rtnetlink.h&gt;

typedef struct NetlinkList
{
    struct NetlinkList *m_next;
    struct nlmsghdr *m_data;
    unsigned int m_size;
} NetlinkList;

static int netlink_socket(void)
{
   struct sockaddr_nl l_addr;
   int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

   if (l_socket &lt; 0)
      return -1;

   memset(&amp;l_addr, 0, sizeof(l_addr));
   l_addr.nl_family = AF_NETLINK;

   if (bind(l_socket, (struct sockaddr *)&amp;l_addr, sizeof(l_addr)) &lt; 0)
   {
      close(l_socket);
      return -1;
   }

   return l_socket;
}

static int netlink_send(int p_socket, int p_request)
{
   struct
   {
      struct nlmsghdr m_hdr;
      struct rtgenmsg m_msg;
   } l_data;
   struct sockaddr_nl l_addr;

   memset(&amp;l_data, 0, sizeof(l_data));

   l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
   l_data.m_hdr.nlmsg_type = p_request;
   l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
   l_data.m_hdr.nlmsg_pid = 0;
   l_data.m_hdr.nlmsg_seq = p_socket;
   l_data.m_msg.rtgen_family = AF_UNSPEC;

   memset(&amp;l_addr, 0, sizeof(l_addr));
   l_addr.nl_family = AF_NETLINK;
   return (sendto(p_socket, &amp;l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&amp;l_addr, sizeof(l_addr)));
}

static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
{
   struct msghdr l_msg;
   struct iovec l_iov = { p_buffer, p_len };
   struct sockaddr_nl l_addr;

   for (;;)
   {
      int l_result;

      l_msg.msg_name       = (void *)&amp;l_addr;
      l_msg.msg_namelen    = sizeof(l_addr);
      l_msg.msg_iov        = &amp;l_iov;
      l_msg.msg_iovlen     = 1;
      l_msg.msg_control    = NULL;
      l_msg.msg_controllen = 0;
      l_msg.msg_flags      = 0;

      l_result             = recvmsg(p_socket, &amp;l_msg, 0);

      if (l_result &lt; 0)
      {
         if (errno == EINTR)
            continue;
         return -2;
      }

      if (l_msg.msg_flags &amp; MSG_TRUNC) /* buffer too small */
         return -1;
      return l_result;
   }
}

static struct nlmsghdr *getNetlinkResponse(int p_socket,
      int *p_size, int *p_done)
{
   size_t l_size  = 4096;
   void *l_buffer = NULL;

   for (;;)
   {
      int l_read;

      free(l_buffer);
      l_buffer = malloc(l_size);
      if (!l_buffer)
         return NULL;

      l_read  = netlink_recv(p_socket, l_buffer, l_size);
      *p_size = l_read;

      if (l_read == -2)
      {
         free(l_buffer);
         return NULL;
      }

      if (l_read &gt;= 0)
      {
         pid_t l_pid = getpid();
         struct nlmsghdr *l_hdr;

         for (l_hdr = (struct nlmsghdr *)l_buffer;
               NLMSG_OK(l_hdr, (unsigned int)l_read);
               l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
         {
            if (  (pid_t)l_hdr-&gt;nlmsg_pid != l_pid || 
                  (int)l_hdr-&gt;nlmsg_seq   != p_socket)
               continue;

            if (l_hdr-&gt;nlmsg_type == NLMSG_DONE)
            {
               *p_done = 1;
               break;
            }

            if (l_hdr-&gt;nlmsg_type == NLMSG_ERROR)
            {
               free(l_buffer);
               return NULL;
            }
         }
         return l_buffer;
      }

      l_size *= 2;
   }
}

static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
{
   NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList));
   if (!l_item)
      return NULL;

   l_item-&gt;m_next = NULL;
   l_item-&gt;m_data = p_data;
   l_item-&gt;m_size = p_size;
   return l_item;
}

static void freeResultList(NetlinkList *p_list)
{
   NetlinkList *l_cur;

   while (p_list)
   {
      l_cur = p_list;
      p_list = p_list-&gt;m_next;
      free(l_cur-&gt;m_data);
      free(l_cur);
   }
}

static NetlinkList *getResultList(int p_socket, int p_request)
{
   int l_size;
   NetlinkList *l_list = NULL;
   NetlinkList *l_end  = NULL;
   int l_done          = 0;

   if (netlink_send(p_socket, p_request) &lt; 0)
      return NULL;

   while (!l_done)
   {
      NetlinkList *l_item    = NULL;
      struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &amp;l_size, &amp;l_done);
      if (!l_hdr)
         goto error;

      l_item = newListItem(l_hdr, l_size);
      if (!l_item)
         goto error;

      if (!l_list)
         l_list        = l_item;
      else
         l_end-&gt;m_next = l_item;
      l_end            = l_item;
   }

   return l_list;

error:
   freeResultList(l_list);
   return NULL;
}

static size_t maxSize(size_t a, size_t b)
{
   return (a &gt; b ? a : b);
}

static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
{
   switch(p_family)
   {
      case AF_INET:
         return sizeof(struct sockaddr_in);
      case AF_INET6:
         return sizeof(struct sockaddr_in6);
      case AF_PACKET:
         return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
      default:
         break;
   }

   return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
}

static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
{
   switch(p_family)
   {
      case AF_INET:
         memcpy(&amp;((struct sockaddr_in*)p_dest)-&gt;sin_addr, p_data, p_size);
         break;
      case AF_INET6:
         memcpy(&amp;((struct sockaddr_in6*)p_dest)-&gt;sin6_addr, p_data, p_size);
         break;
      case AF_PACKET:
         memcpy(((struct sockaddr_ll*)p_dest)-&gt;sll_addr, p_data, p_size);
         ((struct sockaddr_ll*)p_dest)-&gt;sll_halen = p_size;
         break;
      default:
         memcpy(p_dest-&gt;sa_data, p_data, p_size);
         break;
   }
   p_dest-&gt;sa_family = p_family;
}

static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
{
   if (!*p_resultList)
      *p_resultList = p_entry;
   else
   {
      struct ifaddrs *l_cur = *p_resultList;
      while (l_cur-&gt;ifa_next)
         l_cur = l_cur-&gt;ifa_next;
      l_cur-&gt;ifa_next = p_entry;
   }
}

static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
{
   struct ifaddrs *l_entry  = NULL;
   struct rtattr *l_rta     = NULL;
   struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
   size_t l_nameSize        = 0;
   size_t l_addrSize        = 0;
   size_t l_dataSize        = 0;
   size_t l_rtaSize         = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));

   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
      switch(l_rta-&gt;rta_type)
      {
         case IFLA_ADDRESS:
         case IFLA_BROADCAST:
            l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
            break;
         case IFLA_IFNAME:
            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
            break;
         case IFLA_STATS:
            l_dataSize += NLMSG_ALIGN(l_rtaSize);
            break;
         default:
            break;
      }
   }

   l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
   if (!l_entry)
      return -1;

   memset(l_entry, 0, sizeof(struct ifaddrs));
   l_entry-&gt;ifa_name = "";

   char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
   char *l_name = l_index + sizeof(int);
   char *l_addr = l_name + l_nameSize;
   char *l_data = l_addr + l_addrSize;

   /* save the interface index so we can look 
    * it up when handling the addresses. */
   memcpy(l_index, &amp;l_info-&gt;ifi_index, sizeof(int));

   l_entry-&gt;ifa_flags = l_info-&gt;ifi_flags;

   l_rtaSize          = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));

   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      void      *l_rtaData = RTA_DATA(l_rta);
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);

      switch(l_rta-&gt;rta_type)
      {
         case IFLA_ADDRESS:
         case IFLA_BROADCAST:
            {
               size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
               makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
               ((struct sockaddr_ll *)l_addr)-&gt;sll_ifindex = l_info-&gt;ifi_index;
               ((struct sockaddr_ll *)l_addr)-&gt;sll_hatype = l_info-&gt;ifi_type;
               if (l_rta-&gt;rta_type == IFLA_ADDRESS)
                  l_entry-&gt;ifa_addr      = (struct sockaddr *)l_addr;
               else
                  l_entry-&gt;ifa_broadaddr = (struct sockaddr *)l_addr;
               l_addr += NLMSG_ALIGN(l_addrLen);
               break;
            }
         case IFLA_IFNAME:
            strncpy(l_name, l_rtaData, l_rtaDataSize);
            l_name[l_rtaDataSize] = '\0';
            l_entry-&gt;ifa_name = l_name;
            break;
         case IFLA_STATS:
            memcpy(l_data, l_rtaData, l_rtaDataSize);
            l_entry-&gt;ifa_data = l_data;
            break;
         default:
            break;
      }
   }

   addToEnd(p_resultList, l_entry);
   return 0;
}

static struct ifaddrs *findInterface(int p_index,
      struct ifaddrs **p_links, int p_numLinks)
{
   int l_num             = 0;
   struct ifaddrs *l_cur = *p_links;

   while (l_cur &amp;&amp; l_num &lt; p_numLinks)
   {
      int l_index;
      char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);

      memcpy(&amp;l_index, l_indexPtr, sizeof(int));
      if (l_index == p_index)
         return l_cur;

      l_cur = l_cur-&gt;ifa_next;
      ++l_num;
   }
   return NULL;
}

static int interpretAddr(struct nlmsghdr *p_hdr,
      struct ifaddrs **p_resultList, int p_numLinks)
{
   struct rtattr *l_rta;
   size_t l_rtaSize;
   size_t l_nameSize           = 0;
   size_t l_addrSize           = 0;
   int l_addedNetmask          = 0;
   struct ifaddrmsg *l_info    = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
   struct ifaddrs *l_interface = findInterface(l_info-&gt;ifa_index, p_resultList, p_numLinks);

   if (l_info-&gt;ifa_family == AF_PACKET)
      return 0;

   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));

   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);

      switch(l_rta-&gt;rta_type)
      {
         case IFA_ADDRESS:
         case IFA_LOCAL:
            if ((l_info-&gt;ifa_family == AF_INET || l_info-&gt;ifa_family == AF_INET6) &amp;&amp; !l_addedNetmask)
            {
               /* make room for netmask */
               l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info-&gt;ifa_family, l_rtaDataSize));
               l_addedNetmask = 1;
            }
         case IFA_BROADCAST:
            l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info-&gt;ifa_family, l_rtaDataSize));
            break;
         case IFA_LABEL:
            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
            break;
         default:
            break;
      }
   }

   struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
   if (!l_entry)
      return -1;

   memset(l_entry, 0, sizeof(struct ifaddrs));
   l_entry-&gt;ifa_name = (l_interface ? l_interface-&gt;ifa_name : "");

   char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
   char *l_addr = l_name + l_nameSize;

   l_entry-&gt;ifa_flags = l_info-&gt;ifa_flags;
   if (l_interface)
      l_entry-&gt;ifa_flags |= l_interface-&gt;ifa_flags;

   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
         l_rta = RTA_NEXT(l_rta, l_rtaSize))
   {
      void *l_rtaData = RTA_DATA(l_rta);
      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
      switch(l_rta-&gt;rta_type)
      {
         case IFA_ADDRESS:
         case IFA_BROADCAST:
         case IFA_LOCAL:
            {
               size_t l_addrLen = calcAddrLen(l_info-&gt;ifa_family, l_rtaDataSize);
               makeSockaddr(l_info-&gt;ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
               if (l_info-&gt;ifa_family == AF_INET6)
               {
                  if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
                     ((struct sockaddr_in6 *)l_addr)-&gt;sin6_scope_id = l_info-&gt;ifa_index;
               }

               if (l_rta-&gt;rta_type == IFA_ADDRESS)
               {
                  /* apparently in a point-to-point network IFA_ADDRESS
                   * contains the dest address and IFA_LOCAL contains the local address */
                  if (l_entry-&gt;ifa_addr)
                     l_entry-&gt;ifa_dstaddr = (struct sockaddr *)l_addr;
                  else
                     l_entry-&gt;ifa_addr = (struct sockaddr *)l_addr;
               }
               else if (l_rta-&gt;rta_type == IFA_LOCAL)
               {
                  if (l_entry-&gt;ifa_addr)
                     l_entry-&gt;ifa_dstaddr = l_entry-&gt;ifa_addr;
                  l_entry-&gt;ifa_addr = (struct sockaddr *)l_addr;
               }
               else
                  l_entry-&gt;ifa_broadaddr = (struct sockaddr *)l_addr;
               l_addr += NLMSG_ALIGN(l_addrLen);
               break;
            }
         case IFA_LABEL:
            strncpy(l_name, l_rtaData, l_rtaDataSize);
            l_name[l_rtaDataSize] = '\0';
            l_entry-&gt;ifa_name = l_name;
            break;
         default:
            break;
      }
   }

   if (l_entry-&gt;ifa_addr &amp;&amp;
         (   l_entry-&gt;ifa_addr-&gt;sa_family == AF_INET
          || l_entry-&gt;ifa_addr-&gt;sa_family == AF_INET6))
   {
      unsigned i;
      char l_mask[16];
      unsigned l_maxPrefix = (l_entry-&gt;ifa_addr-&gt;sa_family == AF_INET
            ? 32 : 128);
      unsigned l_prefix    = (l_info-&gt;ifa_prefixlen &gt; l_maxPrefix
            ? l_maxPrefix : l_info-&gt;ifa_prefixlen);

      l_mask[0] = '\0';

      for (i=0; i&lt;(l_prefix/8); ++i)
         l_mask[i] = 0xff;
      if (l_prefix % 8)
         l_mask[i] = 0xff &lt;&lt; (8 - (l_prefix % 8));

      makeSockaddr(l_entry-&gt;ifa_addr-&gt;sa_family,
            (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
      l_entry-&gt;ifa_netmask = (struct sockaddr *)l_addr;
   }

   addToEnd(p_resultList, l_entry);
   return 0;
}

static int interpretLinks(int p_socket, NetlinkList *p_netlinkList,
      struct ifaddrs **p_resultList)
{
   int l_numLinks = 0;
   pid_t l_pid    = getpid();

   for (; p_netlinkList; p_netlinkList = p_netlinkList-&gt;m_next)
   {
      struct nlmsghdr *l_hdr = NULL;
      unsigned int l_nlsize  = p_netlinkList-&gt;m_size;

      for (l_hdr = p_netlinkList-&gt;m_data; NLMSG_OK(l_hdr, l_nlsize);
            l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
      {
         if (  (pid_t)l_hdr-&gt;nlmsg_pid != l_pid || 
               (int)l_hdr-&gt;nlmsg_seq   != p_socket)
            continue;

         if (l_hdr-&gt;nlmsg_type == NLMSG_DONE)
            break;

         if (l_hdr-&gt;nlmsg_type == RTM_NEWLINK)
         {
            if (interpretLink(l_hdr, p_resultList) == -1)
               return -1;
            ++l_numLinks;
         }
      }
   }
   return l_numLinks;
}

static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
      struct ifaddrs **p_resultList, int p_numLinks)
{
   pid_t l_pid = getpid();
   for (; p_netlinkList; p_netlinkList = p_netlinkList-&gt;m_next)
   {
      struct nlmsghdr *l_hdr = NULL;
      unsigned int l_nlsize  = p_netlinkList-&gt;m_size;

      for (l_hdr = p_netlinkList-&gt;m_data; NLMSG_OK(l_hdr, l_nlsize);
            l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
      {
         if (     (pid_t)l_hdr-&gt;nlmsg_pid != l_pid 
               || (int)l_hdr-&gt;nlmsg_seq   != p_socket)
            continue;

         if (l_hdr-&gt;nlmsg_type == NLMSG_DONE)
            break;

         if (l_hdr-&gt;nlmsg_type == RTM_NEWADDR)
         {
            if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
               return -1;
         }
      }
   }
   return 0;
}

int getifaddrs(struct ifaddrs **ifap)
{
   NetlinkList *l_linkResults;
   NetlinkList *l_addrResults;
   int l_numLinks;
   int l_socket   = 0;
   int l_result   = 0;
   if (!ifap)
      return -1;

   *ifap    = NULL;

   l_socket = netlink_socket();

   if (l_socket &lt; 0)
      return -1;

   l_linkResults = getResultList(l_socket, RTM_GETLINK);
   if (!l_linkResults)
   {
      close(l_socket);
      return -1;
   }

   l_addrResults = getResultList(l_socket, RTM_GETADDR);
   if (!l_addrResults)
   {
      close(l_socket);
      freeResultList(l_linkResults);
      return -1;
   }

   l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);

   if (  l_numLinks == -1 || 
         interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
      l_result = -1;

   freeResultList(l_linkResults);
   freeResultList(l_addrResults);
   close(l_socket);
   return l_result;
}

void freeifaddrs(struct ifaddrs *ifa)
{
   struct ifaddrs *l_cur = NULL;

   while (ifa)
   {
      l_cur = ifa;
      ifa   = ifa-&gt;ifa_next;
      free(l_cur);
   }
}</pre>
<h2>./include/libretro-common/compat/compat_posix_string.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_posix_string.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;ctype.h&gt;

#include &lt;compat/posix_string.h&gt;

#ifdef _WIN32

#undef strcasecmp
#undef strdup
#undef isblank
#undef strtok_r
#include &lt;ctype.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;
#include &lt;compat/strl.h&gt;

#include &lt;string.h&gt;

int retro_strcasecmp__(const char *a, const char *b)
{
   while (*a &amp;&amp; *b)
   {
      int a_ = tolower(*a);
      int b_ = tolower(*b);

      if (a_ != b_)
         return a_ - b_;

      a++;
      b++;
   }

   return tolower(*a) - tolower(*b);
}

char *retro_strdup__(const char *orig)
{
   size_t _len = strlen(orig) + 1;
   char *ret   = (char*)malloc(_len);
   if (!ret)
      return NULL;
   strlcpy(ret, orig, _len);
   return ret;
}

int retro_isblank__(int c)
{
   return (c == ' ') || (c == '\t');
}

char *retro_strtok_r__(char *str, const char *delim, char **saveptr)
{
   char *first = NULL;
   if (!saveptr || !delim)
      return NULL;

   if (str)
      *saveptr = str;

   do
   {
      char *ptr = NULL;
      first = *saveptr;
      while (*first &amp;&amp; strchr(delim, *first))
         *first++ = '\0';

      if (*first == '\0')
         return NULL;

      ptr = first + 1;

      while (*ptr &amp;&amp; !strchr(delim, *ptr))
         ptr++;

      *saveptr = ptr + (*ptr ? 1 : 0);
      *ptr     = '\0';
   } while (strlen(first) == 0);

   return first;
}

#endif</pre>
<h2>./include/libretro-common/compat/compat_snprintf.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_snprintf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
#ifdef _MSC_VER

#include &lt;stdio.h&gt;
#include &lt;stdarg.h&gt;

#if _MSC_VER &lt; 1800
#define va_copy(dst, src) ((dst) = (src))
#endif

#if _MSC_VER &lt; 1300
#define _vscprintf c89_vscprintf_retro__

static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
{
   int _len;
   va_list argcopy;
   va_copy(argcopy, pargs);
   _len = vsnprintf(NULL, 0, fmt, argcopy);
   va_end(argcopy);
   return _len;
}
#endif

/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */

int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
{
   int _len = -1;
   if (len != 0)
   {
#if (_MSC_VER &lt;= 1310)
      _len = _vsnprintf(s, len - 1, fmt, ap);
#else
      _len = _vsnprintf_s(s, len, len - 1, fmt, ap);
#endif
   }
   if (_len == -1)
       _len = _vscprintf(fmt, ap);
   /* there was no room for a NULL, so truncate the last character */
   if (_len == len &amp;&amp; len)
      s[len - 1] = '\0';
   return _len;
}

int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
{
   int _len;
   va_list ap;
   va_start(ap, fmt);
   _len = c99_vsnprintf_retro__(s, len, fmt, ap);
   va_end(ap);
   return _len;
}
#endif</pre>
<h2>./include/libretro-common/compat/compat_strcasestr.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_strcasestr.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;ctype.h&gt;

#include &lt;compat/strcasestr.h&gt;

/* Pretty much strncasecmp. */
static int casencmp(const char *a, const char *b, size_t n)
{
   size_t i;

   for (i = 0; i &lt; n; i++)
   {
      int a_lower = tolower(a[i]);
      int b_lower = tolower(b[i]);
      if (a_lower != b_lower)
         return a_lower - b_lower;
   }

   return 0;
}

char *strcasestr_retro__(const char *haystack, const char *needle)
{
   size_t _len  = strlen(needle);
   size_t __len = strlen(haystack);
   if (_len &lt;= __len)
   {
      size_t i;
      __len -= _len; /* offset */
      for (i = 0; i &lt;= __len; i++)
         if (!casencmp(haystack + i, needle, _len))
            return (char*)haystack + i;
   }
   return NULL;
}</pre>
<h2>./include/libretro-common/compat/compat_strl.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_strl.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;

#include &lt;compat/strl.h&gt;

/* Implementation of strlcpy()/strlcat() based on OpenBSD. */

#ifndef __MACH__
size_t strlcpy(char *s, const char *source, size_t len)
{
   size_t _len  = len;
   size_t __len = 0;
   if (_len)
      while (--_len &amp;&amp; (*s++ = *source++)) __len++;
   if (!_len)
   {
      if (len) *s = '\0';
      while (*source++) __len++;
   }
   return __len;
}

size_t strlcat(char *s, const char *source, size_t len)
{
   size_t _len = strlen(s);
   s += _len;
   if (_len &gt; len)
      len = 0;
   else
      len -= _len;
   return _len + strlcpy(s, source, len);
}
#endif</pre>
<h2>./include/libretro-common/compat/compat_strldup.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_strl.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;

#include &lt;compat/strl.h&gt;

char *strldup(const char *s, size_t n)
{
   char *dst = (char*)malloc(sizeof(char) * (n + 1));
   strlcpy(dst, s, n);
   return dst;
}</pre>
<h2>./include/libretro-common/compat/compat_vscprintf.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_snprintf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
#ifdef _MSC_VER

#include &lt;retro_common.h&gt;

#include &lt;stdio.h&gt;
#include &lt;stdarg.h&gt;

#if defined(_MSC_VER) &amp;&amp; _MSC_VER &lt; 1800
#define va_copy(dst, src) ((dst) = (src))
#endif

int c89_vscprintf_retro__(const char *format, va_list pargs)
{
   int _len;
   va_list argcopy;
   va_copy(argcopy, pargs);
   _len = vsnprintf(NULL, 0, format, argcopy);
   va_end(argcopy);
   return _len;
}
#endif</pre>
<h2>./include/libretro-common/compat/fopen_utf8.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fopen_utf8.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;compat/fopen_utf8.h&gt;
#include &lt;encodings/utf.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500 || defined(_XBOX)
#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif
#endif

#ifdef _WIN32
#undef fopen

void *fopen_utf8(const char * filename, const char * mode)
{
#if defined(LEGACY_WIN32)
   char * filename_local = utf8_to_local_string_alloc(filename);
   if (filename_local)
   {
      FILE *ret          = fopen(filename_local, mode);
      free(filename_local);
      return ret;
   }
#else
   wchar_t * filename_w  = utf8_to_utf16_string_alloc(filename);
   if (filename_w)
   {
      FILE    *ret       = NULL;
      wchar_t *mode_w    = utf8_to_utf16_string_alloc(mode);
      if (mode_w)
      {
         ret             = _wfopen(filename_w, mode_w);
         free(mode_w);
      }
      free(filename_w);
      return ret;
   }
#endif
   return NULL;
}
#endif</pre>
<h2>./include/libretro-common/crt/include/string.h</h2>
<pre>#ifndef __LIBRETRO_SDK_CRT_STRING_H_
#define __LIBRETRO_SDK_CRT_STRING_H_

#include &lt;stdio.h&gt;

void *memcpy(void *dst, const void *src, size_t len);

void *memset(void *b, int c, size_t len);

#endif</pre>
<h2>./include/libretro-common/crt/string.c</h2>
<pre>#ifdef _MSC_VER
#include &lt;cruntime.h&gt;
#endif
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

void *memset(void *dst, int val, size_t count)
{
   void *start = dst;

#if defined(_M_IA64) || defined (_M_AMD64) || defined(_M_ALPHA) || defined (_M_PPC)
   extern void RtlFillMemory(void *, size_t count, char);

   RtlFillMemory(dst, count, (char)val);
#else
   while (count--)
   {
      *(char*)dst = (char)val;
      dst = (char*)dst + 1;
   }
#endif

   return start;
}

void *memcpy(void *dst, const void *src, size_t len)
{
   size_t i;

   for (i = 0; i &lt; len; i++)
      ((unsigned char *)dst)[i] = ((unsigned char *)src)[i];

   return dst;
}</pre>
<h2>./include/libretro-common/dynamic/dylib.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dylib.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;string.h&gt;
#include &lt;stdio.h&gt;
#include &lt;dynamic/dylib.h&gt;
#include &lt;encodings/utf.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;file/file_path.h&gt;

#if defined(ORBIS)
#include &lt;orbis/libkernel.h&gt;
#endif

#ifdef NEED_DYNAMIC

#ifdef _WIN32
#include &lt;compat/posix_string.h&gt;
#include &lt;windows.h&gt;
#else
#if !defined(ORBIS)
#include &lt;dlfcn.h&gt;
#endif
#endif

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#ifdef _WIN32
static char last_dyn_err[512];

static void set_dl_err(void)
{
   DWORD err = GetLastError();
   if (FormatMessage(
              FORMAT_MESSAGE_IGNORE_INSERTS
            | FORMAT_MESSAGE_FROM_SYSTEM,
            NULL, err,
            MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
            last_dyn_err, sizeof(last_dyn_err) - 1,
            NULL) == 0)
      snprintf(last_dyn_err, sizeof(last_dyn_err) - 1,
            "unknown error %lu", err);
}
#endif

/**
 * dylib_load:
 * @path                         : Path to libretro core library.
 *
 * Platform independent dylib loading.
 *
 * @return Library handle on success, otherwise NULL.
 **/
dylib_t dylib_load(const char *path)
{
#ifdef _WIN32
#ifndef __WINRT__
   int prevmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
#endif
#ifdef __WINRT__
   dylib_t lib;
   /* On UWP, you can only load DLLs inside your install directory, using a special function that takes a relative path */
   char relative_path_abbrev[PATH_MAX_LENGTH];
   char *relative_path = relative_path_abbrev;
   wchar_t *path_wide  = NULL;

   relative_path_abbrev[0] = '\0';

   if (!path_is_absolute(path))
      RARCH_WARN("Relative path in dylib_load! This is likely an attempt to load a system library that will fail.\n");

   fill_pathname_abbreviate_special(relative_path_abbrev, path, sizeof(relative_path_abbrev));

   /* Path to dylib_load is not inside app install directory.
    * Loading will probably fail. */
   if (relative_path[0] != ':' || !PATH_CHAR_IS_SLASH(relative_path[1])) { }
   else
      relative_path += 2;

   path_wide = utf8_to_utf16_string_alloc(relative_path);
   lib       = LoadPackagedLibrary(path_wide, 0);
   free(path_wide);
#elif defined(LEGACY_WIN32)
   dylib_t lib        = LoadLibrary(path);
#else
   wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
   dylib_t lib        = LoadLibraryW(path_wide);
   free(path_wide);
#endif

#ifndef __WINRT__
   SetErrorMode(prevmode);
#endif

   if (!lib)
   {
      set_dl_err();
      return NULL;
   }
   last_dyn_err[0] = 0;
#elif defined(ORBIS)
   int res;
   dylib_t lib = (dylib_t)sceKernelLoadStartModule(path, 0, NULL, 0, NULL, &amp;res);
#elif defined(IOS) || defined(OSX)
    dylib_t lib;
    static const char fw_suffix[] = ".framework";
    if (string_ends_with(path, fw_suffix))
    {
        char fw_path[PATH_MAX_LENGTH];
        const char *fw_name = path_basename(path);
        size_t _len         = strlcpy(fw_path, path, sizeof(fw_path));
        _len += strlcpy(fw_path + _len, "/", sizeof(fw_path) - _len);
        /* Assume every framework binary is named for the framework. Not always
         * a great assumption but correct enough for our uses. */
        strlcpy(fw_path + _len, fw_name, strlen(fw_name) - STRLEN_CONST(fw_suffix) + 1);
        lib = dlopen(fw_path, RTLD_LAZY | RTLD_LOCAL);
    }
    else
        lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
#else
   dylib_t lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
#endif
   return lib;
}

char *dylib_error(void)
{
#ifdef _WIN32
   if (last_dyn_err[0])
      return last_dyn_err;
   return NULL;
#else
   return (char*)dlerror();
#endif
}

function_t dylib_proc(dylib_t lib, const char *proc)
{
   function_t sym;

#ifdef _WIN32
   HMODULE mod = (HMODULE)lib;
   if (!mod)
   {
#ifdef __WINRT__
      /* GetModuleHandle is not available on UWP */
      /* It's not possible to lookup symbols in current executable
       * on UWP. */
      DebugBreak();
      return NULL;
#else
      mod = GetModuleHandle(NULL);
#endif
   }
   if (!(sym = (function_t)GetProcAddress(mod, proc)))
   {
      set_dl_err();
      return NULL;
   }
   last_dyn_err[0] = 0;
#elif defined(ORBIS)
   void *ptr_sym = NULL;
   sym = NULL;

   if (lib)
   {
     sceKernelDlsym((SceKernelModule)lib, proc, &amp;ptr_sym);
     memcpy(&amp;sym, &amp;ptr_sym, sizeof(void*));
   }
#else
   void *ptr_sym = NULL;

   if (lib)
      ptr_sym = dlsym(lib, proc);
   else
   {
      void *handle = dlopen(NULL, RTLD_LAZY);
      if (handle)
      {
         ptr_sym = dlsym(handle, proc);
         dlclose(handle);
      }
   }

   /* Dirty hack to workaround the non-legality of
    * (void*) -&gt; fn-pointer casts. */
   memcpy(&amp;sym, &amp;ptr_sym, sizeof(void*));
#endif

   return sym;
}

/**
 * dylib_close:
 * @lib                          : Library handle.
 *
 * Frees library handle.
 **/
void dylib_close(dylib_t lib)
{
#ifdef _WIN32
   if (!FreeLibrary((HMODULE)lib))
      set_dl_err();
   last_dyn_err[0] = 0;
#elif defined(ORBIS)
   int res;
   sceKernelStopUnloadModule((SceKernelModule)lib, 0, NULL, 0, NULL, &amp;res);
#else
#ifndef NO_DLCLOSE
   dlclose(lib);
#endif
#endif
}

#endif</pre>
<h2>./include/libretro-common/encodings/encoding_base64.c</h2>
<pre>/*
  https://github.com/superwills/NibbleAndAHalf
  base64.h -- Fast base64 encoding and decoding.
  version 1.0.0, April 17, 2013 143a
  Copyright (C) 2013 William Sherif
  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.
  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:
  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
  William Sherif
  will.sherif@gmail.com
  YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz


  Modified for RetroArch formatting, logging, and header files.
*/


#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;encodings/base64.h&gt;

static const char* b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/* maps A=&gt;0,B=&gt;1.. */
static const unsigned char unb64[]={
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,  62,   0,   0,   0,  63,  52,  53,
 54,  55,  56,  57,  58,  59,  60,  61,   0,   0,
  0,   0,   0,   0,   0,   0,   1,   2,   3,   4,
  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
 25,   0,   0,   0,   0,   0,   0,  26,  27,  28,
 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
 49,  50,  51,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,
}; /* This array has 256 elements */

/*
   Converts binary data of length=len to base64 characters.
   Length of the resultant string is stored in flen
   (you must pass pointer flen).
*/
char* base64(const void* binaryData, int len, int *flen)
{
   char* res;
   int byteNo; /* I need this after the loop */
   const unsigned char* bin = (const unsigned char*) binaryData;
   int rc                   = 0; /* result counter */
   int modulusLen           = len % 3 ;
   /* 2 gives 1 and 1 gives 2, but 0 gives 0. */
   int pad                  = ((modulusLen&amp;1)&lt;&lt;1) + ((modulusLen&amp;2)&gt;&gt;1);

   *flen                    = 4*(len + pad)/3;
   if (!(res = (char*) malloc(*flen + 1))) /* and one for the NULL */
      return 0;
  
   for (byteNo=0; byteNo &lt;= len-3; byteNo+=3)
   {
      unsigned char BYTE0            = bin[byteNo];
      unsigned char BYTE1            = bin[byteNo+1];
      unsigned char BYTE2            = bin[byteNo+2];

      res[rc++] = b64[BYTE0 &gt;&gt; 2];
      res[rc++] = b64[((0x3&amp;BYTE0)&lt;&lt;4) + (BYTE1 &gt;&gt; 4)];
      res[rc++] = b64[((0x0f&amp;BYTE1)&lt;&lt;2) + (BYTE2&gt;&gt;6)];
      res[rc++] = b64[0x3f&amp;BYTE2];
   }
  
   if (pad==2)
   {
      res[rc++] = b64[bin[byteNo] &gt;&gt; 2];
      res[rc++] = b64[(0x3&amp;bin[byteNo])&lt;&lt;4];
      res[rc++] = '=';
      res[rc++] = '=';
   }
   else if (pad==1)
   {
      res[rc++] = b64[bin[byteNo] &gt;&gt; 2];
      res[rc++] = b64[((0x3&amp;bin[byteNo])&lt;&lt;4) + (bin[byteNo+1] &gt;&gt; 4)];
      res[rc++] = b64[(0x0f&amp;bin[byteNo+1])&lt;&lt;2];
      res[rc++] = '=';
   }
  
   res[rc]=0; /* NULL TERMINATOR! ;) */
   return res;
}

unsigned char* unbase64(const char* ascii, int len, int *flen)
{
   int charNo;
   unsigned char *bin;
   const unsigned char *safeAsciiPtr = (const unsigned char*) ascii;
   int cb                            = 0;
   int pad                           = 0;

   if (len &lt; 2) /* 2 accesses below would be OOB (Out Of Bounds). */
   {
      /* catch empty string, return NULL as result. */
      /* ERROR: You passed an invalid base64 string (too short). 
       * You get NULL back. */
      *flen = 0;
      return 0;
   }

   if (safeAsciiPtr[len-1]=='=')
      ++pad;
   if (safeAsciiPtr[len-2]=='=')
      ++pad;
  
   *flen = 3*len/4 - pad;
   if (!(bin = (unsigned char*)malloc(*flen)))
      return 0;
  
   for (charNo=0; charNo &lt;= len-4-pad; charNo+=4)
   {
      int A = unb64[safeAsciiPtr[charNo]];
      int B = unb64[safeAsciiPtr[charNo+1]];
      int C = unb64[safeAsciiPtr[charNo+2]];
      int D = unb64[safeAsciiPtr[charNo+3]];
    
      bin[cb++] = (A&lt;&lt;2) | (B&gt;&gt;4);
      bin[cb++] = (B&lt;&lt;4) | (C&gt;&gt;2);
      bin[cb++] = (C&lt;&lt;6) | (D);
   }
  
   if (pad==1)
   {
      int A = unb64[safeAsciiPtr[charNo]];
      int B = unb64[safeAsciiPtr[charNo+1]];
      int C = unb64[safeAsciiPtr[charNo+2]];
    
      bin[cb++] = (A&lt;&lt;2) | (B&gt;&gt;4);
      bin[cb++] = (B&lt;&lt;4) | (C&gt;&gt;2);
   }
   else if (pad==2)
   {
      int A = unb64[safeAsciiPtr[charNo]];
      int B = unb64[safeAsciiPtr[charNo+1]];
    
      bin[cb++] = (A&lt;&lt;2) | (B&gt;&gt;4);
   }
  
   return bin;
}</pre>
<h2>./include/libretro-common/encodings/encoding_crc32.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (encoding_crc32.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;encodings/crc32.h&gt;
#include &lt;stdlib.h&gt;

#if __ARM_FEATURE_CRC32

#ifdef _M_ARM64
# include &lt;arm64_neon.h&gt;
#else
# include &lt;arm_acle.h&gt;
#endif

uint32_t encoding_crc32(uint32_t crc, const uint8_t *data, size_t len)
{
   crc = ~crc;
   /* Align data if it is not aligned */
   while (((uintptr_t)data &amp; 7) &amp;&amp; len &gt; 0)
   {
      crc = __crc32b(crc, *(uint8_t *)data);
      data++;
      len--;
   }
   while (len &gt;= 8)
   {
      crc = __crc32d(crc, *(uint64_t *)data);
      data += 8;
      len -= 8;
   }
   while (len &gt; 0)
   {
      crc = __crc32b(crc, *(uint8_t *)data);
      data++;
      len--;
   }
   return ~crc;
}

#else
uint32_t encoding_crc32(uint32_t crc, const uint8_t *s, size_t len)
{
   static const uint32_t crc32_table[256] = {
      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
      0x2d02ef8dL
   };
   crc = ~crc;
   while (len--)
      crc = crc32_table[(crc ^ (*s++)) &amp; 0xff] ^ (crc &gt;&gt; 8);
   return ~crc;
}

#endif</pre>
<h2>./include/libretro-common/encodings/encoding_utf.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (encoding_utf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;
#include &lt;string.h&gt;

#include &lt;boolean.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;retro_inline.h&gt;

#include &lt;encodings/utf.h&gt;

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#include &lt;windows.h&gt;
#elif defined(_XBOX)
#include &lt;xtl.h&gt;
#endif

#define UTF8_WALKBYTE(string) (*((*(string))++))

static unsigned leading_ones(uint8_t c)
{
   unsigned ones = 0;
   while (c &amp; 0x80)
   {
      ones++;
      c &lt;&lt;= 1;
   }

   return ones;
}

/**
 * utf8_conv_utf32:
 *
 * Simple implementation. Assumes the sequence is
 * properly synchronized and terminated.
 **/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
      const char *in, size_t in_size)
{
   unsigned i;
   size_t ret = 0;
   while (in_size &amp;&amp; out_chars)
   {
      unsigned extra, shift;
      uint32_t c;
      uint8_t first = *in++;
      unsigned ones = leading_ones(first);

      if (ones &gt; 6 || ones == 1) /* Invalid or desync. */
         break;

      extra = ones ? ones - 1 : ones;
      if (1 + extra &gt; in_size) /* Overflow. */
         break;

      shift = (extra - 1) * 6;
      c     = (first &amp; ((1 &lt;&lt; (7 - ones)) - 1)) &lt;&lt; (6 * extra);

      for (i = 0; i &lt; extra; i++, in++, shift -= 6)
         c |= (*in &amp; 0x3f) &lt;&lt; shift;

      *out++   = c;
      in_size -= 1 + extra;
      out_chars--;
      ret++;
   }
   return ret;
}

/**
 * utf16_conv_utf8:
 *
 * Leaf function.
 **/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
     const uint16_t *in, size_t in_size)
{
   size_t out_pos            = 0;
   size_t in_pos             = 0;
   static const
      uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };

   for (;;)
   {
      unsigned num_adds;
      uint32_t value;

      if (in_pos == in_size)
      {
         *out_chars = out_pos;
         return true;
      }
      value = in[in_pos++];
      if (value &lt; 0x80)
      {
         if (out)
            out[out_pos] = (char)value;
         out_pos++;
         continue;
      }

      if (value &gt;= 0xD800 &amp;&amp; value &lt; 0xE000)
      {
         uint32_t c2;

         if (value &gt;= 0xDC00 || in_pos == in_size)
            break;
         c2 = in[in_pos++];
         if (c2 &lt; 0xDC00 || c2 &gt;= 0xE000)
            break;
         value = (((value - 0xD800) &lt;&lt; 10) | (c2 - 0xDC00)) + 0x10000;
      }

      for (num_adds = 1; num_adds &lt; 5; num_adds++)
         if (value &lt; (((uint32_t)1) &lt;&lt; (num_adds * 5 + 6)))
            break;
      if (out)
         out[out_pos] = (char)(utf8_limits[num_adds - 1]
               + (value &gt;&gt; (6 * num_adds)));
      out_pos++;
      do
      {
         num_adds--;
         if (out)
            out[out_pos] = (char)(0x80
                  + ((value &gt;&gt; (6 * num_adds)) &amp; 0x3F));
         out_pos++;
      }while (num_adds != 0);
   }

   *out_chars = out_pos;
   return false;
}

/**
 * utf8cpy:
 *
 * Acts mostly like strlcpy.
 *
 * Copies the given number of UTF-8 characters,
 * but at most @len bytes.
 *
 * Always NULL terminates. Does not copy half a character.
 * @s is assumed valid UTF-8.
 * Use only if @chars is considerably less than @len.
 *
 * @return Number of bytes.
 **/
size_t utf8cpy(char *s, size_t len, const char *in, size_t chars)
{
   const uint8_t *sb     = (const uint8_t*)in;
   const uint8_t *sb_org = sb;

   if (!in)
      return 0;

   while (*sb &amp;&amp; chars-- &gt; 0)
   {
      sb++;
      while ((*sb &amp; 0xC0) == 0x80)
         sb++;
   }

   if ((size_t)(sb - sb_org) &gt; len - 1)
   {
      sb = sb_org + len - 1;
      while ((*sb &amp; 0xC0) == 0x80)
         sb--;
   }

   memcpy(s, sb_org, sb - sb_org);
   s[sb-sb_org] = '\0';
   return sb - sb_org;
}

/**
 * utf8skip:
 *
 * Leaf function
 **/
const char *utf8skip(const char *str, size_t chars)
{
   const uint8_t *strb = (const uint8_t*)str;

   if (!chars)
      return str;

   do
   {
      strb++;
      while ((*strb &amp; 0xC0)==0x80)
         strb++;
      chars--;
   }while (chars);

   return (const char*)strb;
}

/**
 * utf8len:
 *
 * Leaf function.
 **/
size_t utf8len(const char *string)
{
   size_t ret = 0;

   if (!string)
      return 0;

   while (*string)
   {
      if ((*string &amp; 0xC0) != 0x80)
         ret++;
      string++;
   }
   return ret;
}

/**
 * utf8_walk:
 *
 * Does not validate the input.
 *
 * Leaf function.
 *
 * @return Returns garbage if it's not UTF-8.
 **/
uint32_t utf8_walk(const char **string)
{
   uint8_t first = UTF8_WALKBYTE(string);
   uint32_t ret  = 0;

   if (first &lt; 128)
      return first;

   ret    = (ret &lt;&lt; 6) | (UTF8_WALKBYTE(string) &amp; 0x3F);
   if (first &gt;= 0xE0)
   {
      ret = (ret &lt;&lt; 6) | (UTF8_WALKBYTE(string) &amp; 0x3F);
      if (first &gt;= 0xF0)
      {
         ret = (ret &lt;&lt; 6) | (UTF8_WALKBYTE(string) &amp; 0x3F);
         return ret | (first &amp; 7) &lt;&lt; 18;
      }
      return ret | (first &amp; 15) &lt;&lt; 12;
   }

   return ret | (first &amp; 31) &lt;&lt; 6;
}

static bool utf16_to_char(uint8_t **utf_data,
      size_t *dest_len, const uint16_t *in)
{
   size_t _len    = 0;
   while (in[_len] != '\0')
      _len++;
   utf16_conv_utf8(NULL, dest_len, in, _len);
   *dest_len  += 1;
   if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)
      return utf16_conv_utf8(*utf_data, dest_len, in, _len);
   return false;
}

/**
 * utf16_to_char_string:
 **/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
{
   size_t  _len        = 0;
   uint8_t *utf16_data = NULL;
   bool            ret = utf16_to_char(&amp;utf16_data, &amp;_len, in);
   if (ret)
   {
      utf16_data[_len] = 0;
      strlcpy(s, (const char*)utf16_data, len);
   }
   free(utf16_data);
   utf16_data          = NULL;
   return ret;
}

#if defined(_WIN32) &amp;&amp; !defined(_XBOX) &amp;&amp; !defined(UNICODE)
/**
 * mb_to_mb_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
static char *mb_to_mb_string_alloc(const char *str,
      enum CodePage cp_in, enum CodePage cp_out)
{
   wchar_t *path_buf_wide = NULL;
   int path_buf_wide_len  = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);

   /* Windows 95 will return 0 from these functions with
    * a UTF8 codepage set without MSLU.
    *
    * From an unknown MSDN version (others omit this info):
    *   - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:
    *   Translate using UTF-8. When this is set, dwFlags must be zero.
    *   - Windows 95: Under the Microsoft Layer for Unicode,
    *   MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
    */

   if (!path_buf_wide_len)
      return strdup(str);

   if ((path_buf_wide = (wchar_t*)
      calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t))))
   {
      MultiByteToWideChar(cp_in, 0,
            str, -1, path_buf_wide, path_buf_wide_len);

      if (*path_buf_wide)
      {
         int path_buf_len = WideCharToMultiByte(cp_out, 0,
               path_buf_wide, -1, NULL, 0, NULL, NULL);

         if (path_buf_len)
         {
            char *path_buf = (char*)
               calloc(path_buf_len + sizeof(char), sizeof(char));

            if (path_buf)
            {
               WideCharToMultiByte(cp_out, 0,
                     path_buf_wide, -1, path_buf,
                     path_buf_len, NULL, NULL);

               free(path_buf_wide);

               if (*path_buf)
                  return path_buf;

               free(path_buf);
               return NULL;
            }
         }
         else
         {
            free(path_buf_wide);
            return strdup(str);
         }
      }

      free(path_buf_wide);
   }

   return NULL;
}
#endif

/**
 * utf8_to_local_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char* utf8_to_local_string_alloc(const char *str)
{
   if (str &amp;&amp; *str)
#if defined(_WIN32) &amp;&amp; !defined(_XBOX) &amp;&amp; !defined(UNICODE)
      return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
#else
      return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
   return NULL;
}

/**
 * local_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *local_to_utf8_string_alloc(const char *str)
{
	if (str &amp;&amp; *str)
#if defined(_WIN32) &amp;&amp; !defined(_XBOX) &amp;&amp; !defined(UNICODE)
		return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
#else
      return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
	return NULL;
}

/**
 * utf8_to_utf16_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
wchar_t* utf8_to_utf16_string_alloc(const char *str)
{
#ifdef _WIN32
   int _len       = 0;
#else
   size_t _len    = 0;
#endif
   wchar_t *buf   = NULL;

   if (!str || !*str)
      return NULL;

#ifdef _WIN32
   if ((_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
   {
      if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))
         return NULL;

      if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, _len)) &lt; 0)
      {
         free(buf);
         return NULL;
      }
   }
   else
   {
      /* Fallback to ANSI codepage instead */
      if ((_len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))
      {
         if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))
            return NULL;

         if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, _len)) &lt; 0)
         {
            free(buf);
            return NULL;
         }
      }
   }
#else
   /* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
   if ((_len = mbstowcs(NULL, str, 0) + 1))
   {
      if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))
         return NULL;

      if ((mbstowcs(buf, str, _len)) == (size_t)-1)
      {
         free(buf);
         return NULL;
      }
   }
#endif

   return buf;
}

/**
 * utf16_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char* utf16_to_utf8_string_alloc(const wchar_t *str)
{
#ifdef _WIN32
   int _len       = 0;
#else
   size_t _len    = 0;
#endif
   char *buf      = NULL;

   if (!str || !*str)
      return NULL;

#ifdef _WIN32
   {
      UINT code_page = CP_UTF8;

      /* fallback to ANSI codepage instead */
      if (!(_len = WideCharToMultiByte(code_page,
            0, str, -1, NULL, 0, NULL, NULL)))
      {
         code_page   = CP_ACP;
         _len        = WideCharToMultiByte(code_page,
               0, str, -1, NULL, 0, NULL, NULL);
      }

      if (!(buf = (char*)calloc(_len, sizeof(char))))
         return NULL;

      if (WideCharToMultiByte(code_page,
            0, str, -1, buf, _len, NULL, NULL) &lt; 0)
      {
         free(buf);
         return NULL;
      }
   }
#else
   /* NOTE: For now, assume non-Windows platforms'
    * locale is already UTF-8. */
   if ((_len = wcstombs(NULL, str, 0) + 1))
   {
      if (!(buf = (char*)calloc(_len, sizeof(char))))
         return NULL;

      if (wcstombs(buf, str, _len) == (size_t)-1)
      {
         free(buf);
         return NULL;
      }
   }
#endif

   return buf;
}</pre>
<h2>./include/libretro-common/features/features_cpu.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (features_cpu.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#if defined(_WIN32)
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt;
#endif

#include &lt;compat/strl.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;libretro.h&gt;
#include &lt;features/features_cpu.h&gt;
#include &lt;retro_timers.h&gt;

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#include &lt;windows.h&gt;
#endif

#ifdef __PSL1GHT__
#include &lt;lv2/systime.h&gt;
#endif

#if defined(_XBOX360)
#include &lt;PPCIntrinsics.h&gt;
#elif !defined(__MACH__) &amp;&amp; !defined(__FreeBSD__) &amp;&amp; (defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC64__) || defined(__powerpc64__))
#ifndef _PPU_INTRINSICS_H
#include &lt;ppu_intrinsics.h&gt;
#endif
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
#include &lt;time.h&gt;
#endif

#if defined(__QNX__) &amp;&amp; !defined(CLOCK_MONOTONIC)
#define CLOCK_MONOTONIC 2
#endif

#if defined(PSP)
#include &lt;pspkernel.h&gt;
#endif

#if defined(PSP) || defined(__PSL1GHT__)
#include &lt;sys/time.h&gt;
#endif

#if defined(PSP)
#include &lt;psprtc.h&gt;
#endif

#if defined(VITA)
#include &lt;psp2/kernel/processmgr.h&gt;
#include &lt;psp2/rtc.h&gt;
#endif

#if defined(ORBIS)
#include &lt;orbis/libkernel.h&gt;
#endif

#if defined(PS2)
#include &lt;ps2sdkapi.h&gt;
#endif

#if !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
#include &lt;sys/sys_time.h&gt;
#endif

#ifdef GEKKO
#include &lt;ogc/lwp_watchdog.h&gt;
#endif

#ifdef WIIU
#include &lt;wiiu/os/time.h&gt;
#endif

#if defined(HAVE_LIBNX)
#include &lt;switch.h&gt;
#elif defined(SWITCH)
#include &lt;libtransistor/types.h&gt;
#include &lt;libtransistor/svc.h&gt;
#endif

#if defined(_3DS)
#include &lt;3ds/svc.h&gt;
#include &lt;3ds/os.h&gt;
#include &lt;3ds/services/cfgu.h&gt;
#endif

/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
#ifdef __MACH__
#include &lt;sys/time.h&gt;

#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 0
#endif

#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif

/**
 * TODO/FIXME: clock_gettime function is part of iOS 10 now
 **/
#if __IPHONE_OS_VERSION_MIN_REQUIRED &lt; 100000
static int ra_clock_gettime(int clk_ik, struct timespec *t)
{
   struct timeval now;
   int rv     = gettimeofday(&amp;now, NULL);
   if (rv)
      return rv;
   t-&gt;tv_sec  = now.tv_sec;
   t-&gt;tv_nsec = now.tv_usec * 1000;
   return 0;
}
#endif
#endif

#if defined(__MACH__) &amp;&amp; __IPHONE_OS_VERSION_MIN_REQUIRED &lt; 100000
#else
#define ra_clock_gettime clock_gettime
#endif

#ifdef EMSCRIPTEN
#include &lt;emscripten.h&gt;
#endif

#if defined(BSD) || defined(__APPLE__)
#include &lt;sys/sysctl.h&gt;
#endif

#include &lt;string.h&gt;

retro_perf_tick_t cpu_features_get_perf_counter(void)
{
   retro_perf_tick_t time_ticks = 0;
#if defined(_WIN32)
   long tv_sec, tv_usec;
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &lt;= 1200
   static const unsigned __int64 epoch = 11644473600000000;
#else
   static const unsigned __int64 epoch = 11644473600000000ULL;
#endif
   FILETIME file_time;
   SYSTEMTIME system_time;
   ULARGE_INTEGER ularge;

   GetSystemTime(&amp;system_time);
   SystemTimeToFileTime(&amp;system_time, &amp;file_time);
   ularge.LowPart  = file_time.dwLowDateTime;
   ularge.HighPart = file_time.dwHighDateTime;

   tv_sec     = (long)((ularge.QuadPart - epoch) / 10000000L);
   tv_usec    = (long)(system_time.wMilliseconds * 1000);
   time_ticks = (1000000 * tv_sec + tv_usec);
#elif defined(GEKKO)
   time_ticks = gettime();
#elif !defined(__MACH__) &amp;&amp; !defined(__FreeBSD__) &amp;&amp; (defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__) || defined(__PPC64__) || defined(__powerpc64__))
   time_ticks = __mftb();
#elif (defined(_POSIX_MONOTONIC_CLOCK) &amp;&amp; _POSIX_MONOTONIC_CLOCK &gt; 0) || defined(__QNX__) || defined(ANDROID)
   struct timespec tv;
   if (ra_clock_gettime(CLOCK_MONOTONIC, &amp;tv) == 0)
      time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
         (retro_perf_tick_t)tv.tv_nsec;

#elif defined(__GNUC__) &amp;&amp; defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)
   __asm__ volatile ("rdtsc" : "=A" (time_ticks));
#elif defined(__GNUC__) &amp;&amp; defined(__x86_64__) || defined(_M_IX86)
   unsigned a, d;
   __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
   time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d &lt;&lt; 32);
#elif defined(__ARM_ARCH_6__)
   __asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
#elif defined(__aarch64__)
   __asm__ volatile( "mrs %0, cntvct_el0" : "=r"(time_ticks) );
#elif defined(PSP) || defined(VITA)
   time_ticks = sceKernelGetSystemTimeWide();
#elif defined(ORBIS)
   sceRtcGetCurrentTick((SceRtcTick*)&amp;time_ticks);
#elif defined(PS2)
   time_ticks = ps2_clock();
#elif defined(_3DS)
   time_ticks = svcGetSystemTick();
#elif defined(WIIU)
   time_ticks = OSGetSystemTime();
#elif defined(HAVE_LIBNX)
   time_ticks = armGetSystemTick();
#elif defined(EMSCRIPTEN)
   time_ticks = emscripten_get_now() * 1000;
#endif

   return time_ticks;
}

retro_time_t cpu_features_get_time_usec(void)
{
#if defined(_WIN32)
   static LARGE_INTEGER freq;
   LARGE_INTEGER count;

   /* Frequency is guaranteed to not change. */
   if (!freq.QuadPart &amp;&amp; !QueryPerformanceFrequency(&amp;freq))
      return 0;

   if (!QueryPerformanceCounter(&amp;count))
      return 0;
   return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);
#elif defined(__PSL1GHT__)
   return sysGetSystemTime();
#elif !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
   return sys_time_get_system_time();
#elif defined(GEKKO)
   return ticks_to_microsecs(gettime());
#elif defined(WIIU)
   return ticks_to_us(OSGetSystemTime());
#elif defined(SWITCH) || defined(HAVE_LIBNX)
   return (svcGetSystemTick() * 10) / 192;
#elif defined(_3DS)
   return osGetTime() * 1000;
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
   struct timespec tv;
   if (ra_clock_gettime(CLOCK_MONOTONIC, &amp;tv) &lt; 0)
      return 0;
   return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
#elif defined(EMSCRIPTEN)
   return emscripten_get_now() * 1000;
#elif defined(PS2)
   return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;
#elif defined(VITA) || defined(PSP)
   return sceKernelGetSystemTimeWide();
#elif defined(DJGPP)
   return uclock() * 1000000LL / UCLOCKS_PER_SEC;
#elif defined(ORBIS)
   return sceKernelGetProcessTime();
#else
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
#endif
}

#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) &amp;&amp; _MSC_VER &gt; 1310) || (defined(_M_IX86) &amp;&amp; _MSC_VER &gt; 1310)
#define CPU_X86
#endif

#if defined(_MSC_VER) &amp;&amp; !defined(_XBOX)
#if (_MSC_VER &gt; 1310)
#include &lt;intrin.h&gt;
#endif
#endif

#if defined(CPU_X86) &amp;&amp; !defined(__MACH__)
#include &lt;limits.h&gt;
void x86_cpuid(int func, int32_t flags[4])
{
   /* On Android, we compile RetroArch with PIC, and we
    * are not allowed to clobber the ebx register. */
#ifdef __x86_64__
#define REG_b "rbx"
#define REG_S "rsi"
#else
#define REG_b "ebx"
#define REG_S "esi"
#endif

#if defined(__GNUC__)
   __asm__ volatile (
         "mov %%" REG_b ", %%" REG_S "\n"
         "cpuid\n"
         "xchg %%" REG_b ", %%" REG_S "\n"
         : "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
         : "a"(func));
#elif defined(_MSC_VER) &amp;&amp; INT_MAX == 2147483647
   __cpuid((int*)flags, func);
#else
#ifndef NDEBUG
   printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
#endif
   memset(flags, 0, 4 * sizeof(int));
#endif
}

/* Only runs on i686 and above. Needs to be conditionally run. */
static uint64_t xgetbv_x86(uint32_t idx)
{
#if defined(__GNUC__)
   uint32_t eax, edx;
   __asm__ volatile (
         /* Older GCC versions (Apple's GCC for example) do
          * not understand xgetbv instruction.
          * Stamp out the machine code directly.
          */
         ".byte 0x0f, 0x01, 0xd0\n"
         : "=a"(eax), "=d"(edx) : "c"(idx));
   return ((uint64_t)edx &lt;&lt; 32) | eax;
#elif _MSC_FULL_VER &gt;= 160040219
   /* Intrinsic only works on 2010 SP1 and above. */
   return _xgetbv(idx);
#else
#ifndef NDEBUG
   printf("Unknown compiler. Cannot check xgetbv bits.\n");
#endif
   return 0;
#endif
}
#endif

#if defined(__ARM_NEON__)
#if defined(__arm__)
static void arm_enable_runfast_mode(void)
{
   /* RunFast mode. Enables flush-to-zero and some
    * floating point optimizations. */
   static const unsigned x = 0x04086060;
   static const unsigned y = 0x03000000;
   int r;
   __asm__ volatile(
         "fmrx	%0, fpscr   \n\t" /* r0 = FPSCR */
         "and	%0, %0, %1  \n\t" /* r0 = r0 &amp; 0x04086060 */
         "orr	%0, %0, %2  \n\t" /* r0 = r0 | 0x03000000 */
         "fmxr	fpscr, %0   \n\t" /* FPSCR = r0 */
         : "=r"(r)
         : "r"(x), "r"(y)
        );
}
#endif
#endif

#if defined(__linux__) &amp;&amp; !defined(CPU_X86)
static unsigned char check_arm_cpu_feature(const char* feature)
{
   char line[1024];
   unsigned char status = 0;
   RFILE *fp = filestream_open("/proc/cpuinfo",
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fp)
      return 0;

   while (filestream_gets(fp, line, sizeof(line)))
   {
      if (strncmp(line, "Features\t: ", 11))
         continue;

      if (strstr(line + 11, feature))
         status = 1;

      break;
   }

   filestream_close(fp);

   return status;
}

#if !defined(_SC_NPROCESSORS_ONLN)
/**
 * parse_decimal:
 *
 * Parse an decimal integer starting from 'input', but not going further
 * than 'limit'. Return the value into '*result'.
 *
 * NOTE: Does not skip over leading spaces, or deal with sign characters.
 * NOTE: Ignores overflows.
 *
 * The function returns NULL in case of error (bad format), or the new
 * position after the decimal number in case of success (which will always
 * be &lt;= 'limit').
 *
 * Leaf function.
 **/
static const char *parse_decimal(const char* input,
      const char* limit, int* result)
{
    const char* p = input;
    int       val = 0;

    while (p &lt; limit)
    {
        int d = (*p - '0');
        if ((unsigned)d &gt;= 10U)
            break;
        val = val*10 + d;
        p++;
    }
    if (p == input)
        return NULL;

    *result = val;
    return p;
}

/**
 * cpulist_parse:
 * Parse a textual list of cpus and store the result inside a CpuList object.
 * Input format is the following:
 * - comma-separated list of items (no spaces)
 * - each item is either a single decimal number (cpu index), or a range made
 *   of two numbers separated by a single dash (-). Ranges are inclusive.
 *
 * Examples:   0
 *             2,4-127,128-143
 *             0-1
 **/
static void cpulist_parse(CpuList* list, char **buf, ssize_t len)
{
   const char* p   = (const char*)buf;
   const char* end = p + len;

   /* NOTE: the input line coming from sysfs typically contains a
    * trailing newline, so take care of it in the code below
    */
   while (p &lt; end &amp;&amp; *p != '\n')
   {
      int val, start_value, end_value;
      /* Find the end of current item, and put it into 'q' */
      const char *q = (const char*)memchr(p, ',', end-p);

      if (!q)
         q = end;

      /* Get first value */
      if (!(p = parse_decimal(p, q, &amp;start_value)))
         return;

      end_value = start_value;

      /* If we're not at the end of the item, expect a dash and
       * and integer; extract end value.
       */
      if (p &lt; q &amp;&amp; *p == '-')
      {
         if (!(p = parse_decimal(p+1, q, &amp;end_value)))
            return;
      }

      /* Set bits CPU list bits */
      for (val = start_value; val &lt;= end_value; val++)
      {
         if ((unsigned)val &lt; 32)
            list-&gt;mask |= (uint32_t)(UINT32_C(1) &lt;&lt; val);
      }

      /* Jump to next item */
      p = q;
      if (p &lt; end)
         p++;
   }
}

/**
 * cpulist_read_from:
 *
 * Read a CPU list from one sysfs file
 **/
static void cpulist_read_from(CpuList* list, const char* filename)
{
   ssize_t _len;
   char *buf  = NULL;

   list-&gt;mask = 0;

   if (filestream_read_file(filename, (void**)&amp;buf, &amp;_len) != 1)
      return;

   cpulist_parse(list, &amp;buf, _len);
   if (buf)
      free(buf);
   buf = NULL;
}
#endif

#endif

unsigned cpu_features_get_core_amount(void)
{
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
   /* Win32 */
   SYSTEM_INFO sysinfo;
#if defined(__WINRT__) || defined(WINAPI_FAMILY) &amp;&amp; WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
   GetNativeSystemInfo(&amp;sysinfo);
#else
   GetSystemInfo(&amp;sysinfo);
#endif
   return sysinfo.dwNumberOfProcessors;
#elif defined(GEKKO)
   return 1;
#elif defined(PSP) || defined(PS2)
   return 1;
#elif defined(__PSL1GHT__) || !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
   return 1; /* Only one PPU, SPUs don't really count */
#elif defined(VITA)
   return 4;
#elif defined(HAVE_LIBNX) || defined(SWITCH)
   return 4;
#elif defined(_3DS)
   u8 device_model = 0xFF;
   CFGU_GetSystemModel(&amp;device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
   switch (device_model)
   {
		case 0:
		case 1:
		case 3:
			/*Old 3/2DS*/
			return 2;

		case 2:
		case 4:
		case 5:
			/*New 3/2DS*/
			return 4;

		default:
			/*Unknown Device Or Check Failed*/
			break;
   }
   return 1;
#elif defined(WIIU)
   return 3;
#elif defined(_SC_NPROCESSORS_ONLN)
   /* Linux, most UNIX-likes. */
   long ret = sysconf(_SC_NPROCESSORS_ONLN);
   if (ret &lt;= 0)
      return (unsigned)1;
   return (unsigned)ret;
#elif defined(BSD) || defined(__APPLE__)
   /* BSD */
   /* Copypasta from stackoverflow, dunno if it works. */
   int num_cpu = 0;
   int mib[4];
   size_t _len = sizeof(num_cpu);

   mib[0] = CTL_HW;
   mib[1] = HW_AVAILCPU;
   sysctl(mib, 2, &amp;num_cpu, &amp;_len, NULL, 0);
   if (num_cpu &lt; 1)
   {
      mib[1] = HW_NCPU;
      sysctl(mib, 2, &amp;num_cpu, &amp;_len, NULL, 0);
      if (num_cpu &lt; 1)
         num_cpu = 1;
   }
   return num_cpu;
#elif defined(__linux__)
   CpuList  cpus_present[1];
   CpuList  cpus_possible[1];
   int amount = 0;

   cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
   cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");

   /* Compute the intersection of both sets to get the actual number of
    * CPU cores that can be used on this device by the kernel.
    */
   cpus_present-&gt;mask &amp;= cpus_possible-&gt;mask;
   amount              = __builtin_popcount(cpus_present-&gt;mask);

   if (amount == 0)
      return 1;
   return amount;
#elif defined(_XBOX360)
   return 3;
#else
   /* No idea, assume single core. */
   return 1;
#endif
}

/* According to http://en.wikipedia.org/wiki/CPUID */
#define VENDOR_INTEL_b  0x756e6547
#define VENDOR_INTEL_c  0x6c65746e
#define VENDOR_INTEL_d  0x49656e69

uint64_t cpu_features_get(void)
{
   uint64_t cpu        = 0;
#if defined(CPU_X86) &amp;&amp; !defined(__MACH__)
   int vendor_is_intel = 0;
   const int avx_flags = (1 &lt;&lt; 27) | (1 &lt;&lt; 28);
#endif
#if defined(__MACH__)
   size_t _len          = sizeof(size_t);
   if (sysctlbyname("hw.optional.floatingpoint", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_CMOV;

#if defined(CPU_X86)
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.mmx", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_MMX | RETRO_SIMD_MMXEXT;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse2", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE2;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse3", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE3;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.supplementalsse3", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSSE3;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse4_1", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE4;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.sse4_2", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_SSE42;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.aes", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_AES;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.avx1_0", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_AVX;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.avx2_0", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_AVX2;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.altivec", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_VMX;
#else
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.neon", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_NEON;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.neon_fp16", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_VFPV3;
   _len            = sizeof(size_t);
   if (sysctlbyname("hw.optional.neon_hpfp", NULL, &amp;_len, NULL, 0) == 0)
      cpu |= RETRO_SIMD_VFPV4;
#endif
#elif defined(_XBOX1)
   cpu |= RETRO_SIMD_MMX | RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
#elif defined(CPU_X86)
   unsigned max_flag   = 0;
   int32_t flags[4];
   int vendor_shuffle[3];
   char vendor[13];
   x86_cpuid(0, flags);
   vendor_shuffle[0] = flags[1];
   vendor_shuffle[1] = flags[3];
   vendor_shuffle[2] = flags[2];

   vendor[0]         = '\0';
   memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));

   /* printf("[CPUID]: Vendor: %s\n", vendor); */

   vendor_is_intel = (
         flags[1] == VENDOR_INTEL_b &amp;&amp;
         flags[2] == VENDOR_INTEL_c &amp;&amp;
         flags[3] == VENDOR_INTEL_d);

   max_flag = flags[0];
   if (max_flag &lt; 1) /* Does CPUID not support func = 1? (unlikely ...) */
      return 0;

   x86_cpuid(1, flags);

   if (flags[3] &amp; (1 &lt;&lt; 15))
      cpu |= RETRO_SIMD_CMOV;

   if (flags[3] &amp; (1 &lt;&lt; 23))
      cpu |= RETRO_SIMD_MMX;

   /* SSE also implies MMXEXT (according to FFmpeg source). */
   if (flags[3] &amp; (1 &lt;&lt; 25))
      cpu |= RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;

   if (flags[3] &amp; (1 &lt;&lt; 26))
      cpu |= RETRO_SIMD_SSE2;

   if (flags[2] &amp; (1 &lt;&lt; 0))
      cpu |= RETRO_SIMD_SSE3;

   if (flags[2] &amp; (1 &lt;&lt; 9))
      cpu |= RETRO_SIMD_SSSE3;

   if (flags[2] &amp; (1 &lt;&lt; 19))
      cpu |= RETRO_SIMD_SSE4;

   if (flags[2] &amp; (1 &lt;&lt; 20))
      cpu |= RETRO_SIMD_SSE42;

   if ((flags[2] &amp; (1 &lt;&lt; 23)))
      cpu |= RETRO_SIMD_POPCNT;

   if (vendor_is_intel &amp;&amp; (flags[2] &amp; (1 &lt;&lt; 22)))
      cpu |= RETRO_SIMD_MOVBE;

   if (flags[2] &amp; (1 &lt;&lt; 25))
      cpu |= RETRO_SIMD_AES;

   /* Must only perform xgetbv check if we have
    * AVX CPU support (guaranteed to have at least i686). */
   if (((flags[2] &amp; avx_flags) == avx_flags)
         &amp;&amp; ((xgetbv_x86(0) &amp; 0x6) == 0x6))
      cpu |= RETRO_SIMD_AVX;

   if (max_flag &gt;= 7)
   {
      x86_cpuid(7, flags);
      if (flags[1] &amp; (1 &lt;&lt; 5))
         cpu |= RETRO_SIMD_AVX2;
   }

   x86_cpuid(0x80000000, flags);
   max_flag = flags[0];
   if (max_flag &gt;= 0x80000001u)
   {
      x86_cpuid(0x80000001, flags);
      if (flags[3] &amp; (1 &lt;&lt; 23))
         cpu |= RETRO_SIMD_MMX;
      if (flags[3] &amp; (1 &lt;&lt; 22))
         cpu |= RETRO_SIMD_MMXEXT;
   }
#elif defined(__linux__)
   if (check_arm_cpu_feature("neon"))
   {
      cpu |= RETRO_SIMD_NEON;
#if defined(__ARM_NEON__) &amp;&amp; defined(__arm__)
      arm_enable_runfast_mode();
#endif
   }

   if (check_arm_cpu_feature("vfpv3"))
      cpu |= RETRO_SIMD_VFPV3;

   if (check_arm_cpu_feature("vfpv4"))
      cpu |= RETRO_SIMD_VFPV4;

   if (check_arm_cpu_feature("asimd"))
   {
      cpu |= RETRO_SIMD_ASIMD;
#ifdef __ARM_NEON__
      cpu |= RETRO_SIMD_NEON;
#if defined(__arm__)
      arm_enable_runfast_mode();
#endif
#endif
   }
#elif defined(__ARM_NEON__)
   cpu |= RETRO_SIMD_NEON;
#if defined(__arm__)
   arm_enable_runfast_mode();
#endif
#elif defined(__ALTIVEC__)
   cpu |= RETRO_SIMD_VMX;
#elif defined(XBOX360)
   cpu |= RETRO_SIMD_VMX128;
#elif defined(PSP) || defined(PS2)
   cpu |= RETRO_SIMD_VFPU;
#elif defined(GEKKO)
   cpu |= RETRO_SIMD_PS;
#endif

   return cpu;
}

void cpu_features_get_model_name(char *s, int len)
{
#if defined(CPU_X86) &amp;&amp; !defined(__MACH__)
   union {
      int32_t i[4];
      uint32_t u[4];
      uint8_t s[16];
   } flags;
   int i, j;
   int pos = 0;
   bool start = false;

   if (!s)
      return;

   x86_cpuid(0x80000000, flags.i);

   /* Check for additional cpuid attributes availability */
   if (flags.u[0] &lt; 0x80000004)
      return;

   for (i = 0; i &lt; 3; i++)
   {
      memset(flags.i, 0, sizeof(flags.i));
      x86_cpuid(0x80000002 + i, flags.i);

      for (j = 0; j &lt; (int)sizeof(flags.s); j++)
      {
         if (!start &amp;&amp; flags.s[j] == ' ')
            continue;
         else
            start = true;

         if (pos == len - 1)
         {
            /* truncate if we ran out of room */
            s[pos] = '\0';
            goto end;
         }

         s[pos++] = flags.s[j];
      }
   }
end:
   /* terminate our string */
   if (pos &lt; len)
      s[pos] = '\0';
#elif defined(__MACH__)
   if (!s)
      return;
   {
      size_t __len = len;
      sysctlbyname("machdep.cpu.brand_string", s, &amp;__len, NULL, 0);
   }
#elif defined(__linux__)
   if (!s)
      return;
   {
      char *model_name, line[128];
      RFILE *fp = filestream_open("/proc/cpuinfo",
            RETRO_VFS_FILE_ACCESS_READ,
            RETRO_VFS_FILE_ACCESS_HINT_NONE);

      if (!fp)
         return;

      while (filestream_gets(fp, line, sizeof(line)))
      {
         if (strncmp(line, "model name", 10))
            continue;

         if ((model_name = strstr(line + 10, ": ")))
         {
            model_name += 2;
            strncpy(s, model_name, len);
            s[len - 1] = '\0';
         }

         break;
      }

      filestream_close(fp);
   }
#endif
}</pre>
<h2>./include/libretro-common/file/archive_file_7z.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file_sevenzip.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;

#include &lt;boolean.h&gt;
#include &lt;file/archive_file.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;encodings/utf.h&gt;
#include &lt;encodings/crc32.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;7zip/7z.h&gt;
#include &lt;7zip/7zCrc.h&gt;
#include &lt;7zip/7zFile.h&gt;

#define SEVENZIP_MAGIC "7z\xBC\xAF\x27\x1C"
#define SEVENZIP_MAGIC_LEN 6
#define SEVENZIP_LOOKTOREAD_BUF_SIZE (1 &lt;&lt; 14)

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500 || defined(_XBOX)
#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif
#endif

struct sevenzip_context_t
{
   uint8_t *output;
   CFileInStream archiveStream;
   CLookToRead2 lookStream;
   ISzAlloc allocImp;
   ISzAlloc allocTempImp;
   CSzArEx db;
   size_t temp_size;
   uint32_t parse_index;
   uint32_t decompress_index;
   uint32_t packIndex;
   uint32_t block_index;
};

static void *sevenzip_stream_alloc_impl(ISzAllocPtr p, size_t len)
{
   if (len == 0)
      return 0;
   return malloc(len);
}

static void sevenzip_stream_free_impl(ISzAllocPtr p, void *address)
{
   if (address)
      free(address);
}

static void *sevenzip_stream_alloc_tmp_impl(ISzAllocPtr p, size_t len)
{
   if (len == 0)
      return 0;
   return malloc(len);
}

static void* sevenzip_stream_new(void)
{
   struct sevenzip_context_t *sevenzip_context =
         (struct sevenzip_context_t*)calloc(1, sizeof(struct sevenzip_context_t));

   /* These are the allocation routines - currently using
    * the non-standard 7zip choices. */
   sevenzip_context-&gt;allocImp.Alloc     = sevenzip_stream_alloc_impl;
   sevenzip_context-&gt;allocImp.Free      = sevenzip_stream_free_impl;
   sevenzip_context-&gt;allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;
   sevenzip_context-&gt;allocTempImp.Free  = sevenzip_stream_free_impl;
   sevenzip_context-&gt;block_index        = 0xFFFFFFFF;
   sevenzip_context-&gt;output             = NULL;

   sevenzip_context-&gt;lookStream.bufSize = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);
   sevenzip_context-&gt;lookStream.buf     = (Byte*)malloc(sevenzip_context-&gt;lookStream.bufSize);

   if (!sevenzip_context-&gt;lookStream.buf)
      sevenzip_context-&gt;lookStream.bufSize = 0;

   return sevenzip_context;
}

static void sevenzip_parse_file_free(void *context)
{
   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;

   if (!sevenzip_context)
      return;

   if (sevenzip_context-&gt;output)
   {
      IAlloc_Free(&amp;sevenzip_context-&gt;allocImp, sevenzip_context-&gt;output);
      sevenzip_context-&gt;output       = NULL;
   }

   SzArEx_Free(&amp;sevenzip_context-&gt;db, &amp;sevenzip_context-&gt;allocImp);
   File_Close(&amp;sevenzip_context-&gt;archiveStream.file);

   if (sevenzip_context-&gt;lookStream.buf)
      free(sevenzip_context-&gt;lookStream.buf);

   free(sevenzip_context);
}

/* Extract the relative path (needle) from a 7z archive
 * (path) and allocate a buf for it to write it in.
 * If optional_outfile is set, extract to that instead
 * and don't allocate buffer.
 */
static int64_t sevenzip_file_read(
      const char *path,
      const char *needle, void **buf,
      const char *optional_outfile)
{
   CSzArEx db;
   CFileInStream archiveStream;
   CLookToRead2 lookStream;
   ISzAlloc allocImp;
   ISzAlloc allocTempImp;
   uint8_t *output      = 0;
   int64_t outsize      = -1;

   /*These are the allocation routines.
    * Currently using the non-standard 7zip choices. */
   allocImp.Alloc       = sevenzip_stream_alloc_impl;
   allocImp.Free        = sevenzip_stream_free_impl;
   allocTempImp.Alloc   = sevenzip_stream_alloc_tmp_impl;
   allocTempImp.Free    = sevenzip_stream_free_impl;

   lookStream.bufSize   = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);
   lookStream.buf       = (Byte*)malloc(lookStream.bufSize);

   if (!lookStream.buf)
      lookStream.bufSize = 0;

#if defined(_WIN32) &amp;&amp; defined(USE_WINDOWS_FILE) &amp;&amp; !defined(LEGACY_WIN32)
   if (!string_is_empty(path))
   {
      wchar_t *path_w = utf8_to_utf16_string_alloc(path);
      if (path_w)
      {
         /* Could not open 7zip archive? */
         if (InFile_OpenW(&amp;archiveStream.file, path_w))
         {
            free(path_w);
            return -1;
         }
         free(path_w);
      }
   }
#else
   /* Could not open 7zip archive? */
   if (InFile_Open(&amp;archiveStream.file, path))
      return -1;
#endif

   FileInStream_CreateVTable(&amp;archiveStream);
   LookToRead2_CreateVTable(&amp;lookStream, false);
   lookStream.realStream = &amp;archiveStream.vt;
   LookToRead2_Init(&amp;lookStream);
   CrcGenerateTable();

   memset(&amp;db, 0, sizeof(db));

   SzArEx_Init(&amp;db);

   if (SzArEx_Open(&amp;db, &amp;lookStream.vt, &amp;allocImp, &amp;allocTempImp) == SZ_OK)
   {
      uint32_t i;
      bool file_found      = false;
      uint16_t *temp       = NULL;
      size_t temp_size     = 0;
      uint32_t block_index   = 0xFFFFFFFF;
      SRes res             = SZ_OK;

      for (i = 0; i &lt; db.NumFiles; i++)
      {
         size_t _len;
         char infile[PATH_MAX_LENGTH];
         size_t offset                = 0;
         size_t outSizeProcessed      = 0;

         /* We skip over everything which is not a directory.
          * FIXME: Why continue then if IsDir is true?*/
         if (SzArEx_IsDir(&amp;db, i))
            continue;

         _len = SzArEx_GetFileNameUtf16(&amp;db, i, NULL);

         if (_len &gt; temp_size)
         {
            if (temp)
               free(temp);
            temp_size = _len;
            temp      = (uint16_t *)malloc(temp_size * sizeof(temp[0]));

            if (temp == 0)
            {
               res = SZ_ERROR_MEM;
               break;
            }
         }

         SzArEx_GetFileNameUtf16(&amp;db, i, temp);
         res       = SZ_ERROR_FAIL;
         infile[0] = '\0';

         if (temp)
            res = utf16_to_char_string(temp, infile, sizeof(infile))
               ? SZ_OK : SZ_ERROR_FAIL;

         if (string_is_equal(infile, needle))
         {
            size_t output_size   = 0;

            /* C LZMA SDK does not support chunked extraction - see here:
             * sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/
             * */
            file_found = true;
            res = SzArEx_Extract(&amp;db, &amp;lookStream.vt, i, &amp;block_index,
                  &amp;output, &amp;output_size, &amp;offset, &amp;outSizeProcessed,
                  &amp;allocImp, &amp;allocTempImp);

            if (res != SZ_OK)
               break; /* This goes to the error section. */

            outsize = (int64_t)outSizeProcessed;

            if (optional_outfile)
            {
               const void *ptr = (const void*)(output + offset);

               if (!filestream_write_file(optional_outfile, ptr, outsize))
               {
                  res        = SZ_OK;
                  file_found = true;
                  outsize    = -1;
               }
            }
            else
            {
               /*We could either use the 7Zip allocated buffer,
                * or create our own and use it.
                * We would however need to realloc anyways, because RetroArch
                * expects a \0 at the end, therefore we allocate new,
                * copy and free the old one. */
               *buf = malloc((size_t)(outsize + 1));
               ((char*)(*buf))[outsize] = '\0';
               memcpy(*buf, output + offset, outsize);
            }
            break;
         }
      }

      if (temp)
         free(temp);
      IAlloc_Free(&amp;allocImp, output);

      if (!(file_found &amp;&amp; res == SZ_OK))
      {
         /* Error handling
          *
          * Failed to open compressed file inside 7zip archive.
          */

         outsize    = -1;
      }
   }

   SzArEx_Free(&amp;db, &amp;allocImp);
   File_Close(&amp;archiveStream.file);

   if (lookStream.buf)
      free(lookStream.buf);

   return outsize;
}

static bool sevenzip_stream_decompress_data_to_file_init(
      void *context, file_archive_file_handle_t *handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
{
   struct sevenzip_context_t *sevenzip_context =
         (struct sevenzip_context_t*)context;

   if (!sevenzip_context)
      return false;

   sevenzip_context-&gt;decompress_index = (uint32_t)(size_t)cdata;

   return true;
}

static int sevenzip_stream_decompress_data_to_file_iterate(
      void *context, file_archive_file_handle_t *handle)
{
   struct sevenzip_context_t *sevenzip_context =
         (struct sevenzip_context_t*)context;

   SRes res                = SZ_ERROR_FAIL;
   size_t output_size      = 0;
   size_t offset           = 0;
   size_t outSizeProcessed = 0;

   res = SzArEx_Extract(&amp;sevenzip_context-&gt;db,
         &amp;sevenzip_context-&gt;lookStream.vt, sevenzip_context-&gt;decompress_index,
         &amp;sevenzip_context-&gt;block_index, &amp;sevenzip_context-&gt;output,
         &amp;output_size, &amp;offset, &amp;outSizeProcessed,
         &amp;sevenzip_context-&gt;allocImp, &amp;sevenzip_context-&gt;allocTempImp);

   if (res != SZ_OK)
      return 0;

   if (handle)
      handle-&gt;data = sevenzip_context-&gt;output + offset;

   return 1;
}

static int sevenzip_parse_file_init(file_archive_transfer_t *state,
      const char *file)
{
   uint8_t magic_buf[SEVENZIP_MAGIC_LEN];
   struct sevenzip_context_t *sevenzip_context = NULL;

   if (state-&gt;archive_size &lt; SEVENZIP_MAGIC_LEN)
      goto error;

   filestream_seek(state-&gt;archive_file, 0, SEEK_SET);
   if (filestream_read(state-&gt;archive_file, magic_buf, SEVENZIP_MAGIC_LEN) != SEVENZIP_MAGIC_LEN)
      goto error;

   if (memcmp(magic_buf, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN) != 0)
      goto error;

   sevenzip_context = (struct sevenzip_context_t*)sevenzip_stream_new();
   state-&gt;context = sevenzip_context;

#if defined(_WIN32) &amp;&amp; defined(USE_WINDOWS_FILE) &amp;&amp; !defined(LEGACY_WIN32)
   if (!string_is_empty(file))
   {
      wchar_t *file_w = utf8_to_utf16_string_alloc(file);

      if (file_w)
      {
         /* could not open 7zip archive? */
         if (InFile_OpenW(&amp;sevenzip_context-&gt;archiveStream.file, file_w))
         {
            free(file_w);
            goto error;
         }

         free(file_w);
      }
   }
#else
   /* could not open 7zip archive? */
   if (InFile_Open(&amp;sevenzip_context-&gt;archiveStream.file, file))
      goto error;
#endif

   FileInStream_CreateVTable(&amp;sevenzip_context-&gt;archiveStream);
   LookToRead2_CreateVTable(&amp;sevenzip_context-&gt;lookStream, false);
   sevenzip_context-&gt;lookStream.realStream = &amp;sevenzip_context-&gt;archiveStream.vt;
   LookToRead2_Init(&amp;sevenzip_context-&gt;lookStream);
   CrcGenerateTable();
   SzArEx_Init(&amp;sevenzip_context-&gt;db);

   if (SzArEx_Open(&amp;sevenzip_context-&gt;db, &amp;sevenzip_context-&gt;lookStream.vt,
         &amp;sevenzip_context-&gt;allocImp, &amp;sevenzip_context-&gt;allocTempImp) != SZ_OK)
      goto error;

   state-&gt;step_total = sevenzip_context-&gt;db.NumFiles;

   return 0;

error:
   if (sevenzip_context)
      sevenzip_parse_file_free(sevenzip_context);
   state-&gt;context = NULL;
   return -1;
}

static int sevenzip_parse_file_iterate_step_internal(
      struct sevenzip_context_t *sevenzip_context,
      char *s,
      const uint8_t **cdata,
      unsigned *cmode,
      uint32_t *size,
      uint32_t *csize,
      uint32_t *checksum,
      unsigned *payback,
      struct archive_extract_userdata *userdata)
{
   if (sevenzip_context-&gt;parse_index &lt; sevenzip_context-&gt;db.NumFiles)
   {
      size_t _len = SzArEx_GetFileNameUtf16(&amp;sevenzip_context-&gt;db,
            sevenzip_context-&gt;parse_index, NULL);
      uint64_t compressed_size = 0;

      if (sevenzip_context-&gt;packIndex &lt; sevenzip_context-&gt;db.db.NumPackStreams)
      {
         compressed_size = sevenzip_context-&gt;db.db.PackPositions[sevenzip_context-&gt;packIndex + 1] -
               sevenzip_context-&gt;db.db.PackPositions[sevenzip_context-&gt;packIndex];

         sevenzip_context-&gt;packIndex++;
      }

      if (   (_len &lt; PATH_MAX_LENGTH)
          &amp;&amp; !SzArEx_IsDir(&amp;sevenzip_context-&gt;db, sevenzip_context-&gt;parse_index))
      {
         SRes res       = SZ_ERROR_FAIL;
         uint16_t *temp = (uint16_t*)malloc(_len * sizeof(uint16_t));

         if (!temp)
            return -1;

         SzArEx_GetFileNameUtf16(&amp;sevenzip_context-&gt;db, sevenzip_context-&gt;parse_index,
               temp);

         if (temp)
         {
            res  = utf16_to_char_string(temp, s, PATH_MAX_LENGTH)
               ? SZ_OK : SZ_ERROR_FAIL;
            free(temp);
         }

         if (res != SZ_OK)
            return -1;

         *cmode    = 0; /* unused for 7zip */
         *checksum = sevenzip_context-&gt;db.CRCs.Vals[sevenzip_context-&gt;parse_index];
         *size     = (uint32_t)SzArEx_GetFileSize(&amp;sevenzip_context-&gt;db, sevenzip_context-&gt;parse_index);
         *csize    = (uint32_t)compressed_size;

         *cdata    = (uint8_t *)(size_t)sevenzip_context-&gt;parse_index;
      }
   }
   else
      return 0;

   *payback = 1;

   return 1;
}

static int sevenzip_parse_file_iterate_step(void *context,
      const char *valid_exts,
      struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)
{
   const uint8_t *cdata = NULL;
   uint32_t checksum    = 0;
   uint32_t size        = 0;
   uint32_t csize       = 0;
   unsigned cmode       = 0;
   unsigned payload     = 0;
   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;
   int ret;

   userdata-&gt;current_file_path[0] = '\0';

   ret = sevenzip_parse_file_iterate_step_internal(sevenzip_context,
         userdata-&gt;current_file_path,
         &amp;cdata, &amp;cmode, &amp;size, &amp;csize,
         &amp;checksum, &amp;payload, userdata);

   if (ret != 1)
      return ret;

   userdata-&gt;crc                 = checksum;

   if (file_cb &amp;&amp; !file_cb(userdata-&gt;current_file_path, valid_exts,
            cdata, cmode,
            csize, size, checksum, userdata))
      return 0;

   sevenzip_context-&gt;parse_index += payload;

   return 1;
}

static uint32_t sevenzip_stream_crc32_calculate(uint32_t crc,
      const uint8_t *data, size_t len)
{
   return encoding_crc32(crc, data, len);
}

const struct file_archive_file_backend sevenzip_backend = {
   sevenzip_parse_file_init,
   sevenzip_parse_file_iterate_step,
   sevenzip_parse_file_free,
   sevenzip_stream_decompress_data_to_file_init,
   sevenzip_stream_decompress_data_to_file_iterate,
   sevenzip_stream_crc32_calculate,
   sevenzip_file_read,
   "7z"
};</pre>
<h2>./include/libretro-common/file/archive_file.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;compat/strl.h&gt;
#include &lt;file/archive_file.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;string/stdstring.h&gt;

#ifdef HAVE_MMAP
#include &lt;fcntl.h&gt;
#include &lt;errno.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;sys/stat.h&gt;
#endif

static int file_archive_get_file_list_cb(
      const char *path,
      const char *valid_exts,
      const uint8_t *cdata,
      unsigned cmode,
      uint32_t csize,
      uint32_t size,
      uint32_t checksum,
      struct archive_extract_userdata *userdata)
{
   union string_list_elem_attr attr;
   attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;

   if (valid_exts)
   {
      size_t _len                  = strlen(path);
      /* Checks if this entry is a directory or a file. */
      char last_char               = path[_len - 1];
      struct string_list ext_list  = {0};

      /* Skip if directory. */
      if (last_char == '/' || last_char == '\\' )
         return 1;

      string_list_initialize(&amp;ext_list);
      if (string_split_noalloc(&amp;ext_list, valid_exts, "|"))
      {
         const char *file_ext = path_get_extension(path);

         if (!file_ext)
         {
            string_list_deinitialize(&amp;ext_list);
            return 1;
         }

         if (!string_list_find_elem_prefix(&amp;ext_list, ".", file_ext))
         {
            /* keep iterating */
            string_list_deinitialize(&amp;ext_list);
            return -1;
         }
      }

      string_list_deinitialize(&amp;ext_list);
   }

   return string_list_append(userdata-&gt;list, path, attr);
}

static int file_archive_extract_cb(const char *name, const char *valid_exts,
      const uint8_t *cdata,
      unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t checksum, struct archive_extract_userdata *userdata)
{
   const char *ext                   = path_get_extension(name);

   /* Extract first file that matches our list. */
   if (ext &amp;&amp; string_list_find_elem(userdata-&gt;ext, ext))
   {
      char new_path[PATH_MAX_LENGTH];
      const char *delim;

      if ((delim = path_get_archive_delim(userdata-&gt;archive_path)))
      {
         if (!string_is_equal_noncase(
                  userdata-&gt;current_file_path, delim + 1))
           return 1; /* keep searching for the right file */
      }

      if (userdata-&gt;extraction_directory)
         fill_pathname_join_special(new_path, userdata-&gt;extraction_directory,
               path_basename(name), sizeof(new_path));
      else
         fill_pathname_resolve_relative(new_path, userdata-&gt;archive_path,
               path_basename(name), sizeof(new_path));

      if (file_archive_perform_mode(new_path,
                valid_exts, cdata, cmode, csize, size,
                checksum, userdata))
      {
         userdata-&gt;found_file = true;
         userdata-&gt;first_extracted_file_path = strdup(new_path);
      }

      return 0;
   }

   return 1;
}

static int file_archive_parse_file_init(file_archive_transfer_t *state,
      const char *file)
{
   char path[PATH_MAX_LENGTH];
   char *last                 = NULL;

   strlcpy(path, file, sizeof(path));

   if ((last = (char*)path_get_archive_delim(path)))
      *last  = '\0';

   if (!(state-&gt;backend = file_archive_get_file_backend(path)))
      return -1;

   /* Failed to open archive. */
   if (!(state-&gt;archive_file = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return -1;

   state-&gt;archive_size = filestream_get_size(state-&gt;archive_file);

#ifdef HAVE_MMAP
   if (state-&gt;archive_size &lt;= (256*1024*1024))
   {
      state-&gt;archive_mmap_fd = open(path, O_RDONLY);
      if (state-&gt;archive_mmap_fd)
      {
         state-&gt;archive_mmap_data = (uint8_t*)mmap(NULL,
               (size_t)state-&gt;archive_size,
               PROT_READ, MAP_SHARED, state-&gt;archive_mmap_fd, 0);

         if (state-&gt;archive_mmap_data == (uint8_t*)MAP_FAILED)
         {
            close(state-&gt;archive_mmap_fd);
            state-&gt;archive_mmap_fd = 0;
            state-&gt;archive_mmap_data = NULL;
         }
      }
   }
#endif

   state-&gt;step_current = 0;
   state-&gt;step_total   = 0;

   return state-&gt;backend-&gt;archive_parse_file_init(state, path);
}

void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state)
{
   if (!state || !state-&gt;archive_file)
      return;

   state-&gt;type = ARCHIVE_TRANSFER_DEINIT;
   file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL);
}

int file_archive_parse_file_iterate(
      file_archive_transfer_t *state,
      bool *returnerr,
      const char *file,
      const char *valid_exts,
      file_archive_file_cb file_cb,
      struct archive_extract_userdata *userdata)
{
   if (!state)
      return -1;

   switch (state-&gt;type)
   {
      case ARCHIVE_TRANSFER_NONE:
         break;
      case ARCHIVE_TRANSFER_INIT:
         if (file_archive_parse_file_init(state, file) == 0)
         {
            if (userdata)
            {
               userdata-&gt;transfer = state;
               strlcpy(userdata-&gt;archive_path, file,
                     sizeof(userdata-&gt;archive_path));
            }
            state-&gt;type = ARCHIVE_TRANSFER_ITERATE;
         }
         else
            state-&gt;type = ARCHIVE_TRANSFER_DEINIT_ERROR;
         break;
      case ARCHIVE_TRANSFER_ITERATE:
         if (state-&gt;backend)
         {
            int ret = state-&gt;backend-&gt;archive_parse_file_iterate_step(
                  state-&gt;context, valid_exts, userdata, file_cb);

            if (ret == 1)
               state-&gt;step_current++; /* found another file */
            if (ret != 1)
               state-&gt;type = ARCHIVE_TRANSFER_DEINIT;
            if (ret == -1)
               state-&gt;type = ARCHIVE_TRANSFER_DEINIT_ERROR;

            /* early return to prevent deinit from never firing */
            return 0;
         }
         return -1;
      case ARCHIVE_TRANSFER_DEINIT_ERROR:
         *returnerr = false;
      case ARCHIVE_TRANSFER_DEINIT:
         if (state-&gt;context)
         {
            if (state-&gt;backend-&gt;archive_parse_file_free)
               state-&gt;backend-&gt;archive_parse_file_free(state-&gt;context);
            state-&gt;context = NULL;
         }

         if (state-&gt;archive_file)
         {
            filestream_close(state-&gt;archive_file);
            state-&gt;archive_file = NULL;
         }

#ifdef HAVE_MMAP
         if (state-&gt;archive_mmap_data)
         {
            munmap(state-&gt;archive_mmap_data, (size_t)state-&gt;archive_size);
            close(state-&gt;archive_mmap_fd);
            state-&gt;archive_mmap_fd = 0;
            state-&gt;archive_mmap_data = NULL;
         }
#endif

         if (userdata)
            userdata-&gt;transfer = NULL;
         break;
   }

   if (  state-&gt;type == ARCHIVE_TRANSFER_DEINIT ||
         state-&gt;type == ARCHIVE_TRANSFER_DEINIT_ERROR)
      return -1;

   return 0;
}

/**
 * file_archive_walk:
 * @file                        : filename path of archive
 * @valid_exts                  : Valid extensions of archive to be parsed.
 *                                If NULL, allow all.
 * @file_cb                     : file_cb function pointer
 * @userdata                    : userdata to pass to file_cb function pointer.
 *
 * Low-level file parsing. Enumerates over all files and calls
 * file_cb with userdata.
 *
 * Returns: true (1) on success, otherwise false (0).
 **/
static bool file_archive_walk(const char *file, const char *valid_exts,
      file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)
{
   file_archive_transfer_t state;
   bool returnerr          = true;

   state.type              = ARCHIVE_TRANSFER_INIT;
   state.archive_file      = NULL;
#ifdef HAVE_MMAP
   state.archive_mmap_fd   = 0;
   state.archive_mmap_data = NULL;
#endif
   state.archive_size      = 0;
   state.context           = NULL;
   state.step_total        = 0;
   state.step_current      = 0;
   state.backend           = NULL;

   for (;;)
   {
      if (file_archive_parse_file_iterate(&amp;state, &amp;returnerr, file,
            valid_exts, file_cb, userdata) != 0)
         break;
   }

   return returnerr;
}

int file_archive_parse_file_progress(file_archive_transfer_t *state)
{
   if (!state || state-&gt;step_total == 0)
      return 0;

   return (int)((state-&gt;step_current * 100) / (state-&gt;step_total));
}

/**
 * file_archive_extract_file:
 * @archive_path                : filename path to archive.
 * @valid_exts                  : valid extensions for the file.
 * @extraction_directory        : the directory to extract temporary
 *                                file to.
 *
 * Extract file from archive. If no file inside the archive is
 * specified, the first file found will be used.
 *
 * Returns : true (1) on success, otherwise false (0).
 **/
bool file_archive_extract_file(
      const char *archive_path,
      const char *valid_exts,
      const char *extraction_directory,
      char *s, size_t len)
{
   struct archive_extract_userdata userdata;
   struct string_list *list                 = string_split(valid_exts, "|");

   userdata.archive_path[0]                 = '\0';
   userdata.current_file_path[0]            = '\0';
   userdata.first_extracted_file_path       = NULL;
   userdata.extraction_directory            = extraction_directory;
   userdata.ext                             = list;
   userdata.list                            = NULL;
   userdata.found_file                      = false;
   userdata.list_only                       = false;
   userdata.crc                             = 0;
   userdata.transfer                        = NULL;
   userdata.dec                             = NULL;

   if (     list
         &amp;&amp; file_archive_walk(archive_path, valid_exts,
            file_archive_extract_cb, &amp;userdata)
         &amp;&amp; userdata.found_file
      )
   {
      if (!string_is_empty(userdata.first_extracted_file_path))
         strlcpy(s, userdata.first_extracted_file_path, len);
      return true;
   }

   if (userdata.first_extracted_file_path)
      free(userdata.first_extracted_file_path);
   if (list)
      string_list_free(list);
   return false;
}

/* Warning: 'list' must zero initialised before
 * calling this function, otherwise memory leaks/
 * undefined behaviour will occur */
bool file_archive_get_file_list_noalloc(struct string_list *list,
      const char *path,
      const char *valid_exts)
{
   struct archive_extract_userdata userdata;

   if (!list || !string_list_initialize(list))
      return false;

   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
   userdata.current_file_path[0]            = '\0';
   userdata.first_extracted_file_path       = NULL;
   userdata.extraction_directory            = NULL;
   userdata.ext                             = NULL;
   userdata.list                            = list;
   userdata.found_file                      = false;
   userdata.list_only                       = true;
   userdata.crc                             = 0;
   userdata.transfer                        = NULL;
   userdata.dec                             = NULL;

   if (!file_archive_walk(path, valid_exts,
            file_archive_get_file_list_cb, &amp;userdata))
      return false;
   return true;
}

/**
 * file_archive_get_file_list:
 * @path                        : filename path of archive
 *
 * Returns: string listing of files from archive on success, otherwise NULL.
 **/
struct string_list *file_archive_get_file_list(const char *path,
      const char *valid_exts)
{
   struct archive_extract_userdata userdata;

   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
   userdata.current_file_path[0]            = '\0';
   userdata.first_extracted_file_path       = NULL;
   userdata.extraction_directory            = NULL;
   userdata.ext                             = NULL;
   userdata.list                            = string_list_new();
   userdata.found_file                      = false;
   userdata.list_only                       = true;
   userdata.crc                             = 0;
   userdata.transfer                        = NULL;
   userdata.dec                             = NULL;

   if (!userdata.list)
      return NULL;
   if (!file_archive_walk(path, valid_exts,
         file_archive_get_file_list_cb, &amp;userdata))
   {
      string_list_free(userdata.list);
      return NULL;
   }
   return userdata.list;
}

bool file_archive_perform_mode(const char *path, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata)
{
   int ret;
   file_archive_file_handle_t handle;

   if (!userdata-&gt;transfer || !userdata-&gt;transfer-&gt;backend)
      return false;

   handle.data          = NULL;
   handle.real_checksum = 0;

   if (!userdata-&gt;transfer-&gt;backend-&gt;stream_decompress_data_to_file_init(
            userdata-&gt;transfer-&gt;context, &amp;handle, cdata, cmode, csize, size))
      return false;

   do
   {
      ret = userdata-&gt;transfer-&gt;backend-&gt;stream_decompress_data_to_file_iterate(
               userdata-&gt;transfer-&gt;context, &amp;handle);
   }while (ret == 0);

   if (ret == -1 || !filestream_write_file(path, handle.data, size))
      return false;

   return true;
}

/**
 * string_list_append_n:
 * @list             : pointer to string list
 * @elem             : element to add to the string list
 * @length           : read at most this many bytes from elem
 * @attr             : attributes of new element.
 *
 * Appends a new element to the string list.
 *
 * @return true if successful, otherwise false.
 **/
static bool string_list_append_n(struct string_list *list,
      const char *elem, unsigned length,
      union string_list_elem_attr attr)
{
   char *data_dup = NULL;

   if (list-&gt;size &gt;= list-&gt;cap &amp;&amp;
         !string_list_capacity(list, list-&gt;cap * 2))
      return false;

   if (!(data_dup = (char*)malloc(length + 1)))
      return false;

   strlcpy(data_dup, elem, length + 1);

   list-&gt;elems[list-&gt;size].data = data_dup;
   list-&gt;elems[list-&gt;size].attr = attr;

   list-&gt;size++;
   return true;
}


/**
 * file_archive_filename_split:
 * @str              : filename to turn into a string list
 *
 * Creates a new string list based on filename @path, delimited by a hash (#).
 *
 * Returns: new string list if successful, otherwise NULL.
 */
static struct string_list *file_archive_filename_split(const char *path)
{
   union string_list_elem_attr attr;
   struct string_list *list = string_list_new();
   const char *delim        = path_get_archive_delim(path);

   attr.i = 0;

   if (delim)
   {
      /* add archive path to list first */
      if (!string_list_append_n(list, path, (unsigned)(delim - path), attr))
      {
         string_list_free(list);
         return NULL;
      }

      /* now add the path within the archive */
      delim++;

      if (*delim)
      {
         if (!string_list_append(list, delim, attr))
         {
            string_list_free(list);
            return NULL;
         }
      }
   }
   else
   {
      if (!string_list_append(list, path, attr))
      {
         string_list_free(list);
         return NULL;
      }
   }

   return list;
}

/* Generic compressed file loader.
 * Extracts to buf, unless optional_filename != 0
 * Then extracts to optional_filename and leaves buf alone.
 */
int file_archive_compressed_read(
      const char * path, void **buf,
      const char* optional_filename, int64_t *len)
{
   const struct
      file_archive_file_backend *backend = NULL;
   struct string_list *str_list          = NULL;

   /* Safety check.
    * If optional_filename and optional_filename
    * exists, we simply return 0,
    * hoping that optional_filename is the
    * same as requested.
    */
   if (optional_filename &amp;&amp; path_is_valid(optional_filename))
   {
      *len = 0;
      return 1;
   }

   str_list       = file_archive_filename_split(path);
   /* We assure that there is something after the '#' symbol.
    *
    * This error condition happens for example, when
    * path = /path/to/file.7z, or
    * path = /path/to/file.7z#
    */
   if (str_list-&gt;size &lt;= 1)
   {
      /* could not extract string and substring. */
      string_list_free(str_list);
      *len = 0;
      return 0;
   }

   backend = file_archive_get_file_backend(str_list-&gt;elems[0].data);
   *len    = backend-&gt;compressed_file_read(str_list-&gt;elems[0].data,
         str_list-&gt;elems[1].data, buf, optional_filename);

   string_list_free(str_list);

   if (*len != -1)
      return 1;

   return 0;
}

const struct file_archive_file_backend *file_archive_get_zlib_file_backend(void)
{
#ifdef HAVE_ZLIB
   return &amp;zlib_backend;
#else
   return NULL;
#endif
}

const struct file_archive_file_backend *file_archive_get_7z_file_backend(void)
{
#ifdef HAVE_7ZIP
   return &amp;sevenzip_backend;
#else
   return NULL;
#endif
}

const struct file_archive_file_backend* file_archive_get_file_backend(const char *path)
{
#if defined(HAVE_7ZIP) || defined(HAVE_ZLIB)
   char newpath[PATH_MAX_LENGTH];
   const char *file_ext          = NULL;
   char *last                    = NULL;

   strlcpy(newpath, path, sizeof(newpath));

   if ((last = (char*)path_get_archive_delim(newpath)))
      *last  = '\0';

   file_ext  = path_get_extension(newpath);

#ifdef HAVE_7ZIP
   if (string_is_equal_noncase(file_ext, "7z"))
      return &amp;sevenzip_backend;
#endif

#ifdef HAVE_ZLIB
   if (     string_is_equal_noncase(file_ext, "zip")
         || string_is_equal_noncase(file_ext, "apk")
      )
      return &amp;zlib_backend;
#endif
#endif

   return NULL;
}

/**
 * file_archive_get_file_crc32:
 * @path                         : filename path of archive
 *
 * Returns: CRC32 of the specified file in the archive, otherwise 0.
 * If no path within the archive is specified, the first
 * file found inside is used.
 **/
uint32_t file_archive_get_file_crc32(const char *path)
{
   file_archive_transfer_t state;
   struct archive_extract_userdata userdata        = {0};
   bool returnerr                                  = false;
   const char *archive_path                        = NULL;
   bool contains_compressed = path_contains_compressed_file(path);

   if (contains_compressed)
   {
      archive_path = path_get_archive_delim(path);

      /* move pointer right after the delimiter to give us the path */
      if (archive_path)
         archive_path += 1;
   }

   state.type              = ARCHIVE_TRANSFER_INIT;
   state.archive_file      = NULL;
#ifdef HAVE_MMAP
   state.archive_mmap_fd   = 0;
   state.archive_mmap_data = NULL;
#endif
   state.archive_size      = 0;
   state.context           = NULL;
   state.step_total        = 0;
   state.step_current      = 0;
   state.backend           = NULL;

   /* Initialize and open archive first.
      Sets next state type to ITERATE. */
   file_archive_parse_file_iterate(&amp;state,
            &amp;returnerr, path, NULL, NULL,
            &amp;userdata);

   for (;;)
   {
      /* Now find the first file in the archive. */
      if (state.type == ARCHIVE_TRANSFER_ITERATE)
         file_archive_parse_file_iterate(&amp;state,
                  &amp;returnerr, path, NULL, NULL,
                  &amp;userdata);

      /* If no path specified within archive, stop after
       * finding the first file.
       */
      if (!contains_compressed)
         break;

      /* Stop when the right file in the archive is found. */
      if (archive_path)
      {
         if (string_is_equal(userdata.current_file_path, archive_path))
            break;
      }
      else
         break;
   }

   file_archive_parse_file_iterate_stop(&amp;state);

   return userdata.crc;
}</pre>
<h2>./include/libretro-common/file/archive_file_zlib.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file_zlib.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;file/archive_file.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;encodings/crc32.h&gt;

#include &lt;zlib.h&gt;

#ifndef CENTRAL_FILE_HEADER_SIGNATURE
#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
#endif

#ifndef END_OF_CENTRAL_DIR_SIGNATURE
#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
#endif

#define _READ_CHUNK_SIZE   (128*1024)   /* Read 128KiB compressed chunks */

enum file_archive_compression_mode
{
   ZIP_MODE_STORED   = 0,
   ZIP_MODE_DEFLATED = 8
};

typedef struct
{
   struct file_archive_transfer *state;
   uint8_t *directory;
   uint8_t *directory_entry;
   uint8_t *directory_end;
   uint64_t fdoffset;
   uint32_t boffset, csize, usize;
   unsigned cmode;
   z_stream *zstream;
   uint8_t *tmpbuf;
   uint8_t *decompressed_data;
} zip_context_t;

static INLINE uint32_t read_le(const uint8_t *data, size_t len)
{
   unsigned i;
   uint32_t val = 0;
   len *= 8;
   for (i = 0; i &lt; len; i += 8)
      val |= (uint32_t)*data++ &lt;&lt; i;
   return val;
}

static void zip_context_free_stream(
      zip_context_t *zip_context, bool keep_decompressed)
{
   if (zip_context-&gt;zstream)
   {
      inflateEnd(zip_context-&gt;zstream);
      free(zip_context-&gt;zstream);
      zip_context-&gt;fdoffset = 0;
      zip_context-&gt;csize = 0;
      zip_context-&gt;usize = 0;
      zip_context-&gt;zstream = NULL;
   }
   if (zip_context-&gt;tmpbuf)
   {
      free(zip_context-&gt;tmpbuf);
      zip_context-&gt;tmpbuf = NULL;
   }
   if (zip_context-&gt;decompressed_data &amp;&amp; !keep_decompressed)
   {
      free(zip_context-&gt;decompressed_data);
      zip_context-&gt;decompressed_data = NULL;
   }
}

static bool zlib_stream_decompress_data_to_file_init(
      void *context, file_archive_file_handle_t *handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
{
   int64_t offsetData;
   uint8_t *local_header;
   uint32_t offsetNL, offsetEL;
   uint8_t local_header_buf[4];
   zip_context_t *zip_context = (zip_context_t *)context;
   struct file_archive_transfer *state = zip_context-&gt;state;

   /* free previous data and stream if left unfinished */
   zip_context_free_stream(zip_context, false);

   /* seek past most of the local directory header */
#ifdef HAVE_MMAP
   if (state-&gt;archive_mmap_data)
      local_header = state-&gt;archive_mmap_data + (size_t)cdata + 26;
   else
#endif
   {
      filestream_seek(state-&gt;archive_file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);
      if (filestream_read(state-&gt;archive_file, local_header_buf, 4) != 4)
      {
         zip_context_free_stream(zip_context, false);
         return false;
      }
      local_header = local_header_buf;
   }

   offsetNL = read_le(local_header,     2); /* file name length */
   offsetEL = read_le(local_header + 2, 2); /* extra field length */
   offsetData = (int64_t)(size_t)cdata + 26 + 4 + offsetNL + offsetEL;

   zip_context-&gt;fdoffset              = offsetData;
   zip_context-&gt;usize                 = size;
   zip_context-&gt;csize                 = csize;
   zip_context-&gt;boffset               = 0;
   zip_context-&gt;cmode                 = cmode;
   zip_context-&gt;decompressed_data     = (uint8_t*)malloc(size);
   zip_context-&gt;zstream               = NULL;
   zip_context-&gt;tmpbuf                = NULL;

   if (cmode == ZIP_MODE_DEFLATED)
   {
      /* Initialize the zlib inflate machinery */
      zip_context-&gt;zstream            = (z_stream*)malloc(sizeof(z_stream));
      zip_context-&gt;tmpbuf             = (uint8_t*)malloc(_READ_CHUNK_SIZE);

      zip_context-&gt;zstream-&gt;next_in   = NULL;
      zip_context-&gt;zstream-&gt;avail_in  = 0;
      zip_context-&gt;zstream-&gt;total_in  = 0;
      zip_context-&gt;zstream-&gt;next_out  = zip_context-&gt;decompressed_data;
      zip_context-&gt;zstream-&gt;avail_out = size;
      zip_context-&gt;zstream-&gt;total_out = 0;

      zip_context-&gt;zstream-&gt;zalloc    = NULL;
      zip_context-&gt;zstream-&gt;zfree     = NULL;
      zip_context-&gt;zstream-&gt;opaque    = NULL;

      if (inflateInit2(zip_context-&gt;zstream, -MAX_WBITS) != Z_OK)
      {
         free(zip_context-&gt;zstream);
         zip_context-&gt;zstream = NULL;
         zip_context_free_stream(zip_context, false);
         return false;
      }
   }

   return true;
}

static int zlib_stream_decompress_data_to_file_iterate(
      void *context, file_archive_file_handle_t *handle)
{
   int64_t rd;
   zip_context_t *zip_context = (zip_context_t *)context;
   struct file_archive_transfer *state = zip_context-&gt;state;

   if (zip_context-&gt;cmode == ZIP_MODE_STORED)
   {
#ifdef HAVE_MMAP
      /* Simply copy the data to the output buffer */
      if (zip_context-&gt;state-&gt;archive_mmap_data)
         memcpy(zip_context-&gt;decompressed_data,
               zip_context-&gt;state-&gt;archive_mmap_data + (size_t)zip_context-&gt;fdoffset,
               zip_context-&gt;usize);
      else
#endif
      {
         /* Read the entire file to memory */
         filestream_seek(state-&gt;archive_file, zip_context-&gt;fdoffset, RETRO_VFS_SEEK_POSITION_START);
         if (filestream_read(state-&gt;archive_file,
                             zip_context-&gt;decompressed_data,
                             zip_context-&gt;usize) &lt; 0)
            return -1;
      }

      handle-&gt;data = zip_context-&gt;decompressed_data;
      return 1;
   }
   else if (zip_context-&gt;cmode == ZIP_MODE_DEFLATED)
   {
      uint8_t *dptr;
      int to_read = MIN(zip_context-&gt;csize - zip_context-&gt;boffset, _READ_CHUNK_SIZE);
      /* File was uncompressed or decompression finished before */
      if (!zip_context-&gt;zstream)
         return 1;

#ifdef HAVE_MMAP
      if (state-&gt;archive_mmap_data)
      {
         /* Decompress from the mapped file */
         dptr = state-&gt;archive_mmap_data + (size_t)zip_context-&gt;fdoffset + zip_context-&gt;boffset;
         rd   = to_read;
      }
      else
#endif
      {
         /* Read some compressed data from file to the temp buffer */
         filestream_seek(state-&gt;archive_file,
               zip_context-&gt;fdoffset + zip_context-&gt;boffset,
               RETRO_VFS_SEEK_POSITION_START);
         rd = filestream_read(state-&gt;archive_file, zip_context-&gt;tmpbuf, to_read);
         if (rd &lt; 0)
            return -1;
         dptr = zip_context-&gt;tmpbuf;
      }

      zip_context-&gt;boffset           += rd;
      zip_context-&gt;zstream-&gt;next_in   = dptr;
      zip_context-&gt;zstream-&gt;avail_in  = (uInt)rd;

      if (inflate(zip_context-&gt;zstream, 0) &lt; 0)
         return -1;

      if (zip_context-&gt;boffset &gt;= zip_context-&gt;csize)
      {
         inflateEnd(zip_context-&gt;zstream);
         free(zip_context-&gt;zstream);
         zip_context-&gt;zstream = NULL;

         handle-&gt;data = zip_context-&gt;decompressed_data;
         return 1;
      }

      return 0;   /* still more data to process */
   }

   /* No idea what kind of compression this is */
   return -1;
}

static uint32_t zlib_stream_crc32_calculate(uint32_t crc,
      const uint8_t *data, size_t len)
{
   return encoding_crc32(crc, data, len);
}

static bool zip_file_decompressed_handle(
      file_archive_transfer_t *transfer,
      file_archive_file_handle_t* handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize,
      uint32_t size, uint32_t crc32)
{
   int ret   = 0;

   transfer-&gt;backend = &amp;zlib_backend;

   if (!transfer-&gt;backend-&gt;stream_decompress_data_to_file_init(
            transfer-&gt;context, handle, cdata, cmode, csize, size))
      return false;

   do
   {
      ret = transfer-&gt;backend-&gt;stream_decompress_data_to_file_iterate(
            transfer-&gt;context, handle);
      if (ret &lt; 0)
         return false;
   }while (ret == 0);

   return true;
}

typedef struct
{
   char *opt_file;
   char *needle;
   void **buf;
   size_t size;
   bool found;
} decomp_state_t;

/* Extract the relative path (needle) from a
 * ZIP archive (path) and allocate a buffer for it to write it in.
 *
 * optional_outfile if not NULL will be used to extract the file to.
 * buf will be 0 then.
 */

static int zip_file_decompressed(
      const char *name, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode,
      uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata)
{
   decomp_state_t* decomp_state = (decomp_state_t*)userdata-&gt;cb_data;
   char last_char = name[strlen(name) - 1];
   /* Ignore directories. */
   if (last_char == '/' || last_char == '\\')
      return 1;

   if (strstr(name, decomp_state-&gt;needle))
   {
      file_archive_file_handle_t handle = {0};

      if (zip_file_decompressed_handle(userdata-&gt;transfer,
               &amp;handle, cdata, cmode, csize, size, crc32))
      {
         if (decomp_state-&gt;opt_file != 0)
         {
            /* Called in case core has need_fullpath enabled. */
            bool success = filestream_write_file(decomp_state-&gt;opt_file, handle.data, size);

            /* Note: Do not free handle.data here - this
             * will be done when stream is deinitialised */
            handle.data = NULL;

            decomp_state-&gt;size = 0;

            if (!success)
               return -1;
         }
         else
         {
            /* Called in case core has need_fullpath disabled.
             * Will move decompressed content directly into
             * RetroArch's ROM buffer. */
            zip_context_t *zip_context = (zip_context_t *)userdata-&gt;transfer-&gt;context;

            decomp_state-&gt;size = 0;
            *decomp_state-&gt;buf             = handle.data;
            decomp_state-&gt;size             = size;
            /* We keep the data, prevent its deallocation during free */
            zip_context-&gt;decompressed_data = NULL;
            handle.data = NULL;
         }
      }

      decomp_state-&gt;found = true;
   }

   return 1;
}

static int64_t zip_file_read(
      const char *path,
      const char *needle, void **buf,
      const char *optional_outfile)
{
   file_archive_transfer_t state            = {0};
   decomp_state_t decomp                    = {0};
   struct archive_extract_userdata userdata = {0};
   int ret                                  = 0;

   if (needle)
      decomp.needle          = strdup(needle);
   if (optional_outfile)
      decomp.opt_file        = strdup(optional_outfile);

   state.type                = ARCHIVE_TRANSFER_INIT;
   userdata.transfer         = &amp;state;
   userdata.cb_data          = &amp;decomp;
   decomp.buf                = buf;

   do
   {
      bool returnerr = true;
      ret = file_archive_parse_file_iterate(&amp;state, &amp;returnerr, path,
            "", zip_file_decompressed, &amp;userdata);
      if (!returnerr)
         break;
   }while (ret == 0 &amp;&amp; !decomp.found);

   file_archive_parse_file_iterate_stop(&amp;state);

   if (decomp.opt_file)
      free(decomp.opt_file);
   if (decomp.needle)
      free(decomp.needle);

   if (!decomp.found)
      return -1;

   return (int64_t)decomp.size;
}

static int zip_parse_file_init(file_archive_transfer_t *state,
      const char *file)
{
   uint8_t footer_buf[1024];
   uint8_t *footer = footer_buf;
   int64_t read_pos = state-&gt;archive_size;
   int64_t read_block = MIN(read_pos, (ssize_t)sizeof(footer_buf));
   int64_t directory_size, directory_offset;
   zip_context_t *zip_context = NULL;

   /* Minimal ZIP file size is 22 bytes */
   if (read_block &lt; 22)
      return -1;

   /* Find the end of central directory record by scanning
    * the file from the end towards the beginning.
    */
   for (;;)
   {
      if (--footer &lt; footer_buf)
      {
         if (read_pos &lt;= 0)
            return -1; /* reached beginning of file */

         /* Read 21 bytes of overlaps except on the first block. */
         if (read_pos == state-&gt;archive_size)
            read_pos = read_pos - read_block;
         else
            read_pos = MAX(read_pos - read_block + 21, 0);

         /* Seek to read_pos and read read_block bytes. */
         filestream_seek(state-&gt;archive_file, read_pos, RETRO_VFS_SEEK_POSITION_START);
         if (filestream_read(state-&gt;archive_file, footer_buf, read_block) != read_block)
            return -1;

         footer = footer_buf + read_block - 22;
      }
      if (read_le(footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)
      {
         unsigned comment_len = read_le(footer + 20, 2);
         if (read_pos + (footer - footer_buf) + 22 + comment_len == state-&gt;archive_size)
            break; /* found it! */
      }
   }

   /* Read directory info and do basic sanity checks. */
   directory_size   = read_le(footer + 12, 4);
   directory_offset = read_le(footer + 16, 4);
   if (directory_size &gt; state-&gt;archive_size
         || directory_offset &gt; state-&gt;archive_size)
      return -1;

   /* This is a ZIP file, allocate one block of memory for both the
    * context and the entire directory, then read the directory.
    */
   zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);
   zip_context-&gt;state             = state;
   zip_context-&gt;directory         = (uint8_t*)(zip_context + 1);
   zip_context-&gt;directory_entry   = zip_context-&gt;directory;
   zip_context-&gt;directory_end     = zip_context-&gt;directory + (size_t)directory_size;
   zip_context-&gt;zstream           = NULL;
   zip_context-&gt;tmpbuf            = NULL;
   zip_context-&gt;decompressed_data = NULL;

   filestream_seek(state-&gt;archive_file, directory_offset, RETRO_VFS_SEEK_POSITION_START);
   if (filestream_read(state-&gt;archive_file, zip_context-&gt;directory, directory_size) != directory_size)
   {
      free(zip_context);
      return -1;
   }

   state-&gt;context = zip_context;
   state-&gt;step_total = read_le(footer + 10, 2); /* total entries */;

   return 0;
}

static int zip_parse_file_iterate_step_internal(
      zip_context_t * zip_context, char *filename,
      const uint8_t **cdata,
      unsigned *cmode, uint32_t *size, uint32_t *csize,
      uint32_t *checksum, unsigned *payback)
{
   uint8_t *entry = zip_context-&gt;directory_entry;
   uint32_t signature, namelength, extralength, commentlength, offset;

   if (entry &lt; zip_context-&gt;directory || entry &gt;= zip_context-&gt;directory_end)
      return 0;

   signature = read_le(zip_context-&gt;directory_entry + 0, 4);

   if (signature != CENTRAL_FILE_HEADER_SIGNATURE)
      return 0;

   *cmode         = read_le(zip_context-&gt;directory_entry + 10, 2); /* compression mode, 0 = store, 8 = deflate */
   *checksum      = read_le(zip_context-&gt;directory_entry + 16, 4); /* CRC32 */
   *csize         = read_le(zip_context-&gt;directory_entry + 20, 4); /* compressed size */
   *size          = read_le(zip_context-&gt;directory_entry + 24, 4); /* uncompressed size */

   namelength     = read_le(zip_context-&gt;directory_entry + 28, 2); /* file name length */
   extralength    = read_le(zip_context-&gt;directory_entry + 30, 2); /* extra field length */
   commentlength  = read_le(zip_context-&gt;directory_entry + 32, 2); /* file comment length */

   if (namelength &gt;= PATH_MAX_LENGTH)
      return -1;

   memcpy(filename, zip_context-&gt;directory_entry + 46, namelength); /* file name */
   filename[namelength] = '\0';

   offset   = read_le(zip_context-&gt;directory_entry + 42, 4); /* relative offset of local file header */

   *cdata   = (uint8_t*)(size_t)offset; /* store file offset in data pointer */

   *payback = 46 + namelength + extralength + commentlength;

   return 1;
}

static int zip_parse_file_iterate_step(void *context,
      const char *valid_exts, struct archive_extract_userdata *userdata,
      file_archive_file_cb file_cb)
{
   zip_context_t *zip_context = (zip_context_t *)context;
   const uint8_t *cdata       = NULL;
   uint32_t checksum          = 0;
   uint32_t size              = 0;
   uint32_t csize             = 0;
   unsigned cmode             = 0;
   unsigned payload           = 0;
   int ret                    = zip_parse_file_iterate_step_internal(zip_context,
         userdata-&gt;current_file_path, &amp;cdata, &amp;cmode, &amp;size, &amp;csize, &amp;checksum, &amp;payload);

   if (ret != 1)
      return ret;

   userdata-&gt;crc = checksum;

   if (file_cb &amp;&amp; !file_cb(userdata-&gt;current_file_path, valid_exts, cdata, cmode,
            csize, size, checksum, userdata))
      return 0;

   zip_context-&gt;directory_entry += payload;

   return 1;
}

static void zip_parse_file_free(void *context)
{
   zip_context_t *zip_context = (zip_context_t *)context;
   zip_context_free_stream(zip_context, false);
   free(zip_context);
}

const struct file_archive_file_backend zlib_backend = {
   zip_parse_file_init,
   zip_parse_file_iterate_step,
   zip_parse_file_free,
   zlib_stream_decompress_data_to_file_init,
   zlib_stream_decompress_data_to_file_iterate,
   zlib_stream_crc32_calculate,
   zip_file_read,
   "zlib"
};</pre>
<h2>./include/libretro-common/file/config_file.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdio.h&gt;
#include &lt;ctype.h&gt;
#include &lt;errno.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;compat/posix_string.h&gt;
#include &lt;compat/fopen_utf8.h&gt;
#include &lt;compat/msvc.h&gt;
#include &lt;file/config_file.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;array/rhmap.h&gt;

#define MAX_INCLUDE_DEPTH 16

struct config_include_list
{
   char *path;
   struct config_include_list *next;
};

/* Forward declaration */
static bool config_file_parse_line(config_file_t *conf,
      struct config_entry_list *list, char *line, config_file_cb_t *cb);

static int config_file_sort_compare_func(struct config_entry_list *a,
      struct config_entry_list *b)
{
   if (a &amp;&amp; b)
   {
      if (a-&gt;key)
      {
         if (b-&gt;key)
            return strcasecmp(a-&gt;key, b-&gt;key);
         return 1;
      }
      else if (b-&gt;key)
         return -1;
   }

   return 0;
}

/* https://stackoverflow.com/questions/7685/merge-sort-a-linked-list */
static struct config_entry_list* config_file_merge_sort_linked_list(
         struct config_entry_list *list, int (*compare)(
         struct config_entry_list *one,struct config_entry_list *two))
{
   struct config_entry_list
         *right  = list,
         *temp   = list,
         *last   = list,
         *result = 0,
         *next   = 0,
         *tail   = 0;

   /* Trivial case. */
   if (!list || !list-&gt;next)
      return list;

   /* Find halfway through the list (by running two pointers,
    * one at twice the speed of the other). */
   while (temp &amp;&amp; temp-&gt;next)
   {
      last     = right;
      right    = right-&gt;next;
      temp     = temp-&gt;next-&gt;next;
   }

   /* Break the list in two. (prev pointers are broken here,
    * but we fix later) */
   last-&gt;next  = 0;

   /* Recurse on the two smaller lists: */
   list        = config_file_merge_sort_linked_list(list, compare);
   right       = config_file_merge_sort_linked_list(right, compare);

   /* Merge: */
   while (list || right)
   {
      /* Take from empty lists, or compare: */
      if (!right)
      {
         next  = list;
         list  = list-&gt;next;
      }
      else if (!list)
      {
         next  = right;
         right = right-&gt;next;
      }
      else if (compare(list, right) &lt; 0)
      {
         next  = list;
         list  = list-&gt;next;
      }
      else
      {
         next  = right;
         right = right-&gt;next;
      }

      if (!result)
         result     = next;
      else
         tail-&gt;next = next;

      tail          = next;
   }

   return result;
}

/**
 * config_file_strip_comment:
 *
 * Searches input string for a comment ('#') entry
 * &gt; If first character is '#', then entire line is
 *   a comment and may correspond to a directive
 *   (command action - e.g. include sub-config file).
 *   In this case, 'str' is set to NUL and the comment
 *   itself (everything after the '#' character) is
 *   returned
 * &gt; If a '#' character is found inside a string literal
 *   value, then it does not correspond to a comment and
 *   is ignored. In this case, 'str' is left untouched
 *   and NULL is returned
 * &gt; If a '#' character is found anywhere else, then the
 *   comment text is a suffix of the input string and
 *   has no programmatic value. In this case, the comment
 *   is removed from the end of 'str' and NULL is returned
 **/
static char *config_file_strip_comment(char *str)
{
   /* Search for a comment (#) character */
   char *comment = strchr(str, '#');

   if (comment)
   {
      char *literal_start = NULL;

      /* Check whether entire line is a comment
       * &gt; First character == '#' */
      if (str == comment)
      {
         /* Set 'str' to NUL and return comment
          * for processing at a higher level */
         *str = '\0';
         return ++comment;
      }

      /* Comment character occurs at an offset:
       * Search for the start of a string literal value */
      literal_start = strchr(str, '\"');

      /* Check whether string literal start occurs
       * *before* the comment character */
      if (literal_start &amp;&amp; (literal_start &lt; comment))
      {
         /* Search for the end of the string literal
          * value */
         char *literal_end = strchr(literal_start + 1, '\"');

         /* Check whether string literal end occurs
          * *after* the comment character
          * &gt; If this is the case, ignore the comment
          * &gt; Leave 'str' untouched and return NULL */
         if (literal_end &amp;&amp; (literal_end &gt; comment))
            return NULL;
      }

      /* If we reach this point, then a comment
       * exists outside of a string literal
       * &gt; Trim the entire comment from the end
       *   of 'str' */
      *comment = '\0';
   }

   return NULL;
}

static char *config_file_extract_value(char *line)
{
   char *dst = NULL;
   while (ISSPACE((int)*line))
      line++;

   /* Note: From this point on, an empty value
    * string is valid - and in this case, strldup("", sizeof(""))
    * will be returned (see Note 2)
    * &gt; If we instead return NULL, the the entry
    *   is ignored completely - which means we cannot
    *   track *changes* in entry value */

   /* If first character is ("), we have a full string
    * literal */
   if (*line == '"')
   {
      size_t idx  = 0;
      char *value = NULL;
      /* Skip to next character */
      line++;

      /* If this a ("), then value string is empty */
      if (*line != '"')
      {
         /* Find the next (") character */
         while (line[idx] &amp;&amp; (line[idx] != '\"'))
            idx++;

         line[idx] = '\0';
         if ((value = line) &amp;&amp; *value)
            return strdup(value);
      }
   }
   /* This is not a string literal - just read
    * until the next space is found
    * &gt; Note: Skip this if line is empty */
   else if (*line != '\0')
   {
      size_t idx  = 0;
      char *value = NULL;
      /* Find next space character */
      while (line[idx] &amp;&amp; isgraph((int)line[idx]))
         idx++;

      line[idx] = '\0';
      if ((value = line) &amp;&amp; *value)
         return strdup(value);
   }

   /* Note 2: This is an unrolled strldup call
    * to avoid an unnecessary dependency -
    * call is strldup("", sizeof(""))
    **/
   dst = (char*)malloc(sizeof(char) * 2);
   strlcpy(dst, "", 1);
   return dst;
}

/* Move semantics? */
static void config_file_add_child_list(config_file_t *parent,
      config_file_t *child)
{
   struct config_entry_list *list = child-&gt;entries;
   bool merge_hash_map            = false;

   if (parent-&gt;entries)
   {
      struct config_entry_list *head = parent-&gt;entries;
      while (head-&gt;next)
         head = head-&gt;next;

      /* set list readonly */
      while (list)
      {
         list-&gt;readonly = true;
         list           = list-&gt;next;
      }
      head-&gt;next        = child-&gt;entries;

      merge_hash_map    = true;
   }
   else
   {
      /* set list readonly */
      while (list)
      {
         list-&gt;readonly = true;
         list           = list-&gt;next;
      }
      parent-&gt;entries   = child-&gt;entries;
   }

   /* Rebase tail. */
   if (parent-&gt;entries)
   {
      struct config_entry_list *head =
         (struct config_entry_list*)parent-&gt;entries;

      while (head-&gt;next)
         head = head-&gt;next;
      parent-&gt;tail = head;
   }
   else
      parent-&gt;tail = NULL;

   /* Update hash map */
   if (merge_hash_map)
   {
      size_t i;
      size_t cap;

      /* We are merging two lists - if any child entry
       * (key) is not present in the parent list, add it
       * to the parent hash map */
      for (i = 0, cap = RHMAP_CAP(child-&gt;entries_map); i != cap; i++)
      {
         uint32_t child_hash   = RHMAP_KEY(child-&gt;entries_map, i);
         const char *child_key = RHMAP_KEY_STR(child-&gt;entries_map, i);

         if (child_hash &amp;&amp;
             child_key &amp;&amp;
             !RHMAP_HAS_FULL(parent-&gt;entries_map, child_hash, child_key))
         {
            struct config_entry_list *entry = child-&gt;entries_map[i];

            if (entry)
               RHMAP_SET_FULL(parent-&gt;entries_map, child_hash, child_key, entry);
         }
      }

      /* Child entries map is no longer required,
       * so free it now */
      RHMAP_FREE(child-&gt;entries_map);
   }
   else
   {
      /* If parent list was originally empty,
       * take map from child list */
      RHMAP_FREE(parent-&gt;entries_map);
      parent-&gt;entries_map = child-&gt;entries_map;
      child-&gt;entries_map  = NULL;
   }

   child-&gt;entries = NULL;
}

static void config_file_get_realpath(char *s, size_t len,
      char *path, const char *config_path)
{
#if !defined(_WIN32) &amp;&amp; !defined(__PSL1GHT__) &amp;&amp; !defined(__PS3__)
   if (*path == '~')
   {
      const char *home = getenv("HOME");
      if (home)
      {
         size_t _len = strlcpy(s, home,     len);
         strlcpy(s + _len, path + 1, len - _len);
      }
      else
         strlcpy(s, path + 1, len);
   }
   else
#endif
   {
      if (!string_is_empty(config_path))
         fill_pathname_resolve_relative(s, config_path,
            path, len);
   }
}

static void config_file_add_sub_conf(config_file_t *conf, char *path,
      char *s, size_t len, config_file_cb_t *cb)
{
   struct config_include_list *head = conf-&gt;includes;
   struct config_include_list *node = (struct config_include_list*)
      malloc(sizeof(*node));

   if (node)
   {
      node-&gt;next        = NULL;
      /* Add include list */
      node-&gt;path        = strdup(path);

      if (head)
      {
         while (head-&gt;next)
            head        = head-&gt;next;

         head-&gt;next     = node;
      }
      else
         conf-&gt;includes = node;
   }

   config_file_get_realpath(s, len, path,
         conf-&gt;path);
}

size_t config_file_add_reference(config_file_t *conf, char *path)
{
   size_t _len;
   /* It is expected that the conf has it's path already set */
   char short_path[NAME_MAX_LENGTH];
   if (!conf-&gt;references)
   {
      conf-&gt;references       = (struct path_linked_list*)malloc(sizeof(*conf-&gt;references));
      conf-&gt;references-&gt;next = NULL;
      conf-&gt;references-&gt;path = NULL;
   }
   _len = fill_pathname_abbreviated_or_relative(short_path, conf-&gt;path, path, sizeof(short_path));
   path_linked_list_add_path(conf-&gt;references, short_path);
   return _len;
}

static int config_file_load_internal(
      struct config_file *conf,
      const char *path, unsigned depth, config_file_cb_t *cb)
{
   RFILE         *file = NULL;
   char      *new_path = strdup(path);
   if (!new_path)
      return 1;

   conf-&gt;path          = new_path;
   conf-&gt;include_depth = depth;

   if (!(file = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
   {
      free(conf-&gt;path);
      return 1;
   }

   while (!filestream_eof(file))
   {
      char *line                     = NULL;
      struct config_entry_list *list = (struct config_entry_list*)
         malloc(sizeof(*list));

      if (!list)
      {
         filestream_close(file);
         return -1;
      }

      list-&gt;readonly  = false;
      list-&gt;key       = NULL;
      list-&gt;value     = NULL;
      list-&gt;next      = NULL;

      line            = filestream_getline(file);

      if (!line)
      {
         free(list);
         continue;
      }

      if (
              !string_is_empty(line)
            &amp;&amp; config_file_parse_line(conf, list, line, cb))
      {
         if (conf-&gt;entries)
            conf-&gt;tail-&gt;next = list;
         else
            conf-&gt;entries    = list;

         conf-&gt;tail = list;

         if (list-&gt;key)
         {
            /* Only add entry to the map if an entry
             * with the specified value does not
             * already exist */
            uint32_t hash = rhmap_hash_string(list-&gt;key);

            if (!RHMAP_HAS_FULL(conf-&gt;entries_map, hash, list-&gt;key))
            {
               RHMAP_SET_FULL(conf-&gt;entries_map, hash, list-&gt;key, list);

               if (cb &amp;&amp; list-&gt;value)
                  cb-&gt;config_file_new_entry_cb(list-&gt;key, list-&gt;value);
            }
         }
      }

      free(line);

      if (list != conf-&gt;tail)
         free(list);
   }

   filestream_close(file);

   return 0;
}

static bool config_file_parse_line(config_file_t *conf,
      struct config_entry_list *list, char *line, config_file_cb_t *cb)
{
   size_t cur_size       = 32;
   size_t idx            = 0;
   char *key             = NULL;
   char *key_tmp         = NULL;
   /* Remove any comment text */
   char *comment         = config_file_strip_comment(line);

   /* Check whether entire line is a comment */
   if (comment)
   {
      char *path               = NULL;
      bool include_found       = string_starts_with_size(comment,
            "include ",   STRLEN_CONST("include "));
      bool reference_found     = string_starts_with_size(comment,
            "reference ", STRLEN_CONST("reference "));

      /* All comments except those starting with the include or
       * reference directive are ignored */
      if (!include_found &amp;&amp; !reference_found)
         return false;

      /* Starting a line with an 'include' directive
       * appends a sub-config file */
      if (include_found)
      {
         config_file_t sub_conf;
         char real_path[PATH_MAX_LENGTH];
         char *include_line = comment + STRLEN_CONST("include ");

         if (string_is_empty(include_line))
            return false;

         if (!(path = config_file_extract_value(include_line)))
            return false;

         if (     string_is_empty(path)
               || conf-&gt;include_depth &gt;= MAX_INCLUDE_DEPTH)
         {
            free(path);
            return false;
         }

         config_file_add_sub_conf(conf, path,
            real_path, sizeof(real_path), cb);

         config_file_initialize(&amp;sub_conf);

         switch (config_file_load_internal(&amp;sub_conf, real_path,
            conf-&gt;include_depth + 1, cb))
         {
            case 0:
               /* Pilfer internal list. */
               config_file_add_child_list(conf, &amp;sub_conf);
               /* fall-through to deinitialize */
            case -1:
               config_file_deinitialize(&amp;sub_conf);
               break;
            case 1:
            default:
               break;
         }
      }

      /* Starting a line with an 'reference' directive
       * sets the reference path */
      if (reference_found)
      {
         char *reference_line = comment + STRLEN_CONST("reference ");

         if (string_is_empty(reference_line))
            return false;

         if (!(path = config_file_extract_value(reference_line)))
            return false;

         config_file_add_reference(conf, path);

         if (!path)
            return false;
      }

      free(path);
      return true;
   }

   /* Skip to first non-space character */
   while (ISSPACE((int)*line))
      line++;

   /* Allocate storage for key */
   if (!(key = (char*)malloc(cur_size + 1)))
      return false;

   /* Copy line contents into key until we
    * reach the next space character */
   while (isgraph((int)*line))
   {
      /* If current key storage is too small,
       * double its size */
      if (idx == cur_size)
      {
         cur_size *= 2;
         if (!(key_tmp   = (char*)realloc(key, cur_size + 1)))
         {
            free(key);
            return false;
         }

         key     = key_tmp;
      }

      key[idx++] = *line++;
   }
   key[idx]      = '\0';

   /* Add key and value entries to list */
   list-&gt;key     = key;

   /* An entry without a value is invalid */
   while (ISSPACE((int)*line))
      line++;

   /* If we don't have an equal sign here,
    * we've got an invalid string. */
   if (*line != '=')
   {
      list-&gt;value = NULL;
      list-&gt;key   = NULL;
      free(key);
      return false;
   }

   line++;

   if (!(list-&gt;value   = config_file_extract_value(line)))
   {
      list-&gt;key   = NULL;
      free(key);
      return false;
   }

   return true;
}

static int config_file_from_string_internal(
      struct config_file *conf,
      char *from_string,
      const char *path)
{
   char *lines                    = from_string;
   char *save_ptr                 = NULL;
   char *line                     = NULL;

   if (!string_is_empty(path))
      conf-&gt;path                  = strdup(path);
   if (string_is_empty(lines))
      return 0;

   /* Get first line of config file */
   line = strtok_r(lines, "\n", &amp;save_ptr);

   while (line)
   {
      struct config_entry_list *list = (struct config_entry_list*)
            malloc(sizeof(*list));

      if (!list)
         return -1;

      list-&gt;readonly  = false;
      list-&gt;key       = NULL;
      list-&gt;value     = NULL;
      list-&gt;next      = NULL;

      /* Parse current line */
      if (
              !string_is_empty(line)
            &amp;&amp; config_file_parse_line(conf, list, line, NULL))
      {
         if (conf-&gt;entries)
            conf-&gt;tail-&gt;next = list;
         else
            conf-&gt;entries    = list;

         conf-&gt;tail          = list;

         if (list-&gt;key)
         {
            /* Only add entry to the map if an entry
             * with the specified value does not
             * already exist */
            uint32_t hash = rhmap_hash_string(list-&gt;key);
            if (!RHMAP_HAS_FULL(conf-&gt;entries_map, hash, list-&gt;key))
               RHMAP_SET_FULL(conf-&gt;entries_map, hash, list-&gt;key, list);
         }
      }

      if (list != conf-&gt;tail)
         free(list);

      /* Get next line of config file */
      line = strtok_r(NULL, "\n", &amp;save_ptr);
   }

   return 0;
}


bool config_file_deinitialize(config_file_t *conf)
{
   struct config_include_list *inc_tmp = NULL;
   struct config_entry_list *tmp       = NULL;

   if (!conf)
      return false;

   tmp = conf-&gt;entries;
   while (tmp)
   {
      struct config_entry_list *hold = NULL;
      if (tmp-&gt;key)
         free(tmp-&gt;key);
      if (tmp-&gt;value)
         free(tmp-&gt;value);

      tmp-&gt;value = NULL;
      tmp-&gt;key   = NULL;

      hold       = tmp;
      tmp        = tmp-&gt;next;

      if (hold)
         free(hold);
   }

   inc_tmp = (struct config_include_list*)conf-&gt;includes;
   while (inc_tmp)
   {
      struct config_include_list *hold = NULL;
      if (inc_tmp-&gt;path)
         free(inc_tmp-&gt;path);
      hold    = (struct config_include_list*)inc_tmp;
      inc_tmp = inc_tmp-&gt;next;
      if (hold)
         free(hold);
   }

   path_linked_list_free(conf-&gt;references);

   if (conf-&gt;path)
      free(conf-&gt;path);

   RHMAP_FREE(conf-&gt;entries_map);

   return true;
}

/**
 * config_file_free:
 *
 * Frees config file.
 **/
void config_file_free(config_file_t *conf)
{
   if (config_file_deinitialize(conf))
      free(conf);
}

/**
 * config_append_file:
 *
 * Loads a new config, and appends its data to @conf.
 * The key-value pairs of the new config file takes priority over the old.
 **/
bool config_append_file(config_file_t *conf, const char *path)
{
   size_t i, cap;
   config_file_t *new_conf = config_file_new_from_path_to_string(path);

   if (!new_conf)
      return false;

   /* Update hash map */
   for (i = 0, cap = RHMAP_CAP(new_conf-&gt;entries_map); i != cap; i++)
   {
      uint32_t new_hash   = RHMAP_KEY(new_conf-&gt;entries_map, i);
      const char *new_key = RHMAP_KEY_STR(new_conf-&gt;entries_map, i);

      if (new_hash &amp;&amp; new_key)
      {
         struct config_entry_list *entry = new_conf-&gt;entries_map[i];

         if (entry)
            RHMAP_SET_FULL(conf-&gt;entries_map, new_hash, new_key, entry);
      }
   }

   if (new_conf-&gt;tail)
   {
      new_conf-&gt;tail-&gt;next = conf-&gt;entries;
      conf-&gt;entries        = new_conf-&gt;entries; /* Pilfer. */
      new_conf-&gt;entries    = NULL;
   }

   config_file_free(new_conf);
   return true;
}

/**
 * config_file_new_from_string:
 *
 * Load a config file from a string.
 *
 * NOTE: This will modify @from_string.
 * Pass a copy of source string if original
 * contents must be preserved
 **/
config_file_t *config_file_new_from_string(char *from_string,
      const char *path)
{
   struct config_file *conf      = config_file_new_alloc();
   if (     conf
         &amp;&amp; config_file_from_string_internal(
            conf, from_string, path) != -1)
      return conf;
   if (conf)
      config_file_free(conf);
   return NULL;
}

config_file_t *config_file_new_from_path_to_string(const char *path)
{
   if (path_is_valid(path))
   {
      uint8_t *ret_buf                 = NULL;
      int64_t length                   = 0;
      if (filestream_read_file(path, (void**)&amp;ret_buf, &amp;length))
      {
         config_file_t *conf           = NULL;
         /* Note: 'ret_buf' is not used outside this
          * function - we do not care that it will be
          * modified by config_file_new_from_string() */
         if (length &gt;= 0)
            conf = config_file_new_from_string((char*)ret_buf, path);

         if ((void*)ret_buf)
            free((void*)ret_buf);

         return conf;
      }
   }

   return NULL;
}

/**
 * config_file_new_with_callback:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 * Includes cb callbacks  to run custom code during config file processing.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new_with_callback(
      const char *path, config_file_cb_t *cb)
{
   int ret                  = 0;
   struct config_file *conf = config_file_new_alloc();
   if (!path || !*path)
      return conf;
   if ((ret = config_file_load_internal(conf, path, 0, cb)) == -1)
   {
      config_file_free(conf);
      return NULL;
   }
   else if (ret == 1)
   {
      free(conf);
      return NULL;
   }
   return conf;
}

/**
 * config_file_new:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new(const char *path)
{
   int ret                  = 0;
   struct config_file *conf = config_file_new_alloc();
   if (!path || !*path)
      return conf;
   if ((ret = config_file_load_internal(conf, path, 0, NULL)) == -1)
   {
      config_file_free(conf);
      return NULL;
   }
   else if (ret == 1)
   {
      free(conf);
      return NULL;
   }
   return conf;
}

/**
 * config_file_initialize:
 *
 * Leaf function.
 **/
void config_file_initialize(struct config_file *conf)
{
   if (!conf)
      return;

   conf-&gt;path                     = NULL;
   conf-&gt;entries_map              = NULL;
   conf-&gt;entries                  = NULL;
   conf-&gt;tail                     = NULL;
   conf-&gt;last                     = NULL;
   conf-&gt;references               = NULL;
   conf-&gt;includes                 = NULL;
   conf-&gt;include_depth            = 0;
   conf-&gt;flags                    = 0;
}

config_file_t *config_file_new_alloc(void)
{
   struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));
   if (!conf)
      return NULL;
   config_file_initialize(conf);
   return conf;
}

/**
 * config_get_entry_internal:
 *
 * Leaf function.
 **/
static struct config_entry_list *config_get_entry_internal(
      const config_file_t *conf,
      const char *key, struct config_entry_list **prev)
{
   struct config_entry_list *entry = RHMAP_GET_STR(conf-&gt;entries_map, key);

   if (entry)
      return entry;

   if (prev)
   {
      struct config_entry_list *previous = *prev;
      for (entry = conf-&gt;entries; entry; entry = entry-&gt;next)
         previous = entry;

      *prev = previous;
   }

   return NULL;
}

struct config_entry_list *config_get_entry(
      const config_file_t *conf, const char *key)
{
   return RHMAP_GET_STR(conf-&gt;entries_map, key);
}

/**
 * config_get_double:
 *
 * Extracts a double from config file.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_double(config_file_t *conf, const char *key, double *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry)
      return false;

   *in = strtod(entry-&gt;value, NULL);
   return true;
}

/**
 * config_get_float:
 *
 * Extracts a float from config file.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_float(config_file_t *conf, const char *key, float *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry)
      return false;

   /* strtof() is C99/POSIX. Just use the more portable kind. */
   *in = (float)strtod(entry-&gt;value, NULL);
   return true;
}

bool config_get_int(config_file_t *conf, const char *key, int *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      int val = (int)strtol(entry-&gt;value, NULL, 0);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

bool config_get_size_t(config_file_t *conf, const char *key, size_t *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      size_t val = 0;
      if (sscanf(entry-&gt;value, "%" PRI_SIZET, &amp;val) == 1)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

#if defined(__STDC_VERSION__) &amp;&amp; __STDC_VERSION__&gt;=199901L
bool config_get_uint64(config_file_t *conf, const char *key, uint64_t *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      uint64_t val = strtoull(entry-&gt;value, NULL, 0);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }
   return false;
}
#endif

bool config_get_uint(config_file_t *conf, const char *key, unsigned *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      unsigned val = (unsigned)strtoul(entry-&gt;value, NULL, 0);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

bool config_get_hex(config_file_t *conf, const char *key, unsigned *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   errno = 0;

   if (entry)
   {
      unsigned val = (unsigned)strtoul(entry-&gt;value, NULL, 16);

      if (errno == 0)
      {
         *in = val;
         return true;
      }
   }

   return false;
}

/**
 * config_get_char:
 *
 * Extracts a single char from config file.
 * If value consists of several chars, this is an error.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_char(config_file_t *conf, const char *key, char *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (entry)
   {
      if (entry-&gt;value[0] &amp;&amp; entry-&gt;value[1])
         return false;

      *in = *entry-&gt;value;
      return true;
   }

   return false;
}

/**
 * config_get_string:
 *
 * Extracts an allocated string in *in. This must be free()-d if
 * this function succeeds.
 *
 * @return true if found, otherwise false.
 **/
bool config_get_string(config_file_t *conf, const char *key, char **str)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry || !entry-&gt;value)
      return false;

   *str = strdup(entry-&gt;value);
   return true;
}

/**
  * config_get_config_path:
  *
  * Extracts a string to a preallocated buffer.
  * Avoid memory allocation.
  **/
size_t config_get_config_path(config_file_t *conf, char *s, size_t len)
{
   if (conf)
      return strlcpy(s, conf-&gt;path, len);
   return 0;
}

bool config_get_array(config_file_t *conf, const char *key,
      char *s, size_t len)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);
   if (entry)
      return strlcpy(s, entry-&gt;value, len) &lt; len;
   return false;
}

bool config_get_path(config_file_t *conf, const char *key,
      char *s, size_t len)
{
#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)
   return config_get_array(conf, key, s, len);
#else
   const struct config_entry_list *entry = config_get_entry(conf, key);
   if (entry)
   {
      fill_pathname_expand_special(s, entry-&gt;value, len);
      return true;
   }
   return false;
#endif
}

/**
 * config_get_bool:
 *
 * Extracts a boolean from config.
 * Valid boolean true are "true" and "1". Valid false are "false" and "0".
 * Other values will be treated as an error.
 *
 * @return true if preconditions are true, otherwise false.
 **/
bool config_get_bool(config_file_t *conf, const char *key, bool *in)
{
   const struct config_entry_list *entry = config_get_entry(conf, key);

   if (!entry)
      return false;

   if      (
         (
            entry-&gt;value[0] == '1'
         &amp;&amp; entry-&gt;value[1] == '\0'
         )
         || string_is_equal(entry-&gt;value, "true")
         )
      *in = true;
   else if (
         (
            entry-&gt;value[0] == '0'
         &amp;&amp; entry-&gt;value[1] == '\0'
         )
         || string_is_equal(entry-&gt;value, "false")
         )
      *in = false;
   else
      return false;

   return true;
}

void config_set_string(config_file_t *conf, const char *key, const char *val)
{
   struct config_entry_list *last  = NULL;
   struct config_entry_list *entry = NULL;

   if (!conf || !key || !val)
      return;

   last                            = conf-&gt;entries;

   if (conf-&gt;flags &amp; CONF_FILE_FLG_GUARANTEED_NO_DUPLICATES)
   {
      if (conf-&gt;last)
         last                      = conf-&gt;last;
   }
   else
   {
      if ((entry = config_get_entry_internal(conf, key, &amp;last)))
      {
         /* An entry corresponding to 'key' already exists
          * &gt; Check whether value is currently set */
         if (entry-&gt;value)
         {
            /* Do nothing if value is unchanged */
            if (string_is_equal(entry-&gt;value, val))
               return;

            /* Value is to be updated
             * &gt; Free existing */
            free(entry-&gt;value);
         }

         /* Update value
          * &gt; Note that once a value is set, it
          *   is no longer considered 'read only' */
         entry-&gt;value    = strdup(val);
         entry-&gt;readonly = false;
         conf-&gt;flags    |= CONF_FILE_FLG_MODIFIED;
         return;
      }
   }

   /* Entry corresponding to 'key' does not exist
    * &gt; Create new entry */
   if (!(entry = (struct config_entry_list*)malloc(sizeof(*entry))))
      return;

   entry-&gt;readonly  = false;
   entry-&gt;key       = strdup(key);
   entry-&gt;value     = strdup(val);
   entry-&gt;next      = NULL;
   conf-&gt;flags     |= CONF_FILE_FLG_MODIFIED;

   if (last)
      last-&gt;next    = entry;
   else
      conf-&gt;entries = entry;

   conf-&gt;last       = entry;

   RHMAP_SET_STR(conf-&gt;entries_map, entry-&gt;key, entry);
}

void config_unset(config_file_t *conf, const char *key)
{
   struct config_entry_list *last  = NULL;
   struct config_entry_list *entry = NULL;

   if (!conf || !key)
      return;

   last  = conf-&gt;entries;

   if (!(entry = config_get_entry_internal(conf, key, &amp;last)))
      return;

   (void)RHMAP_DEL_STR(conf-&gt;entries_map, entry-&gt;key);

   if (entry-&gt;key)
      free(entry-&gt;key);

   if (entry-&gt;value)
      free(entry-&gt;value);

   entry-&gt;key     = NULL;
   entry-&gt;value   = NULL;
   conf-&gt;flags   |= CONF_FILE_FLG_MODIFIED;
}

void config_set_path(config_file_t *conf, const char *entry, const char *val)
{
#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)
   config_set_string(conf, entry, val);
#else
   char buf[PATH_MAX_LENGTH];
   fill_pathname_abbreviate_special(buf, val, sizeof(buf));
   config_set_string(conf, entry, buf);
#endif
}

size_t config_set_double(config_file_t *conf, const char *key, double val)
{
   char buf[320];
#ifdef __cplusplus
   size_t _len = snprintf(buf, sizeof(buf), "%f", (float)val);
#elif defined(__STDC_VERSION__) &amp;&amp; __STDC_VERSION__&gt;=199901L
   size_t _len = snprintf(buf, sizeof(buf), "%lf", val);
#else
   size_t _len = snprintf(buf, sizeof(buf), "%f", (float)val);
#endif
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_float(config_file_t *conf, const char *key, float val)
{
   char buf[64];
   size_t _len = snprintf(buf, sizeof(buf), "%f", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_int(config_file_t *conf, const char *key, int val)
{
   char buf[16];
   size_t _len = snprintf(buf, sizeof(buf), "%d", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_uint(config_file_t *conf, const char *key, unsigned int val)
{
   char buf[16];
   size_t _len = snprintf(buf, sizeof(buf), "%u", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_hex(config_file_t *conf, const char *key, unsigned val)
{
   char buf[16];
   size_t _len = snprintf(buf, sizeof(buf), "%x", val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_uint64(config_file_t *conf, const char *key, uint64_t val)
{
   char buf[32];
   size_t _len = snprintf(buf, sizeof(buf), "%" PRIu64, val);
   config_set_string(conf, key, buf);
   return _len;
}

size_t config_set_char(config_file_t *conf, const char *key, char val)
{
   char buf[2];
   size_t _len = snprintf(buf, sizeof(buf), "%c", val);
   config_set_string(conf, key, buf);
   return _len;
}

/**
 * config_file_write:
 *
 * Write the current config to a file.
 **/
bool config_file_write(config_file_t *conf, const char *path, bool sort)
{
   if (!conf)
      return false;

   if (conf-&gt;flags &amp; CONF_FILE_FLG_MODIFIED)
   {
      if (string_is_empty(path))
         config_file_dump(conf, stdout, sort);
      else
      {
         void* buf  = NULL;
         FILE *file = (FILE*)fopen_utf8(path, "wb");
         if (!file)
            return false;

         buf        = calloc(1, 0x4000);
         setvbuf(file, (char*)buf, _IOFBF, 0x4000);

         config_file_dump(conf, file, sort);

         if (file != stdout)
            fclose(file);
         if (buf)
            free(buf);

         /* Only update modified flag if config file
          * is actually written to disk */
         conf-&gt;flags &amp;= ~CONF_FILE_FLG_MODIFIED;
      }
   }

   return true;
}

/**
 * config_file_dump:
 *
 * Dump the current config to an already opened file.
 * Does not close the file.
 **/
void config_file_dump(config_file_t *conf, FILE *file, bool sort)
{
   struct config_entry_list       *list = NULL;
   struct config_include_list *includes = conf-&gt;includes;
   struct path_linked_list *ref_tmp = conf-&gt;references;

   while (ref_tmp)
   {
      pathname_make_slashes_portable(ref_tmp-&gt;path);
      fprintf(file, "#reference \"%s\"\n", ref_tmp-&gt;path);
      ref_tmp = ref_tmp-&gt;next;
   }

   if (sort)
      list = config_file_merge_sort_linked_list(
            (struct config_entry_list*)conf-&gt;entries,
            config_file_sort_compare_func);
   else
      list = (struct config_entry_list*)conf-&gt;entries;

   conf-&gt;entries = list;

   while (list)
   {
      if (!list-&gt;readonly &amp;&amp; list-&gt;key)
         fprintf(file, "%s = \"%s\"\n", list-&gt;key, list-&gt;value);
      list = list-&gt;next;
   }

   /* Config files are read from the top down - if
    * duplicate entries are found then the topmost
    * one in the list takes precedence. This means
    * '#include' directives must go *after* individual
    * config entries, otherwise they will override
    * any custom-set values */
   while (includes)
   {
      fprintf(file, "#include \"%s\"\n", includes-&gt;path);
      includes = includes-&gt;next;
   }
}

/**
 * config_get_entry_list_head:
 *
 * Leaf function.
 **/
bool config_get_entry_list_head(config_file_t *conf,
      struct config_file_entry *entry)
{
   const struct config_entry_list *head = conf-&gt;entries;

   if (!head)
      return false;

   entry-&gt;key   = head-&gt;key;
   entry-&gt;value = head-&gt;value;
   entry-&gt;next  = head-&gt;next;
   return true;
}

/**
 * config_get_entry_list_next:
 *
 * Leaf function.
 **/
bool config_get_entry_list_next(struct config_file_entry *entry)
{
   const struct config_entry_list *next = entry-&gt;next;

   if (!next)
      return false;

   entry-&gt;key   = next-&gt;key;
   entry-&gt;value = next-&gt;value;
   entry-&gt;next  = next-&gt;next;
   return true;
}</pre>
<h2>./include/libretro-common/file/config_file_userdata.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_userdata.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;file/file_path.h&gt;
#include &lt;lists/string_list.h&gt;

#include &lt;file/config_file_userdata.h&gt;

int config_userdata_get_float(void *userdata, const char *key_str,
      float *value, float default_value)
{
   char key[256];
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key, usr-&gt;prefix[0], key_str, '_', sizeof(key));
   if (config_get_float(usr-&gt;conf, key, value))
      return true;
   *value = default_value;
   fill_pathname_join_delim(key, usr-&gt;prefix[1], key_str, '_', sizeof(key));
   if (config_get_float(usr-&gt;conf, key, value))
      return true;
   return false;
}

int config_userdata_get_int(void *userdata, const char *key_str,
      int *value, int default_value)
{
   char key[256];
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key, usr-&gt;prefix[0], key_str, '_', sizeof(key));
   if (config_get_int(usr-&gt;conf, key, value))
      return true;
   *value = default_value;
   fill_pathname_join_delim(key, usr-&gt;prefix[1], key_str, '_', sizeof(key));
   if (config_get_int(usr-&gt;conf, key, value))
      return true;
   return false;
}

int config_userdata_get_hex(void *userdata, const char *key_str,
      unsigned *value, unsigned default_value)
{
   char key[256];
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key, usr-&gt;prefix[0], key_str, '_', sizeof(key));
   if (config_get_hex(usr-&gt;conf, key, value))
      return true;
   *value = default_value;
   fill_pathname_join_delim(key, usr-&gt;prefix[1], key_str, '_', sizeof(key));
   if (config_get_hex(usr-&gt;conf, key, value))
      return true;
   return false;
}

int config_userdata_get_float_array(void *userdata, const char *key_str,
      float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values)
{
   char key[2][256];
   char *str = NULL;
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;

   fill_pathname_join_delim(key[0], usr-&gt;prefix[0], key_str, '_', sizeof(key[0]));
   fill_pathname_join_delim(key[1], usr-&gt;prefix[1], key_str, '_', sizeof(key[1]));

   if (     config_get_string(usr-&gt;conf, key[0], &amp;str)
         || config_get_string(usr-&gt;conf, key[1], &amp;str))
   {
      unsigned i;
      struct string_list list = {0};
      string_list_initialize(&amp;list);
      string_split_noalloc(&amp;list, str, " ");
      *values = (float*)calloc(list.size, sizeof(float));
      for (i = 0; i &lt; list.size; i++)
         (*values)[i] = (float)strtod(list.elems[i].data, NULL);
      *out_num_values = (unsigned)list.size;
      string_list_deinitialize(&amp;list);
      free(str);
      return true;
   }

   *values = (float*)calloc(num_default_values, sizeof(float));
   memcpy(*values, default_values, sizeof(float) * num_default_values);
   *out_num_values = num_default_values;
   return false;
}

int config_userdata_get_int_array(void *userdata, const char *key_str,
      int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values)
{
   char key[2][256];
   char *str = NULL;
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key[0], usr-&gt;prefix[0], key_str, '_', sizeof(key[0]));
   fill_pathname_join_delim(key[1], usr-&gt;prefix[1], key_str, '_', sizeof(key[1]));

   if (     config_get_string(usr-&gt;conf, key[0], &amp;str)
         || config_get_string(usr-&gt;conf, key[1], &amp;str))
   {
      unsigned i;
      struct string_list list = {0};
      string_list_initialize(&amp;list);
      string_split_noalloc(&amp;list, str, " ");
      *values = (int*)calloc(list.size, sizeof(int));
      for (i = 0; i &lt; list.size; i++)
         (*values)[i] = (int)strtod(list.elems[i].data, NULL);
      *out_num_values = (unsigned)list.size;
      string_list_deinitialize(&amp;list);
      free(str);
      return true;
   }

   *values = (int*)calloc(num_default_values, sizeof(int));
   memcpy(*values, default_values, sizeof(int) * num_default_values);
   *out_num_values = num_default_values;
   return false;
}

int config_userdata_get_string(void *userdata, const char *key_str,
      char **output, const char *default_output)
{
   char key[2][256];
   char *str = NULL;
   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
   fill_pathname_join_delim(key[0], usr-&gt;prefix[0], key_str, '_', sizeof(key[0]));
   fill_pathname_join_delim(key[1], usr-&gt;prefix[1], key_str, '_', sizeof(key[1]));

   if (     config_get_string(usr-&gt;conf, key[0], &amp;str)
         || config_get_string(usr-&gt;conf, key[1], &amp;str))
   {
      *output = str;
      return true;
   }

   *output = strdup(default_output);
   return false;
}

void config_userdata_free(void *ptr)
{
   if (ptr)
      free(ptr);
}</pre>
<h2>./include/libretro-common/file/file_path.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_path.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;time.h&gt;
#include &lt;locale.h&gt;

#include &lt;sys/stat.h&gt;

#include &lt;boolean.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;time/rtime.h&gt;

/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
#ifdef __APPLE__
#include &lt;CoreFoundation/CoreFoundation.h&gt;
#endif
#ifdef __HAIKU__
#include &lt;kernel/image.h&gt;
#endif
#ifndef __MACH__
#include &lt;compat/strl.h&gt;
#include &lt;compat/posix_string.h&gt;
#endif
#include &lt;retro_miscellaneous.h&gt;
#include &lt;encodings/utf.h&gt;

#ifdef _WIN32
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt; /* stat() is defined here */
#endif

#if !defined(RARCH_CONSOLE) &amp;&amp; defined(RARCH_INTERNAL)
#ifdef __WINRT__
#include &lt;uwp/uwp_func.h&gt;
#endif
#endif

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

/* Time format strings with AM-PM designation require special
 * handling due to platform dependence */
size_t strftime_am_pm(char *s, size_t len, const char* format,
      const void *ptr)
{
   size_t _len              = 0;
#if !(defined(__linux__) &amp;&amp; !defined(ANDROID))
   char *local              = NULL;
#endif
   const struct tm *timeptr = (const struct tm*)ptr;
   /* Ensure correct locale is set
    * &gt; Required for localised AM/PM strings */
   setlocale(LC_TIME, "");
   _len = strftime(s, len, format, timeptr);
#if !(defined(__linux__) &amp;&amp; !defined(ANDROID))
   if ((local = local_to_utf8_string_alloc(s)))
   {
      if (!string_is_empty(local))
         _len = strlcpy(s, local, len);

      free(local);
      local = NULL;
   }
#endif
   return _len;
}

/**
 * Create a new linked list with one node in it
 * The path on this node will be set to NULL
**/
struct path_linked_list* path_linked_list_new(void)
{
   struct path_linked_list* paths_list = (struct path_linked_list*)malloc(sizeof(*paths_list));
   paths_list-&gt;next = NULL;
   paths_list-&gt;path = NULL;
   return paths_list;
}

/**
 * path_linked_list_free:
 *
 * Free the entire linked list
 **/
void path_linked_list_free(struct path_linked_list *in_path_llist)
{
   struct path_linked_list *node_tmp = (struct path_linked_list*)in_path_llist;
   while (node_tmp)
   {
      struct path_linked_list *hold = NULL;
      if (node_tmp-&gt;path)
         free(node_tmp-&gt;path);
      hold     = (struct path_linked_list*)node_tmp;
      node_tmp = node_tmp-&gt;next;
      if (hold)
         free(hold);
   }
}

/**
 * path_linked_list_add_path:
 *
 * Add a node to the linked list with this path
 * If the first node's path if it's not yet set the path
 * on this node instead
**/
void path_linked_list_add_path(struct path_linked_list *in_path_llist,
      char *path)
{
    /* If the first item does not have a path this is
      a list which has just been created, so we just fill
      the path for the first item
   */
   if (!in_path_llist-&gt;path)
      in_path_llist-&gt;path = strdup(path);
   else
   {
      struct path_linked_list *node = (struct path_linked_list*)malloc(sizeof(*node));

      if (node)
      {
         struct path_linked_list *head = in_path_llist;

         node-&gt;next        = NULL;
         node-&gt;path        = strdup(path);

         if (head)
         {
            while (head-&gt;next)
               head        = head-&gt;next;
            head-&gt;next     = node;
         }
         else
            in_path_llist  = node;
      }
   }
}

/**
 * path_get_archive_delim:
 * @path               : path
 *
 * Find delimiter of an archive file. Only the first '#'
 * after a compression extension is considered.
 *
 * @return pointer to the delimiter in the path if it contains
 * a path inside a compressed file, otherwise NULL.
 **/
const char *path_get_archive_delim(const char *path)
{
   char buf[5];
   /* Find delimiter position
    * &gt; Since filenames may contain '#' characters,
    *   must loop until we find the first '#' that
    *   is directly *after* a compression extension */
   const char *delim      = strchr(path, '#');

   while (delim)
   {
      /* Check whether this is a known archive type
       * &gt; Note: The code duplication here is
       *   deliberate, to maximise performance */
      if (delim - path &gt; 4)
      {
         strlcpy(buf, delim - 4, sizeof(buf));
         buf[4] = '\0';

         string_to_lower(buf);

         /* Check if this is a '.zip', '.apk' or '.7z' file */
         if (   string_is_equal(buf,     ".zip")
             || string_is_equal(buf,     ".apk")
             || string_is_equal(buf + 1, ".7z"))
            return delim;
      }
      else if (delim - path &gt; 3)
      {
         strlcpy(buf, delim - 3, sizeof(buf));
         buf[3] = '\0';

         string_to_lower(buf);

         /* Check if this is a '.7z' file */
         if (string_is_equal(buf, ".7z"))
            return delim;
      }

      delim++;
      delim = strchr(delim, '#');
   }

   return NULL;
}

/**
 * path_get_extension:
 * @path               : path
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * @return extension part from the path.
 **/
const char *path_get_extension(const char *path)
{
   const char *ext;
   if (!string_is_empty(path) &amp;&amp; ((ext = (char*)strrchr(path_basename(path), '.'))))
      return ext + 1;
   return "";
}

/**
 * path_get_extension_mutable:
 * @path               : path
 *
 * Specialized version of path_get_extension(). Return
 * value is mutable.
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * @return extension part from the path.
 **/
char *path_get_extension_mutable(const char *path)
{
   char *ext = NULL;
   if (    !string_is_empty(path)
       &amp;&amp; ((ext = (char*)strrchr(path_basename(path), '.'))))
      return ext;
   return NULL;
}

/**
 * path_remove_extension:
 * @s                  : path
 *
 * Mutates path by removing its extension. Removes all
 * text after and including the last '.'.
 * Only '.'s after the last slash are considered.
 *
 * @return
 * 1) If path has an extension, returns path with the
 *    extension removed.
 * 2) If there is no extension, returns NULL.
 * 3) If path is empty or NULL, returns NULL
 **/
char *path_remove_extension(char *s)
{
   char *last = path_get_extension_mutable(s);
   if (!last)
      return NULL;
   if (*last)
      *last = '\0';
   return s;
}

/**
 * path_is_compressed_file:
 * @path               : path
 *
 * Checks if path is a compressed file.
 *
 * @return true if path is a compressed file, otherwise false.
 **/
bool path_is_compressed_file(const char* path)
{
   const char *ext = path_get_extension(path);
   if (!string_is_empty(ext))
      return (   string_is_equal_noncase(ext, "zip")
              || string_is_equal_noncase(ext, "apk")
              || string_is_equal_noncase(ext, "7z"));
   return false;
}

/**
 * fill_pathname:
 * @s                  : output path
 * @in_path            : input  path
 * @replace            : what to replace
 * @len                : buffer size of output path
 *
 * FIXME: Verify
 *
 * Replaces filename extension with 'replace' and outputs result to @s.
 * The extension here is considered to be the string from the last '.'
 * to the end.
 *
 * Only '.'s after the last slash are considered as extensions.
 * If no '.' is present, in_path and replace will simply be concatenated.
 * 'len' is buffer size of 's'.
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =&gt;
 * s = "/foo/bar/baz/boo.asm"
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =&gt;
 * s = "/foo/bar/baz/boo"
 *
 * @return Length of the string copied into @out
 */
size_t fill_pathname(char *s, const char *in_path,
      const char *replace, size_t len)
{
   char *tok   = NULL;
   size_t _len = strlcpy(s, in_path, len);
   if ((tok = (char*)strrchr(path_basename(s), '.')))
   {
      *tok = '\0'; _len = tok - s;
   }
   _len += strlcpy(s + _len, replace,  len - _len);
   return _len;
}


/**
 * find_last_slash:
 * @str                : path
 * @size               : size of path
 *
 * Find last slash in path. Tries to find
 * a backslash as used for Windows paths,
 * otherwise checks for a regular slash.

 * @return pointer to last slash/backslash found in @str.
 **/
char *find_last_slash(const char *str)
{
   const char *p;
   const char *last_slash     = NULL;
   const char *last_backslash = NULL;

   /* Traverse the string once */
   for (p = str; *p != '\0'; ++p)
   {
      if (*p == '/')
         last_slash = p; /*   Update last forward slash */
      else if (*p == '\\')
         last_backslash = p; /* Update last backslash */
   }

   /* Determine which one is last */
   if (!last_slash) /* Backslash */
      return (char*)last_backslash;
   if (!last_backslash) /* Forward slash */
      return (char*)last_slash;
   return (last_backslash &gt; last_slash) ? (char*)last_backslash : (char*)last_slash;
}

/**
 * fill_pathname_slash:
 * @s                  : path
 * @len                : size of @s
 *
 * Assumes path is a directory. Appends a slash
 * if not already there.
 **/
size_t fill_pathname_slash(char *s, size_t len)
{
   char *last_slash = find_last_slash(s);
   len              = strlen(s);
   if (!last_slash)
   {
      s[  len]      = PATH_DEFAULT_SLASH_C();
      s[++len]      = '\0';
   }
   else if (last_slash != (s + len - 1))
   {
      /* Try to preserve slash type. */
      s[  len]       = last_slash[0];
      s[++len]       = '\0';
   }
   return len;
}

/**
 * fill_pathname_dir:
 * @s                  : input directory path
 * @in_basename        : input basename to be appended to @s
 * @replace            : replacement to be appended to @in_basename
 * @size               : size of buffer
 *
 * Appends basename of 'in_basename', to 's', along with 'replace'.
 * Basename of in_basename is the string after the last '/' or '\\',
 * i.e the filename without directories.
 *
 * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
 * 'size' is buffer size of 's'.
 *
 * E.g..: s = "/tmp/some_dir", in_basename = "/some_content/foo.c",
 * replace = ".asm" =&gt; s = "/tmp/some_dir/foo.c.asm"
 **/
size_t fill_pathname_dir(char *s, const char *in_basename,
      const char *replace, size_t len)
{
   size_t _len  = fill_pathname_slash(s, len);
   _len        += strlcpy(s + _len, path_basename(in_basename), len - _len);
   _len        += strlcpy(s + _len, replace, len - _len);
   return _len;
}

/**
 * fill_pathname_base:
 * @s                  : output path
 * @in_path            : input path
 * @len                : size of output path
 *
 * Copies basename of @in_path into @s.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_base(char *s, const char *in_path, size_t len)
{
   const char     *ptr = path_basename(in_path);
   if (ptr)
      return strlcpy(s, ptr, len);
   return strlcpy(s, in_path, len);
}

/**
 * fill_pathname_basedir:
 * @s                  : output directory
 * @in_path            : input path
 * @len                : size of output directory
 *
 * Copies base directory of @in_path into @s.
 * If in_path is a path without any slashes (relative current directory),
 * @s will get path "./".
 *
 * @return Length of the string copied in @s
 **/
size_t fill_pathname_basedir(char *s, const char *in_path, size_t len)
{
   if (s != in_path)
      strlcpy(s, in_path, len);
   return path_basedir(s);
}

/**
 * fill_pathname_parent_dir_name:
 * @s                  : output string
 * @in_dir             : input directory
 * @len                : size of @s
 *
 * Copies only the parent directory name of @in_dir into @s.
 * The two buffers must not overlap. Removes trailing '/'.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_parent_dir_name(char *s, const char *in_dir, size_t len)
{
   size_t _len        = 0;
   char *tmp          = strdup(in_dir);
   char *last_slash   = find_last_slash(tmp);

   if (last_slash &amp;&amp; last_slash[1] == 0)
   {
      *last_slash     = '\0';
      last_slash      = find_last_slash(tmp);
   }

   /* Cut the last part of the string (the filename) after the slash,
      leaving the directory name (or nested directory names) only. */
   if (last_slash)
      *last_slash     = '\0';

   /* Point in_dir to the address of the last slash.
    * If in_dir is NULL, it means there was no slash in tmp,
    * so use tmp as-is. */
   if (!(in_dir = find_last_slash(tmp)))
       in_dir         = tmp;

   if (in_dir &amp;&amp; in_dir[1])
   {
       /* If path starts with an slash, eliminate it. */
       if (path_is_absolute(in_dir))
           _len = strlcpy(s, in_dir + 1, len);
       else
           _len = strlcpy(s, in_dir,     len);
   }

   free(tmp);
   return _len;
}

/**
 * fill_pathname_parent_dir:
 * @s                  : output directory
 * @in_dir             : input directory
 * @len                : size of @s
 *
 * Copies parent directory of @in_dir into @s.
 * Assumes @in_dir is a directory. Keeps trailing '/'.
 * If the path was already at the root directory,
 * @s will be an empty string.
 **/
size_t fill_pathname_parent_dir(char *s,
      const char *in_dir, size_t len)
{
   size_t _len = 0;
   if (s == in_dir)
      _len = strlen(s);
   else
      _len = strlcpy(s, in_dir, len);
   return path_parent_dir(s, _len);
}

/**
 * fill_dated_filename:
 * @s                  : output filename
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by 'RetroArch', and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
 **/
size_t fill_dated_filename(char *s,
      const char *ext, size_t len)
{
   size_t _len;
   struct tm tm_;
   time_t cur_time = time(NULL);
   rtime_localtime(&amp;cur_time, &amp;tm_);
   _len  = strftime(s, len,
         "RetroArch-%m%d-%H%M%S", &amp;tm_);
   _len += strlcpy(s + _len, ext, len - _len);
   return _len;
}

/**
 * fill_str_dated_filename:
 * @s                  : output filename
 * @in_str             : input string
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by the string @in_str, and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
 *
 * @return Length of the string copied into @s
 **/
size_t fill_str_dated_filename(char *s,
      const char *in_str, const char *ext, size_t len)
{
   struct tm tm_;
   size_t _len     = 0;
   time_t cur_time = time(NULL);
   rtime_localtime(&amp;cur_time, &amp;tm_);
   _len      = strlcpy(s, in_str, len);
   if (string_is_empty(ext))
      _len += strftime(s + _len, len - _len, "-%y%m%d-%H%M%S", &amp;tm_);
   else
   {
      _len  += strftime(s + _len, len - _len, "-%y%m%d-%H%M%S.", &amp;tm_);
      _len  += strlcpy(s + _len, ext,    len - _len);
   }
   return _len;
}

/**
 * path_basedir:
 * @s                  : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 *
 * @return The new size of @s
 **/
size_t path_basedir(char *s)
{
   char *last_slash = NULL;
   if (!s || s[0] == '\0' || s[1] == '\0')
      return (s &amp;&amp; s[0] != '\0') ? 1 : 0;
   last_slash       = find_last_slash(s);
   if (last_slash)
   {
      last_slash[1] = '\0';
      return last_slash + 1 - s;
   }
   s[0]             = '.';
   s[1]             = PATH_DEFAULT_SLASH_C();
   s[2]             = '\0';
   return 2;
}

/**
 * path_parent_dir:
 * @s                  : path
 * @len                : length of @path
 *
 * Extracts parent directory by mutating path.
 * Assumes that @s is a directory. Keeps trailing '/'.
 * If the path was already at the root directory, returns empty string
 *
 * @return The new size of @s
 **/
size_t path_parent_dir(char *s, size_t len)
{
   if (!s)
      return 0;

   if (len &amp;&amp; PATH_CHAR_IS_SLASH(s[len - 1]))
   {
      char *last_slash;
      bool was_absolute = path_is_absolute(s);

      s[len - 1]        = '\0';
      last_slash        = find_last_slash(s);

      if (was_absolute &amp;&amp; !last_slash)
      {
         /* We removed the only slash from what used to be an absolute path.
          * On Linux, this goes from "/" to an empty string and everything works fine,
          * but on Windows, we went from C:\ to C:, which is not a valid path and that later
          * gets erroneously treated as a relative one by path_basedir and returns "./".
          * What we really wanted is an empty string. */
         s[0] = '\0';
         return 0;
      }
   }
   return path_basedir(s);
}

/**
 * path_basename:
 * @path               : path
 *
 * Get basename from @path.
 *
 * @return basename from path.
 **/
const char *path_basename(const char *path)
{
   /* We cut either at the first compression-related hash,
    * or we cut at the last slash */
   const char *ptr       = NULL;
   char *last_slash      = find_last_slash(path);
   return ((ptr = path_get_archive_delim(path)) || (ptr = last_slash))
      ? (ptr + 1) : path;
}

/* Specialized version */
/**
 * path_basename_nocompression:
 * @path               : path
 *
 * Specialized version of path_basename().
 * Get basename from @path.
 *
 * @return basename from path.
 **/
const char *path_basename_nocompression(const char *path)
{
   /* We cut at the last slash */
   char *last_slash = find_last_slash(path);
   return (last_slash) ? (last_slash + 1) : path;
}

/**
 * path_is_absolute:
 * @path               : path
 *
 * Checks if @path is an absolute path or a relative path.
 *
 * @return true if path is absolute, false if path is relative.
 **/
bool path_is_absolute(const char *path)
{
   if (!string_is_empty(path))
   {
      if (path[0] == '/')
         return true;
#if defined(_WIN32)
      /* Many roads lead to Rome...
       * Note: Drive letter can only be 1 character long */
      return ( string_starts_with_size(path,     "\\\\", STRLEN_CONST("\\\\"))
            || string_starts_with_size(path + 1, ":/",   STRLEN_CONST(":/"))
            || string_starts_with_size(path + 1, ":\\",  STRLEN_CONST(":\\")));
#elif defined(__wiiu__) || defined(VITA)
      {
         const char *separator = strchr(path, ':');
         return (separator &amp;&amp; (separator[1] == '/'));
      }
#endif
   }

   return false;
}

/**
 * path_resolve_realpath:
 * @s                  : input and output buffer for path
 * @len                : size of @s
 * @resolve_symlinks   : whether to resolve symlinks or not
 *
 * Resolves use of ".", "..", multiple slashes etc in absolute paths.
 *
 * Relative paths are rebased on the current working dir.
 *
 * @return @s if successful, NULL otherwise.
 * Note: Not implemented on consoles
 * Note: Symlinks are only resolved on Unix-likes
 * Note: The current working dir might not be what you expect,
 *       e.g. on Android it is "/"
 *       Use of fill_pathname_resolve_relative() should be preferred
 **/
char *path_resolve_realpath(char *s, size_t len, bool resolve_symlinks)
{
#if !defined(RARCH_CONSOLE) &amp;&amp; defined(RARCH_INTERNAL)
#ifdef _WIN32
   char *ret         = NULL;
   wchar_t *rel_path = utf8_to_utf16_string_alloc(s);

   if (rel_path)
   {
      wchar_t abs_path[PATH_MAX_LENGTH];

      if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH))
      {
         char *tmp = utf16_to_utf8_string_alloc(abs_path);

         if (tmp)
         {
            strlcpy(s, tmp, len);
            free(tmp);
            ret = s;
         }
      }

      free(rel_path);
   }

   return ret;
#else
   char tmp[PATH_MAX_LENGTH];
   size_t t;
   char *p;
   const char *next;
   const char *buf_end;

   if (resolve_symlinks)
   {
      strlcpy(tmp, s, sizeof(tmp));

      /* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in @s.
       * Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways.
       * POSIX 2008 can automatically allocate for you,
       * but don't rely on that. */
      if (!realpath(tmp, s))
      {
         strlcpy(s, tmp, len);
         return NULL;
      }

      return s;
   }

   t       = 0; /* length of output */
   buf_end = s + strlen(s);

   if (!path_is_absolute(s))
   {
      size_t _len;
      /* rebase on working directory */
      if (!getcwd(tmp, PATH_MAX_LENGTH - 1))
         return NULL;

      _len = strlen(tmp);
      t  += _len;

      if (tmp[_len - 1] != '/')
         tmp[t++] = '/';

      if (string_is_empty(s))
      {
         tmp[t] = '\0';
         strlcpy(s, tmp, len);
         return s;
      }

      p = s;
   }
   else
   {
      /* UNIX paths can start with multiple '/', copy those */
      for (p = s; *p == '/'; p++)
         tmp[t++] = '/';
   }

   /* p points to just after a slash while 'next' points to the next slash
    * if there are no slashes, they point relative to where one would be */
   do
   {
      if (!(next = strchr(p, '/')))
         next = buf_end;

      if ((next - p == 2 &amp;&amp; p[0] == '.' &amp;&amp; p[1] == '.'))
      {
         p += 3;

         /* fail for illegal /.., //.. etc */
         if (t == 1 || tmp[t-2] == '/')
            return NULL;

         /* delete previous segment in tmp by adjusting size t
          * tmp[t - 1] == '/', find '/' before that */
         t -= 2;
         while (tmp[t] != '/')
            t--;
         t++;
      }
      else if (next - p == 1 &amp;&amp; p[0] == '.')
         p += 2;
      else if (next - p == 0)
         p += 1;
      else
      {
         /* fail when truncating */
         if (t + next - p + 1 &gt; PATH_MAX_LENGTH - 1)
            return NULL;

         while (p &lt;= next)
            tmp[t++] = *p++;
      }
   } while(next &lt; buf_end);

   tmp[t] = '\0';
   strlcpy(s, tmp, len);
   return s;
#endif
#endif
   return NULL;
}

/**
 * path_relative_to:
 * @s                  : buffer to write the relative path to
 * @path               : path to be expressed relatively
 * @base               : base directory to start out on
 * @len                : size of @s
 *
 * Turns @path into a path relative to @base and writes it to @s.
 *
 * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
 * Both @path and @base are assumed to be absolute paths without "." or "..".
 *
 * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg
 *
 * @return Length of the string copied into @s
 **/
size_t path_relative_to(char *s,
      const char *path, const char *base, size_t len)
{
   size_t i, j;
   const char *trimmed_path, *trimmed_base;

#ifdef _WIN32
   /* For different drives, return absolute path */
   if (
            path
         &amp;&amp; base
         &amp;&amp; path[0] != '\0'
         &amp;&amp; path[1] != '\0'
         &amp;&amp; base[0] != '\0'
         &amp;&amp; base[1] != '\0'
         &amp;&amp; path[1] == ':'
         &amp;&amp; base[1] == ':'
         &amp;&amp; path[0] != base[0])
      return strlcpy(s, path, len);
#endif

   /* Trim common beginning */
   for (i = 0, j = 0; path[i] &amp;&amp; base[i] &amp;&amp; path[i] == base[i]; i++)
      if (path[i] == PATH_DEFAULT_SLASH_C())
         j = i + 1;

   trimmed_path = path + j;
   trimmed_base = base + i;

   /* Each segment of base turns into ".." */
   s[0] = '\0';
   for (i = 0; trimmed_base[i]; i++)
      if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
         strlcat(s, ".." PATH_DEFAULT_SLASH(), len);

   return strlcat(s, trimmed_path, len);
}

/**
 * fill_pathname_resolve_relative:
 * @s                  : output path
 * @in_refpath         : input reference path
 * @in_path            : input path
 * @len                : size of @s
 *
 * Joins basedir of @in_refpath together with @in_path.
 * If @in_path is an absolute path, s = in_path.
 * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
 * s = "/foo/bar/foobar.cg".
 **/
void fill_pathname_resolve_relative(char *s,
      const char *in_refpath, const char *in_path, size_t len)
{
   if (path_is_absolute(in_path))
   {
      strlcpy(s, in_path, len);
      return;
   }

   fill_pathname_basedir(s, in_refpath, len);
   strlcat(s, in_path, len);
   path_resolve_realpath(s, len, false);
}

/**
 * fill_pathname_join:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get  two consecutive slashes
 * between directory and path.
 *
 * Deprecated. Use fill_pathname_join_special() instead
 * if you can ensure @dir and @s won't overlap.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join(char *s, const char *dir,
      const char *path, size_t len)
{
   size_t _len = 0;
   if (s != dir)
      _len = strlcpy(s, dir, len);
   if (*s)
      _len = fill_pathname_slash(s, len);
   _len   += strlcpy(s + _len, path, len - _len);
   return _len;
}

/**
 * fill_pathname_join_special:
 * @s                  : output path
 * @dir                : directory. Cannot be identical to @s
 * @path               : path
 * @len                : size of @s
 *
 * Specialized version of fill_pathname_join.
 * Unlike fill_pathname_join(),
 * @dir and @s CANNOT be identical.
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get  two consecutive slashes
 * between directory and path.
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join_special(char *s,
      const char *dir, const char *path, size_t len)
{
   size_t _len = strlcpy(s, dir, len);

   if (*s)
   {
      char *last_slash = find_last_slash(s);
      if (!last_slash)
      {
         s[  _len]     = PATH_DEFAULT_SLASH_C();
         s[++_len]     = '\0';
      }
      else if (last_slash != (s + _len - 1))
      {
         /* Try to preserve slash type. */
         s[  _len]     = last_slash[0];
         s[++_len]     = '\0';
      }
   }

   _len += strlcpy(s + _len, path, len - _len);
   return _len;
}

size_t fill_pathname_join_special_ext(char *s,
      const char *dir,  const char *path,
      const char *last, const char *ext,
      size_t len)
{
   size_t _len = fill_pathname_join(s, dir, path, len);
   if (*s)
      _len     = fill_pathname_slash(s, len);
   _len       += strlcpy(s + _len, last, len - _len);
   _len       += strlcpy(s + _len, ext,  len - _len);
   return _len;
}

/**
 * fill_pathname_join_delim:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @delim              : delimiter
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together
 * using the given delimiter (@delim).
 **/
size_t fill_pathname_join_delim(char *s, const char *dir,
      const char *path, const char delim, size_t len)
{
   size_t _len;
   /* Behavior of strlcpy is undefined if dst and src overlap */
   if (s == dir)
      _len     = strlen(dir);
   else
      _len     = strlcpy(s, dir, len);
   if (len - _len &lt; 2)
      return _len;
   s[_len++]   = delim;
   s[_len  ]   = '\0';
   if (path)
      _len    += strlcpy(s + _len, path, len - _len);
   return _len;
}

size_t fill_pathname_expand_special(char *s, const char *in_path, size_t len)
{
#if !defined(RARCH_CONSOLE) &amp;&amp; defined(RARCH_INTERNAL)
   char *app_dir = NULL;
   if (in_path[0] == '~')
   {
      app_dir    = (char*)malloc(DIR_MAX_LENGTH * sizeof(char));
      fill_pathname_home_dir(app_dir, DIR_MAX_LENGTH * sizeof(char));
   }
   else if (in_path[0] == ':')
   {
      app_dir    = (char*)malloc(DIR_MAX_LENGTH * sizeof(char));
      app_dir[0] = '\0';
      fill_pathname_application_dir(app_dir, DIR_MAX_LENGTH * sizeof(char));
   }

   if (app_dir)
   {
      if (*app_dir)
      {
         size_t _len     = strlcpy(s, app_dir, len);

         s              += _len;
         len            -= _len;

         if (!PATH_CHAR_IS_SLASH(s[-1]))
         {
            _len      = strlcpy(s, PATH_DEFAULT_SLASH(), len);

            s        += _len;
            len      -= _len;
         }

         in_path += 2;
      }

      free(app_dir);
   }
#endif
   return strlcpy(s, in_path, len);
}

size_t fill_pathname_abbreviate_special(char *s,
      const char *in_path, size_t len)
{
#if !defined(RARCH_CONSOLE) &amp;&amp; defined(RARCH_INTERNAL)
   unsigned i;
   const char *candidates[3];
   const char *notations[3];
   char application_dir[DIR_MAX_LENGTH];
   char home_dir[DIR_MAX_LENGTH];

   application_dir[0] = '\0';

   /* application_dir could be zero-string. Safeguard against this.
    *
    * Keep application dir in front of home, moving app dir to a
    * new location inside home would break otherwise. */

   /* ugly hack - use application_dir pointer
    * before filling it in. C89 reasons */
   candidates[0] = application_dir;
   candidates[1] = home_dir;
   candidates[2] = NULL;

   notations [0] = ":";
   notations [1] = "~";
   notations [2] = NULL;

   fill_pathname_application_dir(application_dir, sizeof(application_dir));
   fill_pathname_home_dir(home_dir, sizeof(home_dir));

   for (i = 0; candidates[i]; i++)
   {
      if (  !string_is_empty(candidates[i])
          &amp;&amp; string_starts_with(in_path, candidates[i]))
      {
         size_t _len      = strlcpy(s, notations[i], len);

         s               += _len;
         len             -= _len;
         in_path         += strlen(candidates[i]);

         if (!PATH_CHAR_IS_SLASH(*in_path))
         {
            strcpy(s, PATH_DEFAULT_SLASH());
            s++;
            len--;
         }

         break; /* Don't allow more abbrevs to take place. */
      }
   }
#endif
   return strlcpy(s, in_path, len);
}

/**
 * sanitize_path_part:
 *
 * @path_part               : directory or filename
 *
 * Takes single part of a path eg. single filename
 * or directory, and removes any special chars that are
 * unavailable.
 *
 * @returns new string that has been sanitized
 **/
const char *sanitize_path_part(const char *path_part, size_t len)
{
   int i;
   int j = 0;
   char *tmp = NULL;
   const char *special_chars = "&lt;&gt;:\"/\\|?*";

   if (string_is_empty(path_part))
      return NULL;

   tmp = (char *)malloc((len + 1) * sizeof(char));

   for (i = 0; path_part[i] != '\0'; i++)
   {
      /* Check if the current character is
       * one of the special characters */

      /*  If not, copy it to the temporary array */
      if (!strchr(special_chars, path_part[i]))
         tmp[j++] = path_part[i];
   }

   tmp[j] = '\0';

   /* Return the new string */
   return tmp;
}

/**
 * pathname_conform_slashes_to_os:
 *
 * @s                  : path
 *
 * Leaf function.
 *
 * Changes the slashes to the correct kind for the OS
 * So forward slash on linux and backslash on Windows
 **/
void pathname_conform_slashes_to_os(char *s)
{
   /* Conform slashes to OS standard so we get proper matching */
   char *p;
   for (p = s; *p; p++)
      if (*p == '/' || *p == '\\')
         *p = PATH_DEFAULT_SLASH_C();
}

/**
 * pathname_make_slashes_portable:
 * @s                  : path
 *
 * Leaf function.
 *
 * Change all slashes to forward so they are more
 * portable between Windows and Linux
 **/
void pathname_make_slashes_portable(char *s)
{
   /* Conform slashes to OS standard so we get proper matching */
   char *p;
   for (p = s; *p; p++)
      if (*p == '/' || *p == '\\')
         *p = '/';
}

/**
 * get_pathname_num_slashes:
 * @in_path            : input path
 *
 * Leaf function.
 *
 * Get the number of slashes in a path.
 *
 * @return number of slashes found in @in_path.
 **/
static int get_pathname_num_slashes(const char *in_path)
{
   int num_slashes = 0;
   int i = 0;

   for (i = 0; i &lt; PATH_MAX_LENGTH; i++)
   {
      if (PATH_CHAR_IS_SLASH(in_path[i]))
         num_slashes++;
      if (in_path[i] == '\0')
         break;
   }

   return num_slashes;
}

/**
 * fill_pathname_abbreviated_or_relative:
 *
 * Fills the supplied path with either the abbreviated path or
 * the relative path, which ever one has less depth / number of slashes
 *
 * If lengths of abbreviated and relative paths are the same,
 * the relative path will be used
 * @in_path can be an absolute, relative or abbreviated path
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_abbreviated_or_relative(char *s,
      const char *in_refpath, const char *in_path, size_t len)
{
   size_t _len;
   char in_path_conformed[PATH_MAX_LENGTH];
   char in_refpath_conformed[PATH_MAX_LENGTH];
   char absolute_path[PATH_MAX_LENGTH];
   char relative_path[PATH_MAX_LENGTH];

   absolute_path[0]        = '\0';
   relative_path[0]        = '\0';

   strlcpy(in_path_conformed,    in_path,    sizeof(in_path_conformed));
   strlcpy(in_refpath_conformed, in_refpath, sizeof(in_refpath_conformed));

   pathname_conform_slashes_to_os(in_path_conformed);
   pathname_conform_slashes_to_os(in_refpath_conformed);

   /* Expand paths which start with :\ to an absolute path */
   fill_pathname_expand_special(absolute_path,
         in_path_conformed, sizeof(absolute_path));

   /* Get the absolute path if it is not already */
   if (!path_is_absolute(absolute_path))
      fill_pathname_resolve_relative(absolute_path,
            in_refpath_conformed, in_path_conformed,
            sizeof(absolute_path));
   pathname_conform_slashes_to_os(absolute_path);

   /* Get the relative path and see how many directories long it is */
   path_relative_to(relative_path, absolute_path,
         in_refpath_conformed, sizeof(relative_path));

   /* Get the abbreviated path and see how many directories long it is */
   _len = fill_pathname_abbreviate_special(s, absolute_path, len);

   /* Use the shortest path, preferring the relative path*/
   if (     get_pathname_num_slashes(relative_path)
         &lt;= get_pathname_num_slashes(s))
      return strlcpy(s, relative_path, len);
   return _len;
}

/**
 * path_basedir:
 * @s                  : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 **/
void path_basedir_wrapper(char *s)
{
   char *last_slash = NULL;
   if (!s || s[0] == '\0' || s[1] == '\0')
      return;
#ifdef HAVE_COMPRESSION
   /* We want to find the directory with the archive in basedir. */
   if ((last_slash  = (char*)path_get_archive_delim(s)))
      *last_slash   = '\0';
#endif
   last_slash       = find_last_slash(s);
   if (!last_slash)
   {
      s[0]          = '.';
      s[1]          = PATH_DEFAULT_SLASH_C();
      s[2]          = '\0';
   }
   else
      last_slash[1] = '\0';
}

#if !defined(RARCH_CONSOLE) &amp;&amp; defined(RARCH_INTERNAL)
size_t fill_pathname_application_path(char *s, size_t len)
{
   if (len)
   {
#if defined(_WIN32)
#ifdef LEGACY_WIN32
      DWORD ret = GetModuleFileNameA(NULL, s, len);
#else
      wchar_t wstr[PATH_MAX_LENGTH] = {0};
      DWORD ret = GetModuleFileNameW(NULL, wstr, ARRAY_SIZE(wstr));
      if (*wstr)
      {
         char *str = utf16_to_utf8_string_alloc(wstr);
         if (str)
         {
            strlcpy(s, str, len);
            free(str);
         }
      }
#endif
      s[ret] = '\0';
      return ret;
#elif defined(__APPLE__)
      CFBundleRef bundle = CFBundleGetMainBundle();
      if (bundle)
      {
         size_t rv               = 0;
         CFURLRef bundle_url     = CFBundleCopyBundleURL(bundle);
         CFStringRef bundle_path = CFURLCopyPath(bundle_url);
         CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8);
#ifdef HAVE_COCOATOUCH
         {
            /* This needs to be done so that the path becomes
             * /private/var/... and this
             * is used consistently throughout for the iOS bundle path */
            char resolved_bundle_dir_buf[DIR_MAX_LENGTH] = {0};
            if (realpath(s, resolved_bundle_dir_buf))
            {
               size_t _len = strlcpy(s, resolved_bundle_dir_buf, len - 1);
               s[  _len]   = '/';
               s[++_len]   = '\0';
               rv          = _len;
            }
         }
#else
         rv = CFStringGetLength(bundle_path);
#endif

         CFRelease(bundle_path);
         CFRelease(bundle_url);
         return rv;
      }
#elif defined(__HAIKU__)
      image_info info;
      int32_t cookie = 0;
      while (get_next_image_info(0, &amp;cookie, &amp;info) == B_OK)
      {
         if (info.type == B_APP_IMAGE)
            return strlcpy(s, info.name, len);
      }
#elif defined(__QNX__)
      char *buff  = (char*)malloc(len);
      size_t _len = 0;
      if (_cmdname(buff))
         _len = strlcpy(s, buff, len);
      free(buff);
      return _len;
#else
      size_t i;
      static const char *exts[] = { "exe", "file", "path/a.out" };
      char link_path[255];
      pid_t pid   = getpid();
      size_t _len = snprintf(link_path, sizeof(link_path), "/proc/%u/",
            (unsigned)pid);

      *s           = '\0';

      /* Linux, BSD and Solaris paths. Not standardized. */
      for (i = 0; i &lt; ARRAY_SIZE(exts); i++)
      {
         ssize_t ret;
         strlcpy(link_path + _len, exts[i], sizeof(link_path) - _len);

         if ((ret = readlink(link_path, s, len - 1)) &gt;= 0)
         {
            s[ret] = '\0';
            return ret;
         }
      }
#endif
   }
   return 0;
}

size_t fill_pathname_application_dir(char *s, size_t len)
{
#ifdef __WINRT__
   return strlcpy(s, uwp_dir_install, len);
#else
   fill_pathname_application_path(s, len);
   return path_basedir(s);
#endif
}

size_t fill_pathname_home_dir(char *s, size_t len)
{
#ifdef __WINRT__
   const char *home = uwp_dir_data;
#else
   const char *home = getenv("HOME");
#endif
   if (home)
      return strlcpy(s, home, len);
   *s = 0;
   return 0;
}
#endif

bool is_path_accessible_using_standard_io(const char *path)
{
#ifdef __WINRT__
   return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
#else
   return true;
#endif
}</pre>
<h2>./include/libretro-common/file/file_path_io.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_path_io.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;time.h&gt;

#include &lt;sys/stat.h&gt;

#include &lt;boolean.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;compat/posix_string.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;string/stdstring.h&gt;
#define VFS_FRONTEND
#include &lt;vfs/vfs_implementation.h&gt;

#ifdef _WIN32
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt; /* stat() is defined here */
#endif

/* TODO/FIXME - globals */
static retro_vfs_stat_t path_stat_cb   = retro_vfs_stat_impl;
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;

void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
   const struct retro_vfs_interface* 
      vfs_iface           = vfs_info-&gt;iface;

   path_stat_cb           = retro_vfs_stat_impl;
   path_mkdir_cb          = retro_vfs_mkdir_impl;

   if (vfs_info-&gt;required_interface_version &lt; PATH_REQUIRED_VFS_VERSION || !vfs_iface)
      return;

   path_stat_cb           = vfs_iface-&gt;stat;
   path_mkdir_cb          = vfs_iface-&gt;mkdir;
}

int path_stat(const char *path)
{
   return path_stat_cb(path, NULL);
}

/**
 * path_is_directory:
 * @path               : path
 *
 * Checks if path is a directory.
 *
 * @return true if path is a directory, otherwise false.
 */
bool path_is_directory(const char *path)
{
   return (path_stat_cb(path, NULL) &amp; RETRO_VFS_STAT_IS_DIRECTORY) != 0;
}

bool path_is_character_special(const char *path)
{
   return (path_stat_cb(path, NULL) &amp; RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
}

bool path_is_valid(const char *path)
{
   return (path_stat_cb(path, NULL) &amp; RETRO_VFS_STAT_IS_VALID) != 0;
}

int32_t path_get_size(const char *path)
{
   int32_t filesize = 0;
   if (path_stat_cb(path, &amp;filesize) != 0)
      return filesize;

   return -1;
}

/**
 * path_mkdir:
 * @dir                : directory
 *
 * Create directory on filesystem.
 * 
 * Recursive function.
 *
 * @return true if directory could be created, otherwise false.
 **/
bool path_mkdir(const char *dir)
{
   bool norecurse     = false;
   char     *basedir  = NULL;

   if (!(dir &amp;&amp; *dir))
      return false;

   /* Use heap. Real chance of stack 
    * overflow if we recurse too hard. */
   if (!(basedir = strdup(dir)))
      return false;

   path_parent_dir(basedir, strlen(basedir));

   if (!*basedir || !strcmp(basedir, dir))
   {
      free(basedir);
      return false;
   }

   if (     path_is_directory(basedir)
         || path_mkdir(basedir))
      norecurse = true;

   free(basedir);

   if (norecurse)
   {
      int ret = path_mkdir_cb(dir);

      /* Don't treat this as an error. */
      if (ret == -2 &amp;&amp; path_is_directory(dir))
         return true;
      else if (ret == 0)
         return true;
   }
   return false;
}</pre>
<h2>./include/libretro-common/file/nbio/nbio_intf.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_intf.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include &lt;file/nbio.h&gt;

extern nbio_intf_t nbio_linux;
extern nbio_intf_t nbio_mmap_unix;
extern nbio_intf_t nbio_mmap_win32;
extern nbio_intf_t nbio_stdio;

#ifndef _XBOX
#if defined(_WIN32)
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1500

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif

#elif !defined(_MSC_VER)

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#endif
#endif

#endif

#if defined(_linux__)
static nbio_intf_t *internal_nbio = &amp;nbio_linux;
#elif defined(HAVE_MMAP) &amp;&amp; defined(BSD)
static nbio_intf_t *internal_nbio = &amp;nbio_mmap_unix;
#elif defined(HAVE_MMAP_WIN32)
static nbio_intf_t *internal_nbio = &amp;nbio_mmap_win32;
#else
static nbio_intf_t *internal_nbio = &amp;nbio_stdio;
#endif

void *nbio_open(const char * filename, unsigned mode)
{
   return internal_nbio-&gt;open(filename, mode);
}

void nbio_begin_read(void *data)
{
   internal_nbio-&gt;begin_read(data);
}

void nbio_begin_write(void *data)
{
   internal_nbio-&gt;begin_write(data);
}

bool nbio_iterate(void *data)
{
   return internal_nbio-&gt;iterate(data);
}

void nbio_resize(void *data, size_t len)
{
   internal_nbio-&gt;resize(data, len);
}

void *nbio_get_ptr(void *data, size_t* len)
{
   return internal_nbio-&gt;get_ptr(data, len);
}

void nbio_cancel(void *data)
{
   internal_nbio-&gt;cancel(data);
}

void nbio_free(void *data)
{
   internal_nbio-&gt;free(data);
}</pre>
<h2>./include/libretro-common/file/nbio/nbio_linux.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_linux.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;file/nbio.h&gt;

#if defined(__linux__)

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;
#include &lt;time.h&gt;

#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;sys/syscall.h&gt;
#include &lt;linux/aio_abi.h&gt;

struct nbio_linux_t
{
   void* ptr;
   aio_context_t ctx;
   struct iocb cb;
   size_t len;
   int fd;
   bool busy;
};

/* there's also a Unix AIO thingy, but it's not in glibc
 * and we don't want more dependencies */

static int io_setup(unsigned nr, aio_context_t * ctxp)
{
   return syscall(__NR_io_setup, nr, ctxp);
}

static int io_destroy(aio_context_t ctx)
{
   return syscall(__NR_io_destroy, ctx);
}

static int io_submit(aio_context_t ctx, long nr, struct iocb ** cbp)
{
   return syscall(__NR_io_submit, ctx, nr, cbp);
}

static int io_cancel(aio_context_t ctx, struct iocb * iocb, struct io_event * result)
{
   return syscall(__NR_io_cancel, ctx, iocb, result);
}

static int io_getevents(aio_context_t ctx, long min_nr, long nr,
      struct io_event * events, struct timespec * timeout)
{
   return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
}

static void nbio_begin_op(struct nbio_linux_t* handle, uint16_t op)
{
   struct iocb * cbp         = &amp;handle-&gt;cb;

   memset(&amp;handle-&gt;cb, 0, sizeof(handle-&gt;cb));

   handle-&gt;cb.aio_fildes     = handle-&gt;fd;
   handle-&gt;cb.aio_lio_opcode = op;

   handle-&gt;cb.aio_buf        = (uint64_t)(uintptr_t)handle-&gt;ptr;
   handle-&gt;cb.aio_offset     = 0;
   handle-&gt;cb.aio_nbytes     = handle-&gt;len;

   if (io_submit(handle-&gt;ctx, 1, &amp;cbp) != 1)
      abort();

   handle-&gt;busy = true;
}

static void *nbio_linux_open(const char * filename, unsigned mode)
{
   static const int o_flags[]  =   { O_RDONLY, O_RDWR|O_CREAT|O_TRUNC, O_RDWR, O_RDONLY, O_RDWR|O_CREAT|O_TRUNC };

   aio_context_t ctx           = 0;
   struct nbio_linux_t* handle = NULL;
   int fd                      = open(filename, o_flags[mode]|O_CLOEXEC, 0644);
   if (fd &lt; 0)
      return NULL;

   if (io_setup(128, &amp;ctx) &lt; 0)
   {
      close(fd);
      return NULL;
   }

   handle       = (struct nbio_linux_t*)malloc(sizeof(struct nbio_linux_t));
   handle-&gt;fd   = fd;
   handle-&gt;ctx  = ctx;
   handle-&gt;len  = lseek(fd, 0, SEEK_END);
   handle-&gt;ptr  = malloc(handle-&gt;len);
   handle-&gt;busy = false;

   return handle;
}

static void nbio_linux_begin_read(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (handle)
      nbio_begin_op(handle, IOCB_CMD_PREAD);
}

static void nbio_linux_begin_write(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (handle)
      nbio_begin_op(handle, IOCB_CMD_PWRITE);
}

static bool nbio_linux_iterate(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return false;
   if (handle-&gt;busy)
   {
      struct io_event ev;
      if (io_getevents(handle-&gt;ctx, 0, 1, &amp;ev, NULL) == 1)
         handle-&gt;busy = false;
   }
   return !handle-&gt;busy;
}

static void nbio_linux_resize(void *data, size_t len)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return;

   /* This works perfectly fine if this check is removed, but it
    * won't work on other nbio implementations */
   /* therefore, it's blocked so nobody accidentally relies on it */
   if (len &lt; handle-&gt;len)
      abort();

   if (ftruncate(handle-&gt;fd, len) != 0)
      abort(); /* this one returns void and I can't find any other way
                  for it to report failure */

   handle-&gt;ptr = realloc(handle-&gt;ptr, len);
   handle-&gt;len = len;
}

static void *nbio_linux_get_ptr(void *data, size_t* len)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle-&gt;len;
   if (!handle-&gt;busy)
      return handle-&gt;ptr;
   return NULL;
}

static void nbio_linux_cancel(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return;

   if (handle-&gt;busy)
   {
      struct io_event ev;
      io_cancel(handle-&gt;ctx, &amp;handle-&gt;cb, &amp;ev);
      handle-&gt;busy = false;
   }
}

static void nbio_linux_free(void *data)
{
   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
   if (!handle)
      return;

   io_destroy(handle-&gt;ctx);
   close(handle-&gt;fd);
   free(handle-&gt;ptr);
   free(handle);
}

nbio_intf_t nbio_linux = {
   nbio_linux_open,
   nbio_linux_begin_read,
   nbio_linux_begin_write,
   nbio_linux_iterate,
   nbio_linux_resize,
   nbio_linux_get_ptr,
   nbio_linux_cancel,
   nbio_linux_free,
   "nbio_linux",
};
#else
nbio_intf_t nbio_linux = {
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   "nbio_linux",
};

#endif</pre>
<h2>./include/libretro-common/file/nbio/nbio_orbis.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_orbis.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;file/nbio.h&gt;

#if defined(ORBIS)
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;orbisFile.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/fcntl.h&gt;

struct nbio_orbis_t
{
   void* data;
   size_t progress;
   size_t len;
   int fd;
   unsigned int mode;
   /*
    * possible values:
    * NBIO_READ, NBIO_WRITE - obvious
    * -1 - currently doing nothing
    * -2 - the pointer was reallocated since the last operation
    */
   signed char op;
};

static void *nbio_orbis_open(const char * filename, unsigned int mode)
{
   static const int o_flags[]  =   { O_RDONLY, O_RDWR | O_CREAT | O_TRUNC,
      O_RDWR, O_RDONLY, O_RDWR | O_CREAT | O_TRUNC };
   void *buf                   = NULL;
   struct nbio_orbis_t* handle = NULL;
   size_t len                  = 0;
   int fd                      = orbisOpen(filename, o_flags[mode], 0644);

   if (fd &lt; 0)
      return NULL;
   handle                = (struct nbio_orbis_t*)malloc(sizeof(struct nbio_orbis_t));

   if (!handle)
      goto error;

   handle-&gt;fd             = fd;

   switch (mode)
   {
      case NBIO_WRITE:
      case BIO_WRITE:
         break;
      default:
         len=orbisLseek(handle-&gt;fd, 0, SEEK_END);
         orbisLseek(handle-&gt;fd, 0, SEEK_SET);
         break;
   }

   handle-&gt;mode          = mode;

   if (len)
      buf                = malloc(len);

   if (len &amp;&amp; !buf)
      goto error;

   handle-&gt;data          = buf;
   handle-&gt;len           = len;
   handle-&gt;progress      = handle-&gt;len;
   handle-&gt;op            = -2;

   return handle;

error:
   if (handle)
      free(handle);
   orbisClose(fd);
   return NULL;
}

static void nbio_orbis_begin_read(void *data)
{

   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle-&gt;op &gt;= 0)
      return;

   orbisLseek(handle-&gt;fd, 0, SEEK_SET);

   handle-&gt;op       = NBIO_READ;
   handle-&gt;progress = 0;
}

static void nbio_orbis_begin_write(void *data)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle-&gt;op &gt;= 0)
      return;

   orbisLseek(handle-&gt;fd, 0, SEEK_SET);
   handle-&gt;op = NBIO_WRITE;
   handle-&gt;progress = 0;
}

static bool nbio_orbis_iterate(void *data)
{
   size_t amount               = 65536;
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;

   if (!handle)
      return false;

   if (amount &gt; handle-&gt;len - handle-&gt;progress)
      amount = handle-&gt;len - handle-&gt;progress;

   switch (handle-&gt;op)
   {
      case NBIO_READ:
         if (handle-&gt;mode == BIO_READ)
            amount = handle-&gt;len;
         break;
      case NBIO_WRITE:
         if (handle-&gt;mode == BIO_WRITE)
         {
            size_t written = 0;
            amount = handle-&gt;len;
            written = orbisWrite(handle-&gt;fd, (char*)handle-&gt;data, amount);

            if (written != amount)
               return false;
         }
         break;
   }

   handle-&gt;progress += amount;

   if (handle-&gt;progress == handle-&gt;len)
      handle-&gt;op = -1;
   return (handle-&gt;op &lt; 0);
}

static void nbio_orbis_resize(void *data, size_t len)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle-&gt;op &gt;= 0)
      return;
   if (len &lt; handle-&gt;len)
      return;

   handle-&gt;len      = len;
   handle-&gt;data     = realloc(handle-&gt;data, handle-&gt;len);
   handle-&gt;op       = -1;
   handle-&gt;progress = handle-&gt;len;
}

static void *nbio_orbis_get_ptr(void *data, size_t* len)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle-&gt;len;
   if (handle-&gt;op == -1)
      return handle-&gt;data;
   return NULL;
}

static void nbio_orbis_cancel(void *data)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;
   handle-&gt;op = -1;
   handle-&gt;progress = handle-&gt;len;
}

static void nbio_orbis_free(void *data)
{
   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
   if (!handle)
      return;

   if (handle-&gt;op &gt;= 0)
      return;

   orbisClose(handle-&gt;fd);
   free(handle-&gt;data);

   handle-&gt;data = NULL;
   free(handle);
}

nbio_intf_t nbio_orbis = {
   nbio_orbis_open,
   nbio_orbis_begin_read,
   nbio_orbis_begin_write,
   nbio_orbis_iterate,
   nbio_orbis_resize,
   nbio_orbis_get_ptr,
   nbio_orbis_cancel,
   nbio_orbis_free,
   "nbio_orbis",
};
#endif</pre>
<h2>./include/libretro-common/file/nbio/nbio_stdio.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_stdio.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#if defined(WIIU)
#include &lt;malloc.h&gt;
#endif

#include &lt;file/nbio.h&gt;
#include &lt;encodings/utf.h&gt;

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#if defined(_WIN32)
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1400
#define ATLEAST_VC2005
#endif
#endif

#if (defined(_POSIX_C_SOURCE) &amp;&amp; (_POSIX_C_SOURCE - 0) &gt;= 200112) || (defined(__POSIX_VISIBLE) &amp;&amp; __POSIX_VISIBLE &gt;= 200112) || (defined(_POSIX_VERSION) &amp;&amp; _POSIX_VERSION &gt;= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) &amp;&amp; _FILE_OFFSET_BITS == 64)
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
#endif

struct nbio_stdio_t
{
   FILE* f;
   void* data;
   size_t progress;
   size_t len;
   /*
    * possible values:
    * NBIO_READ, NBIO_WRITE - obvious
    * -1 - currently doing nothing
    * -2 - the pointer was reallocated since the last operation
    */
   signed char op;
   signed char mode;
};

#if !defined(_WIN32) || defined(LEGACY_WIN32)
static const char    *stdio_modes[] = { "rb", "wb", "r+b", "rb", "wb", "r+b" };
#else
static const wchar_t *stdio_modes[] = { L"rb", L"wb", L"r+b", L"rb", L"wb", L"r+b" };
#endif

static int64_t fseek_wrap(FILE *f, int64_t offset, int origin)
{
#ifdef ATLEAST_VC2005
   /* VC2005 and up have a special 64-bit fseek */
   return _fseeki64(f, offset, origin);
#elif defined(HAVE_64BIT_OFFSETS)
   return fseeko(f, (off_t)offset, origin);
#else
   return fseek(f, (long)offset, origin);
#endif
}

static int64_t ftell_wrap(FILE *f)
{
#ifdef ATLEAST_VC2005
   /* VC2005 and up have a special 64-bit ftell */
   return _ftelli64(f);
#elif defined(HAVE_64BIT_OFFSETS)
   return ftello(f);
#else
   return ftell(f);
#endif
}

static void *nbio_stdio_open(const char * filename, unsigned mode)
{
   void *buf                   = NULL;
   struct nbio_stdio_t* handle = NULL;
   int64_t len                 = 0;
#if !defined(_WIN32) || defined(LEGACY_WIN32)
   FILE* f                     = fopen(filename, stdio_modes[mode]);
#else
   wchar_t *filename_wide      = utf8_to_utf16_string_alloc(filename);
   FILE* f                     = _wfopen(filename_wide, stdio_modes[mode]);

   if (filename_wide)
      free(filename_wide);
#endif
   if (!f)
      return NULL;

   handle = (struct nbio_stdio_t*)malloc(sizeof(struct nbio_stdio_t));

   if (!handle)
   {
      fclose(f);
      return NULL;
   }

   handle-&gt;f = f;

   switch (mode)
   {
      case NBIO_WRITE:
      case BIO_WRITE:
         break;
      default:
         fseek_wrap(handle-&gt;f, 0, SEEK_END);
         len = ftell_wrap(handle-&gt;f);
         break;
   }

   handle-&gt;mode          = mode;

#if defined(WIIU)
   /* hit the aligned-buffer fast path on Wii U */
   if (len)
      buf                = memalign(0x40, (size_t)len);
#else
   if (len)
      buf                = malloc((size_t)len);
#endif

   if (len &amp;&amp; !buf)
   {
      free(handle);
      fclose(f);
      return NULL;
   }

   handle-&gt;data          = buf;
   handle-&gt;len           = len;
   handle-&gt;progress      = handle-&gt;len;
   handle-&gt;op            = -2;

   return handle;
}

static void nbio_stdio_begin_read(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   if (handle-&gt;op &gt;= 0)
      abort();

   fseek_wrap(handle-&gt;f, 0, SEEK_SET);

   handle-&gt;op       = NBIO_READ;
   handle-&gt;progress = 0;
}

static void nbio_stdio_begin_write(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   if (handle-&gt;op &gt;= 0)
      abort();

   fseek_wrap(handle-&gt;f, 0, SEEK_SET);
   handle-&gt;op = NBIO_WRITE;
   handle-&gt;progress = 0;
}

static bool nbio_stdio_iterate(void *data)
{
   size_t amount               = 65536;
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;

   if (!handle)
      return false;

   if (amount &gt; handle-&gt;len - handle-&gt;progress)
      amount = handle-&gt;len - handle-&gt;progress;

   switch (handle-&gt;op)
   {
      case NBIO_READ:
         if (handle-&gt;mode == BIO_READ)
         {
            amount = handle-&gt;len;
            fread((char*)handle-&gt;data, 1, amount, handle-&gt;f);
         }
         else
            fread((char*)handle-&gt;data + handle-&gt;progress, 1, amount, handle-&gt;f);
         break;
      case NBIO_WRITE:
         if (handle-&gt;mode == BIO_WRITE)
         {
            size_t written = 0;
            amount = handle-&gt;len;
            written = fwrite((char*)handle-&gt;data, 1, amount, handle-&gt;f);
            if (written != amount)
               return false;
         }
         else
            fwrite((char*)handle-&gt;data + handle-&gt;progress, 1, amount, handle-&gt;f);
         break;
   }

   handle-&gt;progress += amount;

   if (handle-&gt;progress == handle-&gt;len)
      handle-&gt;op = -1;
   return (handle-&gt;op &lt; 0);
}

static void nbio_stdio_resize(void *data, size_t len)
{
   void *new_data              = NULL;
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   if (handle-&gt;op &gt;= 0)
      abort();
   if (len &lt; handle-&gt;len)
      abort();

   handle-&gt;len      = len;
   handle-&gt;progress = len;
   handle-&gt;op       = -1;

   new_data         = realloc(handle-&gt;data, handle-&gt;len);

   if (new_data)
      handle-&gt;data  = new_data;
}

static void *nbio_stdio_get_ptr(void *data, size_t* len)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle-&gt;len;
   if (handle-&gt;op == -1)
      return handle-&gt;data;
   return NULL;
}

static void nbio_stdio_cancel(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;

   handle-&gt;op = -1;
   handle-&gt;progress = handle-&gt;len;
}

static void nbio_stdio_free(void *data)
{
   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
   if (!handle)
      return;
   if (handle-&gt;op &gt;= 0)
      abort();
   fclose(handle-&gt;f);
   free(handle-&gt;data);

   handle-&gt;f    = NULL;
   handle-&gt;data = NULL;
   free(handle);
}

nbio_intf_t nbio_stdio = {
   nbio_stdio_open,
   nbio_stdio_begin_read,
   nbio_stdio_begin_write,
   nbio_stdio_iterate,
   nbio_stdio_resize,
   nbio_stdio_get_ptr,
   nbio_stdio_cancel,
   nbio_stdio_free,
   "nbio_stdio",
};</pre>
<h2>./include/libretro-common/file/nbio/nbio_unixmmap.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_unixmmap.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include &lt;file/nbio.h&gt;

#if defined(HAVE_MMAP) &amp;&amp; defined(BSD)

#ifdef _WIN32
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt;
#endif
#include &lt;fcntl.h&gt;
#include &lt;sys/mman.h&gt;

#ifdef __APPLE__

#ifndef O_CLOEXEC
#define O_CLOEXEC 0x1000000
#endif

#else

#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif

#endif

struct nbio_mmap_unix_t
{
   void* ptr;
   size_t len;
   int fd;
   int map_flags;
};

static void *nbio_mmap_unix_open(const char * filename, unsigned mode)
{
   static const int o_flags[] =   { O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC, O_RDWR,               O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC };
   static const int map_flags[] = { PROT_READ, PROT_WRITE|PROT_READ,   PROT_WRITE|PROT_READ, PROT_READ, PROT_WRITE|PROT_READ   };

   size_t _len;
   void* ptr                       = NULL;
   struct nbio_mmap_unix_t* handle = NULL;
   int fd                          = open(filename, o_flags[mode]|O_CLOEXEC, 0644);
   if (fd &lt; 0)
      return NULL;

   _len = lseek(fd, 0, SEEK_END);
   if (_len != 0)
      ptr = mmap(NULL, _len, map_flags[mode], MAP_SHARED, fd, 0);

   if (ptr == MAP_FAILED)
   {
      close(fd);
      return NULL;
   }

   handle            = malloc(sizeof(struct nbio_mmap_unix_t));
   handle-&gt;fd        = fd;
   handle-&gt;map_flags = map_flags[mode];
   handle-&gt;len       = _len;
   handle-&gt;ptr       = ptr;
   return handle;
}

static void nbio_mmap_unix_begin_read(void *data)
{
   /* not needed */
}

static void nbio_mmap_unix_begin_write(void *data)
{
   /* not needed */
}

static bool nbio_mmap_unix_iterate(void *data)
{
   return true; /* not needed */
}

static void nbio_mmap_unix_resize(void *data, size_t len)
{
   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
   if (!handle)
      return;
   if (len &lt; handle-&gt;len)
   {
      /* this works perfectly fine if this check is removed, but it
       * won't work on other nbio implementations */
      /* therefore, it's blocked so nobody accidentally relies on it */
      abort();
   }

   if (ftruncate(handle-&gt;fd, len) != 0)
      abort(); /* this one returns void and I can't find any other
                  way for it to report failure */

   munmap(handle-&gt;ptr, handle-&gt;len);

   handle-&gt;ptr = mmap(NULL, len, handle-&gt;map_flags, MAP_SHARED, handle-&gt;fd, 0);
   handle-&gt;len = len;

   if (handle-&gt;ptr == MAP_FAILED)
      abort();
}

static void *nbio_mmap_unix_get_ptr(void *data, size_t *len)
{
   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle-&gt;len;
   return handle-&gt;ptr;
}

static void nbio_mmap_unix_cancel(void *data)
{
   /* not needed */
}

static void nbio_mmap_unix_free(void *data)
{
   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
   if (!handle)
      return;
   close(handle-&gt;fd);
   munmap(handle-&gt;ptr, handle-&gt;len);
   free(handle);
}

nbio_intf_t nbio_mmap_unix = {
   nbio_mmap_unix_open,
   nbio_mmap_unix_begin_read,
   nbio_mmap_unix_begin_write,
   nbio_mmap_unix_iterate,
   nbio_mmap_unix_resize,
   nbio_mmap_unix_get_ptr,
   nbio_mmap_unix_cancel,
   nbio_mmap_unix_free,
   "nbio_mmap_unix",
};
#else
nbio_intf_t nbio_mmap_unix = {
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   "nbio_mmap_unix",
};

#endif</pre>
<h2>./include/libretro-common/file/nbio/nbio_windowsmmap.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio_windowsmmap.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;file/nbio.h&gt;

#if defined(_WIN32)
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1500

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif

#elif !defined(_MSC_VER)

#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#endif

#endif

#if defined(HAVE_MMAP_WIN32)

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;encodings/utf.h&gt;

#include &lt;windows.h&gt;

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#ifndef FILE_SHARE_ALL
#define FILE_SHARE_ALL (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)
#endif

struct nbio_mmap_win32_t
{
   HANDLE file;
   void* ptr;
   size_t len;
   bool is_write;
};

static void *nbio_mmap_win32_open(const char * filename, unsigned mode)
{
   static const DWORD dispositions[] = { OPEN_EXISTING, CREATE_ALWAYS, OPEN_ALWAYS, OPEN_EXISTING, CREATE_ALWAYS };
   HANDLE mem;
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &gt;= 0x0500
   LARGE_INTEGER len;
#else
   SIZE_T len;
#endif
   struct nbio_mmap_win32_t* handle  = NULL;
   void* ptr                         = NULL;
   bool is_write                     = (mode == NBIO_WRITE || mode == NBIO_UPDATE || mode == BIO_WRITE);
   DWORD access                      = (is_write ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ);
#if !defined(_WIN32) || defined(LEGACY_WIN32)
   HANDLE file                       = CreateFile(filename, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
#else
   wchar_t *filename_wide            = utf8_to_utf16_string_alloc(filename);
#ifdef __WINRT__
   HANDLE file                       = CreateFile2(filename_wide, access, FILE_SHARE_ALL, dispositions[mode], NULL);
#else
   HANDLE file                       = CreateFileW(filename_wide, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
#endif

   if (filename_wide)
      free(filename_wide);
#endif

   if (file == INVALID_HANDLE_VALUE)
      return NULL;

#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &gt;= 0x0500
   /* GetFileSizeEx is new for Windows 2000 */
   GetFileSizeEx(file, &amp;len);
   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len.QuadPart);
#else
   GetFileSize(file, &amp;len);
   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
#endif

   CloseHandle(mem);

   handle           = (struct nbio_mmap_win32_t*)malloc(sizeof(struct nbio_mmap_win32_t));

   handle-&gt;file     = file;
   handle-&gt;is_write = is_write;
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &gt;= 0x0500
   handle-&gt;len      = len.QuadPart;
#else
   handle-&gt;len      = len;
#endif
   handle-&gt;ptr      = ptr;

   return handle;
}

static void nbio_mmap_win32_begin_read(void *data)
{
   /* not needed */
}

static void nbio_mmap_win32_begin_write(void *data)
{
   /* not needed */
}

static bool nbio_mmap_win32_iterate(void *data)
{
   /* not needed */
   return true;
}

static void nbio_mmap_win32_resize(void *data, size_t len)
{
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &gt;= 0x0500
   LARGE_INTEGER len_li;
#else
   SIZE_T len_li;
#endif
   HANDLE mem;
   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;

   if (!handle)
      return;

   if (len &lt; handle-&gt;len)
   {
      /* this works perfectly fine if this check is removed,
       * but it won't work on other nbio implementations */
      /* therefore, it's blocked so nobody accidentally
       * relies on it. */
      abort();
   }

#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &gt;= 0x0500
   /* SetFilePointerEx is new for Windows 2000 */
   len_li.QuadPart = len;
   SetFilePointerEx(handle-&gt;file, len_li, NULL, FILE_BEGIN);
#else
   len_li = len;
   SetFilePointer(handle-&gt;file, len_li, NULL, FILE_BEGIN);
#endif

   if (!SetEndOfFile(handle-&gt;file))
      abort(); /* this one returns void and I can't find any other way for it to report failure */
   handle-&gt;len = len;

   UnmapViewOfFile(handle-&gt;ptr);
   mem = CreateFileMapping(handle-&gt;file, NULL, handle-&gt;is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
   handle-&gt;ptr = MapViewOfFile(mem, handle-&gt;is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
   CloseHandle(mem);

   if (!handle-&gt;ptr)
      abort();
}

static void *nbio_mmap_win32_get_ptr(void *data, size_t* len)
{
   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;
   if (!handle)
      return NULL;
   if (len)
      *len = handle-&gt;len;
   return handle-&gt;ptr;
}

static void nbio_mmap_win32_cancel(void *data)
{
   /* not needed */
}

static void nbio_mmap_win32_free(void *data)
{
   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;
   if (!handle)
      return;
   CloseHandle(handle-&gt;file);
   UnmapViewOfFile(handle-&gt;ptr);
   free(handle);
}

nbio_intf_t nbio_mmap_win32 = {
   nbio_mmap_win32_open,
   nbio_mmap_win32_begin_read,
   nbio_mmap_win32_begin_write,
   nbio_mmap_win32_iterate,
   nbio_mmap_win32_resize,
   nbio_mmap_win32_get_ptr,
   nbio_mmap_win32_cancel,
   nbio_mmap_win32_free,
   "nbio_mmap_win32",
};
#else
nbio_intf_t nbio_mmap_win32 = {
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   "nbio_mmap_win32",
};

#endif</pre>
<h2>./include/libretro-common/file/retro_dirent.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_dirent.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_common.h&gt;

#include &lt;boolean.h&gt;
#include &lt;retro_dirent.h&gt;
#define VFS_FRONTEND
#include &lt;vfs/vfs_implementation.h&gt;

/* TODO/FIXME - static globals */
static retro_vfs_opendir_t dirent_opendir_cb                 = NULL;
static retro_vfs_readdir_t dirent_readdir_cb                 = NULL;
static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb     = NULL;
static retro_vfs_closedir_t dirent_closedir_cb               = NULL;

void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
   const struct retro_vfs_interface* vfs_iface;

   dirent_opendir_cb         = NULL;
   dirent_readdir_cb         = NULL;
   dirent_dirent_get_name_cb = NULL;
   dirent_dirent_is_dir_cb   = NULL;
   dirent_closedir_cb        = NULL;

   vfs_iface                 = vfs_info-&gt;iface;

   if (
         vfs_info-&gt;required_interface_version &lt; DIRENT_REQUIRED_VFS_VERSION || 
         !vfs_iface)
      return;

   dirent_opendir_cb         = vfs_iface-&gt;opendir;
   dirent_readdir_cb         = vfs_iface-&gt;readdir;
   dirent_dirent_get_name_cb = vfs_iface-&gt;dirent_get_name;
   dirent_dirent_is_dir_cb   = vfs_iface-&gt;dirent_is_dir;
   dirent_closedir_cb        = vfs_iface-&gt;closedir;
}

struct RDIR *retro_opendir_include_hidden(
      const char *name, bool include_hidden)
{
   if (dirent_opendir_cb)
      return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
   return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
}

struct RDIR *retro_opendir(const char *name)
{
   return retro_opendir_include_hidden(name, false);
}

bool retro_dirent_error(struct RDIR *rdir)
{
   /* Left for compatibility */
   return false;
}

int retro_readdir(struct RDIR *rdir)
{
   if (dirent_readdir_cb)
      return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
   return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
}

const char *retro_dirent_get_name(struct RDIR *rdir)
{
   if (dirent_dirent_get_name_cb)
      return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
   return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
}

/**
 *
 * retro_dirent_is_dir:
 * @rdir         : pointer to the directory entry.
 * @unused       : deprecated, included for compatibility reasons, pass NULL
 *
 * Is the directory listing entry a directory?
 *
 * Returns: true if directory listing entry is
 * a directory, false if not.
 */
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
{
   if (dirent_dirent_is_dir_cb)
      return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
   return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
}

void retro_closedir(struct RDIR *rdir)
{
   if (dirent_closedir_cb)
      dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
   else
      retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);
}</pre>
<h2>./include/libretro-common/formats/bmp/rbmp.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbmp.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Modified version of stb_image's BMP sources. */

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stddef.h&gt; /* ptrdiff_t on osx */
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_inline.h&gt;

#include &lt;formats/image.h&gt;
#include &lt;formats/rbmp.h&gt;

/* truncate int to byte without warnings */
#define RBMP_BYTECAST(x)  ((unsigned char) ((x) &amp; 255))

#define RBMP_COMPUTE_Y(r, g, b) ((unsigned char) ((((r) * 77) + ((g) * 150) +  (29 * (b))) &gt;&gt; 8))

typedef struct
{
   unsigned char *img_buffer;
   unsigned char *img_buffer_end;
   unsigned char *img_buffer_original;
   int img_n;
   int img_out_n;
   int buflen;
   uint32_t img_x;
   uint32_t img_y;
   unsigned char buffer_start[128];
} rbmp_context;

struct rbmp
{
   uint8_t *buff_data;
   uint32_t *output_image;
};

static INLINE unsigned char rbmp_get8(rbmp_context *s)
{
   if (s-&gt;img_buffer &lt; s-&gt;img_buffer_end)
      return *s-&gt;img_buffer++;

   return 0;
}

static void rbmp_skip(rbmp_context *s, int n)
{
   if (n &lt; 0)
   {
      s-&gt;img_buffer = s-&gt;img_buffer_end;
      return;
   }

   s-&gt;img_buffer += n;
}

static int rbmp_get16le(rbmp_context *s)
{
   return rbmp_get8(s) + (rbmp_get8(s) &lt;&lt; 8);
}

#define RBMP_GET32LE(s) (rbmp_get16le(s) + (rbmp_get16le(s) &lt;&lt; 16))

static unsigned char *rbmp_convert_format(
      unsigned char *data,
      int img_n,
      int req_comp,
      unsigned int x,
      unsigned int y)
{
   int i,j;
   unsigned char *good = (unsigned char *)malloc(req_comp * x * y);

   if (!good)
      return NULL;

   for (j=0; j &lt; (int) y; ++j)
   {
      unsigned char *src  = data + j * x * img_n   ;
      unsigned char *dest = good + j * x * req_comp;

      switch (((img_n)*8+(req_comp)))
      {
         case 10:
            for (i = x-1; i &gt;= 0; --i, src += 1, dest += 2)
            {
               dest[0]=src[0];
               dest[1]=255;
            }
            break;
         case 11:
            for (i = x-1; i &gt;= 0; --i, src += 1, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case 12:
            for (i = x-1; i &gt;= 0; --i, src += 1, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=255;
            }
            break;
         case 17:
            for (i = x-1; i &gt;= 0; --i, src += 2, dest += 1)
               dest[0]=src[0];
            break;
         case 19:
            for (i = x-1; i &gt;= 0; --i, src += 2, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case 20:
            for (i = x-1; i &gt;= 0; --i, src += 2, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=src[1];
            }
            break;
         case 28:
            for (i = x-1; i &gt;= 0; --i, src += 3, dest += 4)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
               dest[3]=255;
            }
            break;
         case 25:
            for (i = x-1; i &gt;= 0; --i, src += 3, dest += 1)
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case 26:
            for (i = x-1; i &gt;= 0; --i, src += 3, dest += 2)
            {
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = 255;
            }
            break;
         case 33:
            for (i = x-1; i &gt;= 0; --i, src += 4, dest += 1)
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case 34:
            for (i = x-1; i &gt;= 0; --i, src += 4, dest += 2)
            {
               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = src[3];
            }
            break;
         case 35:
            for (i = x-1; i &gt;= 0; --i, src += 4, dest += 3)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
            }
            break;
         default:
            break;
      }

   }

   return good;
}

/* Microsoft/Windows BMP image */

/* returns 0..31 for the highest set bit */
static int rbmp_high_bit(unsigned int z)
{
   int n=0;
   if (z == 0)
      return -1;

   if (z &gt;= 0x10000)
   {
      n  += 16;
      z &gt;&gt;= 16;
   }
   if (z &gt;= 0x00100)
   {
      n  +=  8;
      z &gt;&gt;=  8;
   }
   if (z &gt;= 0x00010)
   {
      n  +=  4;
      z &gt;&gt;=  4;
   }
   if (z &gt;= 0x00004)
   {
      n  +=  2;
      z &gt;&gt;=  2;
   }
   if (z &gt;= 0x00002)
      n +=  1;
   return n;
}

static int rbmp_bitcount(unsigned int a)
{
   a = (a &amp; 0x55555555) + ((a &gt;&gt;  1) &amp; 0x55555555); /* max 2 */
   a = (a &amp; 0x33333333) + ((a &gt;&gt;  2) &amp; 0x33333333); /* max 4 */
   a = (a + (a &gt;&gt; 4)) &amp; 0x0f0f0f0f; /* max 8 per 4, now 8 bits */
   a = (a + (a &gt;&gt; 8));              /* max 16 per 8 bits */
   a = (a + (a &gt;&gt; 16));             /* max 32 per 8 bits */
   return a &amp; 0xff;
}

static int rbmp_shiftsigned(int v, int shift, int bits)
{
   int ret;
   int z = bits;

   if (shift &lt; 0)
      v &lt;&lt;= -shift;
   else
      v &gt;&gt;= shift;

   ret = v;

   while (z &lt; 8)
   {
      ret += v &gt;&gt; z;
      z   += bits;
   }
   return ret;
}

static unsigned char *rbmp_bmp_load(rbmp_context *s, unsigned *x, unsigned *y,
      int *comp, int req_comp)
{
   unsigned char *out;
   int bpp, flip_vertically, pad, target, offset, hsz;
   int psize=0,i,j,width;
   unsigned int mr=0,mg=0,mb=0,ma=0;

   /* Corrupt BMP? */
   if (rbmp_get8(s) != 'B' || rbmp_get8(s) != 'M')
      return 0;

   /* discard filesize */
   rbmp_get16le(s);
   rbmp_get16le(s);
   /* discard reserved */
   rbmp_get16le(s);
   rbmp_get16le(s);

   offset = (uint32_t)RBMP_GET32LE(s);
   hsz    = (uint32_t)RBMP_GET32LE(s);

   /* BMP type not supported? */
   if (hsz != 12 &amp;&amp; hsz != 40 &amp;&amp; hsz != 56 &amp;&amp; hsz != 108 &amp;&amp; hsz != 124)
      return 0;

   if (hsz == 12)
   {
      s-&gt;img_x = rbmp_get16le(s);
      s-&gt;img_y = rbmp_get16le(s);
   }
   else
   {
      s-&gt;img_x = (uint32_t)RBMP_GET32LE(s);
      s-&gt;img_y = (uint32_t)RBMP_GET32LE(s);
   }

   /* Bad BMP? */
   if (rbmp_get16le(s) != 1)
      return 0;

   bpp = rbmp_get16le(s);

   /* BMP 1-bit type not supported? */
   if (bpp == 1)
      return 0;

   flip_vertically = ((int) s-&gt;img_y) &gt; 0;
   s-&gt;img_y        = abs((int) s-&gt;img_y);

   if (hsz == 12)
   {
      if (bpp &lt; 24)
         psize = (offset - 14 - 24) / 3;
   }
   else
   {
      int compress = (uint32_t)RBMP_GET32LE(s);

      /* BMP RLE type not supported? */
      if (compress == 1 || compress == 2)
         return 0;

      /* discard sizeof */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard hres */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard vres */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard colors used */
      rbmp_get16le(s);
      rbmp_get16le(s);
      /* discard max important */
      rbmp_get16le(s);
      rbmp_get16le(s);

      if (hsz == 40 || hsz == 56)
      {
         if (hsz == 56)
         {
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
            rbmp_get16le(s);
         }
         if (bpp == 16 || bpp == 32)
         {
            switch (compress)
            {
               case 0:
                  break;
               case 3:
                  mr = (uint32_t)RBMP_GET32LE(s);
                  mg = (uint32_t)RBMP_GET32LE(s);
                  mb = (uint32_t)RBMP_GET32LE(s);
                  /* not documented, but generated by
                   * Photoshop and handled by MS Paint */
                  /* Bad BMP ?*/
                  if (mr == mg &amp;&amp; mg == mb)
                     return 0;
                  break;
               default:
                  break;
            }

            /* Bad BMP? */
            return 0;
         }
      }
      else
      {
         mr = (uint32_t)RBMP_GET32LE(s);
         mg = (uint32_t)RBMP_GET32LE(s);
         mb = (uint32_t)RBMP_GET32LE(s);
         ma = (uint32_t)RBMP_GET32LE(s);
         /* Discard color space */
         rbmp_get16le(s);
         rbmp_get16le(s);
         for (i = 0; i &lt; 12; ++i)
         {
            /* Discard color space parameters */
            rbmp_get16le(s);
            rbmp_get16le(s);
         }
         if (hsz == 124)
         {
            /* Discard rendering intent */
            rbmp_get16le(s);
            rbmp_get16le(s);
            /* Discard offset of profile data */
            rbmp_get16le(s);
            rbmp_get16le(s);
            /* Discard size of profile data */
            rbmp_get16le(s);
            rbmp_get16le(s);
            /* Discard reserved */
            rbmp_get16le(s);
            rbmp_get16le(s);
         }
      }
      if (bpp &lt; 16)
         psize = (offset - 14 - hsz) &gt;&gt; 2;
   }
   s-&gt;img_n = ma ? 4 : 3;
   if (req_comp &amp;&amp; req_comp &gt;= 3) /* We can directly decode 3 or 4 */
      target = req_comp;
   else
      target = s-&gt;img_n; /* If they want monochrome, we'll post-convert */

   out = (unsigned char *) malloc(target * s-&gt;img_x * s-&gt;img_y);

   if (!out)
      return 0;

   if (bpp &lt; 16)
   {
      unsigned char pal[256][4];
      int z=0;

      /* Corrupt BMP? */
      if (psize == 0 || psize &gt; 256)
      {
         free(out);
         return 0;
      }

      for (i = 0; i &lt; psize; ++i)
      {
         pal[i][2] = rbmp_get8(s);
         pal[i][1] = rbmp_get8(s);
         pal[i][0] = rbmp_get8(s);
         if (hsz != 12)
            rbmp_get8(s);
         pal[i][3] = 255;
      }

      rbmp_skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
      if (bpp == 4)
         width = (s-&gt;img_x + 1) &gt;&gt; 1;
      else if (bpp == 8)
         width = s-&gt;img_x;
      else
      {
         /* Corrupt BMP */
         free(out);
         return 0;
      }

      pad = (-width)&amp;3;
      for (j=0; j &lt; (int) s-&gt;img_y; ++j)
      {
         for (i = 0; i &lt; (int) s-&gt;img_x; i += 2)
         {
            int v  = rbmp_get8(s);
            int v2 = 0;
            if (bpp == 4)
            {
               v2  = v &amp; 15;
               v &gt;&gt;= 4;
            }
            out[z++] = pal[v][0];
            out[z++] = pal[v][1];
            out[z++] = pal[v][2];
            if (target == 4)
               out[z++] = 255;

            if (i+1 == (int)s-&gt;img_x)
               break;

            v        = (bpp == 8) ? rbmp_get8(s) : v2;
            out[z++] = pal[v][0];
            out[z++] = pal[v][1];
            out[z++] = pal[v][2];

            if (target == 4)
               out[z++] = 255;
         }
         rbmp_skip(s, pad);
      }
   }
   else
   {
      int rshift = 0;
      int gshift = 0;
      int bshift = 0;
      int ashift = 0;
      int rcount = 0;
      int gcount = 0;
      int bcount = 0;
      int acount = 0;
      int z      = 0;
      int easy   = 0;

      rbmp_skip(s, offset - 14 - hsz);

      if (bpp == 24)
         width = 3 * s-&gt;img_x;
      else if (bpp == 16)
         width = 2*s-&gt;img_x;
      else /* bpp = 32 and pad = 0 */
         width=0;

      pad = (-width) &amp; 3;

      switch (bpp)
      {
         case 24:
            easy = 1;
            break;
         case 32:
            if (mb == 0xff &amp;&amp; mg == 0xff00 &amp;&amp; mr == 0x00ff0000 &amp;&amp; ma == 0xff000000)
               easy = 2;
            break;
         default:
            break;
      }

      if (!easy)
      {
         /* Corrupt BMP? */
         if (!mr || !mg || !mb)
         {
            free(out);
            return 0;
         }

         /* right shift amt to put high bit in position #7 */
         rshift = rbmp_high_bit(mr)-7;
         rcount = rbmp_bitcount(mr);
         gshift = rbmp_high_bit(mg)-7;
         gcount = rbmp_bitcount(mg);
         bshift = rbmp_high_bit(mb)-7;
         bcount = rbmp_bitcount(mb);
         ashift = rbmp_high_bit(ma)-7;
         acount = rbmp_bitcount(ma);
      }

      for (j=0; j &lt; (int) s-&gt;img_y; ++j)
      {
         if (easy)
         {
            if (target == 4)
            {
               /* Need to apply alpha channel as well */
               if (easy == 2)
               {
                  for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                  {
                     out[z+2]        = rbmp_get8(s);
                     out[z+1]        = rbmp_get8(s);
                     out[z+0]        = rbmp_get8(s);
                     z              += 3;
                     out[z++]        = rbmp_get8(s);
                  }
               }
               else
               {
                  for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                  {
                     out[z+2]        = rbmp_get8(s);
                     out[z+1]        = rbmp_get8(s);
                     out[z+0]        = rbmp_get8(s);
                     z              += 3;
                     out[z++]        = 255;
                  }
               }
            }
            else
            {
               for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
               {
                  out[z+2]        = rbmp_get8(s);
                  out[z+1]        = rbmp_get8(s);
                  out[z+0]        = rbmp_get8(s);
                  z              += 3;
               }
            }
         }
         else
         {
            if (target == 4)
            {
               /* Need to apply alpha channel as well */
               if (ma)
               {
                  if (bpp == 16)
                  {
                     for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)rbmp_get16le(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; ma, ashift, acount));
                     }
                  }
                  else
                  {
                     for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)RBMP_GET32LE(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; ma, ashift, acount));
                     }
                  }
               }
               else
               {
                  if (bpp == 16)
                  {
                     for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)rbmp_get16le(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(255);
                     }
                  }
                  else
                  {
                     for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                     {
                        uint32_t v  = (uint32_t)RBMP_GET32LE(s);
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mr, rshift, rcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mg, gshift, gcount));
                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mb, bshift, bcount));
                        out[z++]    = RBMP_BYTECAST(255);
                     }
                  }
               }
            }
            else
            {
               if (bpp == 16)
               {
                  for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                  {
                     uint32_t v  = (uint32_t)rbmp_get16le(s);
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mr, rshift, rcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mg, gshift, gcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mb, bshift, bcount));
                  }
               }
               else
               {
                  for (i = 0; i &lt; (int) s-&gt;img_x; ++i)
                  {
                     uint32_t v  = (uint32_t)RBMP_GET32LE(s);
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mr, rshift, rcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mg, gshift, gcount));
                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v &amp; mb, bshift, bcount));
                  }
               }
            }
         }
         rbmp_skip(s, pad);
      }
   }

   if (flip_vertically)
   {
      unsigned char t;
      for (j=0; j &lt; (int) s-&gt;img_y&gt;&gt;1; ++j)
      {
         unsigned char *p1 = out +      j     *s-&gt;img_x*target;
         unsigned char *p2 = out + (s-&gt;img_y-1-j)*s-&gt;img_x*target;
         for (i = 0; i &lt; (int) s-&gt;img_x*target; ++i)
         {
            t     = p1[i];
            p1[i] = p2[i];
            p2[i] = t;
         }
      }
   }

   if (
            req_comp
         &amp;&amp; (req_comp &gt;= 1 &amp;&amp; req_comp &lt;= 4)
         &amp;&amp; (req_comp != target))
   {
      unsigned char *tmp = rbmp_convert_format(out, target, req_comp, s-&gt;img_x, s-&gt;img_y);

      free(out);
      out = NULL;

      if (!tmp)
         return NULL;

      out = tmp;
   }

   *x = s-&gt;img_x;
   *y = s-&gt;img_y;

   if (comp)
      *comp = s-&gt;img_n;

   return out;
}

static unsigned char *rbmp_load_from_memory(unsigned char const *buffer, int len,
      unsigned *x, unsigned *y, int *comp, int req_comp)
{
   rbmp_context s;

   s.img_buffer          = (unsigned char*)buffer;
   s.img_buffer_original = (unsigned char*)buffer;
   s.img_buffer_end      = (unsigned char*)buffer+len;

   return rbmp_bmp_load(&amp;s,x,y,comp,req_comp);
}

static void rbmp_convert_frame(uint32_t *frame, unsigned width, unsigned height)
{
   uint32_t *end = frame + (width * height * sizeof(uint32_t))/4;

   while (frame &lt; end)
   {
      uint32_t pixel = *frame;
      *frame = (pixel &amp; 0xff00ff00) | ((pixel &lt;&lt; 16) &amp; 0x00ff0000) | ((pixel &gt;&gt; 16) &amp; 0xff);
      frame++;
   }
}

int rbmp_process_image(rbmp_t *rbmp, void **buf_data,
      size_t size, unsigned *width, unsigned *height)
{
   int comp;

   if (!rbmp)
      return IMAGE_PROCESS_ERROR;

   rbmp-&gt;output_image   = (uint32_t*)rbmp_load_from_memory(rbmp-&gt;buff_data,
                           (int)size, width, height, &amp;comp, 4);
   *buf_data             = rbmp-&gt;output_image;

   rbmp_convert_frame(rbmp-&gt;output_image, *width, *height);

   return IMAGE_PROCESS_END;
}

bool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data)
{
   if (!rbmp)
      return false;

   rbmp-&gt;buff_data = (uint8_t*)data;

   return true;
}

void rbmp_free(rbmp_t *rbmp)
{
   if (!rbmp)
      return;

   free(rbmp);
}

rbmp_t *rbmp_alloc(void)
{
   rbmp_t *rbmp = (rbmp_t*)calloc(1, sizeof(*rbmp));
   if (!rbmp)
      return NULL;
   return rbmp;
}</pre>
<h2>./include/libretro-common/formats/bmp/rbmp_encode.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbmp_encode.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;streams/file_stream.h&gt;
#include &lt;formats/rbmp.h&gt;

void form_bmp_header(uint8_t *header,
      unsigned width, unsigned height,
      bool is32bpp)
{
   unsigned line_size  = (width * (is32bpp?4:3) + 3) &amp; ~3;
   unsigned size       = line_size * height + 54;
   unsigned size_array = line_size * height;

   /* Generic BMP stuff. */
   /* signature */
   header[0] = 'B';
   header[1] = 'M';
   /* file size */
   header[2] = (uint8_t)(size &gt;&gt; 0);
   header[3] = (uint8_t)(size &gt;&gt; 8);
   header[4] = (uint8_t)(size &gt;&gt; 16);
   header[5] = (uint8_t)(size &gt;&gt; 24);
   /* reserved */
   header[6] = 0;
   header[7] = 0;
   header[8] = 0;
   header[9] = 0;
   /* offset */
   header[10] = 54;
   header[11] = 0;
   header[12] = 0;
   header[13] = 0;
   /* DIB size */
   header[14] = 40;
   header[15] = 0;
   header[16] = 0;
   header[17] = 0;
   /* Width */
   header[18] = (uint8_t)(width &gt;&gt; 0);
   header[19] = (uint8_t)(width &gt;&gt; 8);
   header[20] = (uint8_t)(width &gt;&gt; 16);
   header[21] = (uint8_t)(width &gt;&gt; 24);
   /* Height */
   header[22] = (uint8_t)(height &gt;&gt; 0);
   header[23] = (uint8_t)(height &gt;&gt; 8);
   header[24] = (uint8_t)(height &gt;&gt; 16);
   header[25] = (uint8_t)(height &gt;&gt; 24);
   /* Color planes */
   header[26] = 1;
   header[27] = 0;
   /* Bits per pixel */
   header[28] = is32bpp ? 32 : 24;
   header[29] = 0;
   /* Compression method */
   header[30] = 0;
   header[31] = 0;
   header[32] = 0;
   header[33] = 0;
   /* Image data size */
   header[34] = (uint8_t)(size_array &gt;&gt; 0);
   header[35] = (uint8_t)(size_array &gt;&gt; 8);
   header[36] = (uint8_t)(size_array &gt;&gt; 16);
   header[37] = (uint8_t)(size_array &gt;&gt; 24);
   /* Horizontal resolution */
   header[38] = 19;
   header[39] = 11;
   header[40] = 0;
   header[41] = 0;
   /* Vertical resolution */
   header[42] = 19;
   header[43] = 11;
   header[44] = 0;
   header[45] = 0;
   /* Palette size */
   header[46] = 0;
   header[47] = 0;
   header[48] = 0;
   header[49] = 0;
   /* Important color count */
   header[50] = 0;
   header[51] = 0;
   header[52] = 0;
   header[53] = 0;
}

static bool write_header_bmp(RFILE *file, unsigned width, unsigned height, bool is32bpp)
{
   uint8_t header[54];
   form_bmp_header(header, width, height, is32bpp);
   return filestream_write(file, header, sizeof(header)) == sizeof(header);
}

static void dump_line_565_to_24(uint8_t *line, const uint16_t *src, unsigned width)
{
   unsigned i;

   for (i = 0; i &lt; width; i++)
   {
      uint16_t pixel = *src++;
      uint8_t b = (pixel &gt;&gt;  0) &amp; 0x1f;
      uint8_t g = (pixel &gt;&gt;  5) &amp; 0x3f;
      uint8_t r = (pixel &gt;&gt; 11) &amp; 0x1f;
      *line++   = (b &lt;&lt; 3) | (b &gt;&gt; 2);
      *line++   = (g &lt;&lt; 2) | (g &gt;&gt; 4);
      *line++   = (r &lt;&lt; 3) | (r &gt;&gt; 2);
   }
}

static void dump_line_32_to_24(uint8_t *line, const uint32_t *src, unsigned width)
{
   unsigned i;

   for (i = 0; i &lt; width; i++)
   {
      uint32_t pixel = *src++;
      *line++ = (pixel &gt;&gt;  0) &amp; 0xff;
      *line++ = (pixel &gt;&gt;  8) &amp; 0xff;
      *line++ = (pixel &gt;&gt; 16) &amp; 0xff;
   }
}

static void dump_content(RFILE *file, const void *frame,
      int width, int height, int pitch, enum rbmp_source_type type)
{
   int j;
   size_t line_size;
   uint8_t *line       = NULL;
   int bytes_per_pixel = (type==RBMP_SOURCE_TYPE_ARGB8888?4:3);
   union
   {
      const uint8_t *u8;
      const uint16_t *u16;
      const uint32_t *u32;
   } u;

   u.u8      = (const uint8_t*)frame;
   line_size = (width * bytes_per_pixel + 3) &amp; ~3;

   switch (type)
   {
      case RBMP_SOURCE_TYPE_BGR24:
         {
            /* BGR24 byte order input matches output. Can directly copy, but... need to make sure we pad it. */
            uint32_t zeros = 0;
            int padding    = (int)(line_size-pitch);
            for (j = 0; j &lt; height; j++, u.u8 += pitch)
            {
               filestream_write(file, u.u8, pitch);
               if (padding != 0)
                  filestream_write(file, &amp;zeros, padding);
            }
         }
         break;
      case RBMP_SOURCE_TYPE_ARGB8888:
         /* ARGB8888 byte order input matches output. Can directly copy. */
         for (j = 0; j &lt; height; j++, u.u8 += pitch)
            filestream_write(file, u.u8, line_size);
         return;
      default:
         break;
   }

   /* allocate line buffer, and initialize the final four bytes to zero, for deterministic padding */
   if (!(line = (uint8_t*)malloc(line_size)))
      return;
   *(uint32_t*)(line + line_size - 4) = 0;

   switch (type)
   {
      case RBMP_SOURCE_TYPE_XRGB888:
         for (j = 0; j &lt; height; j++, u.u8 += pitch)
         {
            dump_line_32_to_24(line, u.u32, width);
            filestream_write(file, line, line_size);
         }
         break;
      case RBMP_SOURCE_TYPE_RGB565:
         for (j = 0; j &lt; height; j++, u.u8 += pitch)
         {
            dump_line_565_to_24(line, u.u16, width);
            filestream_write(file, line, line_size);
         }
         break;
      default:
         break;
   }

   /* Free allocated line buffer */
   free(line);
}

bool rbmp_save_image(
      const char *filename,
      const void *frame,
      unsigned width, unsigned height,
      unsigned pitch, enum rbmp_source_type type)
{
   bool ret    = false;
   RFILE *file = filestream_open(filename,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!file)
      return false;

   ret = write_header_bmp(file, width, height, type==RBMP_SOURCE_TYPE_ARGB8888);

   if (ret)
      dump_content(file, frame, width, height, pitch, type);

   filestream_close(file);

   return ret;
}</pre>
<h2>./include/libretro-common/formats/cdfs/cdfs.c</h2>
<pre>#include &lt;formats/cdfs.h&gt;

#include &lt;retro_miscellaneous.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;string/stdstring.h&gt;

#ifdef HAVE_CHD
#include &lt;streams/chd_stream.h&gt;
#endif

static void cdfs_determine_sector_size(cdfs_track_t* track)
{
   uint8_t buffer[32];
   const int toc_sector = 16;

   /* MODE information is normally found in the CUE sheet, but we can try to determine it from the raw data.
    *
    *   MODE1/2048 - CDROM Mode1 Data (cooked) [no header, no footer]
    *   MODE1/2352 - CDROM Mode1 Data (raw)    [16 byte header, 288 byte footer]
    *   MODE2/2336 - CDROM-XA Mode2 Data       [8 byte header, 280 byte footer]
    *   MODE2/2352 - CDROM-XA Mode2 Data       [24 byte header, 280 byte footer]
    *
    * Note that MODE is actually a property on each sector and can change between 1 and 2 depending on how much error
    * correction the author desired. To support that, the data format must be "/2352" to include the full header and
    * data without error correction information, at which point the CUE sheet information becomes just a hint.
    */

   /* The boot record or primary volume descriptor is always at sector 16 and will contain a "CD001" marker */
   intfstream_seek(track-&gt;stream, toc_sector * 2352 + track-&gt;first_sector_offset, SEEK_SET);
   if (intfstream_read(track-&gt;stream, &amp;buffer, sizeof(buffer)) != (int64_t)sizeof(buffer))
      return;

   /* if this is a CDROM-XA data source, the "CD001" tag will be 25 bytes into the sector */
   if (  buffer[25] == 0x43
      &amp;&amp; buffer[26] == 0x44
      &amp;&amp; buffer[27] == 0x30
      &amp;&amp; buffer[28] == 0x30
      &amp;&amp; buffer[29] == 0x31)
   {
      track-&gt;stream_sector_size        = 2352;
      track-&gt;stream_sector_header_size = 24;
   }
   /* otherwise it should be 17 bytes into the sector */
   else if (buffer[17] == 0x43
      &amp;&amp;    buffer[18] == 0x44
      &amp;&amp;    buffer[19] == 0x30
      &amp;&amp;    buffer[20] == 0x30
      &amp;&amp;    buffer[21] == 0x31)
   {
      track-&gt;stream_sector_size = 2352;
      track-&gt;stream_sector_header_size = 16;
   }
   else
   {
      /* ISO-9660 says the first twelve bytes of a sector should be the sync pattern 00 FF FF FF FF FF FF FF FF FF FF 00 */
      if (
            buffer[ 0] == 0
         &amp;&amp; buffer[ 1] == 0xFF
         &amp;&amp; buffer[ 2] == 0xFF
         &amp;&amp; buffer[ 3] == 0xFF
         &amp;&amp; buffer[ 4] == 0xFF
         &amp;&amp; buffer[ 5] == 0xFF
         &amp;&amp; buffer[ 6] == 0xFF
         &amp;&amp; buffer[ 7] == 0xFF
         &amp;&amp; buffer[ 8] == 0xFF
         &amp;&amp; buffer[ 9] == 0xFF
         &amp;&amp; buffer[10] == 0xFF
         &amp;&amp; buffer[11] == 0)
      {
         /* if we didn't find a CD001 tag, this format may predate ISO-9660 */

         /* after the 12 byte sync pattern is three bytes identifying the sector and then one byte for the mode (total 16 bytes) */
         track-&gt;stream_sector_size        = 2352;
         track-&gt;stream_sector_header_size = 16;
      }
   }
}

static void cdfs_determine_sector_size_from_file_size(cdfs_track_t* track)
{
   /* attempt to determine stream_sector_size from file size */
   size_t _len = intfstream_get_size(track-&gt;stream);

   if ((_len % 2352) == 0)
   {
      /* raw tracks use all 2352 bytes and have a 24 byte header */
      track-&gt;stream_sector_size        = 2352;
      track-&gt;stream_sector_header_size = 24;
   }
   else if ((_len % 2048) == 0)
   {
      /* cooked tracks eliminate all header/footer data */
      track-&gt;stream_sector_size        = 2048;
      track-&gt;stream_sector_header_size = 0;
   }
   else if ((_len % 2336) == 0)
   {
      /* MODE 2 format without 16-byte sync data */
      track-&gt;stream_sector_size        = 2336;
      track-&gt;stream_sector_header_size = 8;
   }
}

static void cdfs_seek_track_sector(cdfs_track_t* track, unsigned int sector)
{
   intfstream_seek(track-&gt;stream,
           sector * track-&gt;stream_sector_size
         + track-&gt;stream_sector_header_size
         + track-&gt;first_sector_offset, SEEK_SET);
}

void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector)
{
   /* only allowed if open_file was called with a NULL path */
   if (file-&gt;first_sector == 0)
   {
      if (file-&gt;current_sector != (int)sector)
      {
         file-&gt;current_sector      = (int)sector;
         file-&gt;sector_buffer_valid = 0;
      }

      file-&gt;pos                    = sector * 2048;
      file-&gt;current_sector_offset  = 0;
   }
}

uint32_t cdfs_get_num_sectors(cdfs_file_t* file)
{
   uint32_t frame_size = intfstream_get_frame_size(file-&gt;track-&gt;stream);
   if (frame_size == 0)
   {
      frame_size = file-&gt;track-&gt;stream_sector_size;
      if (frame_size == 0)
         frame_size = 1; /* prevent divide by 0 error if sector size is unknown */
   }
   return (uint32_t)(intfstream_get_size(file-&gt;track-&gt;stream) / frame_size);
}

uint32_t cdfs_get_first_sector(cdfs_file_t* file)
{
   return file-&gt;track-&gt;first_sector_index;
}

static int cdfs_find_file(cdfs_file_t* file, const char* path)
{
   size_t path_length;
   int sector;
   uint8_t buffer[2048], *tmp;
   const char* slash = strrchr(path, '\\');

   if (slash)
   {
      /* navigate the path to the directory record for the file */
      const int dir_length = (int)(slash - path);
      memcpy(buffer, path, dir_length);
      buffer[dir_length] = '\0';

      sector = cdfs_find_file(file, (const char*)buffer);
      if (sector &lt; 0)
         return sector;

      path += dir_length + 1;
   }
   else
   {
      int offset;

      /* find the CD information (always 16 frames in) */
      cdfs_seek_track_sector(file-&gt;track, 16);
      intfstream_read(file-&gt;track-&gt;stream, buffer, sizeof(buffer));

      /* the directory_record starts at 156 bytes into the sector.
       * the sector containing the root directory contents is a
       * 3 byte value that is 2 bytes into the directory_record. */
      offset = 156 + 2;
      sector = buffer[offset] | (buffer[offset + 1] &lt;&lt; 8) | (buffer[offset + 2] &lt;&lt; 16);
   }

   /* process the contents of the directory */
   cdfs_seek_track_sector(file-&gt;track, sector);
   intfstream_read(file-&gt;track-&gt;stream, buffer, sizeof(buffer));

   path_length = strlen(path);
   tmp         = buffer;

   while (tmp &lt; buffer + sizeof(buffer))
   {
      /* The first byte of the record is the length of
       * the record - if 0, we reached the end of the data */
      if (!*tmp)
         break;

      /* filename is 33 bytes into the record and
       * the format is "FILENAME;version" or "DIRECTORY" */
      if (        (tmp[33 + path_length] == ';'
               || (tmp[33 + path_length] == '\0'))
               &amp;&amp;  strncasecmp((const char*)(tmp + 33), path, path_length) == 0)
      {
         /* the file size is in bytes 10-13 of the record */
         file-&gt;size =
              (tmp[10])
            | (tmp[11] &lt;&lt; 8)
            | (tmp[12] &lt;&lt; 16)
            | (tmp[13] &lt;&lt; 24);

         /* the file contents are in the sector identified
          * in bytes 2-4 of the record */
         sector = tmp[2] | (tmp[3] &lt;&lt; 8) | (tmp[4] &lt;&lt; 16);
         return sector;
      }

      /* the first byte of the record is the length of the record */
      tmp += tmp[0];
   }

   return -1;
}

int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* track, const char* path)
{
   if (!file || !track)
      return 0;

   memset(file, 0, sizeof(*file));

   file-&gt;track          = track;
   file-&gt;current_sector = -1;
   file-&gt;first_sector   = -1;

   if (path)
      file-&gt;first_sector = cdfs_find_file(file, path);
   else if (file-&gt;track-&gt;stream_sector_size)
   {
      file-&gt;first_sector = 0;
      file-&gt;size         = (unsigned int)((intfstream_get_size(
               file-&gt;track-&gt;stream) / file-&gt;track-&gt;stream_sector_size)
         * 2048);
      return 1;
   }

   return (file-&gt;first_sector &gt;= 0);
}

int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
{
   int bytes_read = 0;

   if (!file || file-&gt;first_sector &lt; 0 || !buffer)
      return 0;

   if (len &gt; file-&gt;size - file-&gt;pos)
      len = file-&gt;size - file-&gt;pos;

   if (len == 0)
      return 0;

   if (file-&gt;sector_buffer_valid)
   {
      size_t remaining = 2048 - file-&gt;current_sector_offset;
      if (remaining &gt; 0)
      {
         if (remaining &gt;= len)
         {
            memcpy(buffer,
                  &amp;file-&gt;sector_buffer[file-&gt;current_sector_offset],
                  (size_t)len);
            file-&gt;current_sector_offset += len;
            return len;
         }

         memcpy(buffer,
               &amp;file-&gt;sector_buffer[file-&gt;current_sector_offset], remaining);
         buffer      = (char*)buffer + remaining;
         bytes_read += remaining;
         len        -= remaining;

         file-&gt;current_sector_offset += remaining;
      }

      ++file-&gt;current_sector;
      file-&gt;current_sector_offset = 0;
      file-&gt;sector_buffer_valid   = 0;
   }
   else if (file-&gt;current_sector &lt; file-&gt;first_sector)
   {
      file-&gt;current_sector        = file-&gt;first_sector;
      file-&gt;current_sector_offset = 0;
   }

   while (len &gt;= 2048)
   {
      cdfs_seek_track_sector(file-&gt;track, file-&gt;current_sector);
      intfstream_read(file-&gt;track-&gt;stream, buffer, 2048);

      buffer      = (char*)buffer + 2048;
      bytes_read += 2048;

      ++file-&gt;current_sector;

      len        -= 2048;
   }

   if (len &gt; 0)
   {
      cdfs_seek_track_sector(file-&gt;track, file-&gt;current_sector);
      intfstream_read(file-&gt;track-&gt;stream, file-&gt;sector_buffer, 2048);
      memcpy(buffer, file-&gt;sector_buffer, (size_t)len);
      file-&gt;current_sector_offset = (unsigned int)len;
      file-&gt;sector_buffer_valid   = 1;

      bytes_read += len;
   }

   file-&gt;pos += bytes_read;
   return bytes_read;
}

void cdfs_close_file(cdfs_file_t* file)
{
   /* Not really anything to do here, just
    * clear out the first_sector so
    * read() won't do anything */
   if (file)
      file-&gt;first_sector = -1;
}

int64_t cdfs_get_size(cdfs_file_t* file)
{
   if (!file || file-&gt;first_sector &lt; 0)
      return 0;
   return file-&gt;size;
}

int64_t cdfs_tell(cdfs_file_t* file)
{
   if (!file || file-&gt;first_sector &lt; 0)
      return -1;
   return file-&gt;pos;
}

int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence)
{
   int64_t new_pos;
   int new_sector;

   if (!file || file-&gt;first_sector &lt; 0)
      return -1;

   switch (whence)
   {
      case SEEK_SET:
         new_pos = offset;
         break;

      case SEEK_CUR:
         new_pos = file-&gt;pos + offset;
         break;

      case SEEK_END:
         new_pos = file-&gt;size - offset;
         break;

      default:
         return -1;
   }

   if (new_pos &lt; 0)
      return -1;
   else if (new_pos &gt; file-&gt;size)
      return -1;

   file-&gt;pos = (unsigned int)new_pos;
   file-&gt;current_sector_offset = file-&gt;pos % 2048;

   new_sector = file-&gt;pos / 2048;
   if (new_sector != file-&gt;current_sector)
   {
      file-&gt;current_sector      = new_sector;
      file-&gt;sector_buffer_valid = false;
   }

   return 0;
}

static void cdfs_skip_spaces(const char** ptr)
{
   while (**ptr &amp;&amp; (**ptr == ' ' || **ptr == '\t'))
      ++(*ptr);
}

static cdfs_track_t* cdfs_wrap_stream(
      intfstream_t* stream,
      unsigned first_sector_offset,
      unsigned first_sector_index)
{
   cdfs_track_t* track = NULL;

   if (!stream)
      return NULL;

   track                      = (cdfs_track_t*)
      calloc(1, sizeof(*track));
   track-&gt;stream              = stream;
   track-&gt;first_sector_offset = first_sector_offset;
   track-&gt;first_sector_index  = first_sector_index;

   cdfs_determine_sector_size(track);

   return track;
}

static cdfs_track_t* cdfs_open_cue_track(
      const char* path, unsigned int track_index)
{
   char* cue                                = NULL;
   const char* line                         = NULL;
   int found_track                          = 0;
   char current_track_path[PATH_MAX_LENGTH] = {0};
   char track_path[PATH_MAX_LENGTH]         = {0};
   unsigned int sector_size                 = 0;
   unsigned int previous_sector_size        = 0;
   unsigned int previous_index_sector_offset= 0;
   unsigned int track_offset                = 0;
   intfstream_t *cue_stream                 = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
   int64_t stream_size                      = intfstream_get_size(cue_stream);
   char *cue_contents                       = (char*)malloc((size_t)(stream_size + 1));
   cdfs_track_t* track                      = NULL;

   if (!cue_contents)
   {
      intfstream_close(cue_stream);
      return NULL;
   }

   intfstream_read(cue_stream, cue_contents, stream_size);
   intfstream_close(cue_stream);

   cue_contents[stream_size] = '\0';

   cue = cue_contents;
   while (*cue)
   {
      cdfs_skip_spaces((const char**)&amp;cue);
      line = cue;

      while (*cue &amp;&amp; *cue != '\n')
         ++cue;
      if (*cue)
         *cue++ = '\0';

      if (!strncasecmp(line, "FILE", 4))
      {
         const char *file = line + 4;
         cdfs_skip_spaces(&amp;file);

         if (file[0])
         {
            const char *file_end = cue - 1;
            while (file_end &gt; file &amp;&amp; *file_end != ' ' &amp;&amp; *file_end != '\t')
               --file_end;

            if (     file[0]      == '"'
                  &amp;&amp; file_end[-1] == '"')
            {
               ++file;
               --file_end;
            }

            memcpy(current_track_path, file, file_end - file);
            current_track_path[file_end - file] = '\0';
         }

         previous_sector_size = 0;
         previous_index_sector_offset = 0;
         track_offset = 0;
      }
      else if (!strncasecmp(line, "TRACK", 5))
      {
         char *ptr             = NULL;
         unsigned track_number = 0;
         const char *track     = line + 5;
         cdfs_skip_spaces(&amp;track);

         track_number = (unsigned)strtol(track, &amp;ptr, 10);
         while (*track &amp;&amp; *track != ' ' &amp;&amp; *track != '\n')
            ++track;

         previous_sector_size = sector_size;

         cdfs_skip_spaces(&amp;track);

         if (!strncasecmp(track, "MODE", 4))
         {
            /* track_index = 0 means find the first data track */
            if (!track_index || track_index == track_number)
               found_track = track_number;

            sector_size = atoi(track + 6);
         }
         else /* assume AUDIO */
            sector_size = 2352;
      }
      else if (!strncasecmp(line, "INDEX", 5))
      {
         unsigned sector_offset;
         unsigned min = 0, sec = 0, frame = 0;
         unsigned index_number = 0;
         const char *index     = line + 5;

         cdfs_skip_spaces(&amp;index);
         sscanf(index, "%u", &amp;index_number);
         while (*index &amp;&amp; *index != ' ' &amp;&amp; *index != '\n')
            ++index;
         cdfs_skip_spaces(&amp;index);

         sscanf(index, "%u:%u:%u", &amp;min, &amp;sec, &amp;frame);
         sector_offset                 = ((min * 60) + sec) * 75 + frame;
         sector_offset                -= previous_index_sector_offset;
         track_offset                 += sector_offset * previous_sector_size;
         previous_sector_size          = sector_size;
         previous_index_sector_offset += sector_offset;

         if (found_track &amp;&amp; index_number == 1)
         {
            if (     strstr(current_track_path, "/")
                  || strstr(current_track_path, "\\"))
               strncpy(track_path, current_track_path, sizeof(track_path));
            else
            {
               fill_pathname_basedir(track_path, path, sizeof(track_path));
               strlcat(track_path, current_track_path, sizeof(track_path));
            }

            break;
         }
      }
   }

   free(cue_contents);

   if (string_is_empty(track_path))
      return NULL;

   /* NOTE: previous_index_sector_offset will only be valid if all tracks are in the same BIN file.
    * Otherwise, we need to determine how many tracks are in each previous BIN file, which is not
    * stored in the CUE file. This will affect cdfs_get_first_sector, which luckily isn't used much. */
   track = cdfs_wrap_stream(intfstream_open_file(
            track_path, RETRO_VFS_FILE_ACCESS_READ,
            RETRO_VFS_FILE_ACCESS_HINT_NONE), track_offset, previous_index_sector_offset);

   if (track &amp;&amp; track-&gt;stream_sector_size == 0)
   {
      track-&gt;stream_sector_size = sector_size;

      if (sector_size == 2352)
         track-&gt;stream_sector_header_size = 16;
      else if (sector_size == 2336)
         track-&gt;stream_sector_header_size = 8;
   }

   return track;
}

#ifdef HAVE_CHD
static cdfs_track_t* cdfs_open_chd_track(const char* path, int32_t track_index)
{
   cdfs_track_t *track;
   intfstream_t *intf_stream = intfstream_open_chd_track(path,
         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE,
         track_index);
   if (!intf_stream)
      return NULL;

   track = cdfs_wrap_stream(intf_stream,
         intfstream_get_offset_to_start(intf_stream),
         intfstream_get_first_sector(intf_stream));

   if (track &amp;&amp; track-&gt;stream_sector_header_size == 0)
   {
      track-&gt;stream_sector_size = intfstream_get_frame_size(intf_stream);

      if (track-&gt;stream_sector_size == 2352)
         track-&gt;stream_sector_header_size = 16;
      else if (track-&gt;stream_sector_size == 2336)
         track-&gt;stream_sector_header_size = 8;
   }

   return track;
}
#endif

struct cdfs_track_t* cdfs_open_track(const char* path,
      unsigned int track_index)
{
   const char* ext = path_get_extension(path);

   if (string_is_equal_noncase(ext, "cue"))
      return cdfs_open_cue_track(path, track_index);

#ifdef HAVE_CHD
   if (string_is_equal_noncase(ext, "chd"))
      return cdfs_open_chd_track(path, track_index);
#endif

   /* if opening track 1, try opening as a raw track */
   if (track_index == 1)
      return cdfs_open_raw_track(path);

   /* unsupported file type */
   return NULL;
}

struct cdfs_track_t* cdfs_open_data_track(const char* path)
{
   const char* ext = path_get_extension(path);

   if (string_is_equal_noncase(ext, "cue"))
      return cdfs_open_cue_track(path, 0);

#ifdef HAVE_CHD
   if (string_is_equal_noncase(ext, "chd"))
      return cdfs_open_chd_track(path, CHDSTREAM_TRACK_PRIMARY);
#endif

   /* unsupported file type - try opening as a raw track */
   return cdfs_open_raw_track(path);
}

cdfs_track_t* cdfs_open_raw_track(const char* path)
{
   const char *ext     = path_get_extension(path);
   cdfs_track_t *track = NULL;

   if (     string_is_equal_noncase(ext, "bin")
         || string_is_equal_noncase(ext, "iso"))
   {
      intfstream_t* file = intfstream_open_file(path,
         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);

      track = cdfs_wrap_stream(file, 0, 0);
      if (track &amp;&amp; track-&gt;stream_sector_size == 0)
      {
         cdfs_determine_sector_size_from_file_size(track);
         if (track-&gt;stream_sector_size == 0)
         {
            cdfs_close_track(track);
            track = NULL;
         }
      }
   }

   return track;
}

void cdfs_close_track(cdfs_track_t* track)
{
   if (track)
   {
      if (track-&gt;stream)
      {
         intfstream_close(track-&gt;stream);
         free(track-&gt;stream);
      }

      free(track);
   }
}</pre>
<h2>./include/libretro-common/formats/image_texture.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (image_texture.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stddef.h&gt;

#include &lt;boolean.h&gt;
#include &lt;formats/image.h&gt;
#include &lt;file/nbio.h&gt;
#include &lt;string/stdstring.h&gt;

enum image_type_enum image_texture_get_type(const char *path)
{
   /* We are comparing against a fixed list of file
    * extensions, the longest (jpeg) being 4 characters
    * in length. We therefore only need to extract the first
    * 5 characters from the extension of the input path
    * to correctly validate a match */
   const char *ext = NULL;
   char ext_lower[6];

   ext_lower[0] = '\0';

   if (string_is_empty(path))
      return IMAGE_TYPE_NONE;

   /* Get file extension */
   ext = strrchr(path, '.');

   if (!ext || (*(++ext) == '\0'))
      return IMAGE_TYPE_NONE;

   /* Copy and convert to lower case */
   strlcpy(ext_lower, ext, sizeof(ext_lower));
   string_to_lower(ext_lower);

#ifdef HAVE_RPNG
   if (string_is_equal(ext_lower, "png"))
      return IMAGE_TYPE_PNG;
#endif
#ifdef HAVE_RJPEG
   if (string_is_equal(ext_lower, "jpg") ||
       string_is_equal(ext_lower, "jpeg"))
      return IMAGE_TYPE_JPEG;
#endif
#ifdef HAVE_RBMP
   if (string_is_equal(ext_lower, "bmp"))
      return IMAGE_TYPE_BMP;
#endif
#ifdef HAVE_RTGA
   if (string_is_equal(ext_lower, "tga"))
      return IMAGE_TYPE_TGA;
#endif

   return IMAGE_TYPE_NONE;
}

bool image_texture_set_color_shifts(
      unsigned *r_shift, unsigned *g_shift, unsigned *b_shift,
      unsigned *a_shift,
      struct texture_image *out_img
      )
{
   *a_shift             = 24;
   *r_shift             = 16;
   *g_shift             = 8;
   *b_shift             = 0;

   if (out_img-&gt;supports_rgba)
   {
      *r_shift = 0;
      *b_shift = 16;
      return true;
   }

   return false;
}

bool image_texture_color_convert(unsigned r_shift,
      unsigned g_shift, unsigned b_shift, unsigned a_shift,
      struct texture_image *out_img)
{
   /* This is quite uncommon. */
   if (a_shift != 24 || r_shift != 16 || g_shift != 8 || b_shift != 0)
   {
      uint32_t i;
      uint32_t num_pixels = out_img-&gt;width * out_img-&gt;height;
      uint32_t *pixels    = (uint32_t*)out_img-&gt;pixels;

      for (i = 0; i &lt; num_pixels; i++)
      {
         uint32_t col = pixels[i];
         uint8_t a    = (uint8_t)(col &gt;&gt; 24);
         uint8_t r    = (uint8_t)(col &gt;&gt; 16);
         uint8_t g    = (uint8_t)(col &gt;&gt;  8);
         uint8_t b    = (uint8_t)(col &gt;&gt;  0);
         /* Explicitly cast these to uint32_t to prevent
          * ASAN runtime error: left shift of 255 by 24 places
          * cannot be represented in type 'int' */
         pixels[i]    = ((uint32_t)a &lt;&lt; a_shift) |
                        ((uint32_t)r &lt;&lt; r_shift) |
                        ((uint32_t)g &lt;&lt; g_shift) |
                        ((uint32_t)b &lt;&lt; b_shift);
      }

      return true;
   }

   return false;
}

#ifdef GEKKO

#define GX_BLIT_LINE_32(off) \
{ \
   unsigned x; \
   const uint16_t *tmp_src = src; \
   uint16_t       *tmp_dst = dst; \
   for (x = 0; x &lt; width2 &gt;&gt; 3; x++, tmp_src += 8, tmp_dst += 32) \
   { \
      tmp_dst[  0 + off] = tmp_src[0]; \
      tmp_dst[ 16 + off] = tmp_src[1]; \
      tmp_dst[  1 + off] = tmp_src[2]; \
      tmp_dst[ 17 + off] = tmp_src[3]; \
      tmp_dst[  2 + off] = tmp_src[4]; \
      tmp_dst[ 18 + off] = tmp_src[5]; \
      tmp_dst[  3 + off] = tmp_src[6]; \
      tmp_dst[ 19 + off] = tmp_src[7]; \
   } \
   src += tmp_pitch; \
}

static bool image_texture_internal_gx_convert_texture32(
      struct texture_image *image)
{
   unsigned tmp_pitch, width2, i;
   const uint16_t *src = NULL;
   uint16_t *dst       = NULL;
   /* Memory allocation in libogc is extremely primitive so try
    * to avoid gaps in memory when converting by copying over to
    * a temporary buffer first, then converting over into
    * main buffer again. */
   void *tmp           = malloc(image-&gt;width
         * image-&gt;height * sizeof(uint32_t));

   if (!tmp)
      return false;

   memcpy(tmp, image-&gt;pixels, image-&gt;width
         * image-&gt;height * sizeof(uint32_t));
   tmp_pitch = (image-&gt;width * sizeof(uint32_t)) &gt;&gt; 1;

   image-&gt;width       &amp;= ~3;
   image-&gt;height      &amp;= ~3;
   width2              = image-&gt;width &lt;&lt; 1;
   src                 = (uint16_t*)tmp;
   dst                 = (uint16_t*)image-&gt;pixels;

   for (i = 0; i &lt; image-&gt;height; i += 4, dst += 4 * width2)
   {
      GX_BLIT_LINE_32(0)
      GX_BLIT_LINE_32(4)
      GX_BLIT_LINE_32(8)
      GX_BLIT_LINE_32(12)
   }

   free(tmp);
   return true;
}
#endif

static bool image_texture_load_internal(
      enum image_type_enum type,
      void *ptr,
      size_t len,
      struct texture_image *out_img,
      unsigned a_shift, unsigned r_shift,
      unsigned g_shift, unsigned b_shift)
{
   int ret;
   void *img    = image_transfer_new(type);

   if (!img)
      return false;

   image_transfer_set_buffer_ptr(img, type, (uint8_t*)ptr, len);

   if (!image_transfer_start(img, type))
   {
      image_transfer_free(img, type);
      return false;
   }

   while (image_transfer_iterate(img, type));

   if (!image_transfer_is_valid(img, type))
   {
      image_transfer_free(img, type);
      return false;
   }

   do
   {
      ret = image_transfer_process(img, type,
            (uint32_t**)&amp;out_img-&gt;pixels, len, &amp;out_img-&gt;width,
            &amp;out_img-&gt;height);
   } while (ret == IMAGE_PROCESS_NEXT);

   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
   {
      image_transfer_free(img, type);
      return false;
   }

   image_texture_color_convert(r_shift, g_shift, b_shift,
         a_shift, out_img);

#ifdef GEKKO
   if (!image_texture_internal_gx_convert_texture32(out_img))
   {
      image_texture_free(out_img);
      image_transfer_free(img, type);
      return false;
   }
#endif

   image_transfer_free(img, type);
   return true;
}

void image_texture_free(struct texture_image *img)
{
   if (!img)
      return;

   if (img-&gt;pixels)
      free(img-&gt;pixels);
   img-&gt;width  = 0;
   img-&gt;height = 0;
   img-&gt;pixels = NULL;
}

bool image_texture_load_buffer(struct texture_image *out_img,
   enum image_type_enum type, void *buffer, size_t buffer_len)
{
   unsigned r_shift, g_shift, b_shift, a_shift;
   image_texture_set_color_shifts(&amp;r_shift, &amp;g_shift, &amp;b_shift,
      &amp;a_shift, out_img);

   if (type != IMAGE_TYPE_NONE)
   {
      if (image_texture_load_internal(
         type, buffer, buffer_len, out_img,
         a_shift, r_shift, g_shift, b_shift))
         return true;
   }

   out_img-&gt;supports_rgba = false;
   out_img-&gt;pixels = NULL;
   out_img-&gt;width = 0;
   out_img-&gt;height = 0;

   return false;
}

bool image_texture_load(struct texture_image *out_img,
      const char *path)
{
   enum image_type_enum type  = image_texture_get_type(path);

   if (type != IMAGE_TYPE_NONE)
   {
      struct nbio_t *handle = (struct nbio_t*)
         nbio_open(path, NBIO_READ);
      if (handle)
      {
         void *ptr       = NULL;
         size_t file_len = 0;

         nbio_begin_read(handle);

         while (!nbio_iterate(handle));

         if ((ptr = nbio_get_ptr(handle, &amp;file_len)))
         {
            unsigned r_shift, g_shift, b_shift, a_shift;
            image_texture_set_color_shifts(&amp;r_shift,
                  &amp;g_shift, &amp;b_shift, &amp;a_shift, out_img);

            if (image_texture_load_internal(
                     type,
                     ptr, file_len, out_img,
                     a_shift, r_shift, g_shift, b_shift))
            {
               nbio_free(handle);
               return true;
            }
         }
         nbio_free(handle);
      }
   }

   out_img-&gt;supports_rgba = false;
   out_img-&gt;pixels        = NULL;
   out_img-&gt;width         = 0;
   out_img-&gt;height        = 0;

   return false;
}</pre>
<h2>./include/libretro-common/formats/image_transfer.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (image_transfer.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;string.h&gt;

#include &lt;boolean.h&gt;

#ifdef HAVE_RPNG
#include &lt;formats/rpng.h&gt;
#endif
#ifdef HAVE_RJPEG
#include &lt;formats/rjpeg.h&gt;
#endif
#ifdef HAVE_RTGA
#include &lt;formats/rtga.h&gt;
#endif
#ifdef HAVE_RBMP
#include &lt;formats/rbmp.h&gt;
#endif

#include &lt;formats/image.h&gt;

void image_transfer_free(void *data, enum image_type_enum type)
{
   switch (type)
   {
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         rtga_free((rtga_t*)data);
#endif
         break;
      case IMAGE_TYPE_PNG:
         {
#ifdef HAVE_RPNG
            rpng_t *rpng = (rpng_t*)data;
            if (rpng)
               rpng_free(rpng);
#endif
         }
         break;
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         rjpeg_free((rjpeg_t*)data);
#endif
         break;
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         rbmp_free((rbmp_t*)data);
#endif
         break;
      case IMAGE_TYPE_NONE:
         break;
   }
}

void *image_transfer_new(enum image_type_enum type)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         return rpng_alloc();
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return rjpeg_alloc();
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return rtga_alloc();
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         return rbmp_alloc();
#else
         break;
#endif
      default:
         break;
   }

   return NULL;
}

bool image_transfer_start(void *data, enum image_type_enum type)
{

   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         if (!rpng_start((rpng_t*)data))
            break;
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
         return true;
      case IMAGE_TYPE_NONE:
         break;
   }

   return false;
}

bool image_transfer_is_valid(
      void *data,
      enum image_type_enum type)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         return rpng_is_valid((rpng_t*)data);
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return true;
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
         return true;
      case IMAGE_TYPE_NONE:
         break;
   }

   return false;
}

void image_transfer_set_buffer_ptr(
      void *data,
      enum image_type_enum type,
      void *ptr,
      size_t len)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         rpng_set_buf_ptr((rpng_t*)data, (uint8_t*)ptr, len);
#endif
         break;
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         rjpeg_set_buf_ptr((rjpeg_t*)data, (uint8_t*)ptr);
#endif
         break;
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         rtga_set_buf_ptr((rtga_t*)data, (uint8_t*)ptr);
#endif
         break;
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         rbmp_set_buf_ptr((rbmp_t*)data, (uint8_t*)ptr);
#endif
         break;
      case IMAGE_TYPE_NONE:
         break;
   }
}

int image_transfer_process(
      void *data,
      enum image_type_enum type,
      uint32_t **buf, size_t len,
      unsigned *width, unsigned *height)
{
   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         return rpng_process_image(
               (rpng_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return rjpeg_process_image((rjpeg_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return rtga_process_image((rtga_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
#ifdef HAVE_RBMP
         return rbmp_process_image((rbmp_t*)data,
               (void**)buf, len, width, height);
#else
         break;
#endif
      case IMAGE_TYPE_NONE:
         break;
   }

   return 0;
}

bool image_transfer_iterate(void *data, enum image_type_enum type)
{

   switch (type)
   {
      case IMAGE_TYPE_PNG:
#ifdef HAVE_RPNG
         if (!rpng_iterate_image((rpng_t*)data))
            return false;
#endif
         break;
      case IMAGE_TYPE_JPEG:
#ifdef HAVE_RJPEG
         return false;
#else
         break;
#endif
      case IMAGE_TYPE_TGA:
#ifdef HAVE_RTGA
         return false;
#else
         break;
#endif
      case IMAGE_TYPE_BMP:
         return false;
      case IMAGE_TYPE_NONE:
         return false;
   }

   return true;
}</pre>
<h2>./include/libretro-common/formats/jpeg/rjpeg.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjpeg.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Modified version of stb_image's JPEG sources. */

#include &lt;stdint.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stddef.h&gt; /* ptrdiff_t on osx */
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;boolean.h&gt;
#include &lt;formats/image.h&gt;
#include &lt;formats/rjpeg.h&gt;
#include &lt;features/features_cpu.h&gt;

enum
{
   RJPEG_DEFAULT = 0, /* only used for req_comp */
   RJPEG_GREY,
   RJPEG_GREY_ALPHA,
   RJPEG_RGB,
   RJPEG_RGB_ALPHA
};

enum
{
   RJPEG_SCAN_LOAD = 0,
   RJPEG_SCAN_TYPE,
   RJPEG_SCAN_HEADER
};

typedef uint8_t *(*rjpeg_resample_row_func)(uint8_t *out, uint8_t *in0, uint8_t *in1,
                                    int w, int hs);

typedef struct
{
   rjpeg_resample_row_func resample;
   uint8_t *line0;
   uint8_t *line1;
   int hs,vs;   /* expansion factor in each axis */
   int w_lores; /* horizontal pixels pre-expansion */
   int ystep;   /* how far through vertical expansion we are */
   int ypos;    /* which pre-expansion row we're on */
} rjpeg_resample;

struct rjpeg
{
   uint8_t *buff_data;
};

#ifdef _MSC_VER
#define RJPEG_HAS_LROTL
#endif

#ifdef RJPEG_HAS_LROTL
   #define RJPEG_LROT(x,y)  _lrotl(x,y)
#else
   #define RJPEG_LROT(x,y)  (((x) &lt;&lt; (y)) | ((x) &gt;&gt; (32 - (y))))
#endif

/* x86/x64 detection */
#if defined(__x86_64__) || defined(_M_X64)
#define RJPEG_X64_TARGET
#elif defined(__i386) || defined(_M_IX86)
#define RJPEG_X86_TARGET
#endif

#if defined(__GNUC__) &amp;&amp; (defined(RJPEG_X86_TARGET) || defined(RJPEG_X64_TARGET)) &amp;&amp; !defined(__SSE2__) &amp;&amp; !defined(RJPEG_NO_SIMD)
/* NOTE: not clear do we actually need this for the 64-bit path?
 * gcc doesn't support sse2 intrinsics unless you compile with -msse2,
 * (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
 * this is just broken and gcc are jerks for not fixing it properly
 * http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
 */
#define RJPEG_NO_SIMD
#endif

#if defined(__MINGW32__) &amp;&amp; defined(RJPEG_X86_TARGET) &amp;&amp; !defined(RJPEG_MINGW_ENABLE_SSE2) &amp;&amp; !defined(RJPEG_NO_SIMD)
/* Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid RJPEG_X64_TARGET
 *
 * 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
 * Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
 * As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
 * simultaneously enabling "-mstackrealign".
 *
 * See https://github.com/nothings/stb/issues/81 for more information.
 *
 * So default to no SSE2 on 32-bit MinGW. If you've read this far and added
 * -mstackrealign to your build settings, feel free to #define RJPEG_MINGW_ENABLE_SSE2.
 */
#define RJPEG_NO_SIMD
#endif

#if defined(__SSE2__)
#include &lt;emmintrin.h&gt;

#ifdef _MSC_VER
#define RJPEG_SIMD_ALIGN(type, name) __declspec(align(16)) type name
#else
#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
#endif

#endif

/* ARM NEON */
#if defined(RJPEG_NO_SIMD) &amp;&amp; defined(RJPEG_NEON)
#undef RJPEG_NEON
#endif

#ifdef RJPEG_NEON
#include &lt;arm_neon.h&gt;
/* assume GCC or Clang on ARM targets */
#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
#endif

#ifndef RJPEG_SIMD_ALIGN
#define RJPEG_SIMD_ALIGN(type, name) type name
#endif

typedef struct
{
   uint8_t *img_buffer;
   uint8_t *img_buffer_end;
   uint8_t *img_buffer_original;
   int      img_n;
   int      img_out_n;
   int      buflen;
   uint32_t img_x;
   uint32_t img_y;
   uint8_t  buffer_start[128];
} rjpeg_context;

static INLINE uint8_t rjpeg_get8(rjpeg_context *s)
{
   if (s-&gt;img_buffer &lt; s-&gt;img_buffer_end)
      return *s-&gt;img_buffer++;

   return 0;
}

#define RJPEG_AT_EOF(s)     ((s)-&gt;img_buffer &gt;= (s)-&gt;img_buffer_end)

#define RJPEG_GET16BE(s)    ((rjpeg_get8((s)) &lt;&lt; 8) + rjpeg_get8((s)))

/* huffman decoding acceleration */
#define FAST_BITS   9  /* larger handles more cases; smaller stomps less cache */

typedef struct
{
   unsigned int maxcode[18];
   int    delta[17];   /* old 'firstsymbol' - old 'firstcode' */
   /* weirdly, repacking this into AoS is a 10% speed loss, instead of a win */
   uint16_t code[256];
   uint8_t  fast[1 &lt;&lt; FAST_BITS];
   uint8_t  values[256];
   uint8_t  size[257];
} rjpeg_huffman;

typedef struct
{
   rjpeg_context *s;
   /* kernels */
   void (*idct_block_kernel)(uint8_t *out, int out_stride, short data[64]);
   void (*YCbCr_to_RGB_kernel)(uint8_t *out, const uint8_t *y, const uint8_t *pcb,
         const uint8_t *pcr, int count, int step);
   uint8_t *(*resample_row_hv_2_kernel)(uint8_t *out, uint8_t *in_near,
         uint8_t *in_far, int w, int hs);

   /* definition of jpeg image component */
   struct
   {
      uint8_t *data;
      void *raw_data, *raw_coeff;
      uint8_t *linebuf;
      short   *coeff;            /* progressive only */
      int id;
      int h,v;
      int tq;
      int hd,ha;
      int dc_pred;

      int x,y,w2,h2;
      int      coeff_w;          /* number of 8x8 coefficient blocks */
      int      coeff_h;          /* number of 8x8 coefficient blocks */
   } img_comp[4];

   /* sizes for components, interleaved MCUs */
   int img_h_max, img_v_max;
   int img_mcu_x, img_mcu_y;
   int img_mcu_w, img_mcu_h;

   int            code_bits;     /* number of valid bits */
   int            nomore;        /* flag if we saw a marker so must stop */
   int            progressive;
   int            spec_start;
   int            spec_end;
   int            succ_high;
   int            succ_low;
   int            eob_run;
   int scan_n, order[4];
   int restart_interval, todo;
   uint32_t       code_buffer;   /* jpeg entropy-coded buffer */
   rjpeg_huffman huff_dc[4];     /* unsigned int alignment */
   rjpeg_huffman huff_ac[4];     /* unsigned int alignment */
   int16_t fast_ac[4][1 &lt;&lt; FAST_BITS];
   unsigned char  marker;        /* marker seen while filling entropy buffer */
   uint8_t dequant[4][64];
} rjpeg_jpeg;

#define RJPEG_F2F(x)  ((int) (((x) * 4096 + 0.5)))
#define RJPEG_FSH(x)  ((x) &lt;&lt; 12)

#define RJPEG_MARKER_NONE  0xff
/* if there's a pending marker from the entropy stream, return that
 * otherwise, fetch from the stream and get a marker. if there's no
 * marker, return 0xff, which is never a valid marker value
 */

/* in each scan, we'll have scan_n components, and the order
 * of the components is specified by order[]
 */
#define RJPEG_RESTART(x)     ((x) &gt;= 0xd0 &amp;&amp; (x) &lt;= 0xd7)

#define JPEG_MARKER           0xFF
#define JPEG_MARKER_SOI       0xD8
#define JPEG_MARKER_SOS       0xDA
#define JPEG_MARKER_EOI       0xD9
#define JPEG_MARKER_APP1      0xE1
#define JPEG_MARKER_APP2      0xE2

/* use comparisons since in some cases we handle more than one case (e.g. SOF) */
#define RJPEG_SOF(x)               ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)

#define RJPEG_SOF_PROGRESSIVE(x)   ((x) == 0xc2)
#define RJPEG_DIV4(x)              ((uint8_t) ((x) &gt;&gt; 2))
#define RJPEG_DIV16(x)             ((uint8_t) ((x) &gt;&gt; 4))

static int rjpeg_build_huffman(rjpeg_huffman *h, int *count)
{
   int i,j,k = 0,code;

   /* build size list for each symbol (from JPEG spec) */
   for (i = 0; i &lt; 16; ++i)
      for (j = 0; j &lt; count[i]; ++j)
         h-&gt;size[k++] = (uint8_t) (i+1);

   h-&gt;size[k] = 0;
   /* compute actual symbols (from jpeg spec) */
   code       = 0;
   k          = 0;

   for (j = 1; j &lt;= 16; ++j)
   {
      /* compute delta to add to code to compute symbol id */
      h-&gt;delta[j] = k - code;
      if (h-&gt;size[k] == j)
      {
         while (h-&gt;size[k] == j)
            h-&gt;code[k++] = (uint16_t) (code++);

         /* Bad code lengths, corrupt JPEG? */
         if (code-1 &gt;= (1 &lt;&lt; j))
            return 0;
      }
      /* compute largest code + 1 for this size, preshifted as needed later */
      h-&gt;maxcode[j] = code &lt;&lt; (16-j);
      code &lt;&lt;= 1;
   }
   h-&gt;maxcode[j] = 0xffffffff;

   /* build non-spec acceleration table; 255 is flag for not-accelerated */
   memset(h-&gt;fast, 255, 1 &lt;&lt; FAST_BITS);
   for (i = 0; i &lt; k; ++i)
   {
      int s = h-&gt;size[i];
      if (s &lt;= FAST_BITS)
      {
         int c = h-&gt;code[i] &lt;&lt; (FAST_BITS-s);
         int m = 1 &lt;&lt; (FAST_BITS-s);
         for (j = 0; j &lt; m; ++j)
            h-&gt;fast[c+j] = (uint8_t) i;
      }
   }
   return 1;
}

/* build a table that decodes both magnitude and value of small ACs in
 * one go. */
static void rjpeg_build_fast_ac(int16_t *fast_ac, rjpeg_huffman *h)
{
   int i;

   for (i = 0; i &lt; (1 &lt;&lt; FAST_BITS); ++i)
   {
      uint8_t fast = h-&gt;fast[i];

      fast_ac[i] = 0;

      if (fast &lt; 255)
      {
         int rs      = h-&gt;values[fast];
         int run     = (rs &gt;&gt; 4) &amp; 15;
         int magbits = rs &amp; 15;
         int len     = h-&gt;size[fast];

         if (magbits &amp;&amp; len + magbits &lt;= FAST_BITS)
         {
            /* magnitude code followed by receive_extend code */
            int k = ((i &lt;&lt; len) &amp; ((1 &lt;&lt; FAST_BITS) - 1)) &gt;&gt; (FAST_BITS - magbits);
            int m = 1 &lt;&lt; (magbits - 1);
            if (k &lt; m)
               k += (~0U &lt;&lt; magbits) + 1;

            /* if the result is small enough, we can fit it in fast_ac table */
            if (k &gt;= -128 &amp;&amp; k &lt;= 127)
               fast_ac[i] = (int16_t) ((k &lt;&lt; 8) + (run &lt;&lt; 4) + (len + magbits));
         }
      }
   }
}

static void rjpeg_grow_buffer_unsafe(rjpeg_jpeg *j)
{
   do
   {
      int b = j-&gt;nomore ? 0 : rjpeg_get8(j-&gt;s);
      if (b == 0xff)
      {
         int c = rjpeg_get8(j-&gt;s);

         if (c != 0)
         {
            j-&gt;marker = (unsigned char) c;
            j-&gt;nomore = 1;
            return;
         }
      }
      j-&gt;code_buffer |= b &lt;&lt; (24 - j-&gt;code_bits);
      j-&gt;code_bits   += 8;
   } while (j-&gt;code_bits &lt;= 24);
}

/* (1 &lt;&lt; n) - 1 */
static uint32_t rjpeg_bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};

/* decode a JPEG huffman value from the bitstream */
static INLINE int rjpeg_jpeg_huff_decode(rjpeg_jpeg *j, rjpeg_huffman *h)
{
   unsigned int temp;
   int c,k;

   if (j-&gt;code_bits &lt; 16)
      rjpeg_grow_buffer_unsafe(j);

   /* look at the top FAST_BITS and determine what symbol ID it is,
    * if the code is &lt;= FAST_BITS */
   c = (j-&gt;code_buffer &gt;&gt; (32 - FAST_BITS)) &amp; ((1 &lt;&lt; FAST_BITS)-1);
   k = h-&gt;fast[c];

   if (k &lt; 255)
   {
      int s = h-&gt;size[k];
      if (s &gt; j-&gt;code_bits)
         return -1;
      j-&gt;code_buffer &lt;&lt;= s;
      j-&gt;code_bits -= s;
      return h-&gt;values[k];
   }

   /* naive test is to shift the code_buffer down so k bits are
    * valid, then test against maxcode. To speed this up, we've
    * preshifted maxcode left so that it has (16-k) 0s at the
    * end; in other words, regardless of the number of bits, it
    * wants to be compared against something shifted to have 16;
    * that way we don't need to shift inside the loop. */
   temp = j-&gt;code_buffer &gt;&gt; 16;
   for (k=FAST_BITS+1 ; ; ++k)
      if (temp &lt; h-&gt;maxcode[k])
         break;

   if (k == 17)
   {
      /* error! code not found */
      j-&gt;code_bits -= 16;
      return -1;
   }

   if (k &gt; j-&gt;code_bits)
      return -1;

   /* convert the huffman code to the symbol id */
   c = ((j-&gt;code_buffer &gt;&gt; (32 - k)) &amp; rjpeg_bmask[k]) + h-&gt;delta[k];

   /* convert the id to a symbol */
   j-&gt;code_bits -= k;
   j-&gt;code_buffer &lt;&lt;= k;
   return h-&gt;values[c];
}

/* bias[n] = (-1&lt;&lt;n) + 1 */
static int const rjpeg_jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};

/* combined JPEG 'receive' and JPEG 'extend', since baseline
 * always extends everything it receives. */
static INLINE int rjpeg_extend_receive(rjpeg_jpeg *j, int n)
{
   unsigned int k;
   int sgn;
   if (j-&gt;code_bits &lt; n)
      rjpeg_grow_buffer_unsafe(j);

   sgn             = (int32_t)j-&gt;code_buffer &gt;&gt; 31; /* sign bit is always in MSB */
   k               = RJPEG_LROT(j-&gt;code_buffer, n);
   j-&gt;code_buffer  = k &amp; ~rjpeg_bmask[n];
   k              &amp;= rjpeg_bmask[n];
   j-&gt;code_bits   -= n;
   return k + (rjpeg_jbias[n] &amp; ~sgn);
}

/* get some unsigned bits */
static INLINE int rjpeg_jpeg_get_bits(rjpeg_jpeg *j, int n)
{
   unsigned int k;
   if (j-&gt;code_bits &lt; n)
      rjpeg_grow_buffer_unsafe(j);
   k              = RJPEG_LROT(j-&gt;code_buffer, n);
   j-&gt;code_buffer = k &amp; ~rjpeg_bmask[n];
   k             &amp;= rjpeg_bmask[n];
   j-&gt;code_bits  -= n;
   return k;
}

static INLINE int rjpeg_jpeg_get_bit(rjpeg_jpeg *j)
{
   unsigned int k;
   if (j-&gt;code_bits &lt; 1)
      rjpeg_grow_buffer_unsafe(j);

   k                = j-&gt;code_buffer;
   j-&gt;code_buffer &lt;&lt;= 1;
   --j-&gt;code_bits;
   return k &amp; 0x80000000;
}

/* given a value that's at position X in the zigzag stream,
 * where does it appear in the 8x8 matrix coded as row-major? */
static uint8_t rjpeg_jpeg_dezigzag[64+15] =
{
    0,  1,  8, 16,  9,  2,  3, 10,
   17, 24, 32, 25, 18, 11,  4,  5,
   12, 19, 26, 33, 40, 48, 41, 34,
   27, 20, 13,  6,  7, 14, 21, 28,
   35, 42, 49, 56, 57, 50, 43, 36,
   29, 22, 15, 23, 30, 37, 44, 51,
   58, 59, 52, 45, 38, 31, 39, 46,
   53, 60, 61, 54, 47, 55, 62, 63,
   /* let corrupt input sample past end */
   63, 63, 63, 63, 63, 63, 63, 63,
   63, 63, 63, 63, 63, 63, 63
};

/* decode one 64-entry block-- */
static int rjpeg_jpeg_decode_block(
      rjpeg_jpeg *j, short data[64],
      rjpeg_huffman *hdc,
      rjpeg_huffman *hac,
      int16_t *fac,
      int b,
      uint8_t *dequant)
{
   int dc,k;
   int t;
   int diff      = 0;

   if (j-&gt;code_bits &lt; 16)
      rjpeg_grow_buffer_unsafe(j);
   t = rjpeg_jpeg_huff_decode(j, hdc);

   /* Bad huffman code. Corrupt JPEG? */
   if (t &lt; 0)
      return 0;

   /* 0 all the ac values now so we can do it 32-bits at a time */
   memset(data,0,64*sizeof(data[0]));

   if (t)
      diff                = rjpeg_extend_receive(j, t);
   dc                     = j-&gt;img_comp[b].dc_pred + diff;
   j-&gt;img_comp[b].dc_pred = dc;
   data[0]                = (short) (dc * dequant[0]);

   /* decode AC components, see JPEG spec */
   k                      = 1;
   do
   {
      unsigned int zig;
      int c,r,s;
      if (j-&gt;code_bits &lt; 16)
         rjpeg_grow_buffer_unsafe(j);
      c = (j-&gt;code_buffer &gt;&gt; (32 - FAST_BITS)) &amp; ((1 &lt;&lt; FAST_BITS)-1);
      r = fac[c];
      if (r)
      {
         /* fast-AC path */
         k               += (r &gt;&gt; 4) &amp; 15; /* run */
         s                = r &amp; 15; /* combined length */
         j-&gt;code_buffer &lt;&lt;= s;
         j-&gt;code_bits    -= s;
         /* decode into unzigzag'd location */
         zig              = rjpeg_jpeg_dezigzag[k++];
         data[zig]        = (short) ((r &gt;&gt; 8) * dequant[zig]);
      }
      else
      {
         int rs = rjpeg_jpeg_huff_decode(j, hac);

         /* Bad huffman code. Corrupt JPEG? */
         if (rs &lt; 0)
            return 0;

         s = rs &amp; 15;
         r = rs &gt;&gt; 4;
         if (s == 0)
         {
            if (rs != 0xf0)
               break; /* end block */
            k += 16;
         }
         else
         {
            k += r;
            /* decode into unzigzag'd location */
            zig = rjpeg_jpeg_dezigzag[k++];
            data[zig] = (short) (rjpeg_extend_receive(j,s) * dequant[zig]);
         }
      }
   } while (k &lt; 64);
   return 1;
}

static int rjpeg_jpeg_decode_block_prog_dc(
      rjpeg_jpeg *j,
      short data[64],
      rjpeg_huffman *hdc,
      int b)
{
   /* Can't merge DC and AC. Corrupt JPEG? */
   if (j-&gt;spec_end != 0)
      return 0;

   if (j-&gt;code_bits &lt; 16)
      rjpeg_grow_buffer_unsafe(j);

   if (j-&gt;succ_high == 0)
   {
      int t;
      int dc;
      int diff = 0;

      /* first scan for DC coefficient, must be first */
      memset(data,0,64*sizeof(data[0])); /* 0 all the ac values now */
      t       = rjpeg_jpeg_huff_decode(j, hdc);
      if (t)
         diff = rjpeg_extend_receive(j, t);

      dc      = j-&gt;img_comp[b].dc_pred + diff;
      j-&gt;img_comp[b].dc_pred = dc;
      data[0] = (short) (dc &lt;&lt; j-&gt;succ_low);
   }
   else
   {
      /* refinement scan for DC coefficient */
      if (rjpeg_jpeg_get_bit(j))
         data[0] += (short) (1 &lt;&lt; j-&gt;succ_low);
   }
   return 1;
}

static int rjpeg_jpeg_decode_block_prog_ac(
      rjpeg_jpeg *j,
      short data[64],
      rjpeg_huffman *hac,
      int16_t *fac)
{
   int k;

   /* Can't merge DC and AC. Corrupt JPEG? */
   if (j-&gt;spec_start == 0)
      return 0;

   if (j-&gt;succ_high == 0)
   {
      int shift = j-&gt;succ_low;

      if (j-&gt;eob_run)
      {
         --j-&gt;eob_run;
         return 1;
      }

      k = j-&gt;spec_start;
      do
      {
         unsigned int zig;
         int c,r,s;
         if (j-&gt;code_bits &lt; 16)
            rjpeg_grow_buffer_unsafe(j);
         c = (j-&gt;code_buffer &gt;&gt; (32 - FAST_BITS)) &amp; ((1 &lt;&lt; FAST_BITS)-1);
         r = fac[c];
         if (r)
         {
            /* fast-AC path */
            k               += (r &gt;&gt; 4) &amp; 15; /* run */
            s                = r &amp; 15; /* combined length */
            j-&gt;code_buffer &lt;&lt;= s;
            j-&gt;code_bits    -= s;
            zig              = rjpeg_jpeg_dezigzag[k++];
            data[zig]        = (short) ((r &gt;&gt; 8) &lt;&lt; shift);
         }
         else
         {
            int rs = rjpeg_jpeg_huff_decode(j, hac);

            /* Bad huffman code. Corrupt JPEG? */
            if (rs &lt; 0)
               return 0;

            s = rs &amp; 15;
            r = rs &gt;&gt; 4;
            if (s == 0)
            {
               if (r &lt; 15)
               {
                  j-&gt;eob_run = (1 &lt;&lt; r);
                  if (r)
                     j-&gt;eob_run += rjpeg_jpeg_get_bits(j, r);
                  --j-&gt;eob_run;
                  break;
               }
               k += 16;
            }
            else
            {
               k         += r;
               zig        = rjpeg_jpeg_dezigzag[k++];
               data[zig]  = (short) (rjpeg_extend_receive(j,s) &lt;&lt; shift);
            }
         }
      } while (k &lt;= j-&gt;spec_end);
   }
   else
   {
      /* refinement scan for these AC coefficients */

      short bit = (short) (1 &lt;&lt; j-&gt;succ_low);

      if (j-&gt;eob_run)
      {
         --j-&gt;eob_run;
         for (k = j-&gt;spec_start; k &lt;= j-&gt;spec_end; ++k)
         {
            short *p = &amp;data[rjpeg_jpeg_dezigzag[k]];
            if (*p != 0)
               if (rjpeg_jpeg_get_bit(j))
                  if ((*p &amp; bit) == 0)
                  {
                     if (*p &gt; 0)
                        *p += bit;
                     else
                        *p -= bit;
                  }
         }
      }
      else
      {
         k = j-&gt;spec_start;
         do
         {
            int r,s;
            int rs = rjpeg_jpeg_huff_decode(j, hac);

            /* Bad huffman code. Corrupt JPEG? */
            if (rs &lt; 0)
               return 0;

            s = rs &amp; 15;
            r = rs &gt;&gt; 4;
            if (s == 0)
            {
               if (r &lt; 15)
               {
                  j-&gt;eob_run = (1 &lt;&lt; r) - 1;
                  if (r)
                     j-&gt;eob_run += rjpeg_jpeg_get_bits(j, r);
                  r = 64; /* force end of block */
               }
               else
               {
                  /* r=15 s=0 should write 16 0s, so we just do
                   * a run of 15 0s and then write s (which is 0),
                   * so we don't have to do anything special here */
               }
            }
            else
            {
               /* Bad huffman code. Corrupt JPEG? */
               if (s != 1)
                  return 0;

               /* sign bit */
               if (rjpeg_jpeg_get_bit(j))
                  s = bit;
               else
                  s = -bit;
            }

            /* advance by r */
            while (k &lt;= j-&gt;spec_end)
            {
               short *p = &amp;data[rjpeg_jpeg_dezigzag[k++]];
               if (*p != 0)
               {
                  if (rjpeg_jpeg_get_bit(j))
                     if ((*p &amp; bit) == 0)
                     {
                        if (*p &gt; 0)
                           *p += bit;
                        else
                           *p -= bit;
                     }
               }
               else
               {
                  if (r == 0)
                  {
                     *p = (short) s;
                     break;
                  }
                  --r;
               }
            }
         } while (k &lt;= j-&gt;spec_end);
      }
   }
   return 1;
}

/* take a -128..127 value and rjpeg_clamp it and convert to 0..255 */
static INLINE uint8_t rjpeg_clamp(int x)
{
   /* trick to use a single test to catch both cases */
   if ((unsigned int) x &gt; 255)
      return 255;
   return (uint8_t) x;
}

/* derived from jidctint -- DCT_ISLOW */
#define RJPEG_IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
   int t0,t1,p4,p5,x0,x1,x2,x3; \
   int p2 = s2;                                \
   int p3 = s6;                                \
   int p1 = (p2+p3) * RJPEG_F2F(0.5411961f);   \
   int t2 = p1 + p3 * RJPEG_F2F(-1.847759065f);\
   int t3 = p1 + p2 * RJPEG_F2F( 0.765366865f);\
   p2 = s0;                                    \
   p3 = s4;                                    \
   t0 = RJPEG_FSH(p2+p3);                      \
   t1 = RJPEG_FSH(p2-p3);                      \
   x0 = t0+t3;                                 \
   x3 = t0-t3;                                 \
   x1 = t1+t2;                                 \
   x2 = t1-t2;                                 \
   t0 = s7;                                    \
   t1 = s5;                                    \
   t2 = s3;                                    \
   t3 = s1;                                    \
   p3 = t0+t2;                                 \
   p4 = t1+t3;                                 \
   p1 = t0+t3;                                 \
   p2 = t1+t2;                                 \
   p5 = (p3+p4) * RJPEG_F2F( 1.175875602f);    \
   t0 = t0      * RJPEG_F2F( 0.298631336f);    \
   t1 = t1      * RJPEG_F2F( 2.053119869f);    \
   t2 = t2      * RJPEG_F2F( 3.072711026f);    \
   t3 = t3      * RJPEG_F2F( 1.501321110f);    \
   p1 = p5 + p1 * RJPEG_F2F(-0.899976223f);    \
   p2 = p5 + p2 * RJPEG_F2F(-2.562915447f);    \
   p3 = p3      * RJPEG_F2F(-1.961570560f);    \
   p4 = p4      * RJPEG_F2F(-0.390180644f);    \
   t3 += p1+p4;                                \
   t2 += p2+p3;                                \
   t1 += p2+p4;                                \
   t0 += p1+p3

static void rjpeg_idct_block(uint8_t *out, int out_stride, short data[64])
{
   int i,val[64],*v=val;
   uint8_t   *o = NULL;
   int16_t   *d = data;

   /* columns */
   for (i = 0; i &lt; 8; ++i,++d, ++v)
   {
      /* if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing */
      if (     d[ 8] == 0
            &amp;&amp; d[16] == 0
            &amp;&amp; d[24] == 0
            &amp;&amp; d[32] == 0
            &amp;&amp; d[40] == 0
            &amp;&amp; d[48] == 0
            &amp;&amp; d[56] == 0)
      {
         /*    no shortcut                 0     seconds
          *    (1|2|3|4|5|6|7)==0          0     seconds
          *    all separate               -0.047 seconds
          *    1 &amp;&amp; 2|3 &amp;&amp; 4|5 &amp;&amp; 6|7:    -0.047 seconds */
         int dcterm = d[0] &lt;&lt; 2;
         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
      }
      else
      {
         RJPEG_IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]);

         /* constants scaled things up by 1&lt;&lt;12; let's bring them back
          * down, but keep 2 extra bits of precision */
         x0 += 512;
         x1 += 512;
         x2 += 512;
         x3 += 512;

         v[ 0] = (x0+t3) &gt;&gt; 10;
         v[56] = (x0-t3) &gt;&gt; 10;
         v[ 8] = (x1+t2) &gt;&gt; 10;
         v[48] = (x1-t2) &gt;&gt; 10;
         v[16] = (x2+t1) &gt;&gt; 10;
         v[40] = (x2-t1) &gt;&gt; 10;
         v[24] = (x3+t0) &gt;&gt; 10;
         v[32] = (x3-t0) &gt;&gt; 10;
      }
   }

   for (i = 0, v=val, o=out; i &lt; 8; ++i,v+=8,o+=out_stride)
   {
      /* no fast case since the first 1D IDCT spread components out */
      RJPEG_IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]);

      /* constants scaled things up by 1&lt;&lt;12, plus we had 1&lt;&lt;2 from first
       * loop, plus horizontal and vertical each scale by sqrt(8) so together
       * we've got an extra 1&lt;&lt;3, so 1&lt;&lt;17 total we need to remove.
       * so we want to round that, which means adding 0.5 * 1&lt;&lt;17,
       * aka 65536. Also, we'll end up with -128 to 127 that we want
       * to encode as 0..255 by adding 128, so we'll add that before the shift
       */
      x0 += 65536 + (128&lt;&lt;17);
      x1 += 65536 + (128&lt;&lt;17);
      x2 += 65536 + (128&lt;&lt;17);
      x3 += 65536 + (128&lt;&lt;17);

      /* Tried computing the shifts into temps, or'ing the temps to see
       * if any were out of range, but that was slower */
      o[0] = rjpeg_clamp((x0+t3) &gt;&gt; 17);
      o[7] = rjpeg_clamp((x0-t3) &gt;&gt; 17);
      o[1] = rjpeg_clamp((x1+t2) &gt;&gt; 17);
      o[6] = rjpeg_clamp((x1-t2) &gt;&gt; 17);
      o[2] = rjpeg_clamp((x2+t1) &gt;&gt; 17);
      o[5] = rjpeg_clamp((x2-t1) &gt;&gt; 17);
      o[3] = rjpeg_clamp((x3+t0) &gt;&gt; 17);
      o[4] = rjpeg_clamp((x3-t0) &gt;&gt; 17);
   }
}

#if defined(__SSE2__)
/* sse2 integer IDCT. not the fastest possible implementation but it
 * produces bit-identical results to the generic C version so it's
 * fully "transparent".
 */
static void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])
{
   /* This is constructed to match our regular (generic) integer IDCT exactly. */
   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
   __m128i tmp;

   /* dot product constant: even elems=x, odd elems=y */
   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))

   /* out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
    * out(1) = c1[even]*x + c1[odd]*y
    */
   #define dct_rot(out0,out1, x,y,c0,c1) \
      __m128i c0##lo   = _mm_unpacklo_epi16((x),(y)); \
      __m128i c0##hi   = _mm_unpackhi_epi16((x),(y)); \
      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)

   /* out = in &lt;&lt; 12  (in 16-bit, out 32-bit) */
   #define dct_widen(out, in) \
      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)

   /* wide add */
   #define dct_wadd(out, a, b) \
      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)

   /* wide sub */
   #define dct_wsub(out, a, b) \
      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)

   /* butterfly a/b, add bias, then shift by "s" and pack */
   #define dct_bfly32o(out0, out1, a,b,bias,s) \
      { \
         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
         dct_wadd(sum, abiased, b); \
         dct_wsub(dif, abiased, b); \
         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
      }

   /* 8-bit interleave step (for transposes) */
   #define dct_interleave8(a, b) \
      tmp = a; \
      a = _mm_unpacklo_epi8(a, b); \
      b = _mm_unpackhi_epi8(tmp, b)

   /* 16-bit interleave step (for transposes) */
   #define dct_interleave16(a, b) \
      tmp = a; \
      a = _mm_unpacklo_epi16(a, b); \
      b = _mm_unpackhi_epi16(tmp, b)

   #define dct_pass(bias,shift) \
      { \
         /* even part */ \
         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
         __m128i sum04 = _mm_add_epi16(row0, row4); \
         __m128i dif04 = _mm_sub_epi16(row0, row4); \
         dct_widen(t0e, sum04); \
         dct_widen(t1e, dif04); \
         dct_wadd(x0, t0e, t3e); \
         dct_wsub(x3, t0e, t3e); \
         dct_wadd(x1, t1e, t2e); \
         dct_wsub(x2, t1e, t2e); \
         /* odd part */ \
         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
         __m128i sum17 = _mm_add_epi16(row1, row7); \
         __m128i sum35 = _mm_add_epi16(row3, row5); \
         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
         dct_wadd(x4, y0o, y4o); \
         dct_wadd(x5, y1o, y5o); \
         dct_wadd(x6, y2o, y5o); \
         dct_wadd(x7, y3o, y4o); \
         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
      }

   __m128i rot0_0 = dct_const(RJPEG_F2F(0.5411961f), RJPEG_F2F(0.5411961f) + RJPEG_F2F(-1.847759065f));
   __m128i rot0_1 = dct_const(RJPEG_F2F(0.5411961f) + RJPEG_F2F( 0.765366865f), RJPEG_F2F(0.5411961f));
   __m128i rot1_0 = dct_const(RJPEG_F2F(1.175875602f) + RJPEG_F2F(-0.899976223f), RJPEG_F2F(1.175875602f));
   __m128i rot1_1 = dct_const(RJPEG_F2F(1.175875602f), RJPEG_F2F(1.175875602f) + RJPEG_F2F(-2.562915447f));
   __m128i rot2_0 = dct_const(RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 0.298631336f), RJPEG_F2F(-1.961570560f));
   __m128i rot2_1 = dct_const(RJPEG_F2F(-1.961570560f), RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 3.072711026f));
   __m128i rot3_0 = dct_const(RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 2.053119869f), RJPEG_F2F(-0.390180644f));
   __m128i rot3_1 = dct_const(RJPEG_F2F(-0.390180644f), RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 1.501321110f));

   /* rounding biases in column/row passes, see rjpeg_idct_block for explanation. */
   __m128i bias_0 = _mm_set1_epi32(512);
   __m128i bias_1 = _mm_set1_epi32(65536 + (128&lt;&lt;17));

   /* load */
   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
   row7 = _mm_load_si128((const __m128i *) (data + 7*8));

   /* column pass */
   dct_pass(bias_0, 10);

   {
      /* 16bit 8x8 transpose pass 1 */
      dct_interleave16(row0, row4);
      dct_interleave16(row1, row5);
      dct_interleave16(row2, row6);
      dct_interleave16(row3, row7);

      /* transpose pass 2 */
      dct_interleave16(row0, row2);
      dct_interleave16(row1, row3);
      dct_interleave16(row4, row6);
      dct_interleave16(row5, row7);

      /* transpose pass 3 */
      dct_interleave16(row0, row1);
      dct_interleave16(row2, row3);
      dct_interleave16(row4, row5);
      dct_interleave16(row6, row7);
   }

   /* row pass */
   dct_pass(bias_1, 17);

   {
      /* pack */
      __m128i p0 = _mm_packus_epi16(row0, row1); /* a0a1a2a3...a7b0b1b2b3...b7 */
      __m128i p1 = _mm_packus_epi16(row2, row3);
      __m128i p2 = _mm_packus_epi16(row4, row5);
      __m128i p3 = _mm_packus_epi16(row6, row7);

      /* 8bit 8x8 transpose pass 1 */
      dct_interleave8(p0, p2); /* a0e0a1e1... */
      dct_interleave8(p1, p3); /* c0g0c1g1... */

      /* transpose pass 2 */
      dct_interleave8(p0, p1); /* a0c0e0g0... */
      dct_interleave8(p2, p3); /* b0d0f0h0... */

      /* transpose pass 3 */
      dct_interleave8(p0, p2); /* a0b0c0d0... */
      dct_interleave8(p1, p3); /* a4b4c4d4... */

      /* store */
      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
   }

#undef dct_const
#undef dct_rot
#undef dct_widen
#undef dct_wadd
#undef dct_wsub
#undef dct_bfly32o
#undef dct_interleave8
#undef dct_interleave16
#undef dct_pass
}

#endif

#ifdef RJPEG_NEON

/* NEON integer IDCT. should produce bit-identical
 * results to the generic C version. */
static void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])
{
   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;

   int16x4_t rot0_0 = vdup_n_s16(RJPEG_F2F(0.5411961f));
   int16x4_t rot0_1 = vdup_n_s16(RJPEG_F2F(-1.847759065f));
   int16x4_t rot0_2 = vdup_n_s16(RJPEG_F2F( 0.765366865f));
   int16x4_t rot1_0 = vdup_n_s16(RJPEG_F2F( 1.175875602f));
   int16x4_t rot1_1 = vdup_n_s16(RJPEG_F2F(-0.899976223f));
   int16x4_t rot1_2 = vdup_n_s16(RJPEG_F2F(-2.562915447f));
   int16x4_t rot2_0 = vdup_n_s16(RJPEG_F2F(-1.961570560f));
   int16x4_t rot2_1 = vdup_n_s16(RJPEG_F2F(-0.390180644f));
   int16x4_t rot3_0 = vdup_n_s16(RJPEG_F2F( 0.298631336f));
   int16x4_t rot3_1 = vdup_n_s16(RJPEG_F2F( 2.053119869f));
   int16x4_t rot3_2 = vdup_n_s16(RJPEG_F2F( 3.072711026f));
   int16x4_t rot3_3 = vdup_n_s16(RJPEG_F2F( 1.501321110f));

#define dct_long_mul(out, inq, coeff) \
   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)

#define dct_long_mac(out, acc, inq, coeff) \
   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)

#define dct_widen(out, inq) \
   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)

/* wide add */
#define dct_wadd(out, a, b) \
   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)

/* wide sub */
#define dct_wsub(out, a, b) \
   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)

/* butterfly a/b, then shift using "shiftop" by "s" and pack */
#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
   { \
      dct_wadd(sum, a, b); \
      dct_wsub(dif, a, b); \
      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
   }

#define dct_pass(shiftop, shift) \
   { \
      /* even part */ \
      int16x8_t sum26 = vaddq_s16(row2, row6); \
      dct_long_mul(p1e, sum26, rot0_0); \
      dct_long_mac(t2e, p1e, row6, rot0_1); \
      dct_long_mac(t3e, p1e, row2, rot0_2); \
      int16x8_t sum04 = vaddq_s16(row0, row4); \
      int16x8_t dif04 = vsubq_s16(row0, row4); \
      dct_widen(t0e, sum04); \
      dct_widen(t1e, dif04); \
      dct_wadd(x0, t0e, t3e); \
      dct_wsub(x3, t0e, t3e); \
      dct_wadd(x1, t1e, t2e); \
      dct_wsub(x2, t1e, t2e); \
      /* odd part */ \
      int16x8_t sum15 = vaddq_s16(row1, row5); \
      int16x8_t sum17 = vaddq_s16(row1, row7); \
      int16x8_t sum35 = vaddq_s16(row3, row5); \
      int16x8_t sum37 = vaddq_s16(row3, row7); \
      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
      dct_long_mul(p5o, sumodd, rot1_0); \
      dct_long_mac(p1o, p5o, sum17, rot1_1); \
      dct_long_mac(p2o, p5o, sum35, rot1_2); \
      dct_long_mul(p3o, sum37, rot2_0); \
      dct_long_mul(p4o, sum15, rot2_1); \
      dct_wadd(sump13o, p1o, p3o); \
      dct_wadd(sump24o, p2o, p4o); \
      dct_wadd(sump23o, p2o, p3o); \
      dct_wadd(sump14o, p1o, p4o); \
      dct_long_mac(x4, sump13o, row7, rot3_0); \
      dct_long_mac(x5, sump24o, row5, rot3_1); \
      dct_long_mac(x6, sump23o, row3, rot3_2); \
      dct_long_mac(x7, sump14o, row1, rot3_3); \
      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
   }

   /* load */
   row0 = vld1q_s16(data + 0*8);
   row1 = vld1q_s16(data + 1*8);
   row2 = vld1q_s16(data + 2*8);
   row3 = vld1q_s16(data + 3*8);
   row4 = vld1q_s16(data + 4*8);
   row5 = vld1q_s16(data + 5*8);
   row6 = vld1q_s16(data + 6*8);
   row7 = vld1q_s16(data + 7*8);

   /* add DC bias */
   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));

   /* column pass */
   dct_pass(vrshrn_n_s32, 10);

   /* 16bit 8x8 transpose */
   {
/* these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
 * whether compilers actually get this is another story, sadly. */
#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }

      /* pass 1 */
      dct_trn16(row0, row1); /* a0b0a2b2a4b4a6b6 */
      dct_trn16(row2, row3);
      dct_trn16(row4, row5);
      dct_trn16(row6, row7);

      /* pass 2 */
      dct_trn32(row0, row2); /* a0b0c0d0a4b4c4d4 */
      dct_trn32(row1, row3);
      dct_trn32(row4, row6);
      dct_trn32(row5, row7);

      /* pass 3 */
      dct_trn64(row0, row4); /* a0b0c0d0e0f0g0h0 */
      dct_trn64(row1, row5);
      dct_trn64(row2, row6);
      dct_trn64(row3, row7);

#undef dct_trn16
#undef dct_trn32
#undef dct_trn64
   }

   /* row pass
    * vrshrn_n_s32 only supports shifts up to 16, we need
    * 17. so do a non-rounding shift of 16 first then follow
    * up with a rounding shift by 1. */
   dct_pass(vshrn_n_s32, 16);

   {
      /* pack and round */
      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);

      /* again, these can translate into one instruction, but often don't. */
#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }

      /* sadly can't use interleaved stores here since we only write
       * 8 bytes to each scan line! */

      /* 8x8 8-bit transpose pass 1 */
      dct_trn8_8(p0, p1);
      dct_trn8_8(p2, p3);
      dct_trn8_8(p4, p5);
      dct_trn8_8(p6, p7);

      /* pass 2 */
      dct_trn8_16(p0, p2);
      dct_trn8_16(p1, p3);
      dct_trn8_16(p4, p6);
      dct_trn8_16(p5, p7);

      /* pass 3 */
      dct_trn8_32(p0, p4);
      dct_trn8_32(p1, p5);
      dct_trn8_32(p2, p6);
      dct_trn8_32(p3, p7);

      /* store */
      vst1_u8(out, p0);
      out += out_stride;
      vst1_u8(out, p1);
      out += out_stride;
      vst1_u8(out, p2);
      out += out_stride;
      vst1_u8(out, p3);
      out += out_stride;
      vst1_u8(out, p4);
      out += out_stride;
      vst1_u8(out, p5);
      out += out_stride;
      vst1_u8(out, p6);
      out += out_stride;
      vst1_u8(out, p7);

#undef dct_trn8_8
#undef dct_trn8_16
#undef dct_trn8_32
   }

#undef dct_long_mul
#undef dct_long_mac
#undef dct_widen
#undef dct_wadd
#undef dct_wsub
#undef dct_bfly32o
#undef dct_pass
}

#endif /* RJPEG_NEON */

static uint8_t rjpeg_get_marker(rjpeg_jpeg *j)
{
   uint8_t x;

   if (j-&gt;marker != RJPEG_MARKER_NONE)
   {
      x = j-&gt;marker;
      j-&gt;marker = RJPEG_MARKER_NONE;
      return x;
   }

   x = rjpeg_get8(j-&gt;s);
   if (x != 0xff)
      return RJPEG_MARKER_NONE;
   while (x == 0xff)
      x = rjpeg_get8(j-&gt;s);
   return x;
}

/* after a restart interval, rjpeg_jpeg_reset the entropy decoder and
 * the dc prediction
 */
static void rjpeg_jpeg_reset(rjpeg_jpeg *j)
{
   j-&gt;code_bits           = 0;
   j-&gt;code_buffer         = 0;
   j-&gt;nomore              = 0;
   j-&gt;img_comp[0].dc_pred = 0;
   j-&gt;img_comp[1].dc_pred = 0;
   j-&gt;img_comp[2].dc_pred = 0;
   j-&gt;marker              = RJPEG_MARKER_NONE;
   j-&gt;todo                = j-&gt;restart_interval ? j-&gt;restart_interval : 0x7fffffff;
   j-&gt;eob_run             = 0;

   /* no more than 1&lt;&lt;31 MCUs if no restart_interval? that's plenty safe,
    * since we don't even allow 1&lt;&lt;30 pixels */
}

static int rjpeg_parse_entropy_coded_data(rjpeg_jpeg *z)
{
   rjpeg_jpeg_reset(z);

   if (z-&gt;scan_n == 1)
   {
      int i, j;
      int n = z-&gt;order[0];
      int w = (z-&gt;img_comp[n].x+7) &gt;&gt; 3;
      int h = (z-&gt;img_comp[n].y+7) &gt;&gt; 3;

      /* non-interleaved data, we just need to process one block at a time,
       * in trivial scanline order
       * number of blocks to do just depends on how many actual "pixels" this
       * component has, independent of interleaved MCU blocking and such */

      if (z-&gt;progressive)
      {
         for (j = 0; j &lt; h; ++j)
         {
            for (i = 0; i &lt; w; ++i)
            {
               short *data = z-&gt;img_comp[n].coeff + 64 * (i + j * z-&gt;img_comp[n].coeff_w);

               if (z-&gt;spec_start == 0)
               {
                  if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &amp;z-&gt;huff_dc[z-&gt;img_comp[n].hd], n))
                     return 0;
               }
               else
               {
                  int ha = z-&gt;img_comp[n].ha;
                  if (!rjpeg_jpeg_decode_block_prog_ac(z, data, &amp;z-&gt;huff_ac[ha], z-&gt;fast_ac[ha]))
                     return 0;
               }

               /* every data block is an MCU, so countdown the restart interval */
               if (--z-&gt;todo &lt;= 0)
               {
                  if (z-&gt;code_bits &lt; 24)
                     rjpeg_grow_buffer_unsafe(z);

                  if (!RJPEG_RESTART(z-&gt;marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
      else
      {
         RJPEG_SIMD_ALIGN(short, data[64]);

         for (j = 0; j &lt; h; ++j)
         {
            for (i = 0; i &lt; w; ++i)
            {
               int ha = z-&gt;img_comp[n].ha;
               if (!rjpeg_jpeg_decode_block(z, data, z-&gt;huff_dc+z-&gt;img_comp[n].hd,
                        z-&gt;huff_ac+ha, z-&gt;fast_ac[ha], n, z-&gt;dequant[z-&gt;img_comp[n].tq]))
                  return 0;

               z-&gt;idct_block_kernel(z-&gt;img_comp[n].data+z-&gt;img_comp[n].w2*j*8+i*8,
                     z-&gt;img_comp[n].w2, data);

               /* every data block is an MCU, so countdown the restart interval */
               if (--z-&gt;todo &lt;= 0)
               {
                  if (z-&gt;code_bits &lt; 24)
                     rjpeg_grow_buffer_unsafe(z);

                  /* if it's NOT a restart, then just bail,
                   * so we get corrupt data rather than no data */
                  if (!RJPEG_RESTART(z-&gt;marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
   }
   else
   {
      /* interleaved */
      int i,j,k,x,y;

      if (z-&gt;progressive)
      {
         for (j = 0; j &lt; z-&gt;img_mcu_y; ++j)
         {
            for (i = 0; i &lt; z-&gt;img_mcu_x; ++i)
            {
               /* scan an interleaved MCU... process scan_n components in order */
               for (k = 0; k &lt; z-&gt;scan_n; ++k)
               {
                  int n = z-&gt;order[k];
                  /* scan out an MCU's worth of this component; that's just determined
                   * by the basic H and V specified for the component */
                  for (y = 0; y &lt; z-&gt;img_comp[n].v; ++y)
                  {
                     for (x = 0; x &lt; z-&gt;img_comp[n].h; ++x)
                     {
                        int      x2 = (i*z-&gt;img_comp[n].h + x);
                        int      y2 = (j*z-&gt;img_comp[n].v + y);
                        short *data = z-&gt;img_comp[n].coeff + 64 * (x2 + y2 * z-&gt;img_comp[n].coeff_w);
                        if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &amp;z-&gt;huff_dc[z-&gt;img_comp[n].hd], n))
                           return 0;
                     }
                  }
               }

               /* after all interleaved components, that's an interleaved MCU,
                * so now count down the restart interval */
               if (--z-&gt;todo &lt;= 0)
               {
                  if (z-&gt;code_bits &lt; 24)
                     rjpeg_grow_buffer_unsafe(z);
                  if (!RJPEG_RESTART(z-&gt;marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
      else
      {
         RJPEG_SIMD_ALIGN(short, data[64]);

         for (j = 0; j &lt; z-&gt;img_mcu_y; ++j)
         {
            for (i = 0; i &lt; z-&gt;img_mcu_x; ++i)
            {
               /* scan an interleaved MCU... process scan_n components in order */
               for (k = 0; k &lt; z-&gt;scan_n; ++k)
               {
                  int n = z-&gt;order[k];
                  /* scan out an MCU's worth of this component; that's just determined
                   * by the basic H and V specified for the component */
                  for (y = 0; y &lt; z-&gt;img_comp[n].v; ++y)
                  {
                     for (x = 0; x &lt; z-&gt;img_comp[n].h; ++x)
                     {
                        int x2 = (i*z-&gt;img_comp[n].h + x)*8;
                        int y2 = (j*z-&gt;img_comp[n].v + y)*8;
                        int ha = z-&gt;img_comp[n].ha;

                        if (!rjpeg_jpeg_decode_block(z, data,
                                 z-&gt;huff_dc+z-&gt;img_comp[n].hd,
                                 z-&gt;huff_ac+ha, z-&gt;fast_ac[ha],
                                 n, z-&gt;dequant[z-&gt;img_comp[n].tq]))
                           return 0;

                        z-&gt;idct_block_kernel(z-&gt;img_comp[n].data+z-&gt;img_comp[n].w2*y2+x2,
                              z-&gt;img_comp[n].w2, data);
                     }
                  }
               }

               /* after all interleaved components, that's an interleaved MCU,
                * so now count down the restart interval */
               if (--z-&gt;todo &lt;= 0)
               {
                  if (z-&gt;code_bits &lt; 24)
                     rjpeg_grow_buffer_unsafe(z);
                  if (!RJPEG_RESTART(z-&gt;marker))
                     return 1;
                  rjpeg_jpeg_reset(z);
               }
            }
         }
      }
   }

   return 1;
}

static void rjpeg_jpeg_dequantize(short *data, uint8_t *dequant)
{
   int i;
   for (i = 0; i &lt; 64; ++i)
      data[i] *= dequant[i];
}

static void rjpeg_jpeg_finish(rjpeg_jpeg *z)
{
   int i,j,n;

   if (!z-&gt;progressive)
      return;

   /* dequantize and IDCT the data */
   for (n = 0; n &lt; z-&gt;s-&gt;img_n; ++n)
   {
      int w = (z-&gt;img_comp[n].x+7) &gt;&gt; 3;
      int h = (z-&gt;img_comp[n].y+7) &gt;&gt; 3;
      for (j = 0; j &lt; h; ++j)
      {
         for (i = 0; i &lt; w; ++i)
         {
            short *data = z-&gt;img_comp[n].coeff + 64 * (i + j * z-&gt;img_comp[n].coeff_w);
            rjpeg_jpeg_dequantize(data, z-&gt;dequant[z-&gt;img_comp[n].tq]);
            z-&gt;idct_block_kernel(z-&gt;img_comp[n].data+z-&gt;img_comp[n].w2*j*8+i*8,
                  z-&gt;img_comp[n].w2, data);
         }
      }
   }
}

static int rjpeg_process_marker(rjpeg_jpeg *z, int m)
{
   int L;
   switch (m)
   {
      case RJPEG_MARKER_NONE: /* no marker found */
         /* Expected marker. Corrupt JPEG? */
         return 0;

      case 0xDD: /* DRI - specify restart interval */

         /* Bad DRI length. Corrupt JPEG? */
         if (RJPEG_GET16BE(z-&gt;s) != 4)
            return 0;

         z-&gt;restart_interval = RJPEG_GET16BE(z-&gt;s);
         return 1;

      case 0xDB: /* DQT - define quantization table */
         L = RJPEG_GET16BE(z-&gt;s)-2;
         while (L &gt; 0)
         {
            int q = rjpeg_get8(z-&gt;s);
            int p = q &gt;&gt; 4;
            int t = q &amp; 15,i;

            /* Bad DQT type. Corrupt JPEG? */
            if (p != 0)
               return 0;

            /* Bad DQT table. Corrupt JPEG? */
            if (t &gt; 3)
               return 0;

            for (i = 0; i &lt; 64; ++i)
               z-&gt;dequant[t][rjpeg_jpeg_dezigzag[i]] = rjpeg_get8(z-&gt;s);
            L -= 65;
         }
         return L == 0;

      case 0xC4: /* DHT - define huffman table */
         L = RJPEG_GET16BE(z-&gt;s)-2;
         while (L &gt; 0)
         {
            int sizes[16],i,n = 0;
            uint8_t *v = NULL;
            int q      = rjpeg_get8(z-&gt;s);
            int tc     = q &gt;&gt; 4;
            int th     = q &amp; 15;

            /* Bad DHT header. Corrupt JPEG? */
            if (tc &gt; 1 || th &gt; 3)
               return 0;

            for (i = 0; i &lt; 16; ++i)
            {
               sizes[i] = rjpeg_get8(z-&gt;s);
               n += sizes[i];
            }
            L -= 17;

            if (tc == 0)
            {
               if (!rjpeg_build_huffman(z-&gt;huff_dc+th, sizes))
                  return 0;
               v = z-&gt;huff_dc[th].values;
            }
            else
            {
               if (!rjpeg_build_huffman(z-&gt;huff_ac+th, sizes))
                  return 0;
               v = z-&gt;huff_ac[th].values;
            }
            for (i = 0; i &lt; n; ++i)
               v[i] = rjpeg_get8(z-&gt;s);
            if (tc != 0)
               rjpeg_build_fast_ac(z-&gt;fast_ac[th], z-&gt;huff_ac + th);
            L -= n;
         }
         return L == 0;
   }

   /* check for comment block or APP blocks */
   if ((m &gt;= 0xE0 &amp;&amp; m &lt;= 0xEF) || m == 0xFE)
   {
      int n = RJPEG_GET16BE(z-&gt;s)-2;

      if (n &lt; 0)
         z-&gt;s-&gt;img_buffer = z-&gt;s-&gt;img_buffer_end;
      else
         z-&gt;s-&gt;img_buffer += n;

      return 1;
   }
   return 0;
}

/* after we see SOS */
static int rjpeg_process_scan_header(rjpeg_jpeg *z)
{
   int i;
   int aa;
   int Ls    = RJPEG_GET16BE(z-&gt;s);

   z-&gt;scan_n = rjpeg_get8(z-&gt;s);

   /* Bad SOS component count. Corrupt JPEG? */
   if (z-&gt;scan_n &lt; 1 || z-&gt;scan_n &gt; 4 || z-&gt;scan_n &gt; (int) z-&gt;s-&gt;img_n)
      return 0;

   /* Bad SOS length. Corrupt JPEG? */
   if (Ls != 6+2*z-&gt;scan_n)
      return 0;

   for (i = 0; i &lt; z-&gt;scan_n; ++i)
   {
      int which;
      int id = rjpeg_get8(z-&gt;s);
      int q  = rjpeg_get8(z-&gt;s);

      for (which = 0; which &lt; z-&gt;s-&gt;img_n; ++which)
         if (z-&gt;img_comp[which].id == id)
            break;
      if (which == z-&gt;s-&gt;img_n)
         return 0; /* no match */

      /* Bad DC huff. Corrupt JPEG? */
      z-&gt;img_comp[which].hd = q &gt;&gt; 4;   if (z-&gt;img_comp[which].hd &gt; 3)
         return 0;

      /* Bad AC huff. Corrupt JPEG? */
      z-&gt;img_comp[which].ha = q &amp; 15;   if (z-&gt;img_comp[which].ha &gt; 3)
         return 0;

      z-&gt;order[i] = which;
   }

   z-&gt;spec_start = rjpeg_get8(z-&gt;s);
   z-&gt;spec_end   = rjpeg_get8(z-&gt;s); /* should be 63, but might be 0 */
   aa            = rjpeg_get8(z-&gt;s);
   z-&gt;succ_high  = (aa &gt;&gt; 4);
   z-&gt;succ_low   = (aa &amp; 15);

   if (z-&gt;progressive)
   {
      /* Bad SOS. Corrupt JPEG? */
      if (  z-&gt;spec_start &gt; 63 ||
            z-&gt;spec_end &gt; 63   ||
            z-&gt;spec_start &gt; z-&gt;spec_end ||
            z-&gt;succ_high &gt; 13           ||
            z-&gt;succ_low &gt; 13)
         return 0;
   }
   else
   {
      /* Bad SOS. Corrupt JPEG? */
      if (z-&gt;spec_start != 0)
         return 0;
      if (z-&gt;succ_high != 0 || z-&gt;succ_low != 0)
         return 0;

      z-&gt;spec_end = 63;
   }

   return 1;
}

static int rjpeg_process_frame_header(rjpeg_jpeg *z, int scan)
{
   rjpeg_context *s = z-&gt;s;
   int Lf,p,i,q, h_max=1,v_max=1,c;
   Lf = RJPEG_GET16BE(s);

   /* JPEG */

   /* Bad SOF len. Corrupt JPEG? */
   if (Lf &lt; 11)
      return 0;

   p  = rjpeg_get8(s);

   /* JPEG baseline */

   /* Only 8-bit. JPEG format not supported? */
   if (p != 8)
      return 0;

   s-&gt;img_y = RJPEG_GET16BE(s);

   /* Legal, but we don't handle it--but neither does IJG */

   /* No header height, JPEG format not supported? */
   if (s-&gt;img_y == 0)
      return 0;

   s-&gt;img_x = RJPEG_GET16BE(s);

   /* No header width. Corrupt JPEG? */
   if (s-&gt;img_x == 0)
      return 0;

   c = rjpeg_get8(s);

   /* JFIF requires */

   /* Bad component count. Corrupt JPEG? */
   if (c != 3 &amp;&amp; c != 1)
      return 0;

   s-&gt;img_n = c;

   for (i = 0; i &lt; c; ++i)
   {
      z-&gt;img_comp[i].data = NULL;
      z-&gt;img_comp[i].linebuf = NULL;
   }

   /* Bad SOF length. Corrupt JPEG? */
   if (Lf != 8+3*s-&gt;img_n)
      return 0;

   for (i = 0; i &lt; s-&gt;img_n; ++i)
   {
      z-&gt;img_comp[i].id = rjpeg_get8(s);
      if (z-&gt;img_comp[i].id != i+1)   /* JFIF requires */
         if (z-&gt;img_comp[i].id != i)  /* some version of jpegtran outputs non-JFIF-compliant files! */
            return 0;

      q                = rjpeg_get8(s);
      z-&gt;img_comp[i].h = (q &gt;&gt; 4);

      /* Bad H. Corrupt JPEG? */
      if (!z-&gt;img_comp[i].h || z-&gt;img_comp[i].h &gt; 4)
         return 0;

      z-&gt;img_comp[i].v = q &amp; 15;

      /* Bad V. Corrupt JPEG? */
      if (!z-&gt;img_comp[i].v || z-&gt;img_comp[i].v &gt; 4)
         return 0;

      z-&gt;img_comp[i].tq = rjpeg_get8(s);

      /* Bad TQ. Corrupt JPEG? */
      if (z-&gt;img_comp[i].tq &gt; 3)
         return 0;
   }

   if (scan != RJPEG_SCAN_LOAD)
      return 1;

   /* Image too large to decode? */
   if ((1 &lt;&lt; 30) / s-&gt;img_x / s-&gt;img_n &lt; s-&gt;img_y)
      return 0;

   for (i = 0; i &lt; s-&gt;img_n; ++i)
   {
      if (z-&gt;img_comp[i].h &gt; h_max)
         h_max = z-&gt;img_comp[i].h;
      if (z-&gt;img_comp[i].v &gt; v_max)
         v_max = z-&gt;img_comp[i].v;
   }

   /* compute interleaved MCU info */
   z-&gt;img_h_max = h_max;
   z-&gt;img_v_max = v_max;
   z-&gt;img_mcu_w = h_max * 8;
   z-&gt;img_mcu_h = v_max * 8;
   z-&gt;img_mcu_x = (s-&gt;img_x + z-&gt;img_mcu_w-1) / z-&gt;img_mcu_w;
   z-&gt;img_mcu_y = (s-&gt;img_y + z-&gt;img_mcu_h-1) / z-&gt;img_mcu_h;

   if (z-&gt;progressive)
   {
      for (i = 0; i &lt; s-&gt;img_n; ++i)
      {
         /* number of effective pixels (e.g. for non-interleaved MCU) */
         z-&gt;img_comp[i].x        = (s-&gt;img_x * z-&gt;img_comp[i].h + h_max-1) / h_max;
         z-&gt;img_comp[i].y        = (s-&gt;img_y * z-&gt;img_comp[i].v + v_max-1) / v_max;

         /* to simplify generation, we'll allocate enough memory to decode
          * the bogus oversized data from using interleaved MCUs and their
          * big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
          * discard the extra data until colorspace conversion */
         z-&gt;img_comp[i].w2       = z-&gt;img_mcu_x * z-&gt;img_comp[i].h * 8;
         z-&gt;img_comp[i].h2       = z-&gt;img_mcu_y * z-&gt;img_comp[i].v * 8;
         z-&gt;img_comp[i].raw_data = malloc(z-&gt;img_comp[i].w2 * z-&gt;img_comp[i].h2+15);

         /* Out of memory? */
         if (!z-&gt;img_comp[i].raw_data)
         {
            for (--i; i &gt;= 0; --i)
            {
               free(z-&gt;img_comp[i].raw_data);
               z-&gt;img_comp[i].data = NULL;
            }

            return 0;
         }

         /* align blocks for IDCT using MMX/SSE */
         z-&gt;img_comp[i].data      = (uint8_t*) (((size_t) z-&gt;img_comp[i].raw_data + 15) &amp; ~15);
         z-&gt;img_comp[i].linebuf   = NULL;
         z-&gt;img_comp[i].coeff_w   = (z-&gt;img_comp[i].w2 + 7) &gt;&gt; 3;
         z-&gt;img_comp[i].coeff_h   = (z-&gt;img_comp[i].h2 + 7) &gt;&gt; 3;
         z-&gt;img_comp[i].raw_coeff = malloc(z-&gt;img_comp[i].coeff_w *
                                    z-&gt;img_comp[i].coeff_h * 64 * sizeof(short) + 15);
         z-&gt;img_comp[i].coeff     = (short*) (((size_t) z-&gt;img_comp[i].raw_coeff + 15) &amp; ~15);
      }
   }
   else
   {
      for (i = 0; i &lt; s-&gt;img_n; ++i)
      {
         /* number of effective pixels (e.g. for non-interleaved MCU) */
         z-&gt;img_comp[i].x        = (s-&gt;img_x * z-&gt;img_comp[i].h + h_max-1) / h_max;
         z-&gt;img_comp[i].y        = (s-&gt;img_y * z-&gt;img_comp[i].v + v_max-1) / v_max;

         /* to simplify generation, we'll allocate enough memory to decode
          * the bogus oversized data from using interleaved MCUs and their
          * big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
          * discard the extra data until colorspace conversion */
         z-&gt;img_comp[i].w2       = z-&gt;img_mcu_x * z-&gt;img_comp[i].h * 8;
         z-&gt;img_comp[i].h2       = z-&gt;img_mcu_y * z-&gt;img_comp[i].v * 8;
         z-&gt;img_comp[i].raw_data = malloc(z-&gt;img_comp[i].w2 * z-&gt;img_comp[i].h2+15);

         /* Out of memory? */
         if (!z-&gt;img_comp[i].raw_data)
         {
            for (--i; i &gt;= 0; --i)
            {
               free(z-&gt;img_comp[i].raw_data);
               z-&gt;img_comp[i].data = NULL;
            }
         }

         /* align blocks for IDCT using MMX/SSE */
         z-&gt;img_comp[i].data      = (uint8_t*) (((size_t) z-&gt;img_comp[i].raw_data + 15) &amp; ~15);
         z-&gt;img_comp[i].linebuf   = NULL;
         z-&gt;img_comp[i].coeff     = 0;
         z-&gt;img_comp[i].raw_coeff = 0;
      }
   }

   return 1;
}

static int rjpeg_decode_jpeg_header(rjpeg_jpeg *z, int scan)
{
   int m;
   z-&gt;marker = RJPEG_MARKER_NONE; /* initialize cached marker to empty */
   m         = rjpeg_get_marker(z);

   /* No SOI. Corrupt JPEG? */
   if (m != JPEG_MARKER_SOI)
      return 0;

   if (scan == RJPEG_SCAN_TYPE)
      return 1;

   m = rjpeg_get_marker(z);
   while (!RJPEG_SOF(m))
   {
      if (!rjpeg_process_marker(z,m))
         return 0;
      m = rjpeg_get_marker(z);
      while (m == RJPEG_MARKER_NONE)
      {
         /* some files have extra padding after their blocks, so ok, we'll scan */

         /* No SOF. Corrupt JPEG? */
         if (RJPEG_AT_EOF(z-&gt;s))
            return 0;

         m = rjpeg_get_marker(z);
      }
   }
   z-&gt;progressive = RJPEG_SOF_PROGRESSIVE(m);
   if (!rjpeg_process_frame_header(z, scan))
      return 0;
   return 1;
}

/* decode image to YCbCr format */
static int rjpeg_decode_jpeg_image(rjpeg_jpeg *j)
{
   int m;
   for (m = 0; m &lt; 4; m++)
   {
      j-&gt;img_comp[m].raw_data = NULL;
      j-&gt;img_comp[m].raw_coeff = NULL;
   }
   j-&gt;restart_interval = 0;
   if (!rjpeg_decode_jpeg_header(j, RJPEG_SCAN_LOAD))
      return 0;
   m = rjpeg_get_marker(j);

   while (m != JPEG_MARKER_EOI)
   {
      if (m == JPEG_MARKER_SOS)
      {
         if (!rjpeg_process_scan_header(j))
            return 0;
         if (!rjpeg_parse_entropy_coded_data(j))
            return 0;

         if (j-&gt;marker == RJPEG_MARKER_NONE )
         {
            /* handle 0s at the end of image data from IP Kamera 9060 */

            while (!RJPEG_AT_EOF(j-&gt;s))
            {
               int x = rjpeg_get8(j-&gt;s);
               if (x == 255)
               {
                  j-&gt;marker = rjpeg_get8(j-&gt;s);
                  break;
               }
               else if (x != 0) /* Junk before marker. Corrupt JPEG? */
                  return 0;
            }

            /* if we reach eof without hitting a marker,
             * rjpeg_get_marker() below will fail and we'll eventually return 0 */
         }
      }
      else
      {
         if (!rjpeg_process_marker(j, m))
            return 0;
      }
      m = rjpeg_get_marker(j);
   }

   if (j-&gt;progressive)
      rjpeg_jpeg_finish(j);
   return 1;
}

/* static jfif-centered resampling (across block boundaries) */

static uint8_t *rjpeg_resample_row_1(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   (void)out;
   (void)in_far;
   (void)w;
   (void)hs;
   return in_near;
}

static uint8_t* rjpeg_resample_row_v_2(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate two samples vertically for every one in input */
   int i;
   (void)hs;
   for (i = 0; i &lt; w; ++i)
      out[i] = RJPEG_DIV4(3*in_near[i] + in_far[i] + 2);
   return out;
}

static uint8_t*  rjpeg_resample_row_h_2(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate two samples horizontally for every one in input */
   int i;
   uint8_t *input = in_near;

   if (w == 1)
   {
      /* if only one sample, can't do any interpolation */
      out[0] = out[1] = input[0];
      return out;
   }

   out[0] = input[0];
   out[1] = RJPEG_DIV4(input[0]*3 + input[1] + 2);

   for (i=1; i &lt; w-1; ++i)
   {
      int n      = 3 * input[i] + 2;
      out[i*2+0] = RJPEG_DIV4(n+input[i-1]);
      out[i*2+1] = RJPEG_DIV4(n+input[i+1]);
   }
   out[i*2+0] = RJPEG_DIV4(input[w-2]*3 + input[w-1] + 2);
   out[i*2+1] = input[w-1];

   (void)in_far;
   (void)hs;

   return out;
}

static uint8_t *rjpeg_resample_row_hv_2(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate 2x2 samples for every one in input */
   int i,t0,t1;
   if (w == 1)
   {
      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);
      return out;
   }

   t1     = 3*in_near[0] + in_far[0];
   out[0] = RJPEG_DIV4(t1+2);

   for (i = 1; i &lt; w; ++i)
   {
      t0         = t1;
      t1         = 3*in_near[i]+in_far[i];
      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);
      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);
   }
   out[w*2-1] = RJPEG_DIV4(t1+2);

   (void)hs;

   return out;
}

#if defined(__SSE2__) || defined(RJPEG_NEON)
static uint8_t *rjpeg_resample_row_hv_2_simd(uint8_t *out, uint8_t *in_near,
      uint8_t *in_far, int w, int hs)
{
   /* need to generate 2x2 samples for every one in input */
   int i = 0,t0,t1;

   if (w == 1)
   {
      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);
      return out;
   }

   t1 = 3*in_near[0] + in_far[0];
   /* process groups of 8 pixels for as long as we can.
    * note we can't handle the last pixel in a row in this loop
    * because we need to handle the filter boundary conditions.
    */
   for (; i &lt; ((w-1) &amp; ~7); i += 8)
   {
#if defined(__SSE2__)
      /* load and perform the vertical filtering pass
       * this uses 3*x + y = 4*x + (y - x) */
      __m128i zero  = _mm_setzero_si128();
      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
      __m128i diff  = _mm_sub_epi16(farw, nearw);
      __m128i nears = _mm_slli_epi16(nearw, 2);
      __m128i curr  = _mm_add_epi16(nears, diff); /* current row */

      /* horizontal filter works the same based on shifted vers of current
       * row. "prev" is current row shifted right by 1 pixel; we need to
       * insert the previous pixel value (from t1).
       * "next" is current row shifted left by 1 pixel, with first pixel
       * of next block of 8 pixels added in.
       */
      __m128i prv0 = _mm_slli_si128(curr, 2);
      __m128i nxt0 = _mm_srli_si128(curr, 2);
      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);

      /* horizontal filter, polyphase implementation since it's convenient:
       * even pixels = 3*cur + prev = cur*4 + (prev - cur)
       * odd  pixels = 3*cur + next = cur*4 + (next - cur)
       * note the shared term. */
      __m128i bias = _mm_set1_epi16(8);
      __m128i curs = _mm_slli_epi16(curr, 2);
      __m128i prvd = _mm_sub_epi16(prev, curr);
      __m128i nxtd = _mm_sub_epi16(next, curr);
      __m128i curb = _mm_add_epi16(curs, bias);
      __m128i even = _mm_add_epi16(prvd, curb);
      __m128i odd  = _mm_add_epi16(nxtd, curb);

      /* interleave even and odd pixels, then undo scaling. */
      __m128i int0 = _mm_unpacklo_epi16(even, odd);
      __m128i int1 = _mm_unpackhi_epi16(even, odd);
      __m128i de0  = _mm_srli_epi16(int0, 4);
      __m128i de1  = _mm_srli_epi16(int1, 4);

      /* pack and write output */
      __m128i outv = _mm_packus_epi16(de0, de1);
      _mm_storeu_si128((__m128i *) (out + i*2), outv);
#elif defined(RJPEG_NEON)
      /* load and perform the vertical filtering pass
       * this uses 3*x + y = 4*x + (y - x) */
      uint8x8_t farb  = vld1_u8(in_far + i);
      uint8x8_t nearb = vld1_u8(in_near + i);
      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
      int16x8_t curr  = vaddq_s16(nears, diff); /* current row */

      /* horizontal filter works the same based on shifted vers of current
       * row. "prev" is current row shifted right by 1 pixel; we need to
       * insert the previous pixel value (from t1).
       * "next" is current row shifted left by 1 pixel, with first pixel
       * of next block of 8 pixels added in. */
      int16x8_t prv0 = vextq_s16(curr, curr, 7);
      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);

      /* horizontal filter, polyphase implementation since it's convenient:
       * even pixels = 3*cur + prev = cur*4 + (prev - cur)
       * odd  pixels = 3*cur + next = cur*4 + (next - cur)
       * note the shared term.
       */
      int16x8_t curs = vshlq_n_s16(curr, 2);
      int16x8_t prvd = vsubq_s16(prev, curr);
      int16x8_t nxtd = vsubq_s16(next, curr);
      int16x8_t even = vaddq_s16(curs, prvd);
      int16x8_t odd  = vaddq_s16(curs, nxtd);

      /* undo scaling and round, then store with even/odd phases interleaved */
      uint8x8x2_t o;
      o.val[0] = vqrshrun_n_s16(even, 4);
      o.val[1] = vqrshrun_n_s16(odd,  4);
      vst2_u8(out + i*2, o);
#endif

      /* "previous" value for next iteration */
      t1 = 3*in_near[i+7] + in_far[i+7];
   }

   t0       = t1;
   t1       = 3*in_near[i] + in_far[i];
   out[i*2] = RJPEG_DIV16(3*t1 + t0 + 8);

   for (++i; i &lt; w; ++i)
   {
      t0         = t1;
      t1         = 3*in_near[i]+in_far[i];
      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);
      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);
   }
   out[w*2-1]    = RJPEG_DIV4(t1+2);

   (void)hs;

   return out;
}
#endif

static uint8_t *rjpeg_resample_row_generic(uint8_t *out,
      uint8_t *in_near, uint8_t *in_far, int w, int hs)
{
   /* resample with nearest-neighbor */
   int i,j;
   (void)in_far;

   for (i = 0; i &lt; w; ++i)
      for (j = 0; j &lt; hs; ++j)
         out[i*hs+j] = in_near[i];
   return out;
}

/* this is a reduced-precision calculation of YCbCr-to-RGB introduced
 * to make sure the code produces the same results in both SIMD and scalar */
#ifndef FLOAT2FIXED
#define FLOAT2FIXED(x)  (((int) ((x) * 4096.0f + 0.5f)) &lt;&lt; 8)
#endif

static void rjpeg_YCbCr_to_RGB_row(uint8_t *out, const uint8_t *y,
      const uint8_t *pcb, const uint8_t *pcr, int count, int step)
{
   int i;
   for (i = 0; i &lt; count; ++i)
   {
      int y_fixed = (y[i] &lt;&lt; 20) + (1&lt;&lt;19); /* rounding */
      int cr = pcr[i] - 128;
      int cb = pcb[i] - 128;
      int r = y_fixed +  cr* FLOAT2FIXED(1.40200f);
      int g = y_fixed + (cr*-FLOAT2FIXED(0.71414f)) + ((cb*-FLOAT2FIXED(0.34414f)) &amp; 0xffff0000);
      int b = y_fixed                               +   cb* FLOAT2FIXED(1.77200f);
      r &gt;&gt;= 20;
      g &gt;&gt;= 20;
      b &gt;&gt;= 20;
      if ((unsigned) r &gt; 255)
         r = 255;
      if ((unsigned) g &gt; 255)
         g = 255;
      if ((unsigned) b &gt; 255)
         b = 255;
      out[0] = (uint8_t)r;
      out[1] = (uint8_t)g;
      out[2] = (uint8_t)b;
      out[3] = 255;
      out += step;
   }
}

#if defined(__SSE2__) || defined(RJPEG_NEON)
static void rjpeg_YCbCr_to_RGB_simd(uint8_t *out, const uint8_t *y,
      const uint8_t *pcb, const uint8_t *pcr, int count, int step)
{
   int i = 0;

#if defined(__SSE2__)
   /* step == 3 is pretty ugly on the final interleave, and i'm not convinced
    * it's useful in practice (you wouldn't use it for textures, for example).
    * so just accelerate step == 4 case.
    */
   if (step == 4)
   {
      /* this is a fairly straightforward implementation and not super-optimized. */
      __m128i signflip  = _mm_set1_epi8(-0x80);
      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
      __m128i y_bias    = _mm_set1_epi8((char) (unsigned char) 128);
      __m128i xw        = _mm_set1_epi16(255); /* alpha channel */

      for (; i+7 &lt; count; i += 8)
      {
         /* load */
         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); /* -128 */
         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); /* -128 */

         /* unpack to short (and left-shift cr, cb by 8) */
         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);

         /* color transform */
         __m128i yws = _mm_srli_epi16(yw, 4);
         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
         __m128i rws = _mm_add_epi16(cr0, yws);
         __m128i gwt = _mm_add_epi16(cb0, yws);
         __m128i bws = _mm_add_epi16(yws, cb1);
         __m128i gws = _mm_add_epi16(gwt, cr1);

         /* descale */
         __m128i rw = _mm_srai_epi16(rws, 4);
         __m128i bw = _mm_srai_epi16(bws, 4);
         __m128i gw = _mm_srai_epi16(gws, 4);

         /* back to byte, set up for transpose */
         __m128i brb = _mm_packus_epi16(rw, bw);
         __m128i gxb = _mm_packus_epi16(gw, xw);

         /* transpose to interleave channels */
         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
         __m128i o1 = _mm_unpackhi_epi16(t0, t1);

         /* store */
         _mm_storeu_si128((__m128i *) (out + 0), o0);
         _mm_storeu_si128((__m128i *) (out + 16), o1);
         out += 32;
      }
   }
#endif

#ifdef RJPEG_NEON
   /* in this version, step=3 support would be easy to add. but is there demand? */
   if (step == 4)
   {
      /* this is a fairly straightforward implementation and not super-optimized. */
      uint8x8_t signflip = vdup_n_u8(0x80);
      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));

      for (; i+7 &lt; count; i += 8)
      {
         uint8x8x4_t o;

         /* load */
         uint8x8_t y_bytes  = vld1_u8(y + i);
         uint8x8_t cr_bytes = vld1_u8(pcr + i);
         uint8x8_t cb_bytes = vld1_u8(pcb + i);
         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));

         /* expand to s16 */
         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
         int16x8_t crw = vshll_n_s8(cr_biased, 7);
         int16x8_t cbw = vshll_n_s8(cb_biased, 7);

         /* color transform */
         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
         int16x8_t rws = vaddq_s16(yws, cr0);
         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
         int16x8_t bws = vaddq_s16(yws, cb1);

         /* undo scaling, round, convert to byte */
         o.val[0] = vqrshrun_n_s16(rws, 4);
         o.val[1] = vqrshrun_n_s16(gws, 4);
         o.val[2] = vqrshrun_n_s16(bws, 4);
         o.val[3] = vdup_n_u8(255);

         /* store, interleaving r/g/b/a */
         vst4_u8(out, o);
         out += 8*4;
      }
   }
#endif

   for (; i &lt; count; ++i)
   {
      int y_fixed = (y[i] &lt;&lt; 20) + (1&lt;&lt;19); /* rounding */
      int cr      = pcr[i] - 128;
      int cb      = pcb[i] - 128;
      int r       = y_fixed + cr* FLOAT2FIXED(1.40200f);
      int g       = y_fixed + cr*-FLOAT2FIXED(0.71414f) + ((cb*-FLOAT2FIXED(0.34414f)) &amp; 0xffff0000);
      int b       = y_fixed                             +   cb* FLOAT2FIXED(1.77200f);
      r &gt;&gt;= 20;
      g &gt;&gt;= 20;
      b &gt;&gt;= 20;
      if ((unsigned) r &gt; 255)
         r = 255;
      if ((unsigned) g &gt; 255)
         g = 255;
      if ((unsigned) b &gt; 255)
         b = 255;
      out[0] = (uint8_t)r;
      out[1] = (uint8_t)g;
      out[2] = (uint8_t)b;
      out[3] = 255;
      out += step;
   }
}
#endif

/* set up the kernels */
static void rjpeg_setup_jpeg(rjpeg_jpeg *j)
{
   uint64_t mask = cpu_features_get();

   (void)mask;

   j-&gt;idct_block_kernel        = rjpeg_idct_block;
   j-&gt;YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_row;
   j-&gt;resample_row_hv_2_kernel = rjpeg_resample_row_hv_2;

#if defined(__SSE2__)
   if (mask &amp; RETRO_SIMD_SSE2)
   {
      j-&gt;idct_block_kernel        = rjpeg_idct_simd;
      j-&gt;YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_simd;
      j-&gt;resample_row_hv_2_kernel = rjpeg_resample_row_hv_2_simd;
   }
#endif

#ifdef RJPEG_NEON
   j-&gt;idct_block_kernel           = rjpeg_idct_simd;
   j-&gt;YCbCr_to_RGB_kernel         = rjpeg_YCbCr_to_RGB_simd;
   j-&gt;resample_row_hv_2_kernel    = rjpeg_resample_row_hv_2_simd;
#endif
}

/* clean up the temporary component buffers */
static void rjpeg_cleanup_jpeg(rjpeg_jpeg *j)
{
   int i;
   for (i = 0; i &lt; j-&gt;s-&gt;img_n; ++i)
   {
      if (j-&gt;img_comp[i].raw_data)
      {
         free(j-&gt;img_comp[i].raw_data);
         j-&gt;img_comp[i].raw_data = NULL;
         j-&gt;img_comp[i].data = NULL;
      }

      if (j-&gt;img_comp[i].raw_coeff)
      {
         free(j-&gt;img_comp[i].raw_coeff);
         j-&gt;img_comp[i].raw_coeff = 0;
         j-&gt;img_comp[i].coeff = 0;
      }

      if (j-&gt;img_comp[i].linebuf)
      {
         free(j-&gt;img_comp[i].linebuf);
         j-&gt;img_comp[i].linebuf = NULL;
      }
   }
}

static uint8_t *rjpeg_load_jpeg_image(rjpeg_jpeg *z,
      unsigned *out_x, unsigned *out_y, int *comp, int req_comp)
{
   int n, decode_n;
   int k;
   unsigned int i,j;
   rjpeg_resample res_comp[4];
   uint8_t *coutput[4] = {0};
   uint8_t *output     = NULL;
   z-&gt;s-&gt;img_n         = 0;

   /* load a jpeg image from whichever source, but leave in YCbCr format */
   if (!rjpeg_decode_jpeg_image(z))
      goto error;

   /* determine actual number of components to generate */
   n = req_comp ? req_comp : z-&gt;s-&gt;img_n;

   if (z-&gt;s-&gt;img_n == 3 &amp;&amp; n &lt; 3)
      decode_n = 1;
   else
      decode_n = z-&gt;s-&gt;img_n;

   /* resample and color-convert */
   for (k = 0; k &lt; decode_n; ++k)
   {
      rjpeg_resample *r = &amp;res_comp[k];

      /* allocate line buffer big enough for upsampling off the edges
       * with upsample factor of 4 */
      z-&gt;img_comp[k].linebuf = (uint8_t *) malloc(z-&gt;s-&gt;img_x + 3);
      if (!z-&gt;img_comp[k].linebuf)
         goto error;

      r-&gt;hs       = z-&gt;img_h_max / z-&gt;img_comp[k].h;
      r-&gt;vs       = z-&gt;img_v_max / z-&gt;img_comp[k].v;
      r-&gt;ystep    = r-&gt;vs &gt;&gt; 1;
      r-&gt;w_lores  = (z-&gt;s-&gt;img_x + r-&gt;hs-1) / r-&gt;hs;
      r-&gt;ypos     = 0;
      r-&gt;line0    = r-&gt;line1 = z-&gt;img_comp[k].data;
      r-&gt;resample = rjpeg_resample_row_generic;

      if      (r-&gt;hs == 1 &amp;&amp; r-&gt;vs == 1)
         r-&gt;resample = rjpeg_resample_row_1;
      else if (r-&gt;hs == 1 &amp;&amp; r-&gt;vs == 2)
         r-&gt;resample = rjpeg_resample_row_v_2;
      else if (r-&gt;hs == 2 &amp;&amp; r-&gt;vs == 1)
         r-&gt;resample = rjpeg_resample_row_h_2;
      else if (r-&gt;hs == 2 &amp;&amp; r-&gt;vs == 2)
         r-&gt;resample = z-&gt;resample_row_hv_2_kernel;
   }

   /* can't error after this so, this is safe */
   output = (uint8_t *) malloc(n * z-&gt;s-&gt;img_x * z-&gt;s-&gt;img_y + 1);

   if (!output)
      goto error;

   /* now go ahead and resample */
   for (j = 0; j &lt; z-&gt;s-&gt;img_y; ++j)
   {
      uint8_t *out = output + n * z-&gt;s-&gt;img_x * j;
      for (k = 0; k &lt; decode_n; ++k)
      {
         rjpeg_resample *r = &amp;res_comp[k];
         int         y_bot  = r-&gt;ystep &gt;= (r-&gt;vs &gt;&gt; 1);

         coutput[k]         = r-&gt;resample(z-&gt;img_comp[k].linebuf,
               y_bot ? r-&gt;line1 : r-&gt;line0,
               y_bot ? r-&gt;line0 : r-&gt;line1,
               r-&gt;w_lores, r-&gt;hs);

         if (++r-&gt;ystep &gt;= r-&gt;vs)
         {
            r-&gt;ystep = 0;
            r-&gt;line0 = r-&gt;line1;
            if (++r-&gt;ypos &lt; z-&gt;img_comp[k].y)
               r-&gt;line1 += z-&gt;img_comp[k].w2;
         }
      }

      if (n &gt;= 3)
      {
         uint8_t *y = coutput[0];
         if (y)
         {
            if (z-&gt;s-&gt;img_n == 3)
               z-&gt;YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z-&gt;s-&gt;img_x, n);
            else
               for (i = 0; i &lt; z-&gt;s-&gt;img_x; ++i)
               {
                  out[0]  = out[1] = out[2] = y[i];
                  out[3]  = 255; /* not used if n==3 */
                  out    += n;
               }
         }
      }
      else
      {
         uint8_t *y = coutput[0];
         if (n == 1)
            for (i = 0; i &lt; z-&gt;s-&gt;img_x; ++i)
               out[i] = y[i];
         else
            for (i = 0; i &lt; z-&gt;s-&gt;img_x; ++i)
            {
               *out++ = y[i];
               *out++ = 255;
            }
      }
   }

   rjpeg_cleanup_jpeg(z);
   *out_x = z-&gt;s-&gt;img_x;
   *out_y = z-&gt;s-&gt;img_y;

   if (comp)
      *comp  = z-&gt;s-&gt;img_n; /* report original components, not output */
   return output;

error:
   rjpeg_cleanup_jpeg(z);
   return NULL;
}

int rjpeg_process_image(rjpeg_t *rjpeg, void **buf_data,
      size_t size, unsigned *width, unsigned *height)
{
   rjpeg_jpeg j;
   rjpeg_context s;
   int comp;
   uint32_t *img         = NULL;
   uint32_t *pixels      = NULL;
   unsigned size_tex     = 0;

   if (!rjpeg)
      return IMAGE_PROCESS_ERROR;

   s.img_buffer          = (uint8_t*)rjpeg-&gt;buff_data;
   s.img_buffer_original = (uint8_t*)rjpeg-&gt;buff_data;
   s.img_buffer_end      = (uint8_t*)rjpeg-&gt;buff_data + (int)size;

   j.s                   = &amp;s;

   rjpeg_setup_jpeg(&amp;j);

   img                   =  (uint32_t*)rjpeg_load_jpeg_image(&amp;j, width, height, &amp;comp, 4);

   if (!img)
      return IMAGE_PROCESS_ERROR;

   size_tex = (*width) * (*height);
   pixels   = (uint32_t*)malloc(size_tex * sizeof(uint32_t));

   if (!pixels)
   {
      free(img);
      return IMAGE_PROCESS_ERROR;
   }

   *buf_data = pixels;

   /* Convert RGBA to ARGB */
   while (size_tex--)
   {
      unsigned int texel = img[size_tex];
      unsigned int A     = texel &amp; 0xFF000000;
      unsigned int B     = texel &amp; 0x00FF0000;
      unsigned int G     = texel &amp; 0x0000FF00;
      unsigned int R     = texel &amp; 0x000000FF;
      ((unsigned int*)pixels)[size_tex] = A | (R &lt;&lt; 16) | G | (B &gt;&gt; 16);
   }

   free(img);

   return IMAGE_PROCESS_END;
}

bool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data)
{
   if (!rjpeg)
      return false;

   rjpeg-&gt;buff_data = (uint8_t*)data;

   return true;
}

void rjpeg_free(rjpeg_t *rjpeg)
{
   if (!rjpeg)
      return;

   free(rjpeg);
}

rjpeg_t *rjpeg_alloc(void)
{
   rjpeg_t *rjpeg = (rjpeg_t*)calloc(1, sizeof(*rjpeg));
   if (!rjpeg)
      return NULL;
   return rjpeg;
}</pre>
<h2>./include/libretro-common/formats/json/rjson.c</h2>
<pre>/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjson.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* The parser is based on Public Domain JSON Parser for C by Christopher Wellons - https://github.com/skeeto/pdjson */

#include &lt;stdio.h&gt;  /* snprintf, vsnprintf */
#include &lt;stdarg.h&gt; /* va_list */
#include &lt;string.h&gt; /* memcpy */
#include &lt;stdint.h&gt; /* int64_t */
#include &lt;stdlib.h&gt; /* malloc, realloc, atof, atoi */

#include &lt;formats/rjson.h&gt;
#include &lt;compat/posix_string.h&gt;
#include &lt;streams/interface_stream.h&gt;
#include &lt;streams/file_stream.h&gt;

struct _rjson_stack { enum rjson_type type; size_t count; };

struct rjson
{
   /* Order of the top few struct elements have an impact on performance */
   /* Place most frequently accessed things on top */
   const unsigned char *input_p;
   struct _rjson_stack *stack_top;
   const unsigned char *input_end;
   const unsigned char* source_column_p;
   size_t source_line;

   char *string, *string_pass_through;
   size_t string_len, string_cap;

   struct _rjson_stack inline_stack[10];
   struct _rjson_stack *stack;

   rjson_io_t io;
   void *user_data;

   unsigned int stack_cap, stack_max;
   int input_len;

   char option_flags;
   char decimal_sep;
   char error_text[80];
   char inline_string[512];

   /* Must be at the end of the struct, can be allocated with custom size */
   unsigned char input_buf[512];
};

enum _rjson_token
{
   _rJSON_TOK_WHITESPACE, _rJSON_TOK_NEWLINE, _rJSON_TOK_OPTIONAL_SKIP,
   _rJSON_TOK_OBJECT, _rJSON_TOK_ARRAY, _rJSON_TOK_STRING, _rJSON_TOK_NUMBER,
   _rJSON_TOK_TRUE, _rJSON_TOK_FALSE, _rJSON_TOK_NULL,
   _rJSON_TOK_OBJECT_END, _rJSON_TOK_ARRAY_END, _rJSON_TOK_COLON,
   _rJSON_TOK_COMMA, _rJSON_TOK_ERROR, _rJSON_TOK_EOF, _rJSON_TOKCOUNT
};

/* The used char type is int and not short for better performance */
typedef unsigned int _rjson_char_t;
#define _rJSON_EOF ((_rjson_char_t)256)

/* Compiler branching hint for expression with high probability
 * Explicitly only have likely (and no unlikely) because compilers
 * that don't support it expect likely branches to come first. */
#if defined(__GNUC__) || defined(__clang__)
#define _rJSON_LIKELY(x) __builtin_expect(!!(x), 1)
#else
#define _rJSON_LIKELY(x) (x)
#endif

/* These 3 error functions return RJSON_ERROR for convenience */
static enum rjson_type _rjson_error(rjson_t *json, const char *fmt, ...)
{
   va_list ap;
   if (json-&gt;stack_top-&gt;type == RJSON_ERROR)
      return RJSON_ERROR;
   json-&gt;stack_top-&gt;type = RJSON_ERROR;
   va_start(ap, fmt);
   vsnprintf(json-&gt;error_text, sizeof(json-&gt;error_text), fmt, ap);
   va_end(ap);
   return RJSON_ERROR;
}

static enum rjson_type _rjson_error_char(rjson_t *json,
      const char *fmt, _rjson_char_t chr)
{
   char buf[16];
   if (json-&gt;stack_top-&gt;type == RJSON_ERROR)
      return RJSON_ERROR;
   snprintf(buf, sizeof(buf),
         (chr == _rJSON_EOF ? "end of stream" :
         (chr &gt;= ' ' &amp;&amp; chr &lt;= '~' ? "'%c'" : "byte 0x%02X")), chr);
   return _rjson_error(json, fmt, buf);
}

static enum rjson_type _rjson_error_token(rjson_t *json,
   const char *fmt, enum _rjson_token tok)
{
   return _rjson_error_char(json, fmt,
         (tok == _rJSON_TOK_EOF ? _rJSON_EOF : json-&gt;input_p[-1]));
}

static bool _rjson_io_input(rjson_t *json)
{
   if (json-&gt;input_end == json-&gt;input_buf)
      return false;
   json-&gt;source_column_p -= (json-&gt;input_end - json-&gt;input_buf);
   json-&gt;input_p = json-&gt;input_buf;
   json-&gt;input_end = json-&gt;input_buf +
         json-&gt;io(json-&gt;input_buf, json-&gt;input_len, json-&gt;user_data);
   if (json-&gt;input_end &lt; json-&gt;input_buf)
   {
      _rjson_error(json, "input stream read error");
      json-&gt;input_end = json-&gt;input_buf;
   }
   return (json-&gt;input_end != json-&gt;input_p);
}

static bool _rjson_grow_string(rjson_t *json)
{
   char *string;
   size_t new_string_cap = json-&gt;string_cap * 2;
   if (json-&gt;string != json-&gt;inline_string)
      string             = (char*)realloc(json-&gt;string, new_string_cap);
   else if ((string      = (char*)malloc(new_string_cap)) != NULL)
      memcpy(string, json-&gt;inline_string, sizeof(json-&gt;inline_string));
   if (!string)
   {
      _rjson_error(json, "out of memory");
      return false;
   }
   json-&gt;string_cap      = new_string_cap;
   json-&gt;string          = string;
   return true;
}

static INLINE bool _rjson_pushchar(rjson_t *json, _rjson_char_t c)
{
   json-&gt;string[json-&gt;string_len++] = (char)c;
   return (json-&gt;string_len != json-&gt;string_cap || _rjson_grow_string(json));
}

static INLINE bool _rjson_pushchars(rjson_t *json,
      const unsigned char *from, const unsigned char *to)
{
   unsigned char* string;
   size_t _len    = json-&gt;string_len;
   size_t new_len = _len + (to - from);
   while (new_len &gt;= json-&gt;string_cap)
      if (!_rjson_grow_string(json))
         return false;
   string = (unsigned char *)json-&gt;string;
   while (_len != new_len)
      string[_len++] = *(from++);
   json-&gt;string_len = new_len;
   return true;
}

static INLINE _rjson_char_t _rjson_char_get(rjson_t *json)
{
   return (json-&gt;input_p != json-&gt;input_end || _rjson_io_input(json)
        ? *json-&gt;input_p++ : _rJSON_EOF);
}

static unsigned int _rjson_get_unicode_cp(rjson_t *json)
{
   unsigned int cp = 0, shift = 16;
   for (;;)
   {
      _rjson_char_t c = _rjson_char_get(json);
      switch (c)
      {
         case '0': case '1': case '2': case '3': case '4':
         case '5': case '6': case '7': case '8': case '9':
            c -= '0';
            break;
         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
            c -= ('a' - 10);
            break;
         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
            c -= ('A' - 10);
            break;
         case _rJSON_EOF:
            _rjson_error(json, "unterminated string literal in Unicode");
            return (unsigned int)-1;
         default:
            _rjson_error_char(json, "invalid Unicode escape hexadecimal %s", c);
            return (unsigned int)-1;
      }
      shift -= 4;
      cp |= ((unsigned int)c &lt;&lt; shift);
      if (!shift)
         return cp;
   }
}

static bool _rjson_read_unicode(rjson_t *json)
{
   #define _rJSON_READ_UNICODE_REPLACE_OR_IGNORE \
      if (json-&gt;option_flags &amp; (RJSON_OPTION_IGNORE_INVALID_ENCODING \
            | RJSON_OPTION_REPLACE_INVALID_ENCODING)) goto replace_or_ignore;

   unsigned int cp;

   if ((cp = _rjson_get_unicode_cp(json)) == (unsigned int)-1)
      return false;

   if (cp &gt;= 0xd800 &amp;&amp; cp &lt;= 0xdbff)
   {
      /* This is the high portion of a surrogate pair; we need to read the
       * lower portion to get the codepoint */
      unsigned int l, h = cp;

      _rjson_char_t c = _rjson_char_get(json);
      if (c == _rJSON_EOF)
      {
         _rjson_error(json, "unterminated string literal in Unicode");
         return false;
      }
      if (c != '\\')
      {
         _rjson_error_char(json, "invalid continuation %s"
               " for surrogate pair, expected '\\'", c);
         return false;
      }

      c = _rjson_char_get(json);
      if (c == _rJSON_EOF)
      {
         _rjson_error(json, "unterminated string literal in Unicode");
         return false;
      }
      if (c != 'u')
      {
         _rjson_error_char(json, "invalid continuation %s"
               " for surrogate pair, expected 'u'", c);
         return false;
      }
      if ((l = _rjson_get_unicode_cp(json)) == (unsigned int)-1)
         return false;
      if (l &lt; 0xdc00 || l &gt; 0xdfff)
      {
         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
         _rjson_error(json, "surrogate pair continuation \\u%04x out "
            "of range (dc00-dfff)", l);
         return false;
      }
      cp = ((h - 0xd800) * 0x400) + ((l - 0xdc00) + 0x10000);
   }
   else if (cp &gt;= 0xdc00 &amp;&amp; cp &lt;= 0xdfff)
   {
      _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
      _rjson_error(json, "dangling surrogate \\u%04x", cp);
      return false;
   }

   if (cp &lt; 0x80UL)
      return _rjson_pushchar(json, cp);

   if (cp &lt; 0x0800UL)
      return (_rjson_pushchar(json, (cp &gt;&gt; 6 &amp; 0x1F) | 0xC0) &amp;&amp;
              _rjson_pushchar(json, (cp &gt;&gt; 0 &amp; 0x3F) | 0x80));

   if (cp &lt; 0x010000UL)
   {
      if (cp &gt;= 0xd800 &amp;&amp; cp &lt;= 0xdfff)
      {
         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
         _rjson_error(json, "invalid codepoint %04x", cp);
         return false;
      }
      return (_rjson_pushchar(json, (cp &gt;&gt; 12 &amp; 0x0F) | 0xE0) &amp;&amp;
              _rjson_pushchar(json, (cp &gt;&gt;  6 &amp; 0x3F) | 0x80) &amp;&amp;
              _rjson_pushchar(json, (cp &gt;&gt;  0 &amp; 0x3F) | 0x80));
   }
   if (cp &lt; 0x110000UL)
      return (_rjson_pushchar(json, (cp &gt;&gt; 18 &amp; 0x07) | 0xF0) &amp;&amp;
              _rjson_pushchar(json, (cp &gt;&gt; 12 &amp; 0x3F) | 0x80) &amp;&amp;
              _rjson_pushchar(json, (cp &gt;&gt;  6 &amp; 0x3F) | 0x80) &amp;&amp;
              _rjson_pushchar(json, (cp &gt;&gt;  0 &amp; 0x3F) | 0x80));

   _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
   _rjson_error(json, "unable to encode %04x as UTF-8", cp);
   return false;

replace_or_ignore:
   return ((json-&gt;option_flags &amp; RJSON_OPTION_IGNORE_INVALID_ENCODING) ||
         _rjson_pushchar(json, '?'));
   #undef _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
}

static bool _rjson_validate_utf8(rjson_t *json)
{
   unsigned char first, c;
   unsigned char *p;
   unsigned char *from = (unsigned char *)
         (json-&gt;string_pass_through ? json-&gt;string_pass_through : json-&gt;string);
   unsigned char *to = from + json-&gt;string_len;

   if (json-&gt;option_flags &amp; RJSON_OPTION_IGNORE_INVALID_ENCODING)
      return true;

   for (;;)
   {
      if (from == to)
         return true;
      first = *from;
      if (first &lt;= 0x7F) /* ASCII */
      {
         from++;
         continue;
      }
      p = from;
      /* Continuation or overlong encoding of an ASCII byte */
      if (first &lt;= 0xC1)
         goto invalid_utf8;
      if (first &lt;= 0xDF)
      {
         if ((from = p + 2) &gt; to)
            goto invalid_utf8;
continue_length_2:
         c = p[1];
         switch (first)
         {
            case 0xE0:
               c = (c &lt; 0xA0 || c &gt; 0xBF);
               break;
            case 0xED:
               c = (c &lt; 0x80 || c &gt; 0x9F);
               break;
            case 0xF0:
               c = (c &lt; 0x90 || c &gt; 0xBF);
               break;
            case 0xF4:
               c = (c &lt; 0x80 || c &gt; 0x8F);
               break;
            default:
               c = (c &lt; 0x80 || c &gt; 0xBF);
               break;
         }
         if (c)
            goto invalid_utf8;
      }
      else if (first &lt;= 0xEF)
      {
         if ((from = p + 3) &gt; to)
            goto invalid_utf8;
continue_length_3:
         if ((c = p[2]) &lt; 0x80 || c &gt; 0xBF)
            goto invalid_utf8;
         goto continue_length_2;
      }
      else if (first &lt;= 0xF4)
      {
         if ((from = p + 4) &gt; to)
            goto invalid_utf8;
         if ((c = p[3]) &lt; 0x80 || c &gt; 0xBF)
            goto invalid_utf8;
         goto continue_length_3;
      }
      else
         goto invalid_utf8; /* length 5 or 6 or invalid UTF-8 */
      continue;
invalid_utf8:
      if (!(json-&gt;option_flags &amp; RJSON_OPTION_REPLACE_INVALID_ENCODING))
      {
         _rjson_error(json, "invalid UTF-8 character in string");
         return false;
      }
      from    = p;
      *from++ = '?';
      while (from != to &amp;&amp; (*from &amp; 0x80))
         *from++ = '?';
   }
}

static enum rjson_type _rjson_read_string(rjson_t *json)
{
   const unsigned char *p    = json-&gt;input_p, *raw = p;
   const unsigned char *end  = json-&gt;input_end;
   unsigned char utf8mask    = 0;
   json-&gt;string_pass_through = NULL;
   json-&gt;string_len          = 0;

   for (;;)
   {
      if (_rJSON_LIKELY(p != end))
      {
         unsigned char c = *p;
         if (_rJSON_LIKELY(c != '"' &amp;&amp; c != '\\' &amp;&amp; c &gt;= 0x20))
         {
            /* handle most common case first, it's faster */
            utf8mask |= c;
            p++;
         }
         else if (c == '"')
         {
            json-&gt;input_p = p + 1;
            if (json-&gt;string_len == 0 &amp;&amp; p + 1 != end)
            {
               /* raw string fully inside input buffer, pass through */
               json-&gt;string_len          = p - raw;
               json-&gt;string_pass_through = (char*)raw;
            }
            else if (raw != p &amp;&amp; !_rjson_pushchars(json, raw, p)) /* OOM */
               return RJSON_ERROR;
            /* Contains invalid UTF-8 byte sequences */
            if ((utf8mask &amp; 0x80) &amp;&amp; !_rjson_validate_utf8(json))
               return RJSON_ERROR;
            return RJSON_STRING;
         }
         else if (c == '\\')
         {
            _rjson_char_t esc;
            if (raw != p)
            {
               /* Can't pass through string with escapes, use string buffer */
               if (!_rjson_pushchars(json, raw, p))
                  return RJSON_ERROR;
            }
            json-&gt;input_p = p + 1;
            esc = _rjson_char_get(json);
            switch (esc)
            {
               case 'u':
                  if (!_rjson_read_unicode(json))
                     return RJSON_ERROR;
                  break;

               case 'b':
                  esc = '\b';
                  goto escape_pushchar;
               case 'f':
                  esc = '\f';
                  goto escape_pushchar;
               case 'n':
                  esc = '\n';
                  goto escape_pushchar;
               case 'r':
                  if (!(json-&gt;option_flags &amp; RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN))
                  {
                     esc = '\r';
                     goto escape_pushchar;
                  }
                  break;
               case 't':
                  esc = '\t';
                  goto escape_pushchar;
               case '/':
               case '"':
               case '\\':
escape_pushchar:
                  if (!_rjson_pushchar(json, esc))
                     return RJSON_ERROR;
                  break;

               case _rJSON_EOF:
                  return _rjson_error(json, "unterminated string literal in escape");

               default:
                  return _rjson_error_char(json, "invalid escaped %s", esc);
            }
            raw = p = json-&gt;input_p;
            end     = json-&gt;input_end;
         }
         else if (!(json-&gt;option_flags &amp; RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS))
            return _rjson_error_char(json, "unescaped control character %s in string", c);
         else
            p++;
      }
      else
      {
         if (raw != p)
         {
            /* not fully inside input buffer, copy to string buffer */
            if (!_rjson_pushchars(json, raw, p))
               return RJSON_ERROR;
         }
         if (!_rjson_io_input(json))
            return _rjson_error(json, "unterminated string literal");
         raw = p = json-&gt;input_p;
         end     = json-&gt;input_end;
      }
   }
}

static enum rjson_type _rjson_read_number(rjson_t *json)
{
   const unsigned char *p     = json-&gt;input_p - 1;
   const unsigned char *end   = json-&gt;input_end;
   const unsigned char *start = p;

   json-&gt;string_len = 0;
   json-&gt;string_pass_through = NULL;
   for (;;)
   {
      if (_rJSON_LIKELY(p != end))
      {
         switch (*p++)
         {
            case '+': case '-': case '.':
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
            case 'E': case 'e':
               continue;
         }
         p--;
         json-&gt;input_p = p;
         if (!_rjson_pushchars(json, start, p))
            return RJSON_ERROR; /* out of memory */
         break;
      }
      else
      {
         /* number sequences are always copied to the string buffer */
         if (!_rjson_pushchars(json, start, p))
            return RJSON_ERROR;
         if (!_rjson_io_input(json))
         {
            /* EOF here is not an error for a number */
            json-&gt;input_p = json-&gt;input_end;
            break;
         }
         start = p = json-&gt;input_p;
         end = json-&gt;input_end;
      }
   }

   p = (const unsigned char *)json-&gt;string;
   end = (p + json-&gt;string_len);

   /* validate json number */
   if (*p == '-' &amp;&amp; ++p == end)
      goto invalid_number;
   if (*p == '0')
   {
      if (++p == end)
         return RJSON_NUMBER;
   }
   else
   {
      if (*p &lt; '1' || *p &gt; '9')
         goto invalid_number;
      do
      {
         if (++p == end)
            return RJSON_NUMBER;
      }
      while (*p &gt;= '0' &amp;&amp; *p &lt;= '9');
   }
   if (*p == '.')
   {
      if (++p == end)
         goto invalid_number;
      if (*p &lt; '0' || *p &gt; '9')
         goto invalid_number;
      do
      {
         if (++p == end)
            return RJSON_NUMBER;
      }
      while (*p &gt;= '0' &amp;&amp; *p &lt;= '9');
   }
   if (((*p)|0x20) == 'e')
   {
      if (++p == end)
         goto invalid_number;
      if ((*p == '-' || *p == '+') &amp;&amp; ++p == end)
         goto invalid_number;
      if (*p &lt; '0' || *p &gt; '9')
         goto invalid_number;
      do
      {
         if (++p == end)
            return RJSON_NUMBER;
      }
      while (*p &gt;= '0' &amp;&amp; *p &lt;= '9');
   }
invalid_number:
   return _rjson_error_char(json, "unexpected %s in number",
         (p == json-&gt;input_end ? _rJSON_EOF : p[p == end ? -1 : 0]));
}

static enum rjson_type _rjson_push_stack(rjson_t *json, enum _rjson_token t)
{
   if (json-&gt;stack_top + 1 == json-&gt;stack + json-&gt;stack_cap)
   {
      /* reached allocated stack size, either reallocate or abort */
      unsigned int new_stack_cap;
      struct _rjson_stack *new_stack;
      size_t stack_alloc;
      if (json-&gt;stack_cap == json-&gt;stack_max)
         return _rjson_error(json, "maximum depth of nesting reached");

      new_stack_cap = json-&gt;stack_cap + 4;
      if (new_stack_cap &gt; json-&gt;stack_max)
         new_stack_cap = json-&gt;stack_max;
      stack_alloc = new_stack_cap * sizeof(struct _rjson_stack);
      if (json-&gt;stack != json-&gt;inline_stack)
         new_stack = (struct _rjson_stack *)realloc(json-&gt;stack, stack_alloc);
      else if ((new_stack = (struct _rjson_stack*)malloc(stack_alloc)) != NULL)
         memcpy(new_stack, json-&gt;inline_stack, sizeof(json-&gt;inline_stack));
      if (!new_stack)
         return _rjson_error(json, "out of memory");

      json-&gt;stack     = new_stack;
      json-&gt;stack_top = new_stack + json-&gt;stack_cap - 1;
      json-&gt;stack_cap = new_stack_cap;
   }
   json-&gt;stack_top++;
   json-&gt;stack_top-&gt;count = 0;
   return (json-&gt;stack_top-&gt;type =
            (t == _rJSON_TOK_ARRAY ? RJSON_ARRAY : RJSON_OBJECT));
}

static enum rjson_type _rjson_read_name(rjson_t *json, const char *pattern, enum rjson_type type)
{
   _rjson_char_t c;
   const char *p;
   for (p = pattern; *p; p++)
   {
      if ((_rjson_char_t)*p != (c = _rjson_char_get(json)))
         return _rjson_error_char(json, "unexpected %s in value", c);
   }
   return type;
}

static bool _rjson_optional_skip(rjson_t *json, const unsigned char **p, const unsigned char **end)
{
   unsigned char c, skip = (*p)[-1];
   int state = 0;

   if (skip == '/' &amp;&amp; !(json-&gt;option_flags &amp; RJSON_OPTION_ALLOW_COMMENTS))
      return false;

   if (     skip == 0xEF &amp;&amp; (!(json-&gt;option_flags &amp; RJSON_OPTION_ALLOW_UTF8BOM)
         || json-&gt;source_line != 1 || json-&gt;source_column_p != json-&gt;input_p))
      return false;

   for (;;)
   {
      if (*p == *end)
      {
         if (!_rjson_io_input(json))
         {
            _rjson_error(json, "unfinished %s",
                  (skip == '/' ? "comment" : "utf8 byte order mark"));
            break;
         }
         *p   = json-&gt;input_p;
         *end = json-&gt;input_end;
      }
      c = *(*p)++;
      if (skip == '/')
      {
         if      (state == 0 &amp;&amp; c == '/')
            state = 1;
         else if (state == 0 &amp;&amp; c == '*')
            state = 2;
         else if (state == 0)
            break;
         else if (state == 1 &amp;&amp; c == '\n')
            return true;
         else if (state == 2 &amp;&amp; c == '*')
            state = 3;
         else if (state == 3 &amp;&amp; c == '/')
            return true;
         else if (state == 3 &amp;&amp; c != '*')
            state = 2;
      }
      else if (skip == 0xEF)
      {
         /* Silence warning - state being set never used */
         if      (state == 0 &amp;&amp; c == 0xBB)
            state = 1;
         else if (state == 1 &amp;&amp; c == 0xBF)
            return true;
         else
            break;
      }
   }
   return false;
}

enum rjson_type rjson_next(rjson_t *json)
{
   unsigned char tok;
   struct _rjson_stack *stack = json-&gt;stack_top;
   const unsigned char *p     = json-&gt;input_p;
   const unsigned char *end   = json-&gt;input_end;
   unsigned char passed_token = false;

   /* JSON token look-up-table */
   static const unsigned char token_lut[256] =
   {
      #define i _rJSON_TOK_ERROR
      /*   0 | 0x00 |   */ i,i,i,i,i,i,i,i,i,
      /*   9 | 0x09 |\t */ _rJSON_TOK_WHITESPACE,
      /*  10 | 0x0A |\n */ _rJSON_TOK_NEWLINE, i,i,
      /*  13 | 0x0D |\r */ _rJSON_TOK_WHITESPACE, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /*  32 | 0x20 |   */ _rJSON_TOK_WHITESPACE, i,
      /*  34 | 0x22 | " */ _rJSON_TOK_STRING, i,i,i,i,i,i,i,i,i,
      /*  44 | 0x2C | , */ _rJSON_TOK_COMMA,
      /*  45 | 0x2D | - */ _rJSON_TOK_NUMBER, i,
      /*  47 | 0x2F | / */ _rJSON_TOK_OPTIONAL_SKIP,
      /*  48 | 0x30 | 0 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,
      /*  53 | 0x35 | 5 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,
      /*  58 | 0x3A | : */ _rJSON_TOK_COLON, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /*  91 | 0x5B | [ */ _rJSON_TOK_ARRAY, i,
      /*  93 | 0x5D | ] */ _rJSON_TOK_ARRAY_END, i,i,i,i,i,i,i,i,
      /* 102 | 0x66 | f */ _rJSON_TOK_FALSE, i,i,i,i,i,i,i,
      /* 110 | 0x6E | n */ _rJSON_TOK_NULL, i,i,i,i,i,
      /* 116 | 0x74 | t */ _rJSON_TOK_TRUE, i,i,i,i,i,i,
      /* 123 | 0x7B | { */ _rJSON_TOK_OBJECT, i,
      /* 125 | 0x7D | } */ _rJSON_TOK_OBJECT_END,
      /* 126 | 0x7E | ~ */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /* 164 | 0xA4 |   */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /* 202 | 0xCA |   */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
      /* 239 | 0xEF |   */ _rJSON_TOK_OPTIONAL_SKIP, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i
      #undef i
   };

   if (_rJSON_LIKELY(stack-&gt;type != RJSON_ERROR))
   {
      for (;;)
      {
         if (_rJSON_LIKELY(p != end))
         {
            tok = token_lut[*p++];
            if (_rJSON_LIKELY(tok &gt; _rJSON_TOK_OPTIONAL_SKIP))
            {
               /* Actual JSON token, process below */
            }
            else if (_rJSON_LIKELY(tok == _rJSON_TOK_WHITESPACE))
               continue;
            else if (tok == _rJSON_TOK_NEWLINE)
            {
               json-&gt;source_line++;
               json-&gt;source_column_p = p;
               continue;
            }
            else if (tok == _rJSON_TOK_OPTIONAL_SKIP)
            {
               if (_rjson_optional_skip(json, &amp;p, &amp;end))
                  continue;
            }
         }
         else if (_rJSON_LIKELY(_rjson_io_input(json)))
         {
            p   = json-&gt;input_p;
            end = json-&gt;input_end;
            continue;
         }
         else
         {
            p   = json-&gt;input_end;
            tok = _rJSON_TOK_EOF;
         }

         if (stack-&gt;type == RJSON_OBJECT)
         {
            if (stack-&gt;count &amp; 1)
            {
               /* Expecting colon followed by value. */
               if (passed_token)
                  goto read_value;
               if (_rJSON_LIKELY(tok == _rJSON_TOK_COLON))
               {
                  passed_token = true;
                  continue;
               }
               json-&gt;input_p = p;
               return _rjson_error_token(json,
                     "expected ':' not %s after member name", (enum _rjson_token)tok);
            }
            if (passed_token)
            {
               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))
                  goto read_value;
               json-&gt;input_p = p;
               return _rjson_error(json, "expected member name after ','");
            }
            if (tok == _rJSON_TOK_OBJECT_END)
            {
               json-&gt;input_p = p;
               json-&gt;stack_top--;
               return RJSON_OBJECT_END;
            }
            if (stack-&gt;count == 0)
            {
               /* No member name/value pairs yet. */
               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))
                  goto read_value;
               json-&gt;input_p = p;
               return _rjson_error(json, "expected member name or '}'");
            }
            /* Expecting comma followed by member name. */
            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))
            {
               passed_token = true;
               continue;
            }
            json-&gt;input_p = p;
            return _rjson_error_token(json,
                  "expected ',' or '}' not %s after member value", (enum _rjson_token)tok);
         }
         else if (stack-&gt;type == RJSON_ARRAY)
         {
            if (passed_token)
               goto read_value;
            if (tok == _rJSON_TOK_ARRAY_END)
            {
               json-&gt;input_p = p;
               json-&gt;stack_top--;
               return RJSON_ARRAY_END;
            }
            if (stack-&gt;count == 0)
               goto read_value;
            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))
            {
               passed_token = true;
               continue;
            }
            json-&gt;input_p = p;
            return _rjson_error_token(json,
                  "expected ',' or ']' not %s in array", (enum _rjson_token)tok);
         }
         else
         {
            if (_rJSON_LIKELY(!stack-&gt;count &amp;&amp; tok != _rJSON_TOK_EOF))
               goto read_value;
            json-&gt;input_p = p;
            if (!stack-&gt;count)
               return _rjson_error(json, "reached end without any data");
            if (tok == _rJSON_TOK_EOF)
               return RJSON_DONE;
            if (!(json-&gt;option_flags &amp; RJSON_OPTION_ALLOW_TRAILING_DATA))
               return _rjson_error_token(json,
                     "expected end of stream instead of %s", (enum _rjson_token)tok);
            json-&gt;input_p--;
            return RJSON_DONE;
         }

         /* read value for current token */
         read_value:
         json-&gt;input_p = p;
         stack-&gt;count++;
         /* This is optimal when there are many strings, otherwise a switch statement
          * or a function pointer table is better (depending on compiler/cpu) */
         if      (tok == _rJSON_TOK_STRING)
            return _rjson_read_string(json);
         else if (tok == _rJSON_TOK_NUMBER)
            return _rjson_read_number(json);
         else if (tok == _rJSON_TOK_OBJECT)
            return _rjson_push_stack(json, _rJSON_TOK_OBJECT);
         else if (tok == _rJSON_TOK_ARRAY)
            return _rjson_push_stack(json, _rJSON_TOK_ARRAY);
         else if (tok == _rJSON_TOK_TRUE)
            return _rjson_read_name(json, "rue", RJSON_TRUE);
         else if (tok == _rJSON_TOK_FALSE)
            return _rjson_read_name(json, "alse", RJSON_FALSE);
         else if (tok == _rJSON_TOK_NULL)
            return _rjson_read_name(json, "ull", RJSON_NULL);
         else return _rjson_error_token(json,
               "unexpected %s in value", (enum _rjson_token)tok);
      }
   }
   return RJSON_ERROR;
}

void _rjson_setup(rjson_t *json, rjson_io_t io, void *user_data, int input_len)
{
   json-&gt;io                  = io;
   json-&gt;user_data           = user_data;
   json-&gt;input_len           = input_len;
   json-&gt;input_p             = json-&gt;input_end = json-&gt;input_buf + input_len;

   json-&gt;stack               = json-&gt;inline_stack;
   json-&gt;stack_top           = json-&gt;stack;
   json-&gt;stack_top-&gt;type     = RJSON_DONE;
   json-&gt;stack_top-&gt;count    = 0;
   json-&gt;stack_cap           = (unsigned int)(sizeof(json-&gt;inline_stack) / sizeof(json-&gt;inline_stack[0]));
   json-&gt;stack_max           = (unsigned int)50;

   json-&gt;string              = json-&gt;inline_string;
   json-&gt;string_pass_through = NULL;
   json-&gt;string_len          = 0;
   json-&gt;string_cap          = sizeof(json-&gt;inline_string);

   json-&gt;source_line         = 1;
   json-&gt;source_column_p     = json-&gt;input_p;
   json-&gt;option_flags        = 0;
   json-&gt;decimal_sep         = 0;
}

rjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size)
{
   rjson_t* json = (rjson_t*)malloc(
         sizeof(rjson_t) - sizeof(((rjson_t*)0)-&gt;input_buf) + io_block_size);
   if (json) _rjson_setup(json, io, user_data, io_block_size);
   return json;
}

static int _rjson_buffer_io(void* buf, int len, void *user)
{
   const char **ud = (const char **)user;
   if (ud[1] - ud[0] &lt; len) len = (int)(ud[1] - ud[0]);
   memcpy(buf, ud[0], len);
   ud[0] += len;
   return len;
}

rjson_t *rjson_open_buffer(const void *buffer, size_t len)
{
   rjson_t *json   = (rjson_t *)malloc(sizeof(rjson_t) + sizeof(const char *)*2);
   const char **ud = (const char **)(json + 1);
   if (!json)
      return NULL;
   ud[0] = (const char *)buffer;
   ud[1] = ud[0] + len;
   _rjson_setup(json, _rjson_buffer_io, (void*)ud, sizeof(json-&gt;input_buf));
   return json;
}

rjson_t *rjson_open_string(const char *string, size_t len)
{
   return rjson_open_buffer(string, len);
}

static int _rjson_stream_io(void* buf, int len, void *user)
{
   return (int)intfstream_read((intfstream_t*)user, buf, (uint64_t)len);
}

rjson_t *rjson_open_stream(struct intfstream_internal *stream)
{
   /* Allocate an input buffer based on the file size */
   int64_t size = intfstream_get_size(stream);
   int io_size  =
         (size &gt; 1024*1024 ? 4096 :
         (size &gt;  256*1024 ? 2048 : 1024));
   return rjson_open_user(_rjson_stream_io, stream, io_size);
}

static int _rjson_rfile_io(void* buf, int len, void *user)
{
   return (int)filestream_read((RFILE*)user, buf, (int64_t)len);
}

rjson_t *rjson_open_rfile(RFILE *rfile)
{
   /* Allocate an input buffer based on the file size */
   int64_t size = filestream_get_size(rfile);
   int io_size =
         (size &gt; 1024*1024 ? 4096 :
         (size &gt;  256*1024 ? 2048 : 1024));
   return rjson_open_user(_rjson_rfile_io, rfile, io_size);
}

void rjson_set_options(rjson_t *json, char rjson_option_flags)
{
   json-&gt;option_flags = rjson_option_flags;
}

void rjson_set_max_depth(rjson_t *json, unsigned int max_depth)
{
   json-&gt;stack_max = max_depth;
}

const char *rjson_get_string(rjson_t *json, size_t *len)
{
   char* str             = (json-&gt;string_pass_through
         ? json-&gt;string_pass_through : json-&gt;string);
   if (len)
      *len               = json-&gt;string_len;
   str[json-&gt;string_len] = '\0';
   return str;
}

double rjson_get_double(rjson_t *json)
{
   char* str = (json-&gt;string_pass_through ? json-&gt;string_pass_through : json-&gt;string);
   str[json-&gt;string_len] = '\0';
   if (json-&gt;decimal_sep != '.')
   {
      /* handle locale that uses a non-standard decimal separator */
      char *p;
      if (json-&gt;decimal_sep == 0)
      {
         char test[4];
         snprintf(test, sizeof(test), "%.1f", 0.0f);
         json-&gt;decimal_sep = test[1];
      }
      if (json-&gt;decimal_sep != '.' &amp;&amp; (p = memchr(str, '.', strlen(str) + 1)) != NULL)
      {
         double res;
         *p  = json-&gt;decimal_sep;
         res = atof(str);
         *p  = '.';
         return res;
      }
   }
   return atof(str);
}

int rjson_get_int(rjson_t *json)
{
   char* str = (json-&gt;string_pass_through ? json-&gt;string_pass_through : json-&gt;string);
   str[json-&gt;string_len] = '\0';
   return atoi(str);
}

const char *rjson_get_error(rjson_t *json)
{
   return (json-&gt;stack_top-&gt;type == RJSON_ERROR ? json-&gt;error_text : "");
}

void rjson_set_error(rjson_t *json, const char* error)
{
   _rjson_error(json, "%s", error);
}

size_t rjson_get_source_line(rjson_t *json)
{
   return json-&gt;source_line;
}

size_t rjson_get_source_column(rjson_t *json)
{
   return (json-&gt;input_p == json-&gt;source_column_p ? 1 :
         json-&gt;input_p - json-&gt;source_column_p);
}

int rjson_get_source_context_len(rjson_t *json)
{
   const unsigned char *from = json-&gt;input_buf, *to = json-&gt;input_end, *p = json-&gt;input_p;
   return (int)(((p + 256 &lt; to ? p + 256 : to) - (p &gt; from + 256 ? p - 256 : from)));
}

const char* rjson_get_source_context_buf(rjson_t *json)
{
   /* inside the input buffer, some " may have been replaced with \0. */
   const unsigned char *p = json-&gt;input_p, *from = json-&gt;input_buf;
   unsigned char *i = json-&gt;input_buf;
   for (; i != json-&gt;input_end; i++)
   {
      if (*i == '\0')
         *i = '"';
   }
   return (const char*)(p &gt; from + 256 ? p - 256 : from);
}

bool rjson_check_context(rjson_t *json, unsigned int depth, ...)
{
   va_list ap;
   const struct _rjson_stack *stack = json-&gt;stack, *stack_top = json-&gt;stack_top;
   if ((unsigned int)(stack_top - stack) != depth)
      return false;
   va_start(ap, depth);
   while (++stack &lt;= stack_top)
   {
      if (va_arg(ap, int) == (int)stack-&gt;type) continue;
      va_end(ap);
      return false;
   }
   va_end(ap);
   return true;
}

unsigned int rjson_get_context_depth(rjson_t *json)
{
   return (unsigned int)(json-&gt;stack_top - json-&gt;stack);
}

size_t rjson_get_context_count(rjson_t *json)
{
   return json-&gt;stack_top-&gt;count;
}

enum rjson_type rjson_get_context_type(rjson_t *json)
{
   return json-&gt;stack_top-&gt;type;
}

void rjson_free(rjson_t *json)
{
   if (json-&gt;stack != json-&gt;inline_stack)
      free(json-&gt;stack);
   if (json-&gt;string != json-&gt;inline_string)
      free(json-&gt;string);
   free(json);
}

static bool _rjson_nop_default(void *context) { return true; }
static bool _rjson_nop_string(void *context, const char *value, size_t len) { return true; }
static bool _rjson_nop_bool(void *context, bool value) { return true; }

enum rjson_type rjson_parse(rjson_t *json, void* context,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context))
{
   bool in_object = false;
   size_t _len;
   const char* string;
   if (!object_member_handler) object_member_handler = _rjson_nop_string;
   if (!string_handler       ) string_handler        = _rjson_nop_string;
   if (!number_handler       ) number_handler        = _rjson_nop_string;
   if (!start_object_handler ) start_object_handler  = _rjson_nop_default;
   if (!end_object_handler   ) end_object_handler    = _rjson_nop_default;
   if (!start_array_handler  ) start_array_handler   = _rjson_nop_default;
   if (!end_array_handler    ) end_array_handler     = _rjson_nop_default;
   if (!boolean_handler      ) boolean_handler       = _rjson_nop_bool;
   if (!null_handler         ) null_handler          = _rjson_nop_default;
   for (;;)
   {
      switch (rjson_next(json))
      {
         case RJSON_STRING:
            string = rjson_get_string(json, &amp;_len);
            if (_rJSON_LIKELY(
                  (in_object &amp;&amp; (json-&gt;stack_top-&gt;count &amp; 1) ?
                     object_member_handler : string_handler)
                     (context, string, _len)))
               continue;
            return RJSON_STRING;
         case RJSON_NUMBER:
            string = rjson_get_string(json, &amp;_len);
            if (_rJSON_LIKELY(number_handler(context, string, _len)))
               continue;
            return RJSON_NUMBER;
         case RJSON_OBJECT:
            in_object = true;
            if (_rJSON_LIKELY(start_object_handler(context)))
               continue;
            return RJSON_OBJECT;
         case RJSON_ARRAY:
            in_object = false;
            if (_rJSON_LIKELY(start_array_handler(context)))
               continue;
            return RJSON_ARRAY;
         case RJSON_OBJECT_END:
            if (_rJSON_LIKELY(end_object_handler(context)))
            {
               in_object = (json-&gt;stack_top-&gt;type == RJSON_OBJECT);
               continue;
            }
            return RJSON_OBJECT_END;
         case RJSON_ARRAY_END:
            if (_rJSON_LIKELY(end_array_handler(context)))
            {
               in_object = (json-&gt;stack_top-&gt;type == RJSON_OBJECT);
               continue;
            }
            return RJSON_ARRAY_END;
         case RJSON_TRUE:
            if (_rJSON_LIKELY(boolean_handler(context, true)))
               continue;
            return RJSON_TRUE;
         case RJSON_FALSE:
            if (_rJSON_LIKELY(boolean_handler(context, false)))
               continue;
            return RJSON_FALSE;
         case RJSON_NULL:
            if (_rJSON_LIKELY(null_handler(context)))
               continue;
            return RJSON_NULL;
         case RJSON_ERROR:
            return RJSON_ERROR;
         case RJSON_DONE:
            return RJSON_DONE;
      }
   }
}

bool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context),
      void (*error_handler        )(void *context, int line, int col, const char* error))
{
   const char *user_data[2];
   rjson_t json;
   user_data[0] = string;
   user_data[1] = string + len;
   _rjson_setup(&amp;json, _rjson_buffer_io, (void*)user_data, sizeof(json.input_buf));
   rjson_set_options(&amp;json, option_flags);
   if (rjson_parse(&amp;json, context,
         object_member_handler, string_handler, number_handler,
         start_object_handler, end_object_handler,
         start_array_handler, end_array_handler,
         boolean_handler, null_handler) == RJSON_DONE)
      return true;
   if (error_handler)
      error_handler(context,
            (int)rjson_get_source_line(&amp;json),
            (int)rjson_get_source_column(&amp;json),
            rjson_get_error(&amp;json));
   return false;
}

struct rjsonwriter
{
   char* buf;
   int buf_num, buf_cap;

   rjsonwriter_io_t io;
   void *user_data;

   const char* error_text;
   char option_flags, decimal_sep;
   bool buf_is_output, final_flush;

   char inline_buf[1024];
};

rjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data)
{
   rjsonwriter_t* writer = (rjsonwriter_t*)malloc(sizeof(rjsonwriter_t));
   if (!writer)
      return NULL;

   writer-&gt;buf           = writer-&gt;inline_buf;
   writer-&gt;buf_num       = 0;
   writer-&gt;buf_cap       = sizeof(writer-&gt;inline_buf);

   writer-&gt;error_text    = NULL;
   writer-&gt;option_flags  = writer-&gt;decimal_sep = 0;
   writer-&gt;buf_is_output = writer-&gt;final_flush = false;

   writer-&gt;io            = io;
   writer-&gt;user_data     = user_data;

   return writer;
}

static int _rjsonwriter_stream_io(const void* buf, int len, void *user)
{
   return (int)intfstream_write((intfstream_t*)user, buf, (uint64_t)len);
}

rjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream)
{
   return rjsonwriter_open_user(_rjsonwriter_stream_io, stream);
}

static int _rjsonwriter_rfile_io(const void* buf, int len, void *user)
{
   return (int)filestream_write((RFILE*)user, buf, (int64_t)len);
}

rjsonwriter_t *rjsonwriter_open_rfile(RFILE *rfile)
{
   return rjsonwriter_open_user(_rjsonwriter_rfile_io, rfile);
}

static int _rjsonwriter_memory_io(const void* buf, int len, void *user)
{
   rjsonwriter_t *writer = (rjsonwriter_t *)user;
   bool is_append        = (buf != writer-&gt;buf);
   int new_cap           = writer-&gt;buf_num + (is_append ? len : 0) + 512;
   if (!writer-&gt;final_flush &amp;&amp; (is_append || new_cap &gt; writer-&gt;buf_cap))
   {
      bool can_realloc   = (writer-&gt;buf != writer-&gt;inline_buf);
      char* new_buf      = (char*)(can_realloc ? realloc(writer-&gt;buf, new_cap) : malloc(new_cap));
      if (!new_buf)
         return 0;
      if (!can_realloc)
         memcpy(new_buf, writer-&gt;buf, writer-&gt;buf_num);
      if (is_append)
      {
         memcpy(new_buf + writer-&gt;buf_num, buf, len);
         writer-&gt;buf_num += len;
      }
      writer-&gt;buf        = new_buf;
      writer-&gt;buf_cap    = new_cap;
   }
   return len;
}

rjsonwriter_t *rjsonwriter_open_memory(void)
{
   rjsonwriter_t *writer = rjsonwriter_open_user(_rjsonwriter_memory_io, NULL);
   if (!writer)
      return NULL;
   writer-&gt;user_data     = writer;
   writer-&gt;buf_is_output = true;
   return writer;
}

char* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len)
{
   if (writer-&gt;io != _rjsonwriter_memory_io || writer-&gt;error_text)
      return NULL;
   if (writer-&gt;buf_num == writer-&gt;buf_cap)
      rjsonwriter_flush(writer);
   writer-&gt;buf[writer-&gt;buf_num] = '\0';
   if (len)
      *len = writer-&gt;buf_num;
   return writer-&gt;buf;
}

int rjsonwriter_count_memory_buffer(rjsonwriter_t *writer)
{
   return writer-&gt;buf_num;
}

void rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len)
{
   if (keep_len &lt;= writer-&gt;buf_num)
      writer-&gt;buf_num = (keep_len &lt; 0 ? 0 : keep_len);
}

bool rjsonwriter_free(rjsonwriter_t *writer)
{
   bool res;
   writer-&gt;final_flush = true;
   res = rjsonwriter_flush(writer);
   if (writer-&gt;buf != writer-&gt;inline_buf)
      free(writer-&gt;buf);
   free(writer);
   return res;
}

void rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags)
{
   writer-&gt;option_flags = rjsonwriter_option_flags;
}

bool rjsonwriter_flush(rjsonwriter_t *writer)
{
   if (writer-&gt;buf_num &amp;&amp; !writer-&gt;error_text &amp;&amp; writer-&gt;io(writer-&gt;buf,
            writer-&gt;buf_num, writer-&gt;user_data) != writer-&gt;buf_num)
      writer-&gt;error_text = "output error";
   if (!writer-&gt;buf_is_output || writer-&gt;error_text)
      writer-&gt;buf_num = 0;
   return !writer-&gt;error_text;
}

const char *rjsonwriter_get_error(rjsonwriter_t *writer)
{
   return (writer-&gt;error_text ? writer-&gt;error_text : "");
}

void rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len)
{
   if (writer-&gt;buf_num + len &gt; writer-&gt;buf_cap)
      rjsonwriter_flush(writer);
   if (len == 1)
   {
      if (buf[0] &gt; ' ' ||
            !(writer-&gt;option_flags &amp; RJSONWRITER_OPTION_SKIP_WHITESPACE))
         writer-&gt;buf[writer-&gt;buf_num++] = buf[0];
   }
   else
   {
      int add = writer-&gt;buf_cap - writer-&gt;buf_num;
      if (add &gt; len)
         add = len;
      memcpy(writer-&gt;buf + writer-&gt;buf_num, buf, add);
      writer-&gt;buf_num += add;
      if (len == add)
         return;
      rjsonwriter_flush(writer);
      len -= add;
      buf += add;
      if (writer-&gt;buf_num + len &lt;= writer-&gt;buf_cap)
      {
         memcpy(writer-&gt;buf + writer-&gt;buf_num, buf, len);
         writer-&gt;buf_num += len;
      }
      else if (writer-&gt;io(buf, len, writer-&gt;user_data) != len)
         writer-&gt;error_text = "output error";
   }
}

void rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...)
{
   int available, need;
   va_list ap, ap2;
   if (writer-&gt;buf_num &gt;= writer-&gt;buf_cap - 16)
      rjsonwriter_flush(writer);
   available = (writer-&gt;buf_cap - writer-&gt;buf_num);
   va_start(ap, fmt);
   need = vsnprintf(writer-&gt;buf + writer-&gt;buf_num, available, fmt, ap);
   va_end(ap);
   if (need &lt;= 0)
      return;
   if (need &lt; available)
   {
      writer-&gt;buf_num += need;
      return;
   }
   rjsonwriter_flush(writer);
   if (writer-&gt;buf_num + need &gt;= writer-&gt;buf_cap)
   {
      int newcap   = writer-&gt;buf_num + need + 1;
      char* newbuf = (char*)malloc(newcap);
      if (!newbuf)
      {
         if (!writer-&gt;error_text)
            writer-&gt;error_text = "out of memory";
         return;
      }
      if (writer-&gt;buf_num)
         memcpy(newbuf, writer-&gt;buf, writer-&gt;buf_num);
      if (writer-&gt;buf != writer-&gt;inline_buf)
         free(writer-&gt;buf);
      writer-&gt;buf = newbuf;
      writer-&gt;buf_cap = newcap;
   }
   va_start(ap2, fmt);
   vsnprintf(writer-&gt;buf + writer-&gt;buf_num, writer-&gt;buf_cap - writer-&gt;buf_num, fmt, ap2);
   va_end(ap2);
   writer-&gt;buf_num += need;
}

void _rjsonwriter_add_escaped(rjsonwriter_t *writer, unsigned char c)
{
   char esc_buf[8], esc_len = 2;
   const char* esc;
   switch (c)
   {
      case '\b':
         esc = "\\b";
         break;
      case '\t':
         esc = "\\t";
         break;
      case '\n':
         esc = "\\n";
         break;
      case '\f':
         esc = "\\f";
         break;
      case '\r':
         esc = "\\r";
         break;
      case '\"':
         esc = "\\\"";
         break;
      case '\\':
         esc = "\\\\";
         break;
      case '/':
         esc = "\\/";
         break;
      default:
         snprintf(esc_buf, sizeof(esc_buf), "\\u%04x", c);
         esc     = esc_buf;
         esc_len = 6;
   }
   rjsonwriter_raw(writer, esc, esc_len);
}

void rjsonwriter_add_string(rjsonwriter_t *writer, const char *value)
{
   const char *p = (const char*)value, *raw = p;
   unsigned char c;
   rjsonwriter_raw(writer, "\"", 1);
   if (!p)
      goto string_end;
   while ((c = (unsigned char)*p++) != '\0')
   {
      /* forward slash is special, it should be escaped if the previous character
       * was a &lt; (intended to avoid having &lt;/script&gt; html tags in JSON files) */
      if (   c &gt;= 0x20 &amp;&amp; c != '\"' &amp;&amp; c != '\\' &amp;&amp;
            (c != '/' || p &lt; value + 2 || p[-2] != '&lt;'))
         continue;
      if (raw != p - 1)
         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
      _rjsonwriter_add_escaped(writer, c);
      raw = p;
   }
   if (raw != p - 1)
      rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
string_end:
   rjsonwriter_raw(writer, "\"", 1);
}

void rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len)
{
   const char *p = (const char*)value, *raw = p, *end = p + len;
   rjsonwriter_raw(writer, "\"", 1);
   while (p != end)
   {
      unsigned char c = (unsigned char)*p++;
      if (      c &gt;= 0x20 &amp;&amp; c != '\"' &amp;&amp; c != '\\'
            &amp;&amp; (c != '/' || p &lt; value + 2 || p[-2] != '&lt;'))
         continue;
      if (raw != p - 1)
         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
      _rjsonwriter_add_escaped(writer, c);
      raw = p;
   }
   if (raw != end)
      rjsonwriter_raw(writer, raw, (int)(end - raw));
   rjsonwriter_raw(writer, "\"", 1);
}

void rjsonwriter_add_double(rjsonwriter_t *writer, double value)
{
   int old_buf_num = writer-&gt;buf_num;
   rjsonwriter_rawf(writer, "%G", value);
   if (writer-&gt;decimal_sep != '.')
   {
      /* handle locale that uses a non-standard decimal separator */
      char *p, *str;
      if (writer-&gt;decimal_sep == 0)
      {
         char test[4];
         snprintf(test, sizeof(test), "%.1f", 0.0f);
         if ((writer-&gt;decimal_sep = test[1]) == '.')
            return;
      }
      str = writer-&gt;buf + (old_buf_num &gt; writer-&gt;buf_num ? 0 : old_buf_num);
      if ((p = strchr(str, writer-&gt;decimal_sep)) != NULL)
         *p = '.';
   }
}

void rjsonwriter_add_spaces(rjsonwriter_t *writer, int count)
{
   if (!(writer-&gt;option_flags &amp; RJSONWRITER_OPTION_SKIP_WHITESPACE))
      for (; count &gt; 0; count -= 8)
         rjsonwriter_raw(writer, "        ", (count &gt; 8 ? 8 : count));
}

void rjsonwriter_add_tabs(rjsonwriter_t *writer, int count)
{
   if (!(writer-&gt;option_flags &amp; RJSONWRITER_OPTION_SKIP_WHITESPACE))
      for (; count &gt; 0; count -= 8)
         rjsonwriter_raw(writer, "\t\t\t\t\t\t\t\t", (count &gt; 8 ? 8 : count));
}

#undef _rJSON_EOF
#undef _rJSON_LIKELY</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_bitstream.c</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    bitstream.c

    Helper classes for reading/writing at the bit level.

***************************************************************************/

#include &lt;stdlib.h&gt;
#include &lt;libchdr/bitstream.h&gt;

/***************************************************************************
 *  INLINE FUNCTIONS
 ***************************************************************************
 */

int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream-&gt;doffset - bitstream-&gt;bits / 8) &gt; bitstream-&gt;dlength); }

/*-------------------------------------------------
 *  create_bitstream - constructor
 *-------------------------------------------------
 */

struct bitstream* create_bitstream(const void *src, uint32_t srclength)
{
	struct bitstream* bitstream = (struct bitstream*)malloc(sizeof(struct bitstream));
	bitstream-&gt;buffer = 0;
	bitstream-&gt;bits = 0;
	bitstream-&gt;read = (const uint8_t*)src;
	bitstream-&gt;doffset = 0;
	bitstream-&gt;dlength = srclength;
	return bitstream;
}


/*-----------------------------------------------------
 *  bitstream_peek - fetch the requested number of bits
 *  but don't advance the input pointer
 *-----------------------------------------------------
 */

uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
{
	if (numbits == 0)
		return 0;

	/* fetch data if we need more */
	if (numbits &gt; bitstream-&gt;bits)
	{
		while (bitstream-&gt;bits &lt;= 24)
		{
			if (bitstream-&gt;doffset &lt; bitstream-&gt;dlength)
				bitstream-&gt;buffer |= bitstream-&gt;read[bitstream-&gt;doffset] &lt;&lt; (24 - bitstream-&gt;bits);
			bitstream-&gt;doffset++;
			bitstream-&gt;bits += 8;
		}
	}

	/* return the data */
	return bitstream-&gt;buffer &gt;&gt; (32 - numbits);
}


/*-----------------------------------------------------
 *  bitstream_remove - advance the input pointer by the
 *  specified number of bits
 *-----------------------------------------------------
 */

void bitstream_remove(struct bitstream* bitstream, int numbits)
{
	bitstream-&gt;buffer &lt;&lt;= numbits;
	bitstream-&gt;bits -= numbits;
}


/*-----------------------------------------------------
 *  bitstream_read - fetch the requested number of bits
 *-----------------------------------------------------
 */

uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
{
	uint32_t result = bitstream_peek(bitstream, numbits);
	bitstream_remove(bitstream, numbits);
	return result;
}


/*-------------------------------------------------
 *  read_offset - return the current read offset
 *-------------------------------------------------
 */

uint32_t bitstream_read_offset(struct bitstream* bitstream)
{
	uint32_t result = bitstream-&gt;doffset;
	int bits = bitstream-&gt;bits;
	while (bits &gt;= 8)
	{
		result--;
		bits -= 8;
	}
	return result;
}


/*-------------------------------------------------
 *  flush - flush to the nearest byte
 *-------------------------------------------------
 */

uint32_t bitstream_flush(struct bitstream* bitstream)
{
	while (bitstream-&gt;bits &gt;= 8)
	{
		bitstream-&gt;doffset--;
		bitstream-&gt;bits -= 8;
	}
	bitstream-&gt;bits = bitstream-&gt;buffer = 0;
	return bitstream-&gt;doffset;
}</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_cdrom.c</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    cdrom.c

    Generic MAME CD-ROM utilities - build IDE and SCSI CD-ROMs on top of this

****************************************************************************

    IMPORTANT:
    "physical" block addresses are the actual addresses on the emulated CD.
    "chd" block addresses are the block addresses in the CHD file.
    Because we pad each track to a 4-frame boundary, these addressing
    schemes will differ after track 1!

***************************************************************************/

#include &lt;string.h&gt;

#include &lt;libchdr/cdrom.h&gt;

#ifdef WANT_RAW_DATA_SECTOR

/***************************************************************************
    DEBUGGING
***************************************************************************/

/** @brief  The verbose. */
#define VERBOSE (0)
#if VERBOSE

/**
 * @def LOG(x) do
 *
 * @brief   A macro that defines log.
 *
 * @param   x   The void to process.
 */

#define LOG(x) do { if (VERBOSE) logerror x; } while (0)

/**
 * @fn  void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
 *
 * @brief   Logerrors the given text.
 *
 * @param   text    The text.
 *
 * @return  A CLIB_DECL.
 */

void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
#else

/**
 * @def LOG(x);
 *
 * @brief   A macro that defines log.
 *
 * @param   x   The void to process.
 */

#define LOG(x)
#endif

/***************************************************************************
    CONSTANTS
***************************************************************************/

/** @brief  offset within sector. */
#define SYNC_OFFSET 0x000
/** @brief  12 bytes. */
#define SYNC_NUM_BYTES 12

/** @brief  offset within sector. */
#define MODE_OFFSET 0x00f

/** @brief  offset within sector. */
#define ECC_P_OFFSET 0x81c
/** @brief  2 lots of 86. */
#define ECC_P_NUM_BYTES 86
/** @brief  24 bytes each. */
#define ECC_P_COMP 24

/** @brief  The ECC q offset. */
#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES)
/** @brief  2 lots of 52. */
#define ECC_Q_NUM_BYTES 52
/** @brief  43 bytes each. */
#define ECC_Q_COMP 43

/**
 * @brief   -------------------------------------------------
 *            ECC lookup tables pre-calculated tables for ECC data calcs
 *          -------------------------------------------------.
 */

static const uint8_t ecclow[256] =
{
	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
	0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
	0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
	0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
	0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
	0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
	0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
	0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
	0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03,
	0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23,
	0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43,
	0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63,
	0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83,
	0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3,
	0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3,
	0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3
};

/** @brief  The ecchigh[ 256]. */
static const uint8_t ecchigh[256] =
{
	0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05,
	0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe,
	0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee,
	0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15,
	0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce,
	0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35,
	0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25,
	0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde,
	0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e,
	0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75,
	0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65,
	0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e,
	0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45,
	0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe,
	0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae,
	0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55
};

/**
 * @brief   -------------------------------------------------
 *            poffsets - each row represents the addresses used to calculate a byte of the ECC P
 *            data 86 (*2) ECC P bytes, 24 values represented by each
 *          -------------------------------------------------.
 */

static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] =
{
	{ 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba },
	{ 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb },
	{ 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc },
	{ 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd },
	{ 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be },
	{ 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf },
	{ 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 },
	{ 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 },
	{ 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 },
	{ 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 },
	{ 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 },
	{ 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 },
	{ 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 },
	{ 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 },
	{ 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 },
	{ 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 },
	{ 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca },
	{ 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb },
	{ 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc },
	{ 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd },
	{ 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce },
	{ 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf },
	{ 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 },
	{ 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 },
	{ 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 },
	{ 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 },
	{ 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 },
	{ 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 },
	{ 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 },
	{ 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 },
	{ 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 },
	{ 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 },
	{ 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da },
	{ 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db },
	{ 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc },
	{ 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd },
	{ 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de },
	{ 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df },
	{ 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 },
	{ 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 },
	{ 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 },
	{ 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 },
	{ 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 },
	{ 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 },
	{ 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 },
	{ 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 },
	{ 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 },
	{ 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 },
	{ 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea },
	{ 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb },
	{ 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec },
	{ 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed },
	{ 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee },
	{ 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef },
	{ 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 },
	{ 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 },
	{ 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 },
	{ 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 },
	{ 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 },
	{ 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 },
	{ 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 },
	{ 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 },
	{ 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 },
	{ 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 },
	{ 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa },
	{ 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb },
	{ 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc },
	{ 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd },
	{ 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe },
	{ 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff },
	{ 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 },
	{ 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 },
	{ 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 },
	{ 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 },
	{ 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 },
	{ 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 },
	{ 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 },
	{ 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 },
	{ 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 },
	{ 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 },
	{ 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a },
	{ 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b },
	{ 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c },
	{ 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d },
	{ 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e },
	{ 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f }
};

/**
 * @brief   -------------------------------------------------
 *            qoffsets - each row represents the addresses used to calculate a byte of the ECC Q
 *            data 52 (*2) ECC Q bytes, 43 values represented by each
 *          -------------------------------------------------.
 */

static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =
{
	{ 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 },
	{ 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 },
	{ 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a },
	{ 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b },
	{ 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 },
	{ 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 },
	{ 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 },
	{ 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 },
	{ 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c },
	{ 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d },
	{ 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 },
	{ 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 },
	{ 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 },
	{ 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 },
	{ 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e },
	{ 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f },
	{ 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 },
	{ 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 },
	{ 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba },
	{ 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb },
	{ 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 },
	{ 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 },
	{ 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa },
	{ 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab },
	{ 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 },
	{ 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 },
	{ 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 },
	{ 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 },
	{ 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac },
	{ 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad },
	{ 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 },
	{ 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 },
	{ 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 },
	{ 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 },
	{ 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae },
	{ 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af },
	{ 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 },
	{ 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 },
	{ 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a },
	{ 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b },
	{ 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 },
	{ 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 },
	{ 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 },
	{ 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 },
	{ 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c },
	{ 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d },
	{ 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 },
	{ 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 },
	{ 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 },
	{ 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 },
	{ 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e },
	{ 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f }
};

/*-------------------------------------------------
 *  ecc_source_byte - return data from the sector
 *  at the given offset, masking anything
 *  particular to a mode
 *-------------------------------------------------
 */

static INLINE uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
{
	/* in mode 2 always treat these as 0 bytes */
	return (sector[MODE_OFFSET] == 2 &amp;&amp; offset &lt; 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];
}

/**
 * @fn  void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &amp;val1, uint8_t &amp;val2)
 *
 * @brief   -------------------------------------------------
 *            ecc_compute_bytes - calculate an ECC value (P or Q)
 *          -------------------------------------------------.
 *
 * @param   sector          The sector.
 * @param   row             The row.
 * @param   rowlen          The rowlen.
 * @param [in,out]  val1    The first value.
 * @param [in,out]  val2    The second value.
 */

void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)
{
	int component;
	*val1 = *val2 = 0;
	for (component = 0; component &lt; rowlen; component++)
	{
		*val1 ^= ecc_source_byte(sector, row[component]);
		*val2 ^= ecc_source_byte(sector, row[component]);
		*val1 = ecclow[*val1];
	}
	*val1 = ecchigh[ecclow[*val1] ^ *val2];
	*val2 ^= *val1;
}

/**
 * @fn  int ecc_verify(const uint8_t *sector)
 *
 * @brief   -------------------------------------------------
 *            ecc_verify - verify the P and Q ECC codes in a sector
 *          -------------------------------------------------.
 *
 * @param   sector  The sector.
 *
 * @return  true if it succeeds, false if it fails.
 */

int ecc_verify(const uint8_t *sector)
{
	int byte;
	/* first verify P bytes */
	for (byte = 0; byte &lt; ECC_P_NUM_BYTES; byte++)
	{
		uint8_t val1, val2;
		ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &amp;val1, &amp;val2);
		if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2)
			return 0;
	}

	/* then verify Q bytes */
	for (byte = 0; byte &lt; ECC_Q_NUM_BYTES; byte++)
	{
		uint8_t val1, val2;
		ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &amp;val1, &amp;val2);
		if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2)
			return 0;
	}
	return 1;
}

/**
 * @fn  void ecc_generate(uint8_t *sector)
 *
 * @brief   -------------------------------------------------
 *            ecc_generate - generate the P and Q ECC codes for a sector, overwriting any
 *            existing codes
 *          -------------------------------------------------.
 *
 * @param [in,out]  sector  If non-null, the sector.
 */

void ecc_generate(uint8_t *sector)
{
	int byte;
	/* first verify P bytes */
	for (byte = 0; byte &lt; ECC_P_NUM_BYTES; byte++)
		ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &amp;sector[ECC_P_OFFSET + byte], &amp;sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);

	/* then verify Q bytes */
	for (byte = 0; byte &lt; ECC_Q_NUM_BYTES; byte++)
		ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &amp;sector[ECC_Q_OFFSET + byte], &amp;sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);
}

/**
 * @fn  void ecc_clear(uint8_t *sector)
 *
 * @brief   -------------------------------------------------
 *            ecc_clear - erase the ECC P and Q cods to 0 within a sector
 *          -------------------------------------------------.
 *
 * @param [in,out]  sector  If non-null, the sector.
 */

void ecc_clear(uint8_t *sector)
{
	memset(&amp;sector[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES);
	memset(&amp;sector[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES);
}

#endif /* WANT_RAW_DATA_SECTOR */</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_chd.c</h2>
<pre>/***************************************************************************

    chd.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include &lt;stddef.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;time.h&gt;

#include &lt;libchdr/chd.h&gt;
#include &lt;libchdr/cdrom.h&gt;
#include &lt;libchdr/huffman.h&gt;
#include &lt;libchdr/minmax.h&gt;

#ifdef HAVE_FLAC
#include &lt;libchdr/flac.h&gt;
#endif

#ifdef HAVE_ZLIB
#include &lt;libchdr/libchdr_zlib.h&gt;
#endif

#ifdef HAVE_7ZIP
#include &lt;libchdr/lzma.h&gt;
#endif

#ifdef HAVE_ZSTD
#include &lt;libchdr/libchdr_zstd.h&gt;
#endif

#if defined(__PS3__) || defined(__PSL1GHT__)
#define __MACTYPES__
#endif

#define TRUE 1
#define FALSE 0
#define SHA1_DIGEST_SIZE 20

/***************************************************************************
    DEBUGGING
***************************************************************************/

#define PRINTF_MAX_HUNK				(0)

/***************************************************************************
    CONSTANTS
***************************************************************************/

#define MAP_STACK_ENTRIES			512			/* max number of entries to use on the stack */
#define MAP_ENTRY_SIZE				16			/* V3 and later */
#define OLD_MAP_ENTRY_SIZE			8			/* V1-V2 */
#define METADATA_HEADER_SIZE		16			/* metadata header size */

#define MAP_ENTRY_FLAG_TYPE_MASK	0x0f		/* what type of hunk */
#define MAP_ENTRY_FLAG_NO_CRC		0x10		/* no CRC is present */

#define CHD_V1_SECTOR_SIZE			512			/* size of a "sector" in the V1 header */

#define COOKIE_VALUE				0xbaadf00d
#define MAX_ZLIB_ALLOCS				64

#define END_OF_LIST_COOKIE			"EndOfListCookie"

#define NO_MATCH					(~0)

/* V3-V4 entry types */
enum
{
	V34_MAP_ENTRY_TYPE_INVALID = 0,             /* invalid type */
	V34_MAP_ENTRY_TYPE_COMPRESSED = 1,          /* standard compression */
	V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,        /* uncompressed data */
	V34_MAP_ENTRY_TYPE_MINI = 3,                /* mini: use offset as raw data */
	V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,           /* same as another hunk in this file */
	V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         /* same as a hunk in the parent file */
	V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6       /* compressed with secondary algorithm (usually FLAC CDDA) */
};

/* V5 compression types */
enum
{
	/* codec #0
	 * these types are live when running */
	COMPRESSION_TYPE_0 = 0,
	/* codec #1 */
	COMPRESSION_TYPE_1 = 1,
	/* codec #2 */
	COMPRESSION_TYPE_2 = 2,
	/* codec #3 */
	COMPRESSION_TYPE_3 = 3,
	/* no compression; implicit length = hunkbytes */
	COMPRESSION_NONE = 4,
	/* same as another block in this chd */
	COMPRESSION_SELF = 5,
	/* same as a hunk's worth of units in the parent chd */
	COMPRESSION_PARENT = 6,

	/* start of small RLE run (4-bit length)
	 * these additional pseudo-types are used for compressed encodings: */
	COMPRESSION_RLE_SMALL,
	/* start of large RLE run (8-bit length) */
	COMPRESSION_RLE_LARGE,
	/* same as the last COMPRESSION_SELF block */
	COMPRESSION_SELF_0,
	/* same as the last COMPRESSION_SELF block + 1 */
	COMPRESSION_SELF_1,
	/* same block in the parent */
	COMPRESSION_PARENT_SELF,
	/* same as the last COMPRESSION_PARENT block */
	COMPRESSION_PARENT_0,
	/* same as the last COMPRESSION_PARENT block + 1 */
	COMPRESSION_PARENT_1
};

/***************************************************************************
    MACROS
***************************************************************************/

#define EARLY_EXIT(x)				do { (void)(x); goto cleanup; } while (0)

/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

/* interface to a codec */
typedef struct _codec_interface codec_interface;
struct _codec_interface
{
	uint32_t		compression;								/* type of compression */
	const char *compname;									/* name of the algorithm */
	uint8_t		lossy;										/* is this a lossy algorithm? */
	chd_error	(*init)(void *codec, uint32_t hunkbytes);		/* codec initialize */
	void		(*free)(void *codec);						/* codec free */
	chd_error	(*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */
	chd_error	(*config)(void *codec, int param, void *config); /* configure */
};

/* a single map entry */
typedef struct _map_entry map_entry;
struct _map_entry
{
	uint64_t					offset;			/* offset within the file of the data */
	uint32_t					crc;			/* 32-bit CRC of the data */
	uint32_t					length;			/* length of the data */
	uint8_t					flags;			/* misc flags */
};

/* a single metadata entry */
typedef struct _metadata_entry metadata_entry;
struct _metadata_entry
{
	uint64_t					offset;			/* offset within the file of the header */
	uint64_t					next;			/* offset within the file of the next header */
	uint64_t					prev;			/* offset within the file of the previous header */
	uint32_t					length;			/* length of the metadata */
	uint32_t					metatag;		/* metadata tag */
	uint8_t					flags;			/* flag bits */
};


typedef struct _huff_codec_data huff_codec_data;
struct _huff_codec_data
{
	struct huffman_decoder* decoder;
};


/* internal representation of an open CHD file */
struct _chd_file
{
	uint32_t					cookie;			/* cookie, should equal COOKIE_VALUE */

	core_file *				file;			/* handle to the open core file */
	chd_header				header;			/* header, extracted from file */

	chd_file *				parent;			/* pointer to parent file, or NULL */

	map_entry *				map;			/* array of map entries */

#ifdef NEED_CACHE_HUNK
	uint8_t *					cache;			/* hunk cache pointer */
	uint32_t					cachehunk;		/* index of currently cached hunk */

	uint8_t *					compare;		/* hunk compare pointer */
	uint32_t					comparehunk;	/* index of current compare data */
#endif

	uint8_t *					compressed;		/* pointer to buffer for compressed data */
	const codec_interface *	codecintf[4];	/* interface to the codec */

	huff_codec_data			huff_codec_data;		/* huff codec data */
#ifdef HAVE_ZLIB
	zlib_codec_data			zlib_codec_data;		/* zlib codec data */
	cdzl_codec_data			cdzl_codec_data;		/* cdzl codec data */
#endif
#ifdef HAVE_7ZIP
	lzma_codec_data			lzma_codec_data;		/* lzma codec data */
	cdlz_codec_data			cdlz_codec_data;		/* cdlz codec data */
#endif
#ifdef HAVE_FLAC
	flac_codec_data			flac_codec_data;		/* flac codec data */
	cdfl_codec_data			cdfl_codec_data;		/* cdfl codec data */
#endif
#ifdef HAVE_ZSTD
	zstd_codec_data			zstd_codec_data;		/* zstd codec data */
	cdzs_codec_data			cdzs_codec_data;		/* cdzs codec data */
#endif

#ifdef NEED_CACHE_HUNK
	uint32_t					maxhunk;		/* maximum hunk accessed */
#endif

	uint8_t *					file_cache;		/* cache of underlying file */
};


/***************************************************************************
    GLOBAL VARIABLES
***************************************************************************/

static const uint8_t nullmd5[CHD_MD5_BYTES] = { 0 };
static const uint8_t nullsha1[CHD_SHA1_BYTES] = { 0 };

/***************************************************************************
    PROTOTYPES
***************************************************************************/

/* core_file wrappers over stdio */
static core_file *core_stdio_fopen(char const *path);
static uint64_t core_stdio_fsize(core_file *file);
static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file);
static int core_stdio_fclose(core_file *file);
static int core_stdio_fclose_nonowner(core_file *file); /* alternate fclose used by chd_open_file */
static int core_stdio_fseek(core_file* file, int64_t offset, int whence);

/* internal header operations */
static chd_error header_validate(const chd_header *header);
static chd_error header_read(chd_file *chd, chd_header *header);

/* internal hunk read/write */
#ifdef NEED_CACHE_HUNK
static chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum);
#endif
static chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest);

/* internal map access */
static chd_error map_read(chd_file *chd);

/* metadata management */
static chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry);

/* zlib compression codec */
chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
void zlib_codec_free(void *codec);
chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
void zlib_fast_free(voidpf opaque, voidpf address);
void zlib_allocator_free(voidpf opaque);

/* lzma compression codec */
chd_error lzma_codec_init(void *codec, uint32_t hunkbytes);
void lzma_codec_free(void *codec);
chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* huff compression codec */
static chd_error huff_codec_init(void *codec, uint32_t hunkbytes);
static void huff_codec_free(void *codec);
static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* flac compression codec */
chd_error flac_codec_init(void *codec, uint32_t hunkbytes);
void flac_codec_free(void *codec);
chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* zstd compression codec */
chd_error zstd_codec_init(void *codec, uint32_t hunkbytes);
void zstd_codec_free(void *codec);
chd_error zstd_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdzl compression codec */
chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);
void cdzl_codec_free(void* codec);
chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdlz compression codec */
chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);
void cdlz_codec_free(void* codec);
chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdfl compression codec */
chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
void cdfl_codec_free(void* codec);
chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

/* cdzs compression codec */
chd_error cdzs_codec_init(void *codec, uint32_t hunkbytes);
void cdzs_codec_free(void *codec);
chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);


/***************************************************************************
 *  HUFFMAN DECOMPRESSOR
 ***************************************************************************
 */

static chd_error huff_codec_init(void* codec, uint32_t hunkbytes)
{
	huff_codec_data* huff_codec = (huff_codec_data*) codec;
	huff_codec-&gt;decoder = create_huffman_decoder(256, 16);
	return CHDERR_NONE;
}

static void huff_codec_free(void *codec)
{
	huff_codec_data* huff_codec = (huff_codec_data*) codec;
	delete_huffman_decoder(huff_codec-&gt;decoder);
}

static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t cur;
	chd_error result;
	huff_codec_data* huff_codec = (huff_codec_data*) codec;
	struct bitstream* bitbuf = create_bitstream(src, complen);

	/* first import the tree */
	enum huffman_error err = huffman_import_tree_huffman(huff_codec-&gt;decoder, bitbuf);
	if (err != HUFFERR_NONE)
	{
		free(bitbuf);
		return CHDERR_DECOMPRESSION_ERROR;
	}

	/* then decode the data */
	for (cur = 0; cur &lt; destlen; cur++)
		dest[cur] = huffman_decode_one(huff_codec-&gt;decoder, bitbuf);
	bitstream_flush(bitbuf);
	result = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE;

	free(bitbuf);
	return result;
}
 

/***************************************************************************
    CODEC INTERFACES
***************************************************************************/

static const codec_interface codec_interfaces[] =
{
	/* "none" or no compression */
	{
		CHDCOMPRESSION_NONE,
		"none",
		FALSE,
		NULL,
		NULL,
		NULL,
		NULL
	},

#ifdef HAVE_ZLIB
	/* standard zlib compression */
	{
		CHDCOMPRESSION_ZLIB,
		"zlib",
		FALSE,
		zlib_codec_init,
		zlib_codec_free,
		zlib_codec_decompress,
		NULL
	},

	/* zlib+ compression */
	{
		CHDCOMPRESSION_ZLIB_PLUS,
		"zlib+",
		FALSE,
		zlib_codec_init,
		zlib_codec_free,
		zlib_codec_decompress,
		NULL
	},

	/* V5 zlib compression */
	{
		CHD_CODEC_ZLIB,
		"zlib (Deflate)",
		FALSE,
		zlib_codec_init,
		zlib_codec_free,
		zlib_codec_decompress,
		NULL
	},
	/* V5 CD zlib compression */
	{
		CHD_CODEC_CD_ZLIB,
		"cdzl (CD Deflate)",
		FALSE,
		cdzl_codec_init,
		cdzl_codec_free,
		cdzl_codec_decompress,
		NULL
	},
#endif
#ifdef HAVE_7ZIP
	/* V5 lzma compression */
	{
		CHD_CODEC_LZMA,
		"lzma (LZMA)",
		FALSE,
		lzma_codec_init,
		lzma_codec_free,
		lzma_codec_decompress,
		NULL
	},
	/* V5 CD lzma compression */
	{
		CHD_CODEC_CD_LZMA,
		"cdlz (CD LZMA)",
		FALSE,
		cdlz_codec_init,
		cdlz_codec_free,
		cdlz_codec_decompress,
		NULL
	},
#endif
	/* V5 huffman compression */
	{
		CHD_CODEC_HUFFMAN,
		"Huffman",
		FALSE,
		huff_codec_init,
		huff_codec_free,
		huff_codec_decompress,
		NULL
	},
#ifdef HAVE_FLAC
	/* V5 flac compression */
	{
		CHD_CODEC_FLAC,
		"flac (FLAC)",
		FALSE,
		flac_codec_init,
		flac_codec_free,
		flac_codec_decompress,
		NULL
	},
	/* V5 CD flac compression */
	{
		CHD_CODEC_CD_FLAC,
		"cdfl (CD FLAC)",
		FALSE,
		cdfl_codec_init,
		cdfl_codec_free,
		cdfl_codec_decompress,
		NULL
	},
#endif
#ifdef HAVE_ZSTD
	/* V5 zstd compression */
	{
		CHD_CODEC_ZSTD,
		"zstd (Zstandard)",
		FALSE,
		zstd_codec_init,
		zstd_codec_free,
		zstd_codec_decompress,
		NULL
	},
	/* V5 CD zstd compression */
	{
		CHD_CODEC_CD_ZSTD,
		"cdzs (CD Zstandard)",
		FALSE,
		cdzs_codec_init,
		cdzs_codec_free,
		cdzs_codec_decompress,
		NULL
	}
#endif
	
};

/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

/*-------------------------------------------------
    get_bigendian_uint64_t - fetch a uint64_t from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint64_t get_bigendian_uint64_t(const uint8_t *base)
{
	return ((uint64_t)base[0] &lt;&lt; 56) | ((uint64_t)base[1] &lt;&lt; 48) | ((uint64_t)base[2] &lt;&lt; 40) | ((uint64_t)base[3] &lt;&lt; 32) |
			((uint64_t)base[4] &lt;&lt; 24) | ((uint64_t)base[5] &lt;&lt; 16) | ((uint64_t)base[6] &lt;&lt; 8) | (uint64_t)base[7];
}

/*-------------------------------------------------
    put_bigendian_uint64_t - write a uint64_t to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint64_t(uint8_t *base, uint64_t value)
{
	base[0] = value &gt;&gt; 56;
	base[1] = value &gt;&gt; 48;
	base[2] = value &gt;&gt; 40;
	base[3] = value &gt;&gt; 32;
	base[4] = value &gt;&gt; 24;
	base[5] = value &gt;&gt; 16;
	base[6] = value &gt;&gt; 8;
	base[7] = value;
}

/*-------------------------------------------------
    get_bigendian_uint48 - fetch a UINT48 from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint64_t get_bigendian_uint48(const uint8_t *base)
{
	return  ((uint64_t)base[0] &lt;&lt; 40) | ((uint64_t)base[1] &lt;&lt; 32) |
			((uint64_t)base[2] &lt;&lt; 24) | ((uint64_t)base[3] &lt;&lt; 16) | ((uint64_t)base[4] &lt;&lt; 8) | (uint64_t)base[5];
}

/*-------------------------------------------------
    put_bigendian_uint48 - write a UINT48 to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint48(uint8_t *base, uint64_t value)
{
	value &amp;= 0xffffffffffff;
	base[0] = value &gt;&gt; 40;
	base[1] = value &gt;&gt; 32;
	base[2] = value &gt;&gt; 24;
	base[3] = value &gt;&gt; 16;
	base[4] = value &gt;&gt; 8;
	base[5] = value;
}
/*-------------------------------------------------
    get_bigendian_uint32_t - fetch a uint32_t from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint32_t get_bigendian_uint32_t(const uint8_t *base)
{
	return (base[0] &lt;&lt; 24) | (base[1] &lt;&lt; 16) | (base[2] &lt;&lt; 8) | base[3];
}

/*-------------------------------------------------
    put_bigendian_uint32_t - write a uint32_t to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint32_t(uint8_t *base, uint32_t value)
{
	base[0] = value &gt;&gt; 24;
	base[1] = value &gt;&gt; 16;
	base[2] = value &gt;&gt; 8;
	base[3] = value;
}

/*-------------------------------------------------
    put_bigendian_uint24 - write a UINT24 to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint24(uint8_t *base, uint32_t value)
{
	value &amp;= 0xffffff;
	base[0] = value &gt;&gt; 16;
	base[1] = value &gt;&gt; 8;
	base[2] = value;
}

/*-------------------------------------------------
    get_bigendian_uint24 - fetch a UINT24 from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint32_t get_bigendian_uint24(const uint8_t *base)
{
	return (base[0] &lt;&lt; 16) | (base[1] &lt;&lt; 8) | base[2];
}

/*-------------------------------------------------
    get_bigendian_uint16 - fetch a uint16_t from
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE uint16_t get_bigendian_uint16(const uint8_t *base)
{
	return (base[0] &lt;&lt; 8) | base[1];
}

/*-------------------------------------------------
    put_bigendian_uint16 - write a uint16_t to
    the data stream in bigendian order
-------------------------------------------------*/

static INLINE void put_bigendian_uint16(uint8_t *base, uint16_t value)
{
	base[0] = value &gt;&gt; 8;
	base[1] = value;
}

/*-------------------------------------------------
    map_extract - extract a single map
    entry from the datastream
-------------------------------------------------*/

static INLINE void map_extract(const uint8_t *base, map_entry *entry)
{
	entry-&gt;offset = get_bigendian_uint64_t(&amp;base[0]);
	entry-&gt;crc = get_bigendian_uint32_t(&amp;base[8]);
	entry-&gt;length = get_bigendian_uint16(&amp;base[12]) | (base[14] &lt;&lt; 16);
	entry-&gt;flags = base[15];
}

/*-------------------------------------------------
    map_assemble - write a single map
    entry to the datastream
-------------------------------------------------*/

static INLINE void map_assemble(uint8_t *base, map_entry *entry)
{
	put_bigendian_uint64_t(&amp;base[0], entry-&gt;offset);
	put_bigendian_uint32_t(&amp;base[8], entry-&gt;crc);
	put_bigendian_uint16(&amp;base[12], entry-&gt;length);
	base[14] = entry-&gt;length &gt;&gt; 16;
	base[15] = entry-&gt;flags;
}

/*-------------------------------------------------
    map_size_v5 - calculate CHDv5 map size
-------------------------------------------------*/
static INLINE int map_size_v5(chd_header* header)
{
	return header-&gt;hunkcount * header-&gt;mapentrybytes;
}

/*-------------------------------------------------
    crc16 - calculate CRC16 (from hashing.cpp)
-------------------------------------------------*/
uint16_t crc16(const void *data, uint32_t length)
{
	uint16_t crc = 0xffff;

	static const uint16_t s_table[256] =
	{
		0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
		0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
		0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
		0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
		0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
		0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
		0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
		0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
		0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
		0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
		0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
		0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
		0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
		0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
		0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
		0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
		0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
		0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
		0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
		0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
		0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
		0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
		0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
		0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
		0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
		0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
		0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
		0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
		0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
		0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
		0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
		0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
	};

	const uint8_t *src = (uint8_t*)data;

	/* fetch the current value into a local and rip through the source data */
	while (length-- != 0)
		crc = (crc &lt;&lt; 8) ^ s_table[(crc &gt;&gt; 8) ^ *src++];
	return crc;
}

/*-------------------------------------------------
	compressed - test if CHD file is compressed
+-------------------------------------------------*/
static INLINE int chd_compressed(chd_header* header) {
	return header-&gt;compression[0] != CHD_CODEC_NONE;
}

/*-------------------------------------------------
	decompress_v5_map - decompress the v5 map
-------------------------------------------------*/

static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
{
	uint32_t hunknum;
	int repcount = 0;
	uint8_t lastcomp = 0;
	uint32_t last_self = 0;
	uint64_t last_parent = 0;
	struct bitstream* bitbuf;
	uint32_t mapbytes;
	uint64_t firstoffs;
	uint16_t mapcrc;
	uint8_t lengthbits;
	uint8_t selfbits;
	uint8_t parentbits;
	uint8_t *compressed_ptr;
	uint8_t rawbuf[16];
	struct huffman_decoder* decoder;
	enum huffman_error err;
	uint64_t curoffset;	
	int rawmapsize = map_size_v5(header);

	if (!chd_compressed(header))
	{
		header-&gt;rawmap = (uint8_t*)malloc(rawmapsize);
		if (header-&gt;rawmap == NULL)
			return CHDERR_OUT_OF_MEMORY;
		core_fseek(chd-&gt;file, header-&gt;mapoffset, SEEK_SET);
		core_fread(chd-&gt;file, header-&gt;rawmap, rawmapsize);
		return CHDERR_NONE;
	}

	/* read the reader */
	core_fseek(chd-&gt;file, header-&gt;mapoffset, SEEK_SET);
	core_fread(chd-&gt;file, rawbuf, sizeof(rawbuf));
	mapbytes = get_bigendian_uint32_t(&amp;rawbuf[0]);
	firstoffs = get_bigendian_uint48(&amp;rawbuf[4]);
	mapcrc = get_bigendian_uint16(&amp;rawbuf[10]);
	lengthbits = rawbuf[12];
	selfbits = rawbuf[13];
	parentbits = rawbuf[14];

	/* now read the map */
	compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
	if (compressed_ptr == NULL)
		return CHDERR_OUT_OF_MEMORY;
	core_fseek(chd-&gt;file, header-&gt;mapoffset + 16, SEEK_SET);
	core_fread(chd-&gt;file, compressed_ptr, mapbytes);
	bitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes);
	header-&gt;rawmap = (uint8_t*)malloc(rawmapsize);
	if (header-&gt;rawmap == NULL)
	{
		free(compressed_ptr);
		free(bitbuf);
		return CHDERR_OUT_OF_MEMORY;
	}

	/* first decode the compression types */
	decoder = create_huffman_decoder(16, 8);
	if (decoder == NULL)
	{
		free(compressed_ptr);
		free(bitbuf);
		return CHDERR_OUT_OF_MEMORY;
	}

	err = huffman_import_tree_rle(decoder, bitbuf);
	if (err != HUFFERR_NONE)
	{
		free(compressed_ptr);
		free(bitbuf);
		delete_huffman_decoder(decoder);
		return CHDERR_DECOMPRESSION_ERROR;
	}

	for (hunknum = 0; hunknum &lt; header-&gt;hunkcount; hunknum++)
	{
		uint8_t *rawmap = header-&gt;rawmap + (hunknum * 12);
		if (repcount &gt; 0)
			rawmap[0] = lastcomp, repcount--;
		else
		{
			uint8_t val = huffman_decode_one(decoder, bitbuf);
			if (val == COMPRESSION_RLE_SMALL)
				rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf);
			else if (val == COMPRESSION_RLE_LARGE)
				rawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) &lt;&lt; 4), repcount += huffman_decode_one(decoder, bitbuf);
			else
				rawmap[0] = lastcomp = val;
		}
	}

	/* then iterate through the hunks and extract the needed data */
	curoffset = firstoffs;
	for (hunknum = 0; hunknum &lt; header-&gt;hunkcount; hunknum++)
	{
		uint8_t *rawmap = header-&gt;rawmap + (hunknum * 12);
		uint64_t offset = curoffset;
		uint32_t length = 0;
		uint16_t crc = 0;
		switch (rawmap[0])
		{
			/* base types */
			case COMPRESSION_TYPE_0:
			case COMPRESSION_TYPE_1:
			case COMPRESSION_TYPE_2:
			case COMPRESSION_TYPE_3:
				curoffset += length = bitstream_read(bitbuf, lengthbits);
				crc = bitstream_read(bitbuf, 16);
				break;

			case COMPRESSION_NONE:
				curoffset += length = header-&gt;hunkbytes;
				crc = bitstream_read(bitbuf, 16);
				break;

			case COMPRESSION_SELF:
				last_self = offset = bitstream_read(bitbuf, selfbits);
				break;

			case COMPRESSION_PARENT:
				offset = bitstream_read(bitbuf, parentbits);
				last_parent = offset;
				break;

			/* pseudo-types; convert into base types */
			case COMPRESSION_SELF_1:
				last_self++;
			case COMPRESSION_SELF_0:
				rawmap[0] = COMPRESSION_SELF;
				offset = last_self;
				break;

			case COMPRESSION_PARENT_SELF:
				rawmap[0] = COMPRESSION_PARENT;
				last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header-&gt;hunkbytes) ) / header-&gt;unitbytes;
				break;

			case COMPRESSION_PARENT_1:
				last_parent += header-&gt;hunkbytes / header-&gt;unitbytes;
			case COMPRESSION_PARENT_0:
				rawmap[0] = COMPRESSION_PARENT;
				offset = last_parent;
				break;
		}
		/* UINT24 length */
		put_bigendian_uint24(&amp;rawmap[1], length);

		/* UINT48 offset */
		put_bigendian_uint48(&amp;rawmap[4], offset);

		/* crc16 */
		put_bigendian_uint16(&amp;rawmap[10], crc);
	}

	/* free memory */
	free(compressed_ptr);
	free(bitbuf);
	delete_huffman_decoder(decoder);

	/* verify the final CRC */
	if (crc16(&amp;header-&gt;rawmap[0], header-&gt;hunkcount * 12) != mapcrc)
		return CHDERR_DECOMPRESSION_ERROR;

	return CHDERR_NONE;
}

/*-------------------------------------------------
    map_extract_old - extract a single map
    entry in old format from the datastream
-------------------------------------------------*/

static INLINE void map_extract_old(const uint8_t *base, map_entry *entry, uint32_t hunkbytes)
{
	entry-&gt;offset = get_bigendian_uint64_t(&amp;base[0]);
	entry-&gt;crc = 0;
	entry-&gt;length = entry-&gt;offset &gt;&gt; 44;
	entry-&gt;flags = MAP_ENTRY_FLAG_NO_CRC | ((entry-&gt;length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
#ifdef __MWERKS__
	entry-&gt;offset = entry-&gt;offset &amp; 0x00000FFFFFFFFFFFLL;
#else
	entry-&gt;offset = (entry-&gt;offset &lt;&lt; 20) &gt;&gt; 20;
#endif
}

/***************************************************************************
    CHD FILE MANAGEMENT
***************************************************************************/

/*-------------------------------------------------
    chd_open_file - open a CHD file for access
-------------------------------------------------*/

CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd) {
	core_file *stream = malloc(sizeof(core_file));
	if (!stream)
		return CHDERR_OUT_OF_MEMORY;
	stream-&gt;argp = file;
	stream-&gt;fsize = core_stdio_fsize;
	stream-&gt;fread = core_stdio_fread;
	stream-&gt;fclose = core_stdio_fclose_nonowner;
	stream-&gt;fseek = core_stdio_fseek;

	return chd_open_core_file(stream, mode, parent, chd);
}

/*-------------------------------------------------
    chd_open_core_file - open a CHD file for access
-------------------------------------------------*/

CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd)
{
	chd_file *newchd = NULL;
	chd_error err;
	size_t intfnum;

	/* verify parameters */
	if (file == NULL)
		EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);

	/* punt if invalid parent */
	if (parent != NULL &amp;&amp; parent-&gt;cookie != COOKIE_VALUE)
		EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);

	/* allocate memory for the final result */
	newchd = (chd_file *)malloc(sizeof(**chd));
	if (newchd == NULL)
		EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
	memset(newchd, 0, sizeof(*newchd));
	newchd-&gt;cookie = COOKIE_VALUE;
	newchd-&gt;parent = parent;
	newchd-&gt;file = file;

	/* now attempt to read the header */
	err = header_read(newchd, &amp;newchd-&gt;header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

	/* validate the header */
	err = header_validate(&amp;newchd-&gt;header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

	/* make sure we don't open a read-only file writeable */
	if (mode == CHD_OPEN_READWRITE &amp;&amp; !(newchd-&gt;header.flags &amp; CHDFLAGS_IS_WRITEABLE))
		EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);

	/* also, never open an older version writeable */
	if (mode == CHD_OPEN_READWRITE &amp;&amp; newchd-&gt;header.version &lt; CHD_HEADER_VERSION)
		EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);

	/* if we need a parent, make sure we have one */
	if (parent == NULL)
	{
		/* Detect parent requirement for versions below 5 */
		if (newchd-&gt;header.version &lt; 5 &amp;&amp; newchd-&gt;header.flags &amp; CHDFLAGS_HAS_PARENT)
			EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
		/* Detection for version 5 and above - if parentsha1 != 0, we have a parent */
		else if (newchd-&gt;header.version &gt;= 5 &amp;&amp; memcmp(nullsha1, newchd-&gt;header.parentsha1, sizeof(newchd-&gt;header.parentsha1)) != 0)
			EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
	}

	/* make sure we have a valid parent */
	if (parent != NULL)
	{
		/* check MD5 if it isn't empty */
		if (memcmp(nullmd5, newchd-&gt;header.parentmd5, sizeof(newchd-&gt;header.parentmd5)) != 0 &amp;&amp;
			memcmp(nullmd5, newchd-&gt;parent-&gt;header.md5, sizeof(newchd-&gt;parent-&gt;header.md5)) != 0 &amp;&amp;
			memcmp(newchd-&gt;parent-&gt;header.md5, newchd-&gt;header.parentmd5, sizeof(newchd-&gt;header.parentmd5)) != 0)
			EARLY_EXIT(err = CHDERR_INVALID_PARENT);

		/* check SHA1 if it isn't empty */
		if (memcmp(nullsha1, newchd-&gt;header.parentsha1, sizeof(newchd-&gt;header.parentsha1)) != 0 &amp;&amp;
			memcmp(nullsha1, newchd-&gt;parent-&gt;header.sha1, sizeof(newchd-&gt;parent-&gt;header.sha1)) != 0 &amp;&amp;
			memcmp(newchd-&gt;parent-&gt;header.sha1, newchd-&gt;header.parentsha1, sizeof(newchd-&gt;header.parentsha1)) != 0)
			EARLY_EXIT(err = CHDERR_INVALID_PARENT);
	}

	/* now read the hunk map */
	if (newchd-&gt;header.version &lt; 5)
	{
		err = map_read(newchd);
		if (err != CHDERR_NONE)
			EARLY_EXIT(err);
	}
	else
	{
		err = decompress_v5_map(newchd, &amp;(newchd-&gt;header));
	}
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

#ifdef NEED_CACHE_HUNK
	/* allocate and init the hunk cache */
	newchd-&gt;cache = (uint8_t *)malloc(newchd-&gt;header.hunkbytes);
	newchd-&gt;compare = (uint8_t *)malloc(newchd-&gt;header.hunkbytes);
	if (newchd-&gt;cache == NULL || newchd-&gt;compare == NULL)
		EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
	newchd-&gt;cachehunk = ~0;
	newchd-&gt;comparehunk = ~0;
#endif

	/* allocate the temporary compressed buffer */
	newchd-&gt;compressed = (uint8_t *)malloc(newchd-&gt;header.hunkbytes);
	if (newchd-&gt;compressed == NULL)
		EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);

	/* find the codec interface */
	if (newchd-&gt;header.version &lt; 5)
	{
		for (intfnum = 0; intfnum &lt; ARRAY_LENGTH(codec_interfaces); intfnum++)
		{
			if (codec_interfaces[intfnum].compression == newchd-&gt;header.compression[0])
			{
				newchd-&gt;codecintf[0] = &amp;codec_interfaces[intfnum];
				break;
			}
		}

		if (intfnum == ARRAY_LENGTH(codec_interfaces))
			EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);

#ifdef HAVE_ZLIB
		/* initialize the codec */
		if (newchd-&gt;codecintf[0]-&gt;init != NULL)
		{
			err = (*newchd-&gt;codecintf[0]-&gt;init)(&amp;newchd-&gt;zlib_codec_data, newchd-&gt;header.hunkbytes);
			if (err != CHDERR_NONE)
				EARLY_EXIT(err);
		}
#endif
	}
	else
	{
		size_t decompnum;
		/* verify the compression types and initialize the codecs */
		for (decompnum = 0; decompnum &lt; ARRAY_LENGTH(newchd-&gt;header.compression); decompnum++)
		{
			size_t i;
			for (i = 0 ; i &lt; ARRAY_LENGTH(codec_interfaces) ; i++)
			{
				if (codec_interfaces[i].compression == newchd-&gt;header.compression[decompnum])
				{
					newchd-&gt;codecintf[decompnum] = &amp;codec_interfaces[i];
					break;
				}
			}

			if (newchd-&gt;codecintf[decompnum] == NULL &amp;&amp; newchd-&gt;header.compression[decompnum] != 0)
				EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);

			/* initialize the codec */
			if (newchd-&gt;codecintf[decompnum]-&gt;init != NULL)
			{
				void* codec = NULL;
				switch (newchd-&gt;header.compression[decompnum])
				{
					case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
						codec = &amp;newchd-&gt;zlib_codec_data;
#endif
						break;

					case CHD_CODEC_LZMA:
#ifdef HAVE_7ZIP
						codec = &amp;newchd-&gt;lzma_codec_data;
#endif
						break;

					case CHD_CODEC_HUFFMAN:
						codec = &amp;newchd-&gt;huff_codec_data;
						break;

					case CHD_CODEC_FLAC:
#ifdef HAVE_FLAC
						codec = &amp;newchd-&gt;flac_codec_data;
#endif
						break;

					case CHD_CODEC_ZSTD:
#ifdef HAVE_ZSTD
						codec = &amp;newchd-&gt;zstd_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
						codec = &amp;newchd-&gt;cdzl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_LZMA:
#ifdef HAVE_7ZIP
						codec = &amp;newchd-&gt;cdlz_codec_data;
#endif
						break;

					case CHD_CODEC_CD_FLAC:
#ifdef HAVE_FLAC
						codec = &amp;newchd-&gt;cdfl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZSTD:
#ifdef HAVE_ZSTD
						codec = &amp;newchd-&gt;cdzs_codec_data;
#endif
						break;
				}

				if (codec == NULL)
					EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);

				err = (*newchd-&gt;codecintf[decompnum]-&gt;init)(codec, newchd-&gt;header.hunkbytes);
				if (err != CHDERR_NONE)
					EARLY_EXIT(err);
			}
		}
	}

	/* all done */
	*chd = newchd;
	return CHDERR_NONE;

cleanup:
	if (newchd != NULL)
		chd_close(newchd);
	return err;
}

/*-------------------------------------------------
    chd_precache - precache underlying file in
    memory
-------------------------------------------------*/

CHD_EXPORT chd_error chd_precache(chd_file *chd)
{
	uint64_t count;
	uint64_t size;

	if (chd-&gt;file_cache == NULL)
	{
		size = core_fsize(chd-&gt;file);
		if ((int64_t)size &lt;= 0)
			return CHDERR_INVALID_DATA;
		chd-&gt;file_cache = malloc(size);
		if (chd-&gt;file_cache == NULL)
			return CHDERR_OUT_OF_MEMORY;
		core_fseek(chd-&gt;file, 0, SEEK_SET);
		count = core_fread(chd-&gt;file, chd-&gt;file_cache, size);
		if (count != size)
		{
			free(chd-&gt;file_cache);
			chd-&gt;file_cache = NULL;
			return CHDERR_READ_ERROR;
		}
	}

	return CHDERR_NONE;
}

/*-------------------------------------------------
    chd_open - open a CHD file by
    filename
-------------------------------------------------*/

CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
{
	chd_error err;
	core_file *file = NULL;

	if (filename == NULL)
	{
		err = CHDERR_INVALID_PARAMETER;
		goto cleanup;
	}

	/* choose the proper mode */
	switch(mode)
	{
		case CHD_OPEN_READ:
			break;

		default:
			err = CHDERR_INVALID_PARAMETER;
			goto cleanup;
	}

	/* open the file */
	file = core_stdio_fopen(filename);
	if (file == 0)
	{
		err = CHDERR_FILE_NOT_FOUND;
		goto cleanup;
	}

	/* now open the CHD */
	return chd_open_core_file(file, mode, parent, chd);

cleanup:
	if ((err != CHDERR_NONE) &amp;&amp; (file != NULL))
		core_fclose(file);
	return err;
}

/*-------------------------------------------------
    chd_close - close a CHD file for access
-------------------------------------------------*/

CHD_EXPORT void chd_close(chd_file *chd)
{
	/* punt if NULL or invalid */
	if (chd == NULL || chd-&gt;cookie != COOKIE_VALUE)
		return;

	/* deinit the codec */
	if (chd-&gt;header.version &lt; 5)
	{
#ifdef HAVE_ZLIB
		if (chd-&gt;codecintf[0] != NULL &amp;&amp; chd-&gt;codecintf[0]-&gt;free != NULL)
			(*chd-&gt;codecintf[0]-&gt;free)(&amp;chd-&gt;zlib_codec_data);
#endif
	}
	else
	{
		size_t i;
		/* Free the codecs */
		for (i = 0 ; i &lt; ARRAY_LENGTH(chd-&gt;codecintf); i++)
		{
			void* codec = NULL;

			if (chd-&gt;codecintf[i] == NULL)
				continue;

			switch (chd-&gt;codecintf[i]-&gt;compression)
			{
				case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
					codec = &amp;chd-&gt;zlib_codec_data;
#endif
					break;

				case CHD_CODEC_LZMA:
#ifdef HAVE_7ZIP
					codec = &amp;chd-&gt;lzma_codec_data;
#endif
					break;

				case CHD_CODEC_HUFFMAN:
					codec = &amp;chd-&gt;huff_codec_data;
					break;

				case CHD_CODEC_FLAC:
#ifdef HAVE_FLAC
					codec = &amp;chd-&gt;flac_codec_data;
#endif
					break;

				case CHD_CODEC_ZSTD:
#ifdef HAVE_ZSTD
					codec = &amp;chd-&gt;zstd_codec_data;
#endif
					break;

				case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
					codec = &amp;chd-&gt;cdzl_codec_data;
#endif
					break;

				case CHD_CODEC_CD_LZMA:
#ifdef HAVE_7ZIP
					codec = &amp;chd-&gt;cdlz_codec_data;
#endif
					break;

				case CHD_CODEC_CD_FLAC:
#ifdef HAVE_FLAC
					codec = &amp;chd-&gt;cdfl_codec_data;
#endif
					break;

				case CHD_CODEC_CD_ZSTD:
#ifdef HAVE_ZSTD
					codec = &amp;chd-&gt;cdzs_codec_data;
#endif
					break;
			}

			if (codec)
			{
				(*chd-&gt;codecintf[i]-&gt;free)(codec);
			}
		}

		/* Free the raw map */
		if (chd-&gt;header.rawmap != NULL)
			free(chd-&gt;header.rawmap);
	}

	/* free the compressed data buffer */
	if (chd-&gt;compressed != NULL)
		free(chd-&gt;compressed);

#ifdef NEED_CACHE_HUNK
	/* free the hunk cache and compare data */
	if (chd-&gt;compare != NULL)
		free(chd-&gt;compare);
	if (chd-&gt;cache != NULL)
		free(chd-&gt;cache);
#endif

	/* free the hunk map */
	if (chd-&gt;map != NULL)
		free(chd-&gt;map);

	/* close the file */
	if (chd-&gt;file != NULL)
		core_fclose(chd-&gt;file);

#ifdef NEED_CACHE_HUNK
	if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd-&gt;maxhunk, chd-&gt;header.totalhunks);
#endif
	if (chd-&gt;file_cache)
		free(chd-&gt;file_cache);

	if (chd-&gt;parent)
		chd_close(chd-&gt;parent);

	/* free our memory */
	free(chd);
}

/*-------------------------------------------------
    chd_core_file - return the associated
    core_file
-------------------------------------------------*/

CHD_EXPORT core_file *chd_core_file(chd_file *chd)
{
	return chd-&gt;file;
}

/*-------------------------------------------------
    chd_error_string - return an error string for
    the given CHD error
-------------------------------------------------*/

CHD_EXPORT const char *chd_error_string(chd_error err)
{
	switch (err)
	{
		case CHDERR_NONE:						return "no error";
		case CHDERR_NO_INTERFACE:				return "no drive interface";
		case CHDERR_OUT_OF_MEMORY:				return "out of memory";
		case CHDERR_INVALID_FILE:				return "invalid file";
		case CHDERR_INVALID_PARAMETER:			return "invalid parameter";
		case CHDERR_INVALID_DATA:				return "invalid data";
		case CHDERR_FILE_NOT_FOUND:				return "file not found";
		case CHDERR_REQUIRES_PARENT:			return "requires parent";
		case CHDERR_FILE_NOT_WRITEABLE:			return "file not writeable";
		case CHDERR_READ_ERROR:					return "read error";
		case CHDERR_WRITE_ERROR:				return "write error";
		case CHDERR_CODEC_ERROR:				return "codec error";
		case CHDERR_INVALID_PARENT:				return "invalid parent";
		case CHDERR_HUNK_OUT_OF_RANGE:			return "hunk out of range";
		case CHDERR_DECOMPRESSION_ERROR:		return "decompression error";
		case CHDERR_COMPRESSION_ERROR:			return "compression error";
		case CHDERR_CANT_CREATE_FILE:			return "can't create file";
		case CHDERR_CANT_VERIFY:				return "can't verify file";
		case CHDERR_NOT_SUPPORTED:				return "operation not supported";
		case CHDERR_METADATA_NOT_FOUND:			return "can't find metadata";
		case CHDERR_INVALID_METADATA_SIZE:		return "invalid metadata size";
		case CHDERR_UNSUPPORTED_VERSION:		return "unsupported CHD version";
		case CHDERR_VERIFY_INCOMPLETE:			return "incomplete verify";
		case CHDERR_INVALID_METADATA:			return "invalid metadata";
		case CHDERR_INVALID_STATE:				return "invalid state";
		case CHDERR_OPERATION_PENDING:			return "operation pending";
		case CHDERR_NO_ASYNC_OPERATION:			return "no async operation in progress";
		case CHDERR_UNSUPPORTED_FORMAT:			return "unsupported format";
		default:								return "undocumented error";
	}
}

/***************************************************************************
    CHD HEADER MANAGEMENT
***************************************************************************/

/*-------------------------------------------------
    chd_get_header - return a pointer to the
    extracted header data
-------------------------------------------------*/

CHD_EXPORT const chd_header *chd_get_header(chd_file *chd)
{
	/* punt if NULL or invalid */
	if (chd == NULL || chd-&gt;cookie != COOKIE_VALUE)
		return NULL;

	return &amp;chd-&gt;header;
}

/*-------------------------------------------------
    chd_read_header - read CHD header data
	from file into the pointed struct
-------------------------------------------------*/
CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header)
{
	chd_error err = CHDERR_NONE;
	chd_file *chd = NULL;

	/* punt if NULL */
	if (filename == NULL || header == NULL)
		EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);

	/* open the file */
	chd-&gt;file = core_stdio_fopen(filename);
	if (chd-&gt;file == NULL)
		EARLY_EXIT(err = CHDERR_FILE_NOT_FOUND);

	/* attempt to read the header */
	err = header_read(chd, header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

	/* validate the header */
	err = header_validate(header);
	if (err != CHDERR_NONE)
		EARLY_EXIT(err);

cleanup:
	if (chd-&gt;file != NULL)
		core_fclose(chd-&gt;file);

	return err;
}

/***************************************************************************
    CORE DATA READ/WRITE
***************************************************************************/

/*-------------------------------------------------
    chd_read - read a single hunk from the CHD
    file
-------------------------------------------------*/

CHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer)
{
	/* punt if NULL or invalid */
	if (chd == NULL || chd-&gt;cookie != COOKIE_VALUE)
		return CHDERR_INVALID_PARAMETER;

	/* if we're past the end, fail */
	if (hunknum &gt;= chd-&gt;header.totalhunks)
		return CHDERR_HUNK_OUT_OF_RANGE;

	/* perform the read */
	return hunk_read_into_memory(chd, hunknum, (uint8_t *)buffer);
}

/***************************************************************************
    METADATA MANAGEMENT
***************************************************************************/

/*-------------------------------------------------
    chd_get_metadata - get the indexed metadata
    of the given type
-------------------------------------------------*/

CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, uint32_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags)
{
	metadata_entry metaentry;
	chd_error err;
	uint32_t count;

	/* if we didn't find it, just return */
	err = metadata_find_entry(chd, searchtag, searchindex, &amp;metaentry);
	if (err != CHDERR_NONE)
	{
		/* unless we're an old version and they are requesting hard disk metadata */
		if (chd-&gt;header.version &lt; 3 &amp;&amp; (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) &amp;&amp; searchindex == 0)
		{
			char faux_metadata[256];
			uint32_t faux_length;

			/* fill in the faux metadata */
			sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd-&gt;header.obsolete_cylinders, chd-&gt;header.obsolete_heads, chd-&gt;header.obsolete_sectors, chd-&gt;header.hunkbytes / chd-&gt;header.obsolete_hunksize);
			faux_length = (uint32_t)strlen(faux_metadata) + 1;

			/* copy the metadata itself */
			memcpy(output, faux_metadata, MIN(outputlen, faux_length));

			/* return the length of the data and the tag */
			if (resultlen != NULL)
				*resultlen = faux_length;
			if (resulttag != NULL)
				*resulttag = HARD_DISK_METADATA_TAG;
			return CHDERR_NONE;
		}
		return err;
	}

	/* read the metadata */
	outputlen = MIN(outputlen, metaentry.length);
	core_fseek(chd-&gt;file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
	count = core_fread(chd-&gt;file, output, outputlen);
	if (count != outputlen)
		return CHDERR_READ_ERROR;

	/* return the length of the data and the tag */
	if (resultlen != NULL)
		*resultlen = metaentry.length;
	if (resulttag != NULL)
		*resulttag = metaentry.metatag;
	if (resultflags != NULL)
		*resultflags = metaentry.flags;
	return CHDERR_NONE;
}

/***************************************************************************
    CODEC INTERFACES
***************************************************************************/

/*-------------------------------------------------
    chd_codec_config - set internal codec
    parameters
-------------------------------------------------*/

CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config)
{
	return CHDERR_INVALID_PARAMETER;
}

/*-------------------------------------------------
    chd_get_codec_name - get the name of a
    particular codec
-------------------------------------------------*/

CHD_EXPORT const char *chd_get_codec_name(uint32_t codec)
{
	return "Unknown";
}

/***************************************************************************
    INTERNAL HEADER OPERATIONS
***************************************************************************/

/*-------------------------------------------------
    header_validate - check the validity of a
    CHD header
-------------------------------------------------*/

static chd_error header_validate(const chd_header *header)
{
	size_t intfnum;

	/* require a valid version */
	if (header-&gt;version == 0 || header-&gt;version &gt; CHD_HEADER_VERSION)
		return CHDERR_UNSUPPORTED_VERSION;

	/* require a valid length */
	if ((header-&gt;version == 1 &amp;&amp; header-&gt;length != CHD_V1_HEADER_SIZE) ||
		(header-&gt;version == 2 &amp;&amp; header-&gt;length != CHD_V2_HEADER_SIZE) ||
		(header-&gt;version == 3 &amp;&amp; header-&gt;length != CHD_V3_HEADER_SIZE) ||
		(header-&gt;version == 4 &amp;&amp; header-&gt;length != CHD_V4_HEADER_SIZE) ||
		(header-&gt;version == 5 &amp;&amp; header-&gt;length != CHD_V5_HEADER_SIZE))
		return CHDERR_INVALID_PARAMETER;

	/* Do not validate v5 header */
	if (header-&gt;version &lt;= 4)
	{
		/* require valid flags */
		if (header-&gt;flags &amp; CHDFLAGS_UNDEFINED)
			return CHDERR_INVALID_PARAMETER;

		/* require a supported compression mechanism */
		for (intfnum = 0; intfnum &lt; ARRAY_LENGTH(codec_interfaces); intfnum++)
			if (codec_interfaces[intfnum].compression == header-&gt;compression[0])
				break;

		if (intfnum == ARRAY_LENGTH(codec_interfaces))
			return CHDERR_INVALID_PARAMETER;

		/* require a valid hunksize */
		if (header-&gt;hunkbytes == 0 || header-&gt;hunkbytes &gt;= 65536 * 256)
			return CHDERR_INVALID_PARAMETER;

		/* require a valid hunk count */
		if (header-&gt;totalhunks == 0)
			return CHDERR_INVALID_PARAMETER;

		/* require a valid MD5 and/or SHA1 if we're using a parent */
		if ((header-&gt;flags &amp; CHDFLAGS_HAS_PARENT) &amp;&amp; memcmp(header-&gt;parentmd5, nullmd5, sizeof(nullmd5)) == 0 &amp;&amp; memcmp(header-&gt;parentsha1, nullsha1, sizeof(nullsha1)) == 0)
			return CHDERR_INVALID_PARAMETER;

		/* if we're V3 or later, the obsolete fields must be 0 */
		if (header-&gt;version &gt;= 3 &amp;&amp;
			(header-&gt;obsolete_cylinders != 0 || header-&gt;obsolete_sectors != 0 ||
			 header-&gt;obsolete_heads != 0 || header-&gt;obsolete_hunksize != 0))
			return CHDERR_INVALID_PARAMETER;

		/* if we're pre-V3, the obsolete fields must NOT be 0 */
		if (header-&gt;version &lt; 3 &amp;&amp;
			(header-&gt;obsolete_cylinders == 0 || header-&gt;obsolete_sectors == 0 ||
			 header-&gt;obsolete_heads == 0 || header-&gt;obsolete_hunksize == 0))
			return CHDERR_INVALID_PARAMETER;
	}

	return CHDERR_NONE;
}

/*-------------------------------------------------
    header_guess_unitbytes - for older CHD formats,
    guess at the bytes/unit based on metadata
-------------------------------------------------*/

static uint32_t header_guess_unitbytes(chd_file *chd)
{
	/* look for hard disk metadata; if found, then the unit size == sector size */
	char metadata[512];
	int i0, i1, i2, i3;
	if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &amp;&amp;
		sscanf(metadata, HARD_DISK_METADATA_FORMAT, &amp;i0, &amp;i1, &amp;i2, &amp;i3) == 4)
		return i3;

	/* look for CD-ROM metadata; if found, then the unit size == CD frame size */
	if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
		chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
		return CD_FRAME_SIZE;

	/* otherwise, just map 1:1 with the hunk size */
	return chd-&gt;header.hunkbytes;
}

/*-------------------------------------------------
    header_read - read a CHD header into the
    internal data structure
-------------------------------------------------*/

static chd_error header_read(chd_file *chd, chd_header *header)
{
	uint8_t rawheader[CHD_MAX_HEADER_SIZE];
	uint32_t count;

	/* punt if NULL */
	if (header == NULL)
		return CHDERR_INVALID_PARAMETER;

	/* punt if invalid file */
	if (chd-&gt;file == NULL)
		return CHDERR_INVALID_FILE;

	/* seek and read */
	core_fseek(chd-&gt;file, 0, SEEK_SET);
	count = core_fread(chd-&gt;file, rawheader, sizeof(rawheader));
	if (count != sizeof(rawheader))
		return CHDERR_READ_ERROR;

	/* verify the tag */
	if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
		return CHDERR_INVALID_DATA;

	/* extract the direct data */
	memset(header, 0, sizeof(*header));
	header-&gt;length        = get_bigendian_uint32_t(&amp;rawheader[8]);
	header-&gt;version       = get_bigendian_uint32_t(&amp;rawheader[12]);

	/* make sure it's a version we understand */
	if (header-&gt;version == 0 || header-&gt;version &gt; CHD_HEADER_VERSION)
		return CHDERR_UNSUPPORTED_VERSION;

	/* make sure the length is expected */
	if ((header-&gt;version == 1 &amp;&amp; header-&gt;length != CHD_V1_HEADER_SIZE) ||
		(header-&gt;version == 2 &amp;&amp; header-&gt;length != CHD_V2_HEADER_SIZE) ||
		(header-&gt;version == 3 &amp;&amp; header-&gt;length != CHD_V3_HEADER_SIZE) ||
		(header-&gt;version == 4 &amp;&amp; header-&gt;length != CHD_V4_HEADER_SIZE) ||
		(header-&gt;version == 5 &amp;&amp; header-&gt;length != CHD_V5_HEADER_SIZE))

		return CHDERR_INVALID_DATA;

	/* extract the common data */
	header-&gt;flags         	= get_bigendian_uint32_t(&amp;rawheader[16]);
	header-&gt;compression[0]	= get_bigendian_uint32_t(&amp;rawheader[20]);
	header-&gt;compression[1]	= CHD_CODEC_NONE;
	header-&gt;compression[2]	= CHD_CODEC_NONE;
	header-&gt;compression[3]	= CHD_CODEC_NONE;

	/* extract the V1/V2-specific data */
	if (header-&gt;version &lt; 3)
	{
		int seclen = (header-&gt;version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32_t(&amp;rawheader[76]);
		header-&gt;obsolete_hunksize  = get_bigendian_uint32_t(&amp;rawheader[24]);
		header-&gt;totalhunks         = get_bigendian_uint32_t(&amp;rawheader[28]);
		header-&gt;obsolete_cylinders = get_bigendian_uint32_t(&amp;rawheader[32]);
		header-&gt;obsolete_heads     = get_bigendian_uint32_t(&amp;rawheader[36]);
		header-&gt;obsolete_sectors   = get_bigendian_uint32_t(&amp;rawheader[40]);
		memcpy(header-&gt;md5, &amp;rawheader[44], CHD_MD5_BYTES);
		memcpy(header-&gt;parentmd5, &amp;rawheader[60], CHD_MD5_BYTES);
		header-&gt;logicalbytes = (uint64_t)header-&gt;obsolete_cylinders * (uint64_t)header-&gt;obsolete_heads * (uint64_t)header-&gt;obsolete_sectors * (uint64_t)seclen;
		header-&gt;hunkbytes = seclen * header-&gt;obsolete_hunksize;
		header-&gt;unitbytes          = header_guess_unitbytes(chd);
		if (header-&gt;unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header-&gt;unitcount          = (header-&gt;logicalbytes + header-&gt;unitbytes - 1) / header-&gt;unitbytes;
		header-&gt;metaoffset = 0;
	}

	/* extract the V3-specific data */
	else if (header-&gt;version == 3)
	{
		header-&gt;totalhunks   = get_bigendian_uint32_t(&amp;rawheader[24]);
		header-&gt;logicalbytes = get_bigendian_uint64_t(&amp;rawheader[28]);
		header-&gt;metaoffset   = get_bigendian_uint64_t(&amp;rawheader[36]);
		memcpy(header-&gt;md5, &amp;rawheader[44], CHD_MD5_BYTES);
		memcpy(header-&gt;parentmd5, &amp;rawheader[60], CHD_MD5_BYTES);
		header-&gt;hunkbytes    = get_bigendian_uint32_t(&amp;rawheader[76]);
		header-&gt;unitbytes    = header_guess_unitbytes(chd);
		if (header-&gt;unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header-&gt;unitcount    = (header-&gt;logicalbytes + header-&gt;unitbytes - 1) / header-&gt;unitbytes;
		memcpy(header-&gt;sha1, &amp;rawheader[80], CHD_SHA1_BYTES);
		memcpy(header-&gt;parentsha1, &amp;rawheader[100], CHD_SHA1_BYTES);
	}

	/* extract the V4-specific data */
	else if (header-&gt;version == 4)
	{
		header-&gt;totalhunks   = get_bigendian_uint32_t(&amp;rawheader[24]);
		header-&gt;logicalbytes = get_bigendian_uint64_t(&amp;rawheader[28]);
		header-&gt;metaoffset   = get_bigendian_uint64_t(&amp;rawheader[36]);
		header-&gt;hunkbytes    = get_bigendian_uint32_t(&amp;rawheader[44]);
		header-&gt;unitbytes    = header_guess_unitbytes(chd);
		if (header-&gt;unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header-&gt;unitcount    = (header-&gt;logicalbytes + header-&gt;unitbytes - 1) / header-&gt;unitbytes;
		memcpy(header-&gt;sha1, &amp;rawheader[48], CHD_SHA1_BYTES);
		memcpy(header-&gt;parentsha1, &amp;rawheader[68], CHD_SHA1_BYTES);
		memcpy(header-&gt;rawsha1, &amp;rawheader[88], CHD_SHA1_BYTES);
	}

	/* extract the V5-specific data */
	else if (header-&gt;version == 5)
	{
		/* TODO */
		header-&gt;compression[0]  = get_bigendian_uint32_t(&amp;rawheader[16]);
		header-&gt;compression[1]  = get_bigendian_uint32_t(&amp;rawheader[20]);
		header-&gt;compression[2]  = get_bigendian_uint32_t(&amp;rawheader[24]);
		header-&gt;compression[3]  = get_bigendian_uint32_t(&amp;rawheader[28]);
		header-&gt;logicalbytes    = get_bigendian_uint64_t(&amp;rawheader[32]);
		header-&gt;mapoffset       = get_bigendian_uint64_t(&amp;rawheader[40]);
		header-&gt;metaoffset      = get_bigendian_uint64_t(&amp;rawheader[48]);
		header-&gt;hunkbytes       = get_bigendian_uint32_t(&amp;rawheader[56]);
		if (header-&gt;hunkbytes == 0)
			return CHDERR_INVALID_DATA;
		header-&gt;hunkcount       = (header-&gt;logicalbytes + header-&gt;hunkbytes - 1) / header-&gt;hunkbytes;
		header-&gt;unitbytes       = get_bigendian_uint32_t(&amp;rawheader[60]);
		if (header-&gt;unitbytes == 0)
			return CHDERR_INVALID_DATA;
		header-&gt;unitcount       = (header-&gt;logicalbytes + header-&gt;unitbytes - 1) / header-&gt;unitbytes;
		memcpy(header-&gt;sha1, &amp;rawheader[84], CHD_SHA1_BYTES);
		memcpy(header-&gt;parentsha1, &amp;rawheader[104], CHD_SHA1_BYTES);
		memcpy(header-&gt;rawsha1, &amp;rawheader[64], CHD_SHA1_BYTES);

		/* determine properties of map entries */
		header-&gt;mapentrybytes = chd_compressed(header) ? 12 : 4;

		/* hack */
		header-&gt;totalhunks 		= header-&gt;hunkcount;
	}

	/* Unknown version */
	else
	{
		/* TODO */
	}

	/* guess it worked */
	return CHDERR_NONE;
}

/***************************************************************************
    INTERNAL HUNK READ/WRITE
***************************************************************************/

/*-------------------------------------------------
    hunk_read_compressed - read a compressed
    hunk
-------------------------------------------------*/

static uint8_t* hunk_read_compressed(chd_file *chd, uint64_t offset, size_t size)
{
	size_t bytes;

	if (chd-&gt;file_cache != NULL)
	{
		return chd-&gt;file_cache + offset;
	}
	else
	{
		core_fseek(chd-&gt;file, offset, SEEK_SET);
		bytes = core_fread(chd-&gt;file, chd-&gt;compressed, size);
		if (bytes != size)
			return NULL;
		return chd-&gt;compressed;
	}
}

/*-------------------------------------------------
    hunk_read_uncompressed - read an uncompressed
    hunk
-------------------------------------------------*/

static chd_error hunk_read_uncompressed(chd_file *chd, uint64_t offset, size_t size, uint8_t *dest)
{
	size_t bytes;

	if (chd-&gt;file_cache != NULL)
	{
		memcpy(dest, chd-&gt;file_cache + offset, size);
	}
	else
	{
		core_fseek(chd-&gt;file, offset, SEEK_SET);
		bytes = core_fread(chd-&gt;file, dest, size);
		if (bytes != size)
			return CHDERR_READ_ERROR;
	}
	return CHDERR_NONE;
}

#ifdef NEED_CACHE_HUNK
/*-------------------------------------------------
    hunk_read_into_cache - read a hunk into
    the CHD's hunk cache
-------------------------------------------------*/

static chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum)
{
	chd_error err;

	/* track the max */
	if (hunknum &gt; chd-&gt;maxhunk)
		chd-&gt;maxhunk = hunknum;

	/* if we're already in the cache, we're done */
	if (chd-&gt;cachehunk == hunknum)
		return CHDERR_NONE;
	chd-&gt;cachehunk = ~0;

	/* otherwise, read the data */
	err = hunk_read_into_memory(chd, hunknum, chd-&gt;cache);
	if (err != CHDERR_NONE)
		return err;

	/* mark the hunk successfully cached in */
	chd-&gt;cachehunk = hunknum;
	return CHDERR_NONE;
}
#endif

/*-------------------------------------------------
    hunk_read_into_memory - read a hunk into
    memory at the given location
-------------------------------------------------*/

static chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest)
{
	chd_error err;

	/* punt if no file */
	if (chd-&gt;file == NULL)
		return CHDERR_INVALID_FILE;

	/* return an error if out of range */
	if (hunknum &gt;= chd-&gt;header.totalhunks)
		return CHDERR_HUNK_OUT_OF_RANGE;

	if (dest == NULL)
		return CHDERR_INVALID_PARAMETER;

	if (chd-&gt;header.version &lt; 5)
	{
		map_entry *entry = &amp;chd-&gt;map[hunknum];
		uint32_t bytes;
		uint8_t* compressed_bytes;

		/* switch off the entry type */
		switch (entry-&gt;flags &amp; MAP_ENTRY_FLAG_TYPE_MASK)
		{
			/* compressed data */
			case V34_MAP_ENTRY_TYPE_COMPRESSED:
            {
               void *codec = NULL;

				/* read it into the decompression buffer */
				compressed_bytes = hunk_read_compressed(chd, entry-&gt;offset, entry-&gt;length);
				if (compressed_bytes == NULL)
					{
					return CHDERR_READ_ERROR;
					}

#ifdef HAVE_ZLIB
				/* now decompress using the codec */
				err = CHDERR_NONE;
				codec = &amp;chd-&gt;zlib_codec_data;
				if (chd-&gt;codecintf[0]-&gt;decompress != NULL)
					err = (*chd-&gt;codecintf[0]-&gt;decompress)(codec, compressed_bytes, entry-&gt;length, dest, chd-&gt;header.hunkbytes);
				if (err != CHDERR_NONE)
					return err;
#endif
				break;
			}

			/* uncompressed data */
			case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
				err = hunk_read_uncompressed(chd, entry-&gt;offset, chd-&gt;header.hunkbytes, dest);
				if (err != CHDERR_NONE)
					return err;
				break;

			/* mini-compressed data */
			case V34_MAP_ENTRY_TYPE_MINI:
				put_bigendian_uint64_t(&amp;dest[0], entry-&gt;offset);
				for (bytes = 8; bytes &lt; chd-&gt;header.hunkbytes; bytes++)
					dest[bytes] = dest[bytes - 8];
				break;

			/* self-referenced data */
			case V34_MAP_ENTRY_TYPE_SELF_HUNK:
#ifdef NEED_CACHE_HUNK
				if (chd-&gt;cachehunk == entry-&gt;offset &amp;&amp; dest == chd-&gt;cache)
					break;
#endif
				return hunk_read_into_memory(chd, entry-&gt;offset, dest);

			/* parent-referenced data */
			case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
				err = hunk_read_into_memory(chd-&gt;parent, entry-&gt;offset, dest);
				if (err != CHDERR_NONE)
					return err;
				break;
		}
		return CHDERR_NONE;
	}
	else
	{
		void* codec = NULL;
		/* get a pointer to the map entry */
		uint64_t blockoffs;
		uint32_t blocklen;
#ifdef VERIFY_BLOCK_CRC
		uint16_t blockcrc;
#endif
		uint8_t *rawmap = &amp;chd-&gt;header.rawmap[chd-&gt;header.mapentrybytes * hunknum];
		uint8_t* compressed_bytes;

		/* uncompressed case */
		if (!chd_compressed(&amp;chd-&gt;header))
		{
			blockoffs = (uint64_t)get_bigendian_uint32_t(rawmap) * (uint64_t)chd-&gt;header.hunkbytes;
			if (blockoffs != 0) {
				core_fseek(chd-&gt;file, blockoffs, SEEK_SET);
				/*int result =*/
				core_fread(chd-&gt;file, dest, chd-&gt;header.hunkbytes);
			/* TODO
			else if (m_parent_missing)
				throw CHDERR_REQUIRES_PARENT; */
			} else if (chd-&gt;parent) {
				err = hunk_read_into_memory(chd-&gt;parent, hunknum, dest);
				if (err != CHDERR_NONE)
					return err;
			} else {
				memset(dest, 0, chd-&gt;header.hunkbytes);
			}

			return CHDERR_NONE;
		}

		/* compressed case */
		blocklen = get_bigendian_uint24(&amp;rawmap[1]);
		blockoffs = get_bigendian_uint48(&amp;rawmap[4]);
#ifdef VERIFY_BLOCK_CRC
		blockcrc = get_bigendian_uint16(&amp;rawmap[10]);
#endif
		codec = NULL;
		switch (rawmap[0])
		{
			case COMPRESSION_TYPE_0:
			case COMPRESSION_TYPE_1:
			case COMPRESSION_TYPE_2:
			case COMPRESSION_TYPE_3:
				compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
				if (compressed_bytes == NULL)
					return CHDERR_READ_ERROR;
				switch (chd-&gt;codecintf[rawmap[0]]-&gt;compression)
				{
					case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
						codec = &amp;chd-&gt;zlib_codec_data;
#endif
						break;

					case CHD_CODEC_LZMA:
#ifdef HAVE_7ZIP
						codec = &amp;chd-&gt;lzma_codec_data;
#endif
						break;

					case CHD_CODEC_HUFFMAN:
						codec = &amp;chd-&gt;huff_codec_data;
						break;

					case CHD_CODEC_FLAC:
#ifdef HAVE_FLAC
						codec = &amp;chd-&gt;flac_codec_data;
#endif
						break;

					case CHD_CODEC_ZSTD:
#ifdef HAVE_ZSTD
						codec = &amp;chd-&gt;zstd_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
						codec = &amp;chd-&gt;cdzl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_LZMA:
#ifdef HAVE_7ZIP
						codec = &amp;chd-&gt;cdlz_codec_data;
#endif
						break;

					case CHD_CODEC_CD_FLAC:
#ifdef HAVE_FLAC
						codec = &amp;chd-&gt;cdfl_codec_data;
#endif
						break;

					case CHD_CODEC_CD_ZSTD:
#ifdef HAVE_ZSTD
						codec = &amp;chd-&gt;cdzs_codec_data;
#endif
						break;
				}
				
				if (codec==NULL)
					return CHDERR_CODEC_ERROR;
				err = chd-&gt;codecintf[rawmap[0]]-&gt;decompress(codec, compressed_bytes, blocklen, dest, chd-&gt;header.hunkbytes);
				if (err != CHDERR_NONE)
					return err;
#ifdef VERIFY_BLOCK_CRC
				if (crc16(dest, chd-&gt;header.hunkbytes) != blockcrc)
					return CHDERR_DECOMPRESSION_ERROR;
#endif
				return CHDERR_NONE;

			case COMPRESSION_NONE:
				err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
				if (err != CHDERR_NONE)
					return err;
#ifdef VERIFY_BLOCK_CRC
				if (crc16(dest, chd-&gt;header.hunkbytes) != blockcrc)
					return CHDERR_DECOMPRESSION_ERROR;
#endif
				return CHDERR_NONE;

			case COMPRESSION_SELF:
				return hunk_read_into_memory(chd, blockoffs, dest);

			case COMPRESSION_PARENT:
			{
				uint8_t units_in_hunk = chd-&gt;header.hunkbytes / chd-&gt;header.unitbytes;

				if (chd-&gt;parent == NULL)
					return CHDERR_REQUIRES_PARENT;

				/* blockoffs is aligned to units_in_hunk */
				if (blockoffs % units_in_hunk == 0) {
					return hunk_read_into_memory(chd-&gt;parent, blockoffs / units_in_hunk, dest);
				/* blockoffs is not aligned to units_in_hunk */
				} else {
					uint32_t unit_in_hunk = blockoffs % units_in_hunk;
					uint8_t *buf = malloc(chd-&gt;header.hunkbytes);
					/* Read first half of hunk which contains blockoffs */
					err = hunk_read_into_memory(chd-&gt;parent, blockoffs / units_in_hunk, buf);
					if (err != CHDERR_NONE) {
						free(buf);
						return err;
					}
					memcpy(dest, buf + unit_in_hunk * chd-&gt;header.unitbytes, (units_in_hunk - unit_in_hunk) * chd-&gt;header.unitbytes);
					/* Read second half of hunk which contains blockoffs */
					err = hunk_read_into_memory(chd-&gt;parent, (blockoffs / units_in_hunk) + 1, buf);
					if (err != CHDERR_NONE) {
						free(buf);
						return err;
					}
					memcpy(dest + (units_in_hunk - unit_in_hunk) * chd-&gt;header.unitbytes, buf, unit_in_hunk * chd-&gt;header.unitbytes);
					free(buf);
				}
			}
		}
		return CHDERR_NONE;
	}

	/* We should not reach this code */
	return CHDERR_DECOMPRESSION_ERROR;
}

/***************************************************************************
    INTERNAL MAP ACCESS
***************************************************************************/

/*-------------------------------------------------
    map_read - read the initial sector map
-------------------------------------------------*/

static chd_error map_read(chd_file *chd)
{
	uint32_t entrysize = (chd-&gt;header.version &lt; 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
	uint8_t raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
	uint64_t fileoffset, maxoffset = 0;
	uint8_t cookie[MAP_ENTRY_SIZE];
	uint32_t count;
	chd_error err;
	uint32_t i;

	/* first allocate memory */
	chd-&gt;map = (map_entry *)malloc(sizeof(chd-&gt;map[0]) * chd-&gt;header.totalhunks);
	if (!chd-&gt;map)
		return CHDERR_OUT_OF_MEMORY;

	/* read the map entries in in chunks and extract to the map list */
	fileoffset = chd-&gt;header.length;
	for (i = 0; i &lt; chd-&gt;header.totalhunks; i += MAP_STACK_ENTRIES)
	{
		/* compute how many entries this time */
		int entries = chd-&gt;header.totalhunks - i, j;
		if (entries &gt; MAP_STACK_ENTRIES)
			entries = MAP_STACK_ENTRIES;

		/* read that many */
		core_fseek(chd-&gt;file, fileoffset, SEEK_SET);
		count = core_fread(chd-&gt;file, raw_map_entries, entries * entrysize);
		if (count != entries * entrysize)
		{
			err = CHDERR_READ_ERROR;
			goto cleanup;
		}
		fileoffset += entries * entrysize;

		/* process that many */
		if (entrysize == MAP_ENTRY_SIZE)
		{
			for (j = 0; j &lt; entries; j++)
				map_extract(&amp;raw_map_entries[j * MAP_ENTRY_SIZE], &amp;chd-&gt;map[i + j]);
		}
		else
		{
			for (j = 0; j &lt; entries; j++)
				map_extract_old(&amp;raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &amp;chd-&gt;map[i + j], chd-&gt;header.hunkbytes);
		}

		/* track the maximum offset */
		for (j = 0; j &lt; entries; j++)
			if ((chd-&gt;map[i + j].flags &amp; MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
				(chd-&gt;map[i + j].flags &amp; MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
				maxoffset = MAX(maxoffset, chd-&gt;map[i + j].offset + chd-&gt;map[i + j].length);
	}

	/* verify the cookie */
	core_fseek(chd-&gt;file, fileoffset, SEEK_SET);
	count = core_fread(chd-&gt;file, &amp;cookie, entrysize);
	if (count != entrysize || memcmp(&amp;cookie, END_OF_LIST_COOKIE, entrysize))
	{
		err = CHDERR_INVALID_FILE;
		goto cleanup;
	}

	/* verify the length */
	if (maxoffset &gt; core_fsize(chd-&gt;file))
	{
		err = CHDERR_INVALID_FILE;
		goto cleanup;
	}
	return CHDERR_NONE;

cleanup:
	if (chd-&gt;map)
		free(chd-&gt;map);
	chd-&gt;map = NULL;
	return err;
}

/***************************************************************************
    INTERNAL METADATA ACCESS
***************************************************************************/

/*-------------------------------------------------
    metadata_find_entry - find a metadata entry
-------------------------------------------------*/

static chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry)
{
	/* start at the beginning */
	metaentry-&gt;offset = chd-&gt;header.metaoffset;
	metaentry-&gt;prev = 0;

	/* loop until we run out of options */
	while (metaentry-&gt;offset != 0)
	{
		uint8_t	raw_meta_header[METADATA_HEADER_SIZE];
		uint32_t	count;

		/* read the raw header */
		core_fseek(chd-&gt;file, metaentry-&gt;offset, SEEK_SET);
		count = core_fread(chd-&gt;file, raw_meta_header, sizeof(raw_meta_header));
		if (count != sizeof(raw_meta_header))
			break;

		/* extract the data */
		metaentry-&gt;metatag = get_bigendian_uint32_t(&amp;raw_meta_header[0]);
		metaentry-&gt;length = get_bigendian_uint32_t(&amp;raw_meta_header[4]);
		metaentry-&gt;next = get_bigendian_uint64_t(&amp;raw_meta_header[8]);

		/* flags are encoded in the high byte of length */
		metaentry-&gt;flags = metaentry-&gt;length &gt;&gt; 24;
		metaentry-&gt;length &amp;= 0x00ffffff;

		/* if we got a match, proceed */
		if (metatag == CHDMETATAG_WILDCARD || metaentry-&gt;metatag == metatag)
			if (metaindex-- == 0)
				return CHDERR_NONE;

		/* no match, fetch the next link */
		metaentry-&gt;prev = metaentry-&gt;offset;
		metaentry-&gt;offset = metaentry-&gt;next;
	}

	/* if we get here, we didn't find it */
	return CHDERR_METADATA_NOT_FOUND;
}

/*-------------------------------------------------
	core_stdio_fopen - core_file wrapper over fopen
-------------------------------------------------*/
static core_file *core_stdio_fopen(char const *path) {
	core_file *file = malloc(sizeof(core_file));
	if (!file)
		return NULL;
	if (!(file-&gt;argp = fopen(path, "rb"))) {
		free(file);
		return NULL;
	}
	file-&gt;fsize = core_stdio_fsize;
	file-&gt;fread = core_stdio_fread;
	file-&gt;fclose = core_stdio_fclose;
	file-&gt;fseek = core_stdio_fseek;
	return file;
}

/*-------------------------------------------------
	core_stdio_fsize - core_file function for
	getting file size with stdio
-------------------------------------------------*/
static uint64_t core_stdio_fsize(core_file *file) {
#if defined USE_LIBRETRO_VFS
	#define core_stdio_fseek_impl fseek
	#define core_stdio_ftell_impl ftell
#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WIN64__)
	#define core_stdio_fseek_impl _fseeki64
	#define core_stdio_ftell_impl _ftelli64
#elif defined(_LARGEFILE_SOURCE) &amp;&amp; defined(_FILE_OFFSET_BITS) &amp;&amp; _FILE_OFFSET_BITS == 64 &amp;&amp; defined(fseeko64) &amp;&amp; defined(ftello64)
	#define core_stdio_fseek_impl fseeko64
	#define core_stdio_ftell_impl ftello64
#elif defined(__PS3__) &amp;&amp; !defined(__PSL1GHT__) || defined(__SWITCH__) || defined(__vita__)
	#define core_stdio_fseek_impl(x,y,z) fseek(x,(off_t)y,z)
	#define core_stdio_ftell_impl(x) (off_t)ftell(x)
#else
	#define core_stdio_fseek_impl fseeko
	#define core_stdio_ftell_impl ftello
#endif
	FILE *fp;
	uint64_t p, rv;
	fp = (FILE*)file-&gt;argp;

	p = core_stdio_ftell_impl(fp);
	core_stdio_fseek_impl(fp, 0, SEEK_END);
	rv = core_stdio_ftell_impl(fp);
	core_stdio_fseek_impl(fp, p, SEEK_SET);
	return rv;
}

/*-------------------------------------------------
	core_stdio_fread - core_file wrapper over fread
-------------------------------------------------*/
static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file) {
	return fread(ptr, size, nmemb, (FILE*)file-&gt;argp);
}

/*-------------------------------------------------
	core_stdio_fclose - core_file wrapper over fclose
-------------------------------------------------*/
static int core_stdio_fclose(core_file *file) {
	int err = fclose((FILE*)file-&gt;argp);
	if (err == 0)
		free(file);
	return err;
}

/*-------------------------------------------------
	core_stdio_fclose_nonowner - don't call fclose because
		we don't own the underlying file, but do free the
		core_file because libchdr did allocate that itself.
-------------------------------------------------*/
static int core_stdio_fclose_nonowner(core_file *file) {
	free(file);
	return 0;
}

/*-------------------------------------------------
	core_stdio_fseek - core_file wrapper over fclose
-------------------------------------------------*/
static int core_stdio_fseek(core_file* file, int64_t offset, int whence) {
	return core_stdio_fseek_impl((FILE*)file-&gt;argp, offset, whence);
}</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_flac.c</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    flac.c

    FLAC compression wrappers

***************************************************************************/

#include &lt;string.h&gt;
#include &lt;stdbool.h&gt;

#include &lt;libchdr/flac.h&gt;
#ifdef HAVE_DR_FLAC
#include &lt;retro_inline.h&gt;
#define DR_FLAC_IMPLEMENTATION
#define DRFLAC_API static INLINE
#include &lt;dr/dr_flac.h&gt;
#endif

/***************************************************************************
 *  FLAC DECODER
 ***************************************************************************
 */

static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes);
static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin);
static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata);
static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes);


/* getters (valid after reset) */
/*static uint32_t sample_rate(flac_decoder *decoder)  { return decoder-&gt;sample_rate; }*/
static uint8_t channels(flac_decoder *decoder)  { return decoder-&gt;channels; }
/*static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder-&gt;bits_per_sample; }*/

/*-------------------------------------------------
 *  flac_decoder - constructor
 *-------------------------------------------------
 */

int flac_decoder_init(flac_decoder *decoder)
{
	decoder-&gt;decoder = NULL;
	decoder-&gt;sample_rate = 0;
	decoder-&gt;channels = 0;
	decoder-&gt;bits_per_sample = 0;
	decoder-&gt;compressed_offset = 0;
	decoder-&gt;compressed_start = NULL;
	decoder-&gt;compressed_length = 0;
	decoder-&gt;compressed2_start = NULL;
	decoder-&gt;compressed2_length = 0;
	decoder-&gt;uncompressed_offset = 0;
	decoder-&gt;uncompressed_length = 0;
	decoder-&gt;uncompressed_swap = 0;
	return 0;
}

/*-------------------------------------------------
 *  flac_decoder - destructor
 *-------------------------------------------------
 */

void flac_decoder_free(flac_decoder* decoder)
{
	if ((decoder != NULL) &amp;&amp; (decoder-&gt;decoder != NULL)) {
		drflac_close(decoder-&gt;decoder);
		decoder-&gt;decoder = NULL;
	}
}

/*-------------------------------------------------
 *  reset - reset state with the original
 *  parameters
 *-------------------------------------------------
 */

static int flac_decoder_internal_reset(flac_decoder* decoder)
{
	decoder-&gt;compressed_offset = 0;
	flac_decoder_free(decoder);
	decoder-&gt;decoder = drflac_open_with_metadata(
		flac_decoder_read_callback, flac_decoder_seek_callback,
		flac_decoder_metadata_callback, decoder, NULL);
	return (decoder-&gt;decoder != NULL);
}

/*-------------------------------------------------
 *  reset - reset state with new memory parameters
 *  and a custom-generated header
 *-------------------------------------------------
 */

int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)
{
	/* modify the template header with our parameters */
	static const uint8_t s_header_template[0x2a] =
	{
		0x66, 0x4C, 0x61, 0x43,                         /* +00: 'fLaC' stream header */
		0x80,                                           /* +04: metadata block type 0 (STREAMINFO), */
								/*      flagged as last block */
		0x00, 0x00, 0x22,                               /* +05: metadata block length = 0x22 */
		0x00, 0x00,                                     /* +08: minimum block size */
		0x00, 0x00,                                     /* +0A: maximum block size */
		0x00, 0x00, 0x00,                               /* +0C: minimum frame size (0 == unknown) */
		0x00, 0x00, 0x00,                               /* +0F: maximum frame size (0 == unknown) */
		0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */
								/*      numchannels (2), sample bits (16), */
								/*      samples in stream (0 == unknown) */
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* +2A: start of stream data */
	};
	memcpy(decoder-&gt;custom_header, s_header_template, sizeof(s_header_template));
	decoder-&gt;custom_header[0x08] = decoder-&gt;custom_header[0x0a] = (block_size*num_channels) &gt;&gt; 8;
	decoder-&gt;custom_header[0x09] = decoder-&gt;custom_header[0x0b] = (block_size*num_channels) &amp; 0xff;
	decoder-&gt;custom_header[0x12] = sample_rate &gt;&gt; 12;
	decoder-&gt;custom_header[0x13] = sample_rate &gt;&gt; 4;
	decoder-&gt;custom_header[0x14] = (sample_rate &lt;&lt; 4) | ((num_channels - 1) &lt;&lt; 1);

	/* configure the header ahead of the provided buffer */
	decoder-&gt;compressed_start = (const uint8_t *)(decoder-&gt;custom_header);
	decoder-&gt;compressed_length = sizeof(decoder-&gt;custom_header);
	decoder-&gt;compressed2_start = (const uint8_t *)(buffer);
	decoder-&gt;compressed2_length = length;
	return flac_decoder_internal_reset(decoder);
}

/*-------------------------------------------------
 *  decode_interleaved - decode to an interleaved
 *  sound stream
 *-------------------------------------------------
 */

int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)
{
#define	BUFFER	2352	/* bytes per CD audio sector */
	int16_t buffer[BUFFER];
	uint32_t buf_samples = BUFFER / channels(decoder);

	/* configure the uncompressed buffer */
	memset(decoder-&gt;uncompressed_start, 0, sizeof(decoder-&gt;uncompressed_start));
	decoder-&gt;uncompressed_start[0] = samples;
	decoder-&gt;uncompressed_offset = 0;
	decoder-&gt;uncompressed_length = num_samples;
	decoder-&gt;uncompressed_swap = swap_endian;

	/* loop until we get everything we want */
	while (decoder-&gt;uncompressed_offset &lt; decoder-&gt;uncompressed_length) {
		uint32_t frames = (num_samples &lt; buf_samples ? num_samples : buf_samples);
		if (!drflac_read_pcm_frames_s16(decoder-&gt;decoder, frames, buffer))
			return 0;
		flac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder));
		num_samples -= frames;
	}
	return 1;
}

/*-------------------------------------------------
 *  finish - finish up the decode
 *-------------------------------------------------
 */

uint32_t flac_decoder_finish(flac_decoder* decoder)
{
	/* get the final decoding position and move forward */
	drflac *flac = decoder-&gt;decoder;
	uint64_t position = decoder-&gt;compressed_offset;

	/* ugh... there's no function to obtain bytes used in drflac :-/ */
	position -= DRFLAC_CACHE_L2_LINES_REMAINING(&amp;flac-&gt;bs) * sizeof(drflac_cache_t);
	position -= DRFLAC_CACHE_L1_BITS_REMAINING(&amp;flac-&gt;bs) / 8;
	position -= flac-&gt;bs.unalignedByteCount;

	/* adjust position if we provided the header */
	if (position == 0)
		return 0;
	if (decoder-&gt;compressed_start == (const uint8_t *)(decoder-&gt;custom_header))
		position -= decoder-&gt;compressed_length;

	flac_decoder_free(decoder);
	return position;
}

/*-------------------------------------------------
 *  read_callback - handle reads from the input
 *  stream
 *-------------------------------------------------
 */

static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes)
{
	flac_decoder* decoder = (flac_decoder*)userdata;
	uint8_t *dst = buffer;

	/* copy from primary buffer first */
	uint32_t outputpos = 0;
	if (outputpos &lt; bytes &amp;&amp; decoder-&gt;compressed_offset &lt; decoder-&gt;compressed_length)
	{
		uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder-&gt;compressed_length - decoder-&gt;compressed_offset);
		memcpy(&amp;dst[outputpos], decoder-&gt;compressed_start + decoder-&gt;compressed_offset, bytes_to_copy);
		outputpos += bytes_to_copy;
		decoder-&gt;compressed_offset += bytes_to_copy;
	}

	/* once we're out of that, copy from the secondary buffer */
	if (outputpos &lt; bytes &amp;&amp; decoder-&gt;compressed_offset &lt; decoder-&gt;compressed_length + decoder-&gt;compressed2_length)
	{
		uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder-&gt;compressed2_length - (decoder-&gt;compressed_offset - decoder-&gt;compressed_length));
		memcpy(&amp;dst[outputpos], decoder-&gt;compressed2_start + decoder-&gt;compressed_offset - decoder-&gt;compressed_length, bytes_to_copy);
		outputpos += bytes_to_copy;
		decoder-&gt;compressed_offset += bytes_to_copy;
	}

	return outputpos;
}

/*-------------------------------------------------
 *  metadata_callback - handle STREAMINFO metadata
 *-------------------------------------------------
 */

static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata)
{
	flac_decoder *decoder = userdata;

	/* ignore all but STREAMINFO metadata */
	if (metadata-&gt;type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO)
		return;

	/* parse out the data we care about */
	decoder-&gt;sample_rate = metadata-&gt;data.streaminfo.sampleRate;
	decoder-&gt;bits_per_sample = metadata-&gt;data.streaminfo.bitsPerSample;
	decoder-&gt;channels = metadata-&gt;data.streaminfo.channels;
}

/*-------------------------------------------------
 *  write_callback - handle writes to the output
 *  stream
 *-------------------------------------------------
 */

static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes)
{
	int sampnum, chan;
	int shift, blocksize;
	flac_decoder * decoder = (flac_decoder *)userdata;
	int16_t *sampbuf = (int16_t *)buffer;
	int sampch = channels(decoder);
	uint32_t offset = decoder-&gt;uncompressed_offset;
	uint16_t usample;

	/* interleaved case */
	shift = decoder-&gt;uncompressed_swap ? 8 : 0;
	blocksize = bytes / (sampch * sizeof(sampbuf[0]));
	if (decoder-&gt;uncompressed_start[1] == NULL)
	{
		int16_t *dest = decoder-&gt;uncompressed_start[0] + offset * sampch;
		for (sampnum = 0; sampnum &lt; blocksize &amp;&amp; offset &lt; decoder-&gt;uncompressed_length; sampnum++, offset++)
			for (chan = 0; chan &lt; sampch; chan++) {
				usample = (uint16_t)*sampbuf++;
				*dest++ = (int16_t)((usample &lt;&lt; shift) | (usample &gt;&gt; shift));
			}
	}

	/* non-interleaved case */
	else
	{
		for (sampnum = 0; sampnum &lt; blocksize &amp;&amp; offset &lt; decoder-&gt;uncompressed_length; sampnum++, offset++)
			for (chan = 0; chan &lt; sampch; chan++) {
				usample = (uint16_t)*sampbuf++;
				if (decoder-&gt;uncompressed_start[chan] != NULL)
					decoder-&gt;uncompressed_start[chan][offset] = (int16_t) ((usample &lt;&lt; shift) | (usample &gt;&gt; shift));
			}
	}
	decoder-&gt;uncompressed_offset = offset;
}


/*-------------------------------------------------
 *  seek_callback - handle seeks on the output
 *  stream
 *-------------------------------------------------
 */

static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin)
{
	flac_decoder * decoder = (flac_decoder *)userdata;
	uint32_t length = decoder-&gt;compressed_length + decoder-&gt;compressed2_length;

	if (origin == drflac_seek_origin_start) {
		uint32_t pos = offset;
		if (pos &lt;= length) {
			decoder-&gt;compressed_offset = pos;
			return 1;
		}
	} else if (origin == drflac_seek_origin_current) {
		uint32_t pos = decoder-&gt;compressed_offset + offset;
		if (pos &lt;= length) {
			decoder-&gt;compressed_offset = pos;
			return 1;
		}
	}
	return 0;
}</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_flac_codec.c</h2>
<pre>/***************************************************************************

    libchdr_flac_codec.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include &lt;stddef.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;libchdr/chd.h&gt;
#include &lt;libchdr/minmax.h&gt;
#include &lt;libchdr/cdrom.h&gt;
#include &lt;libchdr/flac.h&gt;
#include &lt;libchdr/huffman.h&gt;
#include &lt;libchdr/libchdr_zlib.h&gt;
#include &lt;zlib.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;streams/file_stream.h&gt;

/***************************************************************************
 *  CD FLAC DECOMPRESSOR
 ***************************************************************************
 */

/*------------------------------------------------------
 *  flac_codec_blocksize - return the optimal block size
 *------------------------------------------------------
 */

static uint32_t flac_codec_blocksize(uint32_t bytes)
{
	/* determine FLAC block size, which must be 16-65535
	 * clamp to 2k since that's supposed to be the sweet spot */
	uint32_t blocksize = bytes / 4;
	while (blocksize &gt; 2048)
		blocksize /= 2;
	return blocksize;
}

chd_error flac_codec_init(void *codec, uint32_t hunkbytes)
{
	uint16_t native_endian = 0;
	flac_codec_data *flac = (flac_codec_data*)codec;

	/* make sure the CHD's hunk size is an even multiple of the sample size */
	if (hunkbytes % 4 != 0)
		return CHDERR_CODEC_ERROR;

	/* determine whether we want native or swapped samples */
	*(uint8_t *)(&amp;native_endian) = 1;
	flac-&gt;native_endian = (native_endian &amp; 1);

	/* flac decoder init */
	if (flac_decoder_init(&amp;flac-&gt;decoder))
		return CHDERR_OUT_OF_MEMORY;

	return CHDERR_NONE;
}

void flac_codec_free(void *codec)
{
	flac_codec_data *flac = (flac_codec_data*)codec;
	flac_decoder_free(&amp;flac-&gt;decoder);
}

chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	flac_codec_data *flac = (flac_codec_data*)codec;
	int swap_endian;

	if (src[0] == 'L')
		swap_endian = !flac-&gt;native_endian;
	else if (src[0] == 'B')
		swap_endian = flac-&gt;native_endian;
	else
		return CHDERR_DECOMPRESSION_ERROR;

	if (!flac_decoder_reset(&amp;flac-&gt;decoder, 44100, 2, flac_codec_blocksize(destlen), src + 1, complen - 1))
		return CHDERR_DECOMPRESSION_ERROR;
	if (!flac_decoder_decode_interleaved(&amp;flac-&gt;decoder, (int16_t *)(dest), destlen/4, swap_endian))
		return CHDERR_DECOMPRESSION_ERROR;
	flac_decoder_finish(&amp;flac-&gt;decoder);

	return CHDERR_NONE;
}

static uint32_t cdfl_codec_blocksize(uint32_t bytes)
{
	/* for CDs it seems that CD_MAX_SECTOR_DATA is the right target */
	uint32_t blocksize = bytes / 4;
	while (blocksize &gt; CD_MAX_SECTOR_DATA)
		blocksize /= 2;
	return blocksize;
}

chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
{
#ifdef WANT_SUBCODE
	chd_error ret;
#endif
	uint16_t native_endian = 0;
	cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;

	/* make sure the CHD's hunk size is an even multiple of the frame size */
	if (hunkbytes % CD_FRAME_SIZE != 0)
		return CHDERR_CODEC_ERROR;

	cdfl-&gt;buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
	if (cdfl-&gt;buffer == NULL)
		return CHDERR_OUT_OF_MEMORY;

	/* determine whether we want native or swapped samples */
	*(uint8_t *)(&amp;native_endian) = 1;
	cdfl-&gt;swap_endian = (native_endian &amp; 1);

#ifdef WANT_SUBCODE
	/* init zlib inflater */
	ret = zlib_codec_init(&amp;cdfl-&gt;subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#endif

	/* flac decoder init */
	if (flac_decoder_init(&amp;cdfl-&gt;decoder))
		return CHDERR_OUT_OF_MEMORY;

	return CHDERR_NONE;
}

void cdfl_codec_free(void *codec)
{
	cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
	flac_decoder_free(&amp;cdfl-&gt;decoder);
#ifdef WANT_SUBCODE
	zlib_codec_free(&amp;cdfl-&gt;subcode_decompressor);
#endif
	if (cdfl-&gt;buffer)
		free(cdfl-&gt;buffer);
}

chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t framenum;
	uint8_t *buffer;
#ifdef WANT_SUBCODE
	uint32_t offset;
	chd_error ret;
#endif
	cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;

	/* reset and decode */
	uint32_t frames = destlen / CD_FRAME_SIZE;

	if (!flac_decoder_reset(&amp;cdfl-&gt;decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
		return CHDERR_DECOMPRESSION_ERROR;
	buffer = &amp;cdfl-&gt;buffer[0];
	if (!flac_decoder_decode_interleaved(&amp;cdfl-&gt;decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl-&gt;swap_endian))
		return CHDERR_DECOMPRESSION_ERROR;

#ifdef WANT_SUBCODE
	/* inflate the subcode data */
	offset = flac_decoder_finish(&amp;cdfl-&gt;decoder);
	ret = zlib_codec_decompress(&amp;cdfl-&gt;subcode_decompressor, src + offset, complen - offset, &amp;cdfl-&gt;buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#else
	flac_decoder_finish(&amp;cdfl-&gt;decoder);
#endif

	/* reassemble the data */
	for (framenum = 0; framenum &lt; frames; framenum++)
	{
		memcpy(&amp;dest[framenum * CD_FRAME_SIZE], &amp;cdfl-&gt;buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
		memcpy(&amp;dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &amp;cdfl-&gt;buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
#endif
	}

	return CHDERR_NONE;
}</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_huffman.c</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
****************************************************************************

    huffman.c

    Static Huffman compression and decompression helpers.

****************************************************************************

    Maximum codelength is officially (alphabetsize - 1). This would be 255 bits
    (since we use 1 byte values). However, it is also dependent upon the number
    of samples used, as follows:

         2 bits -&gt; 3..4 samples
         3 bits -&gt; 5..7 samples
         4 bits -&gt; 8..12 samples
         5 bits -&gt; 13..20 samples
         6 bits -&gt; 21..33 samples
         7 bits -&gt; 34..54 samples
         8 bits -&gt; 55..88 samples
         9 bits -&gt; 89..143 samples
        10 bits -&gt; 144..232 samples
        11 bits -&gt; 233..376 samples
        12 bits -&gt; 377..609 samples
        13 bits -&gt; 610..986 samples
        14 bits -&gt; 987..1596 samples
        15 bits -&gt; 1597..2583 samples
        16 bits -&gt; 2584..4180 samples   -&gt; note that a 4k data size guarantees codelength &lt;= 16 bits
        17 bits -&gt; 4181..6764 samples
        18 bits -&gt; 6765..10945 samples
        19 bits -&gt; 10946..17710 samples
        20 bits -&gt; 17711..28656 samples
        21 bits -&gt; 28657..46367 samples
        22 bits -&gt; 46368..75024 samples
        23 bits -&gt; 75025..121392 samples
        24 bits -&gt; 121393..196417 samples
        25 bits -&gt; 196418..317810 samples
        26 bits -&gt; 317811..514228 samples
        27 bits -&gt; 514229..832039 samples
        28 bits -&gt; 832040..1346268 samples
        29 bits -&gt; 1346269..2178308 samples
        30 bits -&gt; 2178309..3524577 samples
        31 bits -&gt; 3524578..5702886 samples
        32 bits -&gt; 5702887..9227464 samples

    Looking at it differently, here is where powers of 2 fall into these buckets:

          256 samples -&gt; 11 bits max
          512 samples -&gt; 12 bits max
           1k samples -&gt; 14 bits max
           2k samples -&gt; 15 bits max
           4k samples -&gt; 16 bits max
           8k samples -&gt; 18 bits max
          16k samples -&gt; 19 bits max
          32k samples -&gt; 21 bits max
          64k samples -&gt; 22 bits max
         128k samples -&gt; 24 bits max
         256k samples -&gt; 25 bits max
         512k samples -&gt; 27 bits max
           1M samples -&gt; 28 bits max
           2M samples -&gt; 29 bits max
           4M samples -&gt; 31 bits max
           8M samples -&gt; 32 bits max

****************************************************************************

    Delta-RLE encoding works as follows:

    Starting value is assumed to be 0. All data is encoded as a delta
    from the previous value, such that final[i] = final[i - 1] + delta.
    Long runs of 0s are RLE-encoded as follows:

        0x100 = repeat count of 8
        0x101 = repeat count of 9
        0x102 = repeat count of 10
        0x103 = repeat count of 11
        0x104 = repeat count of 12
        0x105 = repeat count of 13
        0x106 = repeat count of 14
        0x107 = repeat count of 15
        0x108 = repeat count of 16
        0x109 = repeat count of 32
        0x10a = repeat count of 64
        0x10b = repeat count of 128
        0x10c = repeat count of 256
        0x10d = repeat count of 512
        0x10e = repeat count of 1024
        0x10f = repeat count of 2048

    Note that repeat counts are reset at the end of a row, so if a 0 run
    extends to the end of a row, a large repeat count may be used.

    The reason for starting the run counts at 8 is that 0 is expected to
    be the most common symbol, and is typically encoded in 1 or 2 bits.

***************************************************************************/

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#include &lt;libchdr/huffman.h&gt;
#include &lt;libchdr/minmax.h&gt;

/***************************************************************************
 *  MACROS
 ***************************************************************************
 */

#define MAKE_LOOKUP(code,bits)  (((code) &lt;&lt; 5) | ((bits) &amp; 0x1f))

/***************************************************************************
 *  IMPLEMENTATION
 ***************************************************************************
 */

/*-------------------------------------------------
 *  huffman_context_base - create an encoding/
 *  decoding context
 *-------------------------------------------------
 */

struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
{
	struct huffman_decoder* decoder = NULL;

	/* limit to 24 bits */
	if (maxbits &gt; 24)
		return NULL;

	decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));
	decoder-&gt;numcodes = numcodes;
	decoder-&gt;maxbits = maxbits;
	decoder-&gt;lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 &lt;&lt; maxbits));
	decoder-&gt;huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);
	decoder-&gt;datahisto = NULL;
	decoder-&gt;prevdata = 0;
	decoder-&gt;rleremaining = 0;
	return decoder;
}

void delete_huffman_decoder(struct huffman_decoder* decoder)
{
	if (decoder != NULL)
	{
		if (decoder-&gt;lookup != NULL)
			free(decoder-&gt;lookup);
		if (decoder-&gt;huffnode != NULL)
			free(decoder-&gt;huffnode);
		free(decoder);
	}
}

/*-------------------------------------------------
 *  decode_one - decode a single code from the
 *  huffman stream
 *-------------------------------------------------
 */

uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{
	/* peek ahead to get maxbits worth of data */
	uint32_t bits = bitstream_peek(bitbuf, decoder-&gt;maxbits);

	/* look it up, then remove the actual number of bits for this code */
	lookup_value lookup = decoder-&gt;lookup[bits];
	bitstream_remove(bitbuf, lookup &amp; 0x1f);

	/* return the value */
	return lookup &gt;&gt; 5;
}

/*-------------------------------------------------
 *  import_tree_rle - import an RLE-encoded
 *  huffman tree from a source data stream
 *-------------------------------------------------
 */

enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{
	int numbits;
	uint32_t curnode;
	enum huffman_error error;

	/* bits per entry depends on the maxbits */
	if (decoder-&gt;maxbits &gt;= 16)
		numbits = 5;
	else if (decoder-&gt;maxbits &gt;= 8)
		numbits = 4;
	else
		numbits = 3;

	/* loop until we read all the nodes */
	for (curnode = 0; curnode &lt; decoder-&gt;numcodes; )
	{
		/* a non-one value is just raw */
		int nodebits = bitstream_read(bitbuf, numbits);
		if (nodebits != 1)
			decoder-&gt;huffnode[curnode++].numbits = nodebits;

		/* a one value is an escape code */
		else
		{
			/* a double 1 is just a single 1 */
			nodebits = bitstream_read(bitbuf, numbits);
			if (nodebits == 1)
				decoder-&gt;huffnode[curnode++].numbits = nodebits;

			/* otherwise, we need one for value for the repeat count */
			else
			{
				int repcount = bitstream_read(bitbuf, numbits) + 3;
				if (repcount + curnode &gt; decoder-&gt;numcodes)
					return HUFFERR_INVALID_DATA;
				while (repcount--)
					decoder-&gt;huffnode[curnode++].numbits = nodebits;
			}
		}
	}

	/* make sure we ended up with the right number */
	if (curnode != decoder-&gt;numcodes)
		return HUFFERR_INVALID_DATA;

	/* assign canonical codes for all nodes based on their code lengths */
	error = huffman_assign_canonical_codes(decoder);
	if (error != HUFFERR_NONE)
		return error;

	/* build the lookup table */
	huffman_build_lookup_table(decoder);

	/* determine final input length and report errors */
	return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}


/*-------------------------------------------------
 *  import_tree_huffman - import a huffman-encoded
 *  huffman tree from a source data stream
 *-------------------------------------------------
 */

enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{
	int start;
	int last = 0;
	int count = 0;
	int index;
	uint32_t curcode;
	uint8_t rlefullbits = 0;
	uint32_t temp;
	enum huffman_error error;
	/* start by parsing the lengths for the small tree */
	struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
	smallhuff-&gt;huffnode[0].numbits = bitstream_read(bitbuf, 3);
	start = bitstream_read(bitbuf, 3) + 1;
	for (index = 1; index &lt; 24; index++)
	{
		if (index &lt; start || count == 7)
			smallhuff-&gt;huffnode[index].numbits = 0;
		else
		{
			count = bitstream_read(bitbuf, 3);
			smallhuff-&gt;huffnode[index].numbits = (count == 7) ? 0 : count;
		}
	}

	/* then regenerate the tree */
	error = huffman_assign_canonical_codes(smallhuff);
	if (error != HUFFERR_NONE)
		return error;
	huffman_build_lookup_table(smallhuff);

	/* determine the maximum length of an RLE count */
	temp = decoder-&gt;numcodes - 9;
	while (temp != 0)
		temp &gt;&gt;= 1, rlefullbits++;

	/* now process the rest of the data */
	for (curcode = 0; curcode &lt; decoder-&gt;numcodes; )
	{
		int value = huffman_decode_one(smallhuff, bitbuf);
		if (value != 0)
			decoder-&gt;huffnode[curcode++].numbits = last = value - 1;
		else
		{
			int count = bitstream_read(bitbuf, 3) + 2;
			if (count == 7+2)
				count += bitstream_read(bitbuf, rlefullbits);
			for ( ; count != 0 &amp;&amp; curcode &lt; decoder-&gt;numcodes; count--)
				decoder-&gt;huffnode[curcode++].numbits = last;
		}
	}

    /* make sure we free the local huffman decoder */
    delete_huffman_decoder(smallhuff);

	/* make sure we ended up with the right number */
	if (curcode != decoder-&gt;numcodes)
		return HUFFERR_INVALID_DATA;

	/* assign canonical codes for all nodes based on their code lengths */
	error = huffman_assign_canonical_codes(decoder);
	if (error != HUFFERR_NONE)
		return error;

	/* build the lookup table */
	huffman_build_lookup_table(decoder);

	/* determine final input length and report errors */
	return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
}

/*-------------------------------------------------
 *  compute_tree_from_histo - common backend for
 *  computing a tree based on the data histogram
 *-------------------------------------------------
 */

enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
{
	uint32_t i;
	uint32_t lowerweight;
	uint32_t upperweight;
	/* compute the number of data items in the histogram */
	uint32_t sdatacount = 0;
	for (i = 0; i &lt; decoder-&gt;numcodes; i++)
		sdatacount += decoder-&gt;datahisto[i];

	/* binary search to achieve the optimum encoding */
	lowerweight = 0;
	upperweight = sdatacount * 2;
	while (1)
	{
		/* build a tree using the current weight */
		uint32_t curweight = (upperweight + lowerweight) / 2;
		int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);

		/* apply binary search here */
		if (curmaxbits &lt;= decoder-&gt;maxbits)
		{
			lowerweight = curweight;

			/* early out if it worked with the raw weights, or if we're done searching */
			if (curweight == sdatacount || (upperweight - lowerweight) &lt;= 1)
				break;
		}
		else
			upperweight = curweight;
	}

	/* assign canonical codes for all nodes based on their code lengths */
	return huffman_assign_canonical_codes(decoder);
}

/***************************************************************************
 *  INTERNAL FUNCTIONS
 ***************************************************************************
 */

/*-------------------------------------------------
 *  tree_node_compare - compare two tree nodes
 *  by weight
 *-------------------------------------------------
 */

static int huffman_tree_node_compare(const void *item1, const void *item2)
{
	const struct node_t *node1 = *(const struct node_t **)item1;
	const struct node_t *node2 = *(const struct node_t **)item2;
	if (node2-&gt;weight != node1-&gt;weight)
		return node2-&gt;weight - node1-&gt;weight;
	if (node2-&gt;bits - node1-&gt;bits == 0)
		fprintf(stderr, "identical node sort keys, should not happen!\n");
	return (int)node1-&gt;bits - (int)node2-&gt;bits;
}

/*-------------------------------------------------
 *  build_tree - build a huffman tree based on the
 *  data distribution
 *-------------------------------------------------
 */

int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
{
	uint32_t curcode;
	int nextalloc;
	int listitems = 0;
	int maxbits = 0;
	/* make a list of all non-zero nodes */
	struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder-&gt;numcodes * 2);
	memset(decoder-&gt;huffnode, 0, decoder-&gt;numcodes * sizeof(decoder-&gt;huffnode[0]));
	for (curcode = 0; curcode &lt; decoder-&gt;numcodes; curcode++)
		if (decoder-&gt;datahisto[curcode] != 0)
		{
			list[listitems++] = &amp;decoder-&gt;huffnode[curcode];
			decoder-&gt;huffnode[curcode].count = decoder-&gt;datahisto[curcode];
			decoder-&gt;huffnode[curcode].bits = curcode;

			/* scale the weight by the current effective length, ensuring we don't go to 0 */
			decoder-&gt;huffnode[curcode].weight = ((uint64_t)decoder-&gt;datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
			if (decoder-&gt;huffnode[curcode].weight == 0)
				decoder-&gt;huffnode[curcode].weight = 1;
		}

#if 0
        fprintf(stderr, "Pre-sort:\n");
        for (int i = 0; i &lt; listitems; i++) {
            fprintf(stderr, "weight: %d code: %d\n", list[i]-&gt;m_weight, list[i]-&gt;m_bits);
        }
#endif

	/* sort the list by weight, largest weight first */
	qsort(&amp;list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);

#if 0
        fprintf(stderr, "Post-sort:\n");
        for (int i = 0; i &lt; listitems; i++) {
            fprintf(stderr, "weight: %d code: %d\n", list[i]-&gt;m_weight, list[i]-&gt;m_bits);
        }
        fprintf(stderr, "===================\n");
#endif

	/* now build the tree */
	nextalloc = decoder-&gt;numcodes;
	while (listitems &gt; 1)
	{
		int curitem;
		/* remove lowest two items */
		struct node_t* node1 = &amp;(*list[--listitems]);
		struct node_t* node0 = &amp;(*list[--listitems]);

		/* create new node */
		struct node_t* newnode = &amp;decoder-&gt;huffnode[nextalloc++];
		newnode-&gt;parent = NULL;
		node0-&gt;parent = node1-&gt;parent = newnode;
		newnode-&gt;weight = node0-&gt;weight + node1-&gt;weight;

		/* insert into list at appropriate location */
		for (curitem = 0; curitem &lt; listitems; curitem++)
			if (newnode-&gt;weight &gt; list[curitem]-&gt;weight)
			{
				memmove(&amp;list[curitem+1], &amp;list[curitem], (listitems - curitem) * sizeof(list[0]));
				break;
			}
		list[curitem] = newnode;
		listitems++;
	}

	/* compute the number of bits in each code, and fill in another histogram */
	for (curcode = 0; curcode &lt; decoder-&gt;numcodes; curcode++)
	{
		struct node_t *curnode;
		struct node_t* node = &amp;decoder-&gt;huffnode[curcode];
		node-&gt;numbits = 0;
		node-&gt;bits = 0;

		/* if we have a non-zero weight, compute the number of bits */
		if (node-&gt;weight &gt; 0)
		{
			/* determine the number of bits for this node */
			for (curnode = node; curnode-&gt;parent != NULL; curnode = curnode-&gt;parent)
				node-&gt;numbits++;
			if (node-&gt;numbits == 0)
				node-&gt;numbits = 1;

			/* keep track of the max */
			maxbits = MAX(maxbits, ((int)node-&gt;numbits));
		}
	}
	return maxbits;
}

/*-------------------------------------------------
 *  assign_canonical_codes - assign canonical codes
 *  to all the nodes based on the number of bits
 *  in each
 *-------------------------------------------------
 */

enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
{
	uint32_t curcode;
	int codelen;
	uint32_t curstart = 0;
	/* build up a histogram of bit lengths */
	uint32_t bithisto[33] = { 0 };
	for (curcode = 0; curcode &lt; decoder-&gt;numcodes; curcode++)
	{
		struct node_t* node = &amp;decoder-&gt;huffnode[curcode];
		if (node-&gt;numbits &gt; decoder-&gt;maxbits)
			return HUFFERR_INTERNAL_INCONSISTENCY;
		if (node-&gt;numbits &lt;= 32)
			bithisto[node-&gt;numbits]++;
	}

	/* for each code length, determine the starting code number */
	for (codelen = 32; codelen &gt; 0; codelen--)
	{
		uint32_t nextstart = (curstart + bithisto[codelen]) &gt;&gt; 1;
		if (codelen != 1 &amp;&amp; nextstart * 2 != (curstart + bithisto[codelen]))
			return HUFFERR_INTERNAL_INCONSISTENCY;
		bithisto[codelen] = curstart;
		curstart = nextstart;
	}

	/* now assign canonical codes */
	for (curcode = 0; curcode &lt; decoder-&gt;numcodes; curcode++)
	{
		struct node_t* node = &amp;decoder-&gt;huffnode[curcode];
		if (node-&gt;numbits &gt; 0)
			node-&gt;bits = bithisto[node-&gt;numbits]++;
	}
	return HUFFERR_NONE;
}

/*-------------------------------------------------
 *  build_lookup_table - build a lookup table for
 *  fast decoding
 *-------------------------------------------------
 */

void huffman_build_lookup_table(struct huffman_decoder* decoder)
{
	uint32_t curcode;
	/* iterate over all codes */
	for (curcode = 0; curcode &lt; decoder-&gt;numcodes; curcode++)
	{
		/* process all nodes which have non-zero bits */
		struct node_t* node = &amp;decoder-&gt;huffnode[curcode];
		if (node-&gt;numbits &gt; 0)
		{
         int shift;
         lookup_value *dest;
         lookup_value *destend;
			/* set up the entry */
			lookup_value value = MAKE_LOOKUP(curcode, node-&gt;numbits);

			/* fill all matching entries */
			shift = decoder-&gt;maxbits - node-&gt;numbits;
			dest = &amp;decoder-&gt;lookup[node-&gt;bits &lt;&lt; shift];
			destend = &amp;decoder-&gt;lookup[((node-&gt;bits + 1) &lt;&lt; shift) - 1];
			while (dest &lt;= destend)
				*dest++ = value;
		}
	}
}</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_lzma.c</h2>
<pre>/***************************************************************************

    libchdr_lzma_codec.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include &lt;stddef.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;zlib.h&gt;
#include &lt;libchdr/chd.h&gt;
#include &lt;libchdr/minmax.h&gt;
#include &lt;libchdr/cdrom.h&gt;
#include &lt;libchdr/huffman.h&gt;
#include &lt;libchdr/lzma.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;streams/file_stream.h&gt;

/***************************************************************************
 *  LZMA ALLOCATOR HELPER
 ***************************************************************************
 */

void *lzma_fast_alloc(void *p, size_t size);
void lzma_fast_free(void *p, void *address);

/*-------------------------------------------------
 *  lzma_allocator_init
 *-------------------------------------------------
 */

static void lzma_allocator_init(void* p)
{
	lzma_allocator *codec = (lzma_allocator *)(p);

	/* reset pointer list */
	memset(codec-&gt;allocptr, 0, sizeof(codec-&gt;allocptr));
	memset(codec-&gt;allocptr2, 0, sizeof(codec-&gt;allocptr2));
	codec-&gt;Alloc = lzma_fast_alloc;
	codec-&gt;Free = lzma_fast_free;
}

/*-------------------------------------------------
 *  lzma_allocator_free
 *-------------------------------------------------
 */

static void lzma_allocator_free(void* p )
{
	int i;
	lzma_allocator *codec = (lzma_allocator *)(p);

	/* free our memory */
	for (i = 0 ; i &lt; MAX_LZMA_ALLOCS ; i++)
	{
		if (codec-&gt;allocptr[i] != NULL)
			free(codec-&gt;allocptr[i]);
	}
}

/*-------------------------------------------------
 *  lzma_fast_alloc - fast malloc for lzma, which
 *  allocates and frees memory frequently
 *-------------------------------------------------
 */

/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define LZMA_MIN_ALIGNMENT_BITS 512
#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)

void *lzma_fast_alloc(void *p, size_t size)
{
	int scan;
	uint32_t *addr        = NULL;
	lzma_allocator *codec = (lzma_allocator *)(p);
	uintptr_t vaddr = 0;

	/* compute the size, rounding to the nearest 1k */
	size = (size + 0x3ff) &amp; ~0x3ff;

	/* reuse a hunk if we can */
	for (scan = 0; scan &lt; MAX_LZMA_ALLOCS; scan++)
	{
		uint32_t *ptr = codec-&gt;allocptr[scan];
		if (ptr != NULL &amp;&amp; size == *ptr)
		{
			/* set the low bit of the size so we don't match next time */
			*ptr |= 1;

			/* return aligned address of the block */
			return codec-&gt;allocptr2[scan];
		}
	}

	/* alloc a new one and put it into the list */
	addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
	if (addr==NULL)
		return NULL;
	for (scan = 0; scan &lt; MAX_LZMA_ALLOCS; scan++)
	{
		if (codec-&gt;allocptr[scan] == NULL)
		{
			/* store block address */
			codec-&gt;allocptr[scan] = addr;

			/* compute aligned address, store it */
			vaddr = (uintptr_t)addr;
			vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) &amp; (~(LZMA_MIN_ALIGNMENT_BYTES-1));
			codec-&gt;allocptr2[scan] = (uint32_t*)vaddr;
			break;
		}
	}

	/* set the low bit of the size so we don't match next time */
	*addr = size | 1;

	/* return aligned address */
	return (void*)vaddr;
}

/*-------------------------------------------------
 *  lzma_fast_free - fast free for lzma, which
 *  allocates and frees memory frequently
 *-------------------------------------------------
 */

void lzma_fast_free(void *p, void *address)
{
	int scan;
	uint32_t *ptr = NULL;
	lzma_allocator *codec = NULL;

	if (address == NULL)
		return;

	codec = (lzma_allocator *)(p);

	/* find the hunk */
	ptr = (uint32_t *)address;
	for (scan = 0; scan &lt; MAX_LZMA_ALLOCS; scan++)
	{
		if (ptr == codec-&gt;allocptr2[scan])
		{
			/* clear the low bit of the size to allow matches */
			*codec-&gt;allocptr[scan] &amp;= ~1;
			return;
		}
	}
}

/***************************************************************************
 *  LZMA DECOMPRESSOR
 ***************************************************************************
 */

/*-------------------------------------------------
 *  lzma_codec_init - constructor
 *-------------------------------------------------
 */

chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
{
	CLzmaEncHandle enc;
	CLzmaEncProps encoder_props;
	Byte decoder_props[LZMA_PROPS_SIZE];
	SizeT props_size;
	lzma_allocator* alloc;
	lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;

	/* construct the decoder */
	LzmaDec_Construct(&amp;lzma_codec-&gt;decoder);

	/* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
	 * This code assumes that the current version of the encoder imposes the same requirements on the
	 * decoder as the encoder used to produce the file.  This is not necessarily true.  The format
	 * needs to be changed so the encoder properties are written to the file.

	 * configure the properties like the compressor did */
	LzmaEncProps_Init(&amp;encoder_props);
	encoder_props.level = 9;
	encoder_props.reduceSize = hunkbytes;
	LzmaEncProps_Normalize(&amp;encoder_props);

	/* convert to decoder properties */
	alloc = &amp;lzma_codec-&gt;allocator;
	lzma_allocator_init(alloc);
	enc = LzmaEnc_Create((ISzAlloc*)alloc);
	if (!enc)
		return CHDERR_DECOMPRESSION_ERROR;
	if (LzmaEnc_SetProps(enc, &amp;encoder_props) != SZ_OK)
	{
		LzmaEnc_Destroy(enc, (ISzAlloc*)&amp;alloc, (ISzAlloc*)&amp;alloc);
		return CHDERR_DECOMPRESSION_ERROR;
	}
	props_size = sizeof(decoder_props);
	if (LzmaEnc_WriteProperties(enc, decoder_props, &amp;props_size) != SZ_OK)
	{
		LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
		return CHDERR_DECOMPRESSION_ERROR;
	}
	LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);

	/* do memory allocations */
	if (LzmaDec_Allocate(&amp;lzma_codec-&gt;decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
		return CHDERR_DECOMPRESSION_ERROR;

	/* Okay */
	return CHDERR_NONE;
}

/*-------------------------------------------------
 *  lzma_codec_free
 *-------------------------------------------------
 */

void lzma_codec_free(void* codec)
{
	lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;

	/* free memory */
	LzmaDec_Free(&amp;lzma_codec-&gt;decoder, (ISzAlloc*)&amp;lzma_codec-&gt;allocator);
	lzma_allocator_free(&amp;lzma_codec-&gt;allocator);
}

/*-------------------------------------------------
 *  decompress - decompress data using the LZMA
 *  codec
 *-------------------------------------------------
 */

chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	ELzmaStatus status;
	SRes res;
	SizeT consumedlen, decodedlen;
	/* initialize */
	lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
	LzmaDec_Init(&amp;lzma_codec-&gt;decoder);

	/* decode */
	consumedlen = complen;
	decodedlen = destlen;
	res = LzmaDec_DecodeToBuf(&amp;lzma_codec-&gt;decoder, dest, &amp;decodedlen, src, &amp;consumedlen, LZMA_FINISH_END, &amp;status);
	if ((res != SZ_OK &amp;&amp; res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
		return CHDERR_DECOMPRESSION_ERROR;
	return CHDERR_NONE;
}

/* cdlz */
chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
{
	chd_error ret;
	cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;

	/* allocate buffer */
	cdlz-&gt;buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
	if (cdlz-&gt;buffer == NULL)
		return CHDERR_OUT_OF_MEMORY;

	/* make sure the CHD's hunk size is an even multiple of the frame size */
	ret = lzma_codec_init(&amp;cdlz-&gt;base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
	if (ret != CHDERR_NONE)
		return ret;

#ifdef WANT_SUBCODE
	ret = zlib_codec_init(&amp;cdlz-&gt;subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#endif

	if (hunkbytes % CD_FRAME_SIZE != 0)
		return CHDERR_CODEC_ERROR;

	return CHDERR_NONE;
}

void cdlz_codec_free(void* codec)
{
	cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
	free(cdlz-&gt;buffer);
	lzma_codec_free(&amp;cdlz-&gt;base_decompressor);
#ifdef WANT_SUBCODE
	zlib_codec_free(&amp;cdlz-&gt;subcode_decompressor);
#endif
}

chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t framenum;
	cdlz_codec_data* cdlz = (cdlz_codec_data*)codec;

	/* determine header bytes */
	uint32_t frames = destlen / CD_FRAME_SIZE;
	uint32_t complen_bytes = (destlen &lt; 65536) ? 2 : 3;
	uint32_t ecc_bytes = (frames + 7) / 8;
	uint32_t header_bytes = ecc_bytes + complen_bytes;

	/* extract compressed length of base */
	uint32_t complen_base = (src[ecc_bytes + 0] &lt;&lt; 8) | src[ecc_bytes + 1];
	if (complen_bytes &gt; 2)
		complen_base = (complen_base &lt;&lt; 8) | src[ecc_bytes + 2];

	/* reset and decode */
	lzma_codec_decompress(&amp;cdlz-&gt;base_decompressor, &amp;src[header_bytes], complen_base, &amp;cdlz-&gt;buffer[0], frames * CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
	zlib_codec_decompress(&amp;cdlz-&gt;subcode_decompressor, &amp;src[header_bytes + complen_base], complen - complen_base - header_bytes, &amp;cdlz-&gt;buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
#endif

	/* reassemble the data */
	for (framenum = 0; framenum &lt; frames; framenum++)
	{
		uint8_t *sector;

		memcpy(&amp;dest[framenum * CD_FRAME_SIZE], &amp;cdlz-&gt;buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
		memcpy(&amp;dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &amp;cdlz-&gt;buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
#endif

#ifdef WANT_RAW_DATA_SECTOR
		/* reconstitute the ECC data and sync header */
		sector = (uint8_t *)&amp;dest[framenum * CD_FRAME_SIZE];
		if ((src[framenum / 8] &amp; (1 &lt;&lt; (framenum % 8))) != 0)
		{
			const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
			memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
			ecc_generate(sector);
		}
#endif
	}
	return CHDERR_NONE;
}</pre>
<h2>./include/libretro-common/formats/libchdr/libchdr_zlib.c</h2>
<pre>/***************************************************************************

    libchdr_zlib.c

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#include &lt;stddef.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;libchdr/chd.h&gt;
#include &lt;libchdr/minmax.h&gt;
#include &lt;libchdr/cdrom.h&gt;
#include &lt;libchdr/huffman.h&gt;
#include &lt;libchdr/libchdr_zlib.h&gt;
#include &lt;zlib.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;streams/file_stream.h&gt;

/***************************************************************************
    ZLIB COMPRESSION CODEC
***************************************************************************/

/*-------------------------------------------------
    zlib_codec_init - initialize the ZLIB codec
-------------------------------------------------*/

chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
{
	int zerr;
	chd_error err;
	zlib_codec_data *data = (zlib_codec_data*)codec;

	/* clear the buffers */
	memset(data, 0, sizeof(zlib_codec_data));

	/* init the inflater first */
	data-&gt;inflater.next_in = (Bytef *)data;	/* bogus, but that's ok */
	data-&gt;inflater.avail_in = 0;
	data-&gt;inflater.zalloc = zlib_fast_alloc;
	data-&gt;inflater.zfree = zlib_fast_free;
	data-&gt;inflater.opaque = &amp;data-&gt;allocator;
	zerr = inflateInit2(&amp;data-&gt;inflater, -MAX_WBITS);

	/* convert errors */
	if (zerr == Z_MEM_ERROR)
		err = CHDERR_OUT_OF_MEMORY;
	else if (zerr != Z_OK)
		err = CHDERR_CODEC_ERROR;
	else
		err = CHDERR_NONE;

	return err;
}

/*-------------------------------------------------
    zlib_codec_free - free data for the ZLIB
    codec
-------------------------------------------------*/

void zlib_codec_free(void *codec)
{
	zlib_codec_data *data = (zlib_codec_data *)codec;

	/* deinit the streams */
	if (data != NULL)
	{
		inflateEnd(&amp;data-&gt;inflater);

		/* free our fast memory */
		zlib_allocator_free(&amp;data-&gt;allocator);
	}
}

/*-------------------------------------------------
    zlib_codec_decompress - decompress data using
    the ZLIB codec
-------------------------------------------------*/

chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	zlib_codec_data *data = (zlib_codec_data *)codec;
	int zerr;

	/* reset the decompressor */
	data-&gt;inflater.next_in = (Bytef *)src;
	data-&gt;inflater.avail_in = complen;
	data-&gt;inflater.total_in = 0;
	data-&gt;inflater.next_out = (Bytef *)dest;
	data-&gt;inflater.avail_out = destlen;
	data-&gt;inflater.total_out = 0;
	zerr = inflateReset(&amp;data-&gt;inflater);
	if (zerr != Z_OK)
		return CHDERR_DECOMPRESSION_ERROR;

	/* do it */
	zerr = inflate(&amp;data-&gt;inflater, Z_FINISH);
	if (data-&gt;inflater.total_out != destlen)
		return CHDERR_DECOMPRESSION_ERROR;

	return CHDERR_NONE;
}

/*-------------------------------------------------
    zlib_fast_alloc - fast malloc for ZLIB, which
    allocates and frees memory frequently
-------------------------------------------------*/

/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define ZLIB_MIN_ALIGNMENT_BITS 512
#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)

voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
	zlib_allocator *alloc = (zlib_allocator *)opaque;
	uintptr_t paddr = 0;
	uint32_t *ptr;
	int i;

	/* compute the size, rounding to the nearest 1k */
	size = (size * items + 0x3ff) &amp; ~0x3ff;

	/* reuse a hunk if we can */
	for (i = 0; i &lt; MAX_ZLIB_ALLOCS; i++)
	{
		ptr = alloc-&gt;allocptr[i];
		if (ptr &amp;&amp; size == *ptr)
		{
			/* set the low bit of the size so we don't match next time */
			*ptr |= 1;

			/* return aligned block address */
			return (voidpf)(alloc-&gt;allocptr2[i]);
		}
	}

	/* alloc a new one */
    ptr = (uint32_t *)malloc(size + sizeof(uint32_t) + ZLIB_MIN_ALIGNMENT_BYTES);
	if (!ptr)
		return NULL;

	/* put it into the list */
	for (i = 0; i &lt; MAX_ZLIB_ALLOCS; i++)
		if (!alloc-&gt;allocptr[i])
		{
			alloc-&gt;allocptr[i] = ptr;
			paddr = (((uintptr_t)ptr) + sizeof(uint32_t) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) &amp; (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
			alloc-&gt;allocptr2[i] = (uint32_t*)paddr;
			break;
		}

	/* set the low bit of the size so we don't match next time */
	*ptr = size | 1;

	/* return aligned block address */
	return (voidpf)paddr;
}

/*-------------------------------------------------
    zlib_fast_free - fast free for ZLIB, which
    allocates and frees memory frequently
-------------------------------------------------*/

void zlib_fast_free(voidpf opaque, voidpf address)
{
	zlib_allocator *alloc = (zlib_allocator *)opaque;
	uint32_t *ptr = (uint32_t *)address;
	int i;

	/* find the hunk */
	for (i = 0; i &lt; MAX_ZLIB_ALLOCS; i++)
		if (ptr == alloc-&gt;allocptr2[i])
		{
			/* clear the low bit of the size to allow matches */
			*(alloc-&gt;allocptr[i]) &amp;= ~1;
			return;
		}
}

/*-------------------------------------------------
    zlib_allocator_free
-------------------------------------------------*/
void zlib_allocator_free(voidpf opaque)
{
	zlib_allocator *alloc = (zlib_allocator *)opaque;
	int i;

	for (i = 0; i &lt; MAX_ZLIB_ALLOCS; i++)
		if (alloc-&gt;allocptr[i])
			free(alloc-&gt;allocptr[i]);
}


/* cdzl */

chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
{
	chd_error ret;
	cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;

	/* make sure the CHD's hunk size is an even multiple of the frame size */
	if (hunkbytes % CD_FRAME_SIZE != 0)
		return CHDERR_CODEC_ERROR;

	cdzl-&gt;buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
	if (cdzl-&gt;buffer == NULL)
		return CHDERR_OUT_OF_MEMORY;

	ret = zlib_codec_init(&amp;cdzl-&gt;base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
	if (ret != CHDERR_NONE)
		return ret;

#ifdef WANT_SUBCODE
	ret = zlib_codec_init(&amp;cdzl-&gt;subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
	if (ret != CHDERR_NONE)
		return ret;
#endif

	return CHDERR_NONE;
}

void cdzl_codec_free(void *codec)
{
	cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
	zlib_codec_free(&amp;cdzl-&gt;base_decompressor);
#ifdef WANT_SUBCODE
	zlib_codec_free(&amp;cdzl-&gt;subcode_decompressor);
#endif
	free(cdzl-&gt;buffer);
}

chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
	uint32_t framenum;
	cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;

	/* determine header bytes */
	uint32_t frames = destlen / CD_FRAME_SIZE;
	uint32_t complen_bytes = (destlen &lt; 65536) ? 2 : 3;
	uint32_t ecc_bytes = (frames + 7) / 8;
	uint32_t header_bytes = ecc_bytes + complen_bytes;

	/* extract compressed length of base */
	uint32_t complen_base = (src[ecc_bytes + 0] &lt;&lt; 8) | src[ecc_bytes + 1];
	if (complen_bytes &gt; 2)
		complen_base = (complen_base &lt;&lt; 8) | src[ecc_bytes + 2];

	/* reset and decode */
	zlib_codec_decompress(&amp;cdzl-&gt;base_decompressor, &amp;src[header_bytes], complen_base, &amp;cdzl-&gt;buffer[0], frames * CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
	zlib_codec_decompress(&amp;cdzl-&gt;subcode_decompressor, &amp;src[header_bytes + complen_base], complen - complen_base - header_bytes, &amp;cdzl-&gt;buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
#endif

	/* reassemble the data */
	for (framenum = 0; framenum &lt; frames; framenum++)
	{
		uint8_t *sector;

		memcpy(&amp;dest[framenum * CD_FRAME_SIZE], &amp;cdzl-&gt;buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
#ifdef WANT_SUBCODE
		memcpy(&amp;dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &amp;cdzl-&gt;buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
#endif

#ifdef WANT_RAW_DATA_SECTOR
		/* reconstitute the ECC data and sync header */
		sector = (uint8_t *)&amp;dest[framenum * CD_FRAME_SIZE];
		if ((src[framenum / 8] &amp; (1 &lt;&lt; (framenum % 8))) != 0)
		{
			const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
			memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
			ecc_generate(sector);
		}
#endif
	}
	return CHDERR_NONE;
}</pre>
<h2>./include/libretro-common/formats/logiqx_dat/logiqx_dat.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (logiqx_dat.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;file/file_path.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;formats/rxml.h&gt;

#include &lt;formats/logiqx_dat.h&gt;

/* Holds all internal DAT file data */
struct logiqx_dat
{
   rxml_document_t *data;
   rxml_node_t *current_node;
};

/* List of HTML formatting codes that must
 * be replaced when parsing XML data */
const char *logiqx_dat_html_code_list[][2] = {
   {"&amp;amp;",  "&amp;"},
   {"&amp;apos;", "'"},
   {"&amp;gt;",   "&gt;"},
   {"&amp;lt;",   "&lt;"},
   {"&amp;quot;", "\""}
};

#define LOGIQX_DAT_HTML_CODE_LIST_SIZE 5

/* Validation */

/* Performs rudimentary validation of the specified
 * Logiqx XML DAT file path (not rigorous - just
 * enough to prevent obvious errors).
 * Also provides access to file size (DAT files can
 * be very large, so it is useful to have this information
 * on hand - i.e. so we can check that the system has
 * enough free memory to load the file). */
bool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size)
{
   const char *file_ext = NULL;
   int32_t file_size_int;

   if (string_is_empty(path))
      return false;

   /* Check file extension */
   file_ext = path_get_extension(path);

   if (string_is_empty(file_ext))
      return false;

   if (!string_is_equal_noncase(file_ext, "dat") &amp;&amp;
       !string_is_equal_noncase(file_ext, "xml"))
      return false;

   /* Ensure file exists */
   if (!path_is_valid(path))
      return false;

   /* Get file size */
   file_size_int = path_get_size(path);

   if (file_size_int &lt;= 0)
      return false;

   if (file_size)
      *file_size = (uint64_t)file_size_int;

   return true;
}

/* File initialisation/de-initialisation */

/* Loads specified Logiqx XML DAT file from disk.
 * Returned logiqx_dat_t object must be free'd using
 * logiqx_dat_free().
 * Returns NULL if file is invalid or a read error
 * occurs. */
logiqx_dat_t *logiqx_dat_init(const char *path)
{
   logiqx_dat_t *dat_file = NULL;
   rxml_node_t *root_node = NULL;

   /* Check file path */
   if (!logiqx_dat_path_is_valid(path, NULL))
      goto error;

   /* Create logiqx_dat_t object */
   dat_file = (logiqx_dat_t*)calloc(1, sizeof(*dat_file));

   if (!dat_file)
      goto error;

   /* Read file from disk */
   dat_file-&gt;data = rxml_load_document(path);

   if (!dat_file-&gt;data)
      goto error;

   /* Ensure root node has the correct name */
   root_node = rxml_root_node(dat_file-&gt;data);

   if (!root_node)
      goto error;

   if (string_is_empty(root_node-&gt;name))
      goto error;

   /* &gt; Logiqx XML uses:           'datafile'
    * &gt; MAME List XML uses:        'mame'
    * &gt; MAME 'Software List' uses: 'softwarelist' */
   if (!string_is_equal(root_node-&gt;name, "datafile") &amp;&amp;
       !string_is_equal(root_node-&gt;name, "mame") &amp;&amp;
       !string_is_equal(root_node-&gt;name, "softwarelist"))
      goto error;

   /* Get pointer to initial child node */
   dat_file-&gt;current_node = root_node-&gt;children;

   if (!dat_file-&gt;current_node)
      goto error;

   /* All is well - return logiqx_dat_t object */
   return dat_file;

error:
   logiqx_dat_free(dat_file);
   return NULL;
}

/* Frees specified DAT file */
void logiqx_dat_free(logiqx_dat_t *dat_file)
{
   if (!dat_file)
      return;

   dat_file-&gt;current_node = NULL;

   if (dat_file-&gt;data)
   {
      rxml_free_document(dat_file-&gt;data);
      dat_file-&gt;data = NULL;
   }

   free(dat_file);
   dat_file = NULL;
}

/* Game information access */

/* Returns true if specified node is a 'game' entry */
static bool logiqx_dat_is_game_node(rxml_node_t *node)
{
   const char *node_name = NULL;

   if (!node)
      return false;

   /* Check node name */
   node_name = node-&gt;name;

   if (string_is_empty(node_name))
      return false;

   /* &gt; Logiqx XML uses:           'game'
    * &gt; MAME List XML uses:        'machine'
    * &gt; MAME 'Software List' uses: 'software' */
   return string_is_equal(node_name, "game") ||
          string_is_equal(node_name, "machine") ||
          string_is_equal(node_name, "software");
}

/* Returns true if specified node is a game
 * node containing information for a game with
 * the specified name */
static bool logiqx_dat_game_node_matches_name(
      rxml_node_t *node, const char *game_name)
{
   const char *node_game_name = NULL;

   if (!logiqx_dat_is_game_node(node) ||
       string_is_empty(game_name))
      return false;

   /* Get 'name' attribute of XML node */
   node_game_name = rxml_node_attrib(node, "name");

   if (string_is_empty(node_game_name))
      return false;

   return string_is_equal(node_game_name, game_name);
}

/* The XML element data strings returned from
 * DAT files are very 'messy'. This function
 * removes all cruft, replaces formatting strings
 * and copies the result (if valid) to 'str' */
static void logiqx_dat_sanitise_element_data(
      const char *data, char *str, size_t len)
{
   char sanitised_data[PATH_MAX_LENGTH];
   size_t i;

   sanitised_data[0] = '\0';

   if (string_is_empty(data))
      return;

   strlcpy(sanitised_data, data, sizeof(sanitised_data));

   /* Element data includes leading/trailing
    * newline characters - trim them away */
   string_trim_whitespace_right(sanitised_data);
   string_trim_whitespace_left(sanitised_data);

   if (string_is_empty(sanitised_data))
      return;

   /* XML has a number of special characters that
    * are handled using a HTML formatting codes.
    * All of these have to be replaced...
    * &amp;amp;  -&gt; &amp;
    * &amp;apos; -&gt; '
    * &amp;gt;   -&gt; &gt;
    * &amp;lt;   -&gt; &lt;
    * &amp;quot; -&gt; "
    */
   for (i = 0; i &lt; LOGIQX_DAT_HTML_CODE_LIST_SIZE; i++)
   {
      const char *find_string    = logiqx_dat_html_code_list[i][0];
      const char *replace_string = logiqx_dat_html_code_list[i][1];

      /* string_replace_substring() is expensive
       * &gt; only invoke if element string contains
       *   HTML code */
      if (strstr(sanitised_data, find_string))
      {
         char *tmp = string_replace_substring(
               sanitised_data, strlen(sanitised_data),
               find_string,    strlen(find_string),
               replace_string, strlen(replace_string));

         if (!string_is_empty(tmp))
            strlcpy(sanitised_data, tmp, sizeof(sanitised_data));

         if (tmp)
            free(tmp);
      }
   }

   if (string_is_empty(sanitised_data))
      return;

   /* All is well - can copy result */
   strlcpy(str, sanitised_data, len);
}

/* Extracts game information from specified node.
 * Returns false if node is invalid */
static bool logiqx_dat_parse_game_node(
      rxml_node_t *node, logiqx_dat_game_info_t *game_info)
{
   const char *game_name   = NULL;
   const char *is_bios     = NULL;
   const char *is_runnable = NULL;
   rxml_node_t *info_node  = NULL;
   bool description_found  = false;
   bool year_found         = false;
   bool manufacturer_found = false;

   if (!logiqx_dat_is_game_node(node))
      return false;

   if (!game_info)
      return false;

   /* Initialise logiqx_dat_game_info_t object */
   game_info-&gt;name[0]         = '\0';
   game_info-&gt;description[0]  = '\0';
   game_info-&gt;year[0]         = '\0';
   game_info-&gt;manufacturer[0] = '\0';
   game_info-&gt;is_bios         = false;
   game_info-&gt;is_runnable     = true;

   /* Get game name */
   game_name = rxml_node_attrib(node, "name");

   if (!string_is_empty(game_name))
      strlcpy(game_info-&gt;name, game_name, sizeof(game_info-&gt;name));

   /* Get 'is bios' status */
   is_bios = rxml_node_attrib(node, "isbios");

   if (!string_is_empty(is_bios))
      game_info-&gt;is_bios = string_is_equal(is_bios, "yes");

   /* Get 'is runnable' status
    * &gt; Note: This attribute only exists in MAME List
    *   XML files, but there is no harm in checking for
    *   it generally. For normal Logiqx XML files,
    *   'is runnable' is just the inverse of 'is bios' */
   is_runnable = rxml_node_attrib(node, "runnable");

   if (!string_is_empty(is_runnable))
      game_info-&gt;is_runnable = string_is_equal(is_runnable, "yes");
   else
      game_info-&gt;is_runnable = !game_info-&gt;is_bios;

   /* Loop over all game info nodes */
   for (info_node = node-&gt;children; info_node; info_node = info_node-&gt;next)
   {
      const char *info_node_name = info_node-&gt;name;
      const char *info_node_data = info_node-&gt;data;

      if (string_is_empty(info_node_name))
         continue;

      /* Check description */
      if (string_is_equal(info_node_name, "description"))
      {
         logiqx_dat_sanitise_element_data(
            info_node_data, game_info-&gt;description,
            sizeof(game_info-&gt;description));
         description_found = true;
      }
      /* Check year */
      else if (string_is_equal(info_node_name, "year"))
      {
         logiqx_dat_sanitise_element_data(
            info_node_data, game_info-&gt;year,
            sizeof(game_info-&gt;year));
         year_found = true;
      }
      /* Check manufacturer */
      else if (string_is_equal(info_node_name, "manufacturer"))
      {
         logiqx_dat_sanitise_element_data(
            info_node_data, game_info-&gt;manufacturer,
            sizeof(game_info-&gt;manufacturer));
         manufacturer_found = true;
      }

      /* If all required entries have been found,
       * can end loop */
      if (description_found &amp;&amp; year_found &amp;&amp; manufacturer_found)
         break;
   }

   return true;
}

/* Sets/resets internal node pointer to the first
 * entry in the DAT file */
void logiqx_dat_set_first(logiqx_dat_t *dat_file)
{
   rxml_node_t *root_node = NULL;

   if (!dat_file)
      return;

   if (!dat_file-&gt;data)
      return;

   /* Get root node */
   root_node = rxml_root_node(dat_file-&gt;data);

   if (!root_node)
   {
      dat_file-&gt;current_node = NULL;
      return;
   }

   /* Get pointer to initial child node */
   dat_file-&gt;current_node = root_node-&gt;children;
}

/* Fetches game information for the current entry
 * in the DAT file and increments the internal node
 * pointer.
 * Returns false if the end of the DAT file has been
 * reached (in which case 'game_info' will be invalid) */
bool logiqx_dat_get_next(
      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info)
{
   if (!dat_file || !game_info)
      return false;

   if (!dat_file-&gt;data)
      return false;

   while (dat_file-&gt;current_node)
   {
      rxml_node_t *current_node = dat_file-&gt;current_node;

      /* Whatever happens, internal node pointer must
       * be 'incremented' */
      dat_file-&gt;current_node = dat_file-&gt;current_node-&gt;next;

      /* If this is a game node, extract info
       * and return */
      if (logiqx_dat_is_game_node(current_node))
         return logiqx_dat_parse_game_node(current_node, game_info);
   }

   return false;
}

/* Fetches information for the specified game.
 * Returns false if game does not exist, or arguments
 * are invalid. */
bool logiqx_dat_search(
      logiqx_dat_t *dat_file, const char *game_name,
      logiqx_dat_game_info_t *game_info)
{
   rxml_node_t *root_node = NULL;
   rxml_node_t *game_node = NULL;

   if (!dat_file || !game_info || string_is_empty(game_name))
      return false;

   if (!dat_file-&gt;data)
      return false;

   /* Get root node */
   root_node = rxml_root_node(dat_file-&gt;data);

   if (!root_node)
      return false;

   /* Loop over all child nodes of the DAT file */
   for (game_node = root_node-&gt;children; game_node; game_node = game_node-&gt;next)
   {
      /* If this is the requested game, fetch info and return */
      if (logiqx_dat_game_node_matches_name(game_node, game_name))
         return logiqx_dat_parse_game_node(game_node, game_info);
   }

   return false;
}</pre>
<h2>./include/libretro-common/formats/m3u/m3u_file.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (m3u_file.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;retro_miscellaneous.h&gt;

#include &lt;string/stdstring.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;array/rbuf.h&gt;

#include &lt;formats/m3u_file.h&gt;

/* We parse the following types of entry label:
 * - '#LABEL:&lt;label&gt;' non-standard, but used by
 *   some cores
 * - '#EXTINF:&lt;runtime&gt;,&lt;label&gt;' standard extended
 *   M3U directive
 * - '&lt;content path&gt;|&lt;label&gt;' non-standard, but
 *   used by some cores
 * All other comments/directives are ignored */
#define M3U_FILE_COMMENT            '#'
#define M3U_FILE_NONSTD_LABEL       "#LABEL:"
#define M3U_FILE_EXTSTD_LABEL       "#EXTINF:"
#define M3U_FILE_EXTSTD_LABEL_TOKEN ','
#define M3U_FILE_RETRO_LABEL_TOKEN  '|'

/* Holds all internal M3U file data
 * &gt; Note the awkward name: 'content_m3u_file'
 *   If we used just 'm3u_file' here, it would
 *   lead to conflicts elsewhere... */
struct content_m3u_file
{
   char *path;
   m3u_file_entry_t *entries;
};

/* File Initialisation / De-Initialisation */

/* Reads M3U file contents from disk
 * - Does nothing if file does not exist
 * - Returns false in the event of an error */
static bool m3u_file_load(m3u_file_t *m3u_file)
{
   size_t i;
   char entry_label[NAME_MAX_LENGTH];
   char entry_path[PATH_MAX_LENGTH];
   const char *file_ext      = NULL;
   int64_t file_len          = 0;
   uint8_t *file_buf         = NULL;
   struct string_list *lines = NULL;
   bool success              = false;

   entry_path[0]  = '\0';
   entry_label[0] = '\0';

   if (!m3u_file)
      goto end;

   /* Check whether file exists
    * &gt; If path is empty, then an error
    *   has occurred... */
   if (string_is_empty(m3u_file-&gt;path))
      goto end;

   /* &gt; File must have the correct extension */
   file_ext = path_get_extension(m3u_file-&gt;path);

   if (    string_is_empty(file_ext)
       || !string_is_equal_noncase(file_ext, M3U_FILE_EXT))
      goto end;

   /* &gt; If file does not exist, no action
    *   is required */
   if (!path_is_valid(m3u_file-&gt;path))
   {
      success = true;
      goto end;
   }

   /* Read file from disk */
   if (filestream_read_file(m3u_file-&gt;path, (void**)&amp;file_buf, &amp;file_len) &gt;= 0)
   {
      /* Split file into lines */
      if (file_len &gt; 0)
         lines = string_split((const char*)file_buf, "\n");

      /* File buffer no longer required */
      if (file_buf)
      {
         free(file_buf);
         file_buf = NULL;
      }
   }
   /* File IO error... */
   else
      goto end;

   /* If file was empty, no action is required */
   if (!lines)
   {
      success = true;
      goto end;
   }

   /* Parse lines of file */
   for (i = 0; i &lt; lines-&gt;size; i++)
   {
      const char *line = lines-&gt;elems[i].data;

      if (string_is_empty(line))
         continue;

      /* Determine line 'type' */

      /* &gt; '#LABEL:' */
      if (string_starts_with_size(line, M3U_FILE_NONSTD_LABEL,
            STRLEN_CONST(M3U_FILE_NONSTD_LABEL)))
      {
         /* Label is the string to the right
          * of '#LABEL:' */
         const char *label = line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL);

         if (!string_is_empty(label))
         {
            strlcpy(
                  entry_label, line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL),
                  sizeof(entry_label));
            string_trim_whitespace_right(entry_label);
            string_trim_whitespace_left(entry_label);
         }
      }
      /* &gt; '#EXTINF:' */
      else if (string_starts_with_size(line, M3U_FILE_EXTSTD_LABEL,
            STRLEN_CONST(M3U_FILE_EXTSTD_LABEL)))
      {
         /* Label is the string to the right
          * of the first comma */
         const char* label_ptr = strchr(
               line + STRLEN_CONST(M3U_FILE_EXTSTD_LABEL),
               M3U_FILE_EXTSTD_LABEL_TOKEN);

         if (!string_is_empty(label_ptr))
         {
            label_ptr++;
            if (!string_is_empty(label_ptr))
            {
               strlcpy(entry_label, label_ptr, sizeof(entry_label));
               string_trim_whitespace_right(entry_label);
               string_trim_whitespace_left(entry_label);
            }
         }
      }
      /* &gt; Ignore other comments/directives */
      else if (line[0] == M3U_FILE_COMMENT)
         continue;
      /* &gt; An actual 'content' line */
      else
      {
         /* This is normally a file name/path, but may
          * have the format &lt;content path&gt;|&lt;label&gt; */
         const char *token_ptr = strchr(line, M3U_FILE_RETRO_LABEL_TOKEN);

         if (token_ptr)
         {
            size_t _len = (size_t)(1 + token_ptr - line);

            /* Get entry_path segment */
            if (_len &gt; 0)
            {
               memset(entry_path, 0, sizeof(entry_path));
               strlcpy(
                     entry_path, line,
                     ((_len &lt; PATH_MAX_LENGTH ?
                       _len : PATH_MAX_LENGTH) * sizeof(char)));
               string_trim_whitespace_right(entry_path);
               string_trim_whitespace_left(entry_path);
            }

            /* Get entry_label segment */
            token_ptr++;
            if (*token_ptr != '\0')
            {
               strlcpy(entry_label, token_ptr, sizeof(entry_label));
               string_trim_whitespace_right(entry_label);
               string_trim_whitespace_left(entry_label);
            }
         }
         else
         {
            /* Just a normal file name/path */
            strlcpy(entry_path, line, sizeof(entry_path));
            string_trim_whitespace_right(entry_path);
            string_trim_whitespace_left(entry_path);
         }

         /* Add entry to file
          * &gt; Note: The only way that m3u_file_add_entry()
          *   can fail here is if we run out of memory.
          *   This is a critical error, and m3u_file must
          *   be considered invalid in this case */
         if (!string_is_empty(entry_path) &amp;&amp;
             !m3u_file_add_entry(m3u_file, entry_path, entry_label))
            goto end;

         /* Reset entry_path/entry_label */
         entry_path[0]  = '\0';
         entry_label[0] = '\0';
      }
   }

   success = true;

end:
   /* Clean up */
   if (lines)
   {
      string_list_free(lines);
      lines = NULL;
   }

   if (file_buf)
   {
      free(file_buf);
      file_buf = NULL;
   }

   return success;
}

/* Creates and initialises an M3U file
 * - If 'path' refers to an existing file,
 *   contents is parsed
 * - If path does not exist, an empty M3U file
 *   is created
 * - Returned m3u_file_t object must be free'd using
 *   m3u_file_free()
 * - Returns NULL in the event of an error */
m3u_file_t *m3u_file_init(const char *path)
{
   m3u_file_t *m3u_file = NULL;
   char m3u_path[PATH_MAX_LENGTH];

   /* Sanity check */
   if (string_is_empty(path))
      return NULL;

   /* Get 'real' file path */
   strlcpy(m3u_path, path, sizeof(m3u_path));
   path_resolve_realpath(m3u_path, sizeof(m3u_path), false);

   if (string_is_empty(m3u_path))
      return NULL;

   /* Create m3u_file_t object */
   if (!(m3u_file = (m3u_file_t*)malloc(sizeof(*m3u_file))))
      return NULL;

   /* Initialise members */
   m3u_file-&gt;path    = NULL;
   m3u_file-&gt;entries = NULL;

   /* Copy file path */
   m3u_file-&gt;path    = strdup(m3u_path);

   /* Read existing file contents from
    * disk, if required */
   if (!m3u_file_load(m3u_file))
   {
      m3u_file_free(m3u_file);
      return NULL;
   }

   return m3u_file;
}

/* Frees specified M3U file entry */
static void m3u_file_free_entry(m3u_file_entry_t *entry)
{
   if (!entry)
      return;

   if (entry-&gt;path)
      free(entry-&gt;path);

   if (entry-&gt;full_path)
      free(entry-&gt;full_path);

   if (entry-&gt;label)
      free(entry-&gt;label);

   entry-&gt;path      = NULL;
   entry-&gt;full_path = NULL;
   entry-&gt;label     = NULL;
}

/* Frees specified M3U file */
void m3u_file_free(m3u_file_t *m3u_file)
{
   size_t i;

   if (!m3u_file)
      return;

   if (m3u_file-&gt;path)
      free(m3u_file-&gt;path);

   m3u_file-&gt;path = NULL;

   /* Free entries */
   if (m3u_file-&gt;entries)
   {
      for (i = 0; i &lt; RBUF_LEN(m3u_file-&gt;entries); i++)
      {
         m3u_file_entry_t *entry = &amp;m3u_file-&gt;entries[i];
         m3u_file_free_entry(entry);
      }

      RBUF_FREE(m3u_file-&gt;entries);
   }

   free(m3u_file);
}

/* Getters */

/* Returns M3U file path */
char *m3u_file_get_path(m3u_file_t *m3u_file)
{
   if (!m3u_file)
      return NULL;

   return m3u_file-&gt;path;
}

/* Returns number of entries in M3U file */
size_t m3u_file_get_size(m3u_file_t *m3u_file)
{
   if (!m3u_file)
      return 0;

   return RBUF_LEN(m3u_file-&gt;entries);
}

/* Fetches specified M3U file entry
 * - Returns false if 'idx' is invalid, or internal
 *   entry is NULL */
bool m3u_file_get_entry(
      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry)
{
   if (!m3u_file ||
       !entry ||
       (idx &gt;= RBUF_LEN(m3u_file-&gt;entries)))
      return false;

   *entry = &amp;m3u_file-&gt;entries[idx];

   if (!*entry)
      return false;

   return true;
}

/* Setters */

/* Adds specified entry to the M3U file
 * - Returns false if path is invalid, or
 *   memory could not be allocated for the
 *   entry */
bool m3u_file_add_entry(
      m3u_file_t *m3u_file, const char *path, const char *label)
{
   m3u_file_entry_t *entry = NULL;
   size_t num_entries;
   char full_path[PATH_MAX_LENGTH];

   full_path[0] = '\0';

   if (!m3u_file || string_is_empty(path))
      return false;

   /* Get current number of file entries */
   num_entries = RBUF_LEN(m3u_file-&gt;entries);

   /* Attempt to allocate memory for new entry */
   if (!RBUF_TRYFIT(m3u_file-&gt;entries, num_entries + 1))
      return false;

   /* Allocation successful - increment array size */
   RBUF_RESIZE(m3u_file-&gt;entries, num_entries + 1);

   /* Fetch entry at end of list, and zero-initialise
    * members */
   entry = &amp;m3u_file-&gt;entries[num_entries];
   memset(entry, 0, sizeof(*entry));

   /* Copy path and label */
   entry-&gt;path = strdup(path);

   if (!string_is_empty(label))
      entry-&gt;label = strdup(label);

   /* Populate 'full_path' field */
   if (path_is_absolute(path))
   {
      strlcpy(full_path, path, sizeof(full_path));
      path_resolve_realpath(full_path, sizeof(full_path), false);
   }
   else
      fill_pathname_resolve_relative(
            full_path, m3u_file-&gt;path, path,
            sizeof(full_path));

   /* Handle unforeseen errors... */
   if (string_is_empty(full_path))
   {
      m3u_file_free_entry(entry);
      return false;
   }

   entry-&gt;full_path = strdup(full_path);

   return true;
}

/* Removes all entries in M3U file */
void m3u_file_clear(m3u_file_t *m3u_file)
{
   size_t i;

   if (!m3u_file)
      return;

   if (m3u_file-&gt;entries)
   {
      for (i = 0; i &lt; RBUF_LEN(m3u_file-&gt;entries); i++)
      {
         m3u_file_entry_t *entry = &amp;m3u_file-&gt;entries[i];
         m3u_file_free_entry(entry);
      }

      RBUF_FREE(m3u_file-&gt;entries);
   }
}

/* Saving */

/* Saves M3U file to disk
 * - Setting 'label_type' to M3U_FILE_LABEL_NONE
 *   just outputs entry paths - this the most
 *   common format supported by most cores
 * - Returns false in the event of an error */
bool m3u_file_save(
      m3u_file_t *m3u_file, enum m3u_file_label_type label_type)
{
   size_t i;
   char base_dir[DIR_MAX_LENGTH];
   RFILE *file      = NULL;

   if (!m3u_file || !m3u_file-&gt;entries)
      return false;

   /* This should never happen */
   if (string_is_empty(m3u_file-&gt;path))
      return false;

   /* Get M3U file base directory */
   if (find_last_slash(m3u_file-&gt;path))
      fill_pathname_basedir(base_dir, m3u_file-&gt;path, sizeof(base_dir));
   else
      base_dir[0]   = '\0';

   /* Open file for writing */
   if (!(file = filestream_open(m3u_file-&gt;path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return false;

   /* Loop over entries */
   for (i = 0; i &lt; RBUF_LEN(m3u_file-&gt;entries); i++)
   {
      m3u_file_entry_t *entry = &amp;m3u_file-&gt;entries[i];
      char entry_path[PATH_MAX_LENGTH];

      entry_path[0] = '\0';

      if (!entry || string_is_empty(entry-&gt;full_path))
         continue;

      /* When writing M3U files, entry paths are
       * always relative */
      if (string_is_empty(base_dir))
         strlcpy(
               entry_path, entry-&gt;full_path,
               sizeof(entry_path));
      else
         path_relative_to(
               entry_path, entry-&gt;full_path, base_dir,
               sizeof(entry_path));

      if (string_is_empty(entry_path))
         continue;

      /* Check if we need to write a label */
      if (!string_is_empty(entry-&gt;label))
      {
         switch (label_type)
         {
            case M3U_FILE_LABEL_NONSTD:
               filestream_printf(
                     file, "%s%s\n%s\n",
                     M3U_FILE_NONSTD_LABEL, entry-&gt;label,
                     entry_path);
               break;
            case M3U_FILE_LABEL_EXTSTD:
               filestream_printf(
                     file, "%s%c%s\n%s\n",
                     M3U_FILE_EXTSTD_LABEL, M3U_FILE_EXTSTD_LABEL_TOKEN, entry-&gt;label,
                     entry_path);
               break;
            case M3U_FILE_LABEL_RETRO:
               filestream_printf(
                     file, "%s%c%s\n",
                     entry_path, M3U_FILE_RETRO_LABEL_TOKEN, entry-&gt;label);
               break;
            case M3U_FILE_LABEL_NONE:
            default:
               filestream_printf(
                     file, "%s\n", entry_path);
               break;
         }
      }
      /* No label - just write entry path */
      else
         filestream_printf(
               file, "%s\n", entry_path);
   }

   /* Close file */
   filestream_close(file);

   return true;
}

/* Utilities */

/* Internal qsort function */
static int m3u_file_qsort_func(
      const m3u_file_entry_t *a, const m3u_file_entry_t *b)
{
   if (!a || !b)
      return 0;

   if (string_is_empty(a-&gt;full_path) || string_is_empty(b-&gt;full_path))
      return 0;

   return strcasecmp(a-&gt;full_path, b-&gt;full_path);
}

/* Sorts M3U file entries in alphabetical order */
void m3u_file_qsort(m3u_file_t *m3u_file)
{
   size_t num_entries;

   if (!m3u_file)
      return;

   num_entries = RBUF_LEN(m3u_file-&gt;entries);

   if (num_entries &lt; 2)
      return;

   qsort(
         m3u_file-&gt;entries, num_entries,
         sizeof(m3u_file_entry_t),
         (int (*)(const void *, const void *))m3u_file_qsort_func);
}

/* Returns true if specified path corresponds
 * to an M3U file (simple convenience function) */
bool m3u_file_is_m3u(const char *path)
{
   const char *file_ext = NULL;
   if (string_is_empty(path))
      return false;
   /* Check file extension */
   file_ext = path_get_extension(path);
   if (string_is_empty(file_ext))
      return false;
   if (!string_is_equal_noncase(file_ext, M3U_FILE_EXT))
      return false;
   /* Ensure file exists */
   if (!path_is_valid(path))
      return false;
   /* Ensure we have non-zero file size */
   if (path_get_size(path) &lt;= 0)
      return false;
   return true;
}</pre>
<h2>./include/libretro-common/formats/png/rpng.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef DEBUG
#include &lt;stdio.h&gt;
#endif
#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#ifdef GEKKO
#include &lt;malloc.h&gt;
#endif

#include &lt;boolean.h&gt;
#include &lt;formats/image.h&gt;
#include &lt;formats/rpng.h&gt;
#include &lt;streams/trans_stream.h&gt;
#include &lt;string/stdstring.h&gt;

#include "rpng_internal.h"

enum png_ihdr_color_type
{
   PNG_IHDR_COLOR_GRAY       = 0,
   PNG_IHDR_COLOR_RGB        = 2,
   PNG_IHDR_COLOR_PLT        = 3,
   PNG_IHDR_COLOR_GRAY_ALPHA = 4,
   PNG_IHDR_COLOR_RGBA       = 6
};

enum png_line_filter
{
   PNG_FILTER_NONE = 0,
   PNG_FILTER_SUB,
   PNG_FILTER_UP,
   PNG_FILTER_AVERAGE,
   PNG_FILTER_PAETH
};

enum png_chunk_type
{
   PNG_CHUNK_NOOP = 0,
   PNG_CHUNK_ERROR,
   PNG_CHUNK_IHDR,
   PNG_CHUNK_IDAT,
   PNG_CHUNK_PLTE,
   PNG_CHUNK_tRNS,
   PNG_CHUNK_IEND
};

struct adam7_pass
{
   unsigned x;
   unsigned y;
   unsigned stride_x;
   unsigned stride_y;
};

struct idat_buffer
{
   uint8_t *data;
   size_t size;
};

enum rpng_process_flags
{
   RPNG_PROCESS_FLAG_INFLATE_INITIALIZED    = (1 &lt;&lt; 0),
   RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED = (1 &lt;&lt; 1),
   RPNG_PROCESS_FLAG_PASS_INITIALIZED       = (1 &lt;&lt; 2)
};

struct rpng_process
{
   uint32_t *data;
   uint32_t *palette;
   void *stream;
   const struct trans_stream_backend *stream_backend;
   uint8_t *prev_scanline;
   uint8_t *decoded_scanline;
   uint8_t *inflate_buf;
   size_t restore_buf_size;
   size_t adam7_restore_buf_size;
   size_t data_restore_buf_size;
   size_t inflate_buf_size;
   size_t avail_in;
   size_t avail_out;
   size_t total_out;
   size_t pass_size;
   struct png_ihdr ihdr; /* uint32_t alignment */
   unsigned bpp;
   unsigned pitch;
   unsigned h;
   unsigned pass_width;
   unsigned pass_height;
   unsigned pass_pos;
   uint8_t flags;
};

enum rpng_flags
{
   RPNG_FLAG_HAS_IHDR = (1 &lt;&lt; 0),
   RPNG_FLAG_HAS_IDAT = (1 &lt;&lt; 1),
   RPNG_FLAG_HAS_IEND = (1 &lt;&lt; 2),
   RPNG_FLAG_HAS_PLTE = (1 &lt;&lt; 3),
   RPNG_FLAG_HAS_TRNS = (1 &lt;&lt; 4)
};

struct rpng
{
   struct rpng_process *process;
   uint8_t *buff_data;
   uint8_t *buff_end;
   struct idat_buffer idat_buf; /* ptr alignment */
   struct png_ihdr ihdr; /* uint32 alignment */
   uint32_t palette[256];
   uint8_t flags;
};

static const struct adam7_pass rpng_passes[] = {
   { 0, 0, 8, 8 },
   { 4, 0, 8, 8 },
   { 0, 4, 4, 8 },
   { 2, 0, 4, 4 },
   { 0, 2, 2, 4 },
   { 1, 0, 2, 2 },
   { 0, 1, 1, 2 },
};

static INLINE uint32_t rpng_dword_be(const uint8_t *buf)
{
   return (buf[0] &lt;&lt; 24) | (buf[1] &lt;&lt; 16) | (buf[2] &lt;&lt; 8) | (buf[3] &lt;&lt; 0);
}

#if defined(DEBUG) || defined(RPNG_TEST)
static bool rpng_process_ihdr(struct png_ihdr *ihdr)
{
   uint8_t ihdr_depth = ihdr-&gt;depth;

   switch (ihdr-&gt;color_type)
   {
      case PNG_IHDR_COLOR_RGB:
      case PNG_IHDR_COLOR_GRAY_ALPHA:
      case PNG_IHDR_COLOR_RGBA:
         if (ihdr_depth != 8 &amp;&amp; ihdr_depth != 16)
         {
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
            return false;
         }
         break;
      case PNG_IHDR_COLOR_GRAY:
         /* Valid bitdepths are: 1, 2, 4, 8, 16 */
         if (ihdr_depth &gt; 16 || (0x977F7FFF &lt;&lt; ihdr_depth) &amp; 0x80000000)
         {
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
            return false;
         }
         break;
      case PNG_IHDR_COLOR_PLT:
         /* Valid bitdepths are: 1, 2, 4, 8 */
         if (ihdr_depth &gt; 8 || (0x977F7FFF &lt;&lt; ihdr_depth)  &amp; 0x80000000)
         {
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
            return false;
         }
         break;
      default:
         fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
         return false;
   }

#ifdef RPNG_TEST
   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
         ihdr-&gt;width, ihdr-&gt;height,
         ihdr_depth, (ihdr-&gt;color_type == PNG_IHDR_COLOR_PLT) ? "yes" : "no",
         (ihdr-&gt;color_type &amp; PNG_IHDR_COLOR_RGB)              ? "yes" : "no",
         (ihdr-&gt;color_type &amp; PNG_IHDR_COLOR_GRAY_ALPHA)       ? "yes" : "no",
         ihdr-&gt;interlace == 1 ? "yes" : "no");
#endif

   return true;
}
#else
static bool rpng_process_ihdr(struct png_ihdr *ihdr)
{
   uint8_t ihdr_depth = ihdr-&gt;depth;

   switch (ihdr-&gt;color_type)
   {
      case PNG_IHDR_COLOR_RGB:
      case PNG_IHDR_COLOR_GRAY_ALPHA:
      case PNG_IHDR_COLOR_RGBA:
         if (ihdr_depth != 8 &amp;&amp; ihdr_depth != 16)
            return false;
         break;
      case PNG_IHDR_COLOR_GRAY:
         /* Valid bitdepths are: 1, 2, 4, 8, 16 */
         if (ihdr_depth &gt; 16 || (0x977F7FFF &lt;&lt; ihdr_depth) &amp; 0x80000000)
            return false;
         break;
      case PNG_IHDR_COLOR_PLT:
         /* Valid bitdepths are: 1, 2, 4, 8 */
         if (ihdr_depth &gt; 8 || (0x977F7FFF &lt;&lt; ihdr_depth)  &amp; 0x80000000)
            return false;
         break;
      default:
         return false;
   }

   return true;
}
#endif

static void rpng_reverse_filter_copy_line_rgb(uint32_t *data,
      const uint8_t *decoded, unsigned width, unsigned bpp)
{
   int i;

   bpp /= 8;

   for (i = 0; i &lt; (int)width; i++)
   {
      uint32_t r, g, b;

      r        = *decoded;
      decoded += bpp;
      g        = *decoded;
      decoded += bpp;
      b        = *decoded;
      decoded += bpp;
      data[i]  = (0xffu &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);
   }
}

static void rpng_reverse_filter_copy_line_rgba(uint32_t *data,
      const uint8_t *decoded, unsigned width, unsigned bpp)
{
   int i;

   bpp /= 8;

   for (i = 0; i &lt; (int)width; i++)
   {
      uint32_t r, g, b, a;
      r        = *decoded;
      decoded += bpp;
      g        = *decoded;
      decoded += bpp;
      b        = *decoded;
      decoded += bpp;
      a        = *decoded;
      decoded += bpp;
      data[i]  = (a &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);
   }
}

static void rpng_reverse_filter_copy_line_bw(uint32_t *data,
      const uint8_t *decoded, unsigned width, unsigned depth)
{
   int i;
   unsigned bit;
   static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
   unsigned mul, mask;

   if (depth == 16)
   {
      for (i = 0; i &lt; (int)width; i++)
      {
         uint32_t val = decoded[i &lt;&lt; 1];
         data[i]      = (val * 0x010101) | (0xffu &lt;&lt; 24);
      }
      return;
   }

   mul  = mul_table[depth];
   mask = (1 &lt;&lt; depth) - 1;
   bit  = 0;

   for (i = 0; i &lt; (int)width; i++, bit += depth)
   {
      unsigned byte = bit &gt;&gt; 3;
      unsigned val  = decoded[byte] &gt;&gt; (8 - depth - (bit &amp; 7));

      val          &amp;= mask;
      val          *= mul;
      data[i]       = (val * 0x010101) | (0xffu &lt;&lt; 24);
   }
}

static void rpng_reverse_filter_copy_line_gray_alpha(uint32_t *data,
      const uint8_t *decoded, unsigned width,
      unsigned bpp)
{
   int i;

   bpp /= 8;

   for (i = 0; i &lt; (int)width; i++)
   {
      uint32_t gray, alpha;

      gray     = *decoded;
      decoded += bpp;
      alpha    = *decoded;
      decoded += bpp;

      data[i]  = (gray * 0x010101) | (alpha &lt;&lt; 24);
   }
}

static void rpng_reverse_filter_copy_line_plt(uint32_t *data,
      const uint8_t *decoded, unsigned width,
      unsigned depth, const uint32_t *palette)
{
   switch (depth)
   {
      case 1:
         {
            int i;
            unsigned w = width / 8;
            for (i = 0; i &lt; (int)w; i++, decoded++)
            {
               *data++ = palette[(*decoded &gt;&gt; 7) &amp; 1];
               *data++ = palette[(*decoded &gt;&gt; 6) &amp; 1];
               *data++ = palette[(*decoded &gt;&gt; 5) &amp; 1];
               *data++ = palette[(*decoded &gt;&gt; 4) &amp; 1];
               *data++ = palette[(*decoded &gt;&gt; 3) &amp; 1];
               *data++ = palette[(*decoded &gt;&gt; 2) &amp; 1];
               *data++ = palette[(*decoded &gt;&gt; 1) &amp; 1];
               *data++ = palette[*decoded &amp; 1];
            }

            switch (width &amp; 7)
            {
               case 7:
                  data[6] = palette[(*decoded &gt;&gt; 1) &amp; 1];
               case 6:
                  data[5] = palette[(*decoded &gt;&gt; 2) &amp; 1];
               case 5:
                  data[4] = palette[(*decoded &gt;&gt; 3) &amp; 1];
               case 4:
                  data[3] = palette[(*decoded &gt;&gt; 4) &amp; 1];
               case 3:
                  data[2] = palette[(*decoded &gt;&gt; 5) &amp; 1];
               case 2:
                  data[1] = palette[(*decoded &gt;&gt; 6) &amp; 1];
               case 1:
                  data[0] = palette[(*decoded &gt;&gt; 7) &amp; 1];
                  break;
            }
         }
         break;

      case 2:
         {
            int i;
            unsigned w = width / 4;
            for (i = 0; i &lt; (int)w; i++, decoded++)
            {
               *data++ = palette[(*decoded &gt;&gt; 6) &amp; 3];
               *data++ = palette[(*decoded &gt;&gt; 4) &amp; 3];
               *data++ = palette[(*decoded &gt;&gt; 2) &amp; 3];
               *data++ = palette[*decoded &amp; 3];
            }

            switch (width &amp; 3)
            {
               case 3:
                  data[2] = palette[(*decoded &gt;&gt; 2) &amp; 3];
               case 2:
                  data[1] = palette[(*decoded &gt;&gt; 4) &amp; 3];
               case 1:
                  data[0] = palette[(*decoded &gt;&gt; 6) &amp; 3];
                  break;
            }
         }
         break;

      case 4:
         {
            int i;
            unsigned w = width / 2;
            for (i = 0; i &lt; (int)w; i++, decoded++)
            {
               *data++ = palette[*decoded &gt;&gt; 4];
               *data++ = palette[*decoded &amp; 0x0f];
            }

            if (width &amp; 1)
               *data = palette[*decoded &gt;&gt; 4];
         }
         break;

      case 8:
         {
            int i;
            for (i = 0; i &lt; (int)width; i++, decoded++, data++)
               *data = palette[*decoded];
         }
         break;
   }
}

static void rpng_pass_geom(const struct png_ihdr *ihdr,
      unsigned width, unsigned height,
      unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size)
{
   unsigned bpp   = 0;
   unsigned pitch = 0;

   switch (ihdr-&gt;color_type)
   {
      case PNG_IHDR_COLOR_GRAY:
         bpp   = (ihdr-&gt;depth + 7) / 8;
         pitch = (ihdr-&gt;width * ihdr-&gt;depth + 7) / 8;
         break;
      case PNG_IHDR_COLOR_RGB:
         bpp   = (ihdr-&gt;depth * 3 + 7) / 8;
         pitch = (ihdr-&gt;width * ihdr-&gt;depth * 3 + 7) / 8;
         break;
      case PNG_IHDR_COLOR_PLT:
         bpp   = (ihdr-&gt;depth + 7) / 8;
         pitch = (ihdr-&gt;width * ihdr-&gt;depth + 7) / 8;
         break;
      case PNG_IHDR_COLOR_GRAY_ALPHA:
         bpp   = (ihdr-&gt;depth * 2 + 7) / 8;
         pitch = (ihdr-&gt;width * ihdr-&gt;depth * 2 + 7) / 8;
         break;
      case PNG_IHDR_COLOR_RGBA:
         bpp   = (ihdr-&gt;depth * 4 + 7) / 8;
         pitch = (ihdr-&gt;width * ihdr-&gt;depth * 4 + 7) / 8;
         break;
      default:
         break;
   }

   if (pass_size)
      *pass_size = (pitch + 1) * ihdr-&gt;height;
   if (bpp_out)
      *bpp_out   = bpp;
   if (pitch_out)
      *pitch_out = pitch;
}

static void rpng_reverse_filter_adam7_deinterlace_pass(uint32_t *data,
      const struct png_ihdr *ihdr,
      const uint32_t *input, unsigned pass_width, unsigned pass_height,
      const struct adam7_pass *pass)
{
   unsigned x, y;

   data += pass-&gt;y * ihdr-&gt;width + pass-&gt;x;

   for (y = 0; y &lt; pass_height;
         y++, data += ihdr-&gt;width * pass-&gt;stride_y, input += pass_width)
   {
      uint32_t *out = data;

      for (x = 0; x &lt; pass_width; x++, out += pass-&gt;stride_x)
         *out = input[x];
   }
}

static void rpng_reverse_filter_deinit(struct rpng_process *pngp)
{
   if (!pngp)
      return;
   if (pngp-&gt;decoded_scanline)
      free(pngp-&gt;decoded_scanline);
   pngp-&gt;decoded_scanline = NULL;
   if (pngp-&gt;prev_scanline)
      free(pngp-&gt;prev_scanline);
   pngp-&gt;prev_scanline    = NULL;

   pngp-&gt;flags           &amp;= ~RPNG_PROCESS_FLAG_PASS_INITIALIZED;
   pngp-&gt;h                = 0;
}

static int rpng_reverse_filter_init(const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   size_t pass_size;

   if (   !(pngp-&gt;flags &amp; RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED)
         &amp;&amp; ihdr-&gt;interlace)
   {
      if (     ihdr-&gt;width  &lt;= rpng_passes[pngp-&gt;pass_pos].x
            || ihdr-&gt;height &lt;= rpng_passes[pngp-&gt;pass_pos].y) /* Empty pass */
         return 1;

      pngp-&gt;pass_width  = (ihdr-&gt;width -
            rpng_passes[pngp-&gt;pass_pos].x + rpng_passes[pngp-&gt;pass_pos].stride_x
- 1) / rpng_passes[pngp-&gt;pass_pos].stride_x;
      pngp-&gt;pass_height = (ihdr-&gt;height - rpng_passes[pngp-&gt;pass_pos].y +
            rpng_passes[pngp-&gt;pass_pos].stride_y - 1) / rpng_passes[pngp-&gt;pass_pos].stride_y;

      if (!(pngp-&gt;data = (uint32_t*)malloc(
            pngp-&gt;pass_width * pngp-&gt;pass_height * sizeof(uint32_t))))
         return -1;

      pngp-&gt;ihdr        = *ihdr;
      pngp-&gt;ihdr.width  = pngp-&gt;pass_width;
      pngp-&gt;ihdr.height = pngp-&gt;pass_height;

      rpng_pass_geom(&amp;pngp-&gt;ihdr, pngp-&gt;pass_width,
            pngp-&gt;pass_height, NULL, NULL, &amp;pngp-&gt;pass_size);

      if (pngp-&gt;pass_size &gt; pngp-&gt;total_out)
      {
         free(pngp-&gt;data);
         pngp-&gt;data = NULL;
         return -1;
      }

      pngp-&gt;flags |= RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;

      return 0;
   }

   if (pngp-&gt;flags &amp; RPNG_PROCESS_FLAG_PASS_INITIALIZED)
      return 0;

   rpng_pass_geom(ihdr, ihdr-&gt;width, ihdr-&gt;height, &amp;pngp-&gt;bpp, &amp;pngp-&gt;pitch, &amp;pass_size);

   if (pngp-&gt;total_out &lt; pass_size)
      return -1;

   pngp-&gt;restore_buf_size      = 0;
   pngp-&gt;data_restore_buf_size = 0;
   pngp-&gt;prev_scanline         = (uint8_t*)calloc(1, pngp-&gt;pitch);
   pngp-&gt;decoded_scanline      = (uint8_t*)calloc(1, pngp-&gt;pitch);

   if (!pngp-&gt;prev_scanline || !pngp-&gt;decoded_scanline)
      goto error;

   pngp-&gt;h                    = 0;
   pngp-&gt;flags               |= RPNG_PROCESS_FLAG_PASS_INITIALIZED;

   return 0;

error:
   rpng_reverse_filter_deinit(pngp);
   return -1;
}

static int rpng_reverse_filter_copy_line(uint32_t *data,
      const struct png_ihdr *ihdr,
      struct rpng_process *pngp, unsigned filter)
{
   unsigned i;

   switch (filter)
   {
      case PNG_FILTER_NONE:
         memcpy(pngp-&gt;decoded_scanline, pngp-&gt;inflate_buf, pngp-&gt;pitch);
         break;
      case PNG_FILTER_SUB:
         memcpy(pngp-&gt;decoded_scanline, pngp-&gt;inflate_buf, pngp-&gt;pitch);
         for (i = pngp-&gt;bpp; i &lt; pngp-&gt;pitch; i++)
            pngp-&gt;decoded_scanline[i] += pngp-&gt;decoded_scanline[i - pngp-&gt;bpp];
         break;
      case PNG_FILTER_UP:
         memcpy(pngp-&gt;decoded_scanline, pngp-&gt;inflate_buf, pngp-&gt;pitch);
         for (i = 0; i &lt; pngp-&gt;pitch; i++)
            pngp-&gt;decoded_scanline[i] += pngp-&gt;prev_scanline[i];
         break;
      case PNG_FILTER_AVERAGE:
         memcpy(pngp-&gt;decoded_scanline, pngp-&gt;inflate_buf, pngp-&gt;pitch);
         for (i = 0; i &lt; pngp-&gt;bpp; i++)
         {
            uint8_t avg = pngp-&gt;prev_scanline[i] &gt;&gt; 1;
            pngp-&gt;decoded_scanline[i] += avg;
         }
         for (i = pngp-&gt;bpp; i &lt; pngp-&gt;pitch; i++)
         {
            uint8_t avg = (pngp-&gt;decoded_scanline[i - pngp-&gt;bpp] + pngp-&gt;prev_scanline[i]) &gt;&gt; 1;
            pngp-&gt;decoded_scanline[i] += avg;
         }
         break;
      case PNG_FILTER_PAETH:
         memcpy(pngp-&gt;decoded_scanline, pngp-&gt;inflate_buf, pngp-&gt;pitch);
         for (i = 0; i &lt; pngp-&gt;bpp; i++)
            pngp-&gt;decoded_scanline[i] += pngp-&gt;prev_scanline[i];
         for (i = pngp-&gt;bpp; i &lt; pngp-&gt;pitch; i++)
            pngp-&gt;decoded_scanline[i] += paeth(pngp-&gt;decoded_scanline[i - pngp-&gt;bpp],
                  pngp-&gt;prev_scanline[i], pngp-&gt;prev_scanline[i - pngp-&gt;bpp]);
         break;
      default:
         return IMAGE_PROCESS_ERROR_END;
   }

   switch (ihdr-&gt;color_type)
   {
      case PNG_IHDR_COLOR_GRAY:
         rpng_reverse_filter_copy_line_bw(data, pngp-&gt;decoded_scanline, ihdr-&gt;width, ihdr-&gt;depth);
         break;
      case PNG_IHDR_COLOR_RGB:
         rpng_reverse_filter_copy_line_rgb(data, pngp-&gt;decoded_scanline, ihdr-&gt;width, ihdr-&gt;depth);
         break;
      case PNG_IHDR_COLOR_PLT:
         rpng_reverse_filter_copy_line_plt(
               data, pngp-&gt;decoded_scanline, ihdr-&gt;width,
               ihdr-&gt;depth, pngp-&gt;palette);
         break;
      case PNG_IHDR_COLOR_GRAY_ALPHA:
         rpng_reverse_filter_copy_line_gray_alpha(data, pngp-&gt;decoded_scanline, ihdr-&gt;width,
               ihdr-&gt;depth);
         break;
      case PNG_IHDR_COLOR_RGBA:
         rpng_reverse_filter_copy_line_rgba(data, pngp-&gt;decoded_scanline, ihdr-&gt;width, ihdr-&gt;depth);
         break;
   }

   memcpy(pngp-&gt;prev_scanline, pngp-&gt;decoded_scanline, pngp-&gt;pitch);

   return IMAGE_PROCESS_NEXT;
}

static int rpng_reverse_filter_regular_iterate(
      uint32_t **data, const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   int ret = IMAGE_PROCESS_END;
   if (pngp-&gt;h &lt; ihdr-&gt;height)
   {
      unsigned filter         = *pngp-&gt;inflate_buf++;
      pngp-&gt;restore_buf_size += 1;
      ret                     = rpng_reverse_filter_copy_line(*data,
            ihdr, pngp, filter);
      if (ret == IMAGE_PROCESS_END || ret == IMAGE_PROCESS_ERROR_END)
         goto end;
   }
   else
      goto end;

   pngp-&gt;h++;
   pngp-&gt;inflate_buf           += pngp-&gt;pitch;
   pngp-&gt;restore_buf_size      += pngp-&gt;pitch;

   *data                       += ihdr-&gt;width;
   pngp-&gt;data_restore_buf_size += ihdr-&gt;width;

   return IMAGE_PROCESS_NEXT;

end:
   rpng_reverse_filter_deinit(pngp);

   pngp-&gt;inflate_buf -= pngp-&gt;restore_buf_size;
   *data             -= pngp-&gt;data_restore_buf_size;
   pngp-&gt;data_restore_buf_size = 0;
   return ret;
}

static int rpng_reverse_filter_adam7_iterate(uint32_t **data_,
      const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   int        ret = 0;
   bool   to_next = pngp-&gt;pass_pos &lt; ARRAY_SIZE(rpng_passes);
   uint32_t *data = *data_;

   if (!to_next)
      return IMAGE_PROCESS_END;

   if ((ret = rpng_reverse_filter_init(ihdr, pngp)) == 1)
      return IMAGE_PROCESS_NEXT;
   else if (ret == -1)
      return IMAGE_PROCESS_ERROR_END;

   if (rpng_reverse_filter_init(&amp;pngp-&gt;ihdr, pngp) == -1)
      return IMAGE_PROCESS_ERROR;

   do
   {
      ret = rpng_reverse_filter_regular_iterate(&amp;pngp-&gt;data,
            &amp;pngp-&gt;ihdr, pngp);
   } while (ret == IMAGE_PROCESS_NEXT);

   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
      return IMAGE_PROCESS_ERROR;

   pngp-&gt;inflate_buf            += pngp-&gt;pass_size;
   pngp-&gt;adam7_restore_buf_size += pngp-&gt;pass_size;

   pngp-&gt;total_out              -= pngp-&gt;pass_size;

   rpng_reverse_filter_adam7_deinterlace_pass(data,
         ihdr, pngp-&gt;data, pngp-&gt;pass_width, pngp-&gt;pass_height,
         &amp;rpng_passes[pngp-&gt;pass_pos]);

   free(pngp-&gt;data);

   pngp-&gt;data                   = NULL;
   pngp-&gt;pass_width             = 0;
   pngp-&gt;pass_height            = 0;
   pngp-&gt;pass_size              = 0;
   pngp-&gt;flags                 &amp;= ~RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;

   return IMAGE_PROCESS_NEXT;
}

static int rpng_reverse_filter_adam7(uint32_t **data_,
      const struct png_ihdr *ihdr,
      struct rpng_process *pngp)
{
   int ret = rpng_reverse_filter_adam7_iterate(data_,
         ihdr, pngp);

   switch (ret)
   {
      case IMAGE_PROCESS_ERROR_END:
      case IMAGE_PROCESS_END:
         break;
      case IMAGE_PROCESS_NEXT:
         pngp-&gt;pass_pos++;
         return 0;
      case IMAGE_PROCESS_ERROR:
         if (pngp-&gt;data)
         {
            free(pngp-&gt;data);
            pngp-&gt;data = NULL;
         }
         pngp-&gt;inflate_buf -= pngp-&gt;adam7_restore_buf_size;
         pngp-&gt;adam7_restore_buf_size = 0;
         return -1;
   }

   pngp-&gt;inflate_buf            -= pngp-&gt;adam7_restore_buf_size;
   pngp-&gt;adam7_restore_buf_size  = 0;
   return ret;
}

static int rpng_load_image_argb_process_inflate_init(
      rpng_t *rpng, uint32_t **data)
{
   bool zstatus;
   enum trans_stream_error err;
   uint32_t rd, wn;
   struct rpng_process *process = (struct rpng_process*)rpng-&gt;process;
   bool to_continue        = (process-&gt;avail_in &gt; 0
         &amp;&amp; process-&gt;avail_out &gt; 0);

   if (!to_continue)
      goto end;

   zstatus = process-&gt;stream_backend-&gt;trans(process-&gt;stream, false, &amp;rd, &amp;wn, &amp;err);

   if (!zstatus &amp;&amp; err != TRANS_STREAM_ERROR_BUFFER_FULL)
      goto error;

   process-&gt;avail_in -= rd;
   process-&gt;avail_out -= wn;
   process-&gt;total_out += wn;

   if (err)
      return 0;

end:
   process-&gt;stream_backend-&gt;stream_free(process-&gt;stream);
   process-&gt;stream = NULL;

#ifdef GEKKO
   /* we often use these in textures, make sure they're 32-byte aligned */
   *data = (uint32_t*)memalign(32, rpng-&gt;ihdr.width *
         rpng-&gt;ihdr.height * sizeof(uint32_t));
#else
   *data = (uint32_t*)malloc(rpng-&gt;ihdr.width *
         rpng-&gt;ihdr.height * sizeof(uint32_t));
#endif
   if (!*data)
      goto false_end;

   process-&gt;adam7_restore_buf_size = 0;
   process-&gt;restore_buf_size       = 0;
   process-&gt;palette                = rpng-&gt;palette;

   if (rpng-&gt;ihdr.interlace != 1)
      if (rpng_reverse_filter_init(&amp;rpng-&gt;ihdr, process) == -1)
         goto false_end;

   process-&gt;flags              |=  RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;
   return 1;

error:
false_end:
   process-&gt;flags              &amp;= ~RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;
   return -1;
}

static bool rpng_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)
{
   uint8_t *new_buffer = (uint8_t*)realloc(buf-&gt;data, buf-&gt;size + chunk_size);

   if (!new_buffer)
      return false;

   buf-&gt;data  = new_buffer;
   return true;
}

static struct rpng_process *rpng_process_init(rpng_t *rpng)
{
   uint8_t *inflate_buf            = NULL;
   struct rpng_process *process    = (struct rpng_process*)malloc(sizeof(*process));

   if (!process)
      return NULL;

   process-&gt;flags                  = 0;
   process-&gt;prev_scanline          = NULL;
   process-&gt;decoded_scanline       = NULL;
   process-&gt;inflate_buf            = NULL;

   process-&gt;ihdr.width             = 0;
   process-&gt;ihdr.height            = 0;
   process-&gt;ihdr.depth             = 0;
   process-&gt;ihdr.color_type        = 0;
   process-&gt;ihdr.compression       = 0;
   process-&gt;ihdr.filter            = 0;
   process-&gt;ihdr.interlace         = 0;

   process-&gt;restore_buf_size       = 0;
   process-&gt;adam7_restore_buf_size = 0;
   process-&gt;data_restore_buf_size  = 0;
   process-&gt;inflate_buf_size       = 0;
   process-&gt;avail_in               = 0;
   process-&gt;avail_out              = 0;
   process-&gt;total_out              = 0;
   process-&gt;pass_size              = 0;
   process-&gt;bpp                    = 0;
   process-&gt;pitch                  = 0;
   process-&gt;h                      = 0;
   process-&gt;pass_width             = 0;
   process-&gt;pass_height            = 0;
   process-&gt;pass_pos               = 0;
   process-&gt;data                   = 0;
   process-&gt;palette                = 0;
   process-&gt;stream                 = NULL;
   process-&gt;stream_backend         = trans_stream_get_zlib_inflate_backend();

   rpng_pass_geom(&amp;rpng-&gt;ihdr, rpng-&gt;ihdr.width,
         rpng-&gt;ihdr.height, NULL, NULL, &amp;process-&gt;inflate_buf_size);
   if (rpng-&gt;ihdr.interlace == 1) /* To be sure. */
      process-&gt;inflate_buf_size *= 2;

   process-&gt;stream = process-&gt;stream_backend-&gt;stream_new();

   if (!process-&gt;stream)
   {
      free(process);
      return NULL;
   }

   inflate_buf = (uint8_t*)malloc(process-&gt;inflate_buf_size);
   if (!inflate_buf)
      goto error;

   process-&gt;inflate_buf = inflate_buf;
   process-&gt;avail_in    = rpng-&gt;idat_buf.size;
   process-&gt;avail_out   = process-&gt;inflate_buf_size;

   process-&gt;stream_backend-&gt;set_in(
         process-&gt;stream,
         rpng-&gt;idat_buf.data,
         (uint32_t)rpng-&gt;idat_buf.size);
   process-&gt;stream_backend-&gt;set_out(
         process-&gt;stream,
         process-&gt;inflate_buf,
         (uint32_t)process-&gt;inflate_buf_size);

   return process;

error:
   if (process)
   {
      if (process-&gt;stream)
         process-&gt;stream_backend-&gt;stream_free(process-&gt;stream);
      free(process);
   }
   return NULL;
}

/**
 * rpng_read_chunk_header:
 *
 * Leaf function.
 *
 * @return The PNG type of the memory chunk (i.e. IHDR, IDAT, IEND,
   PLTE, and/or tRNS)
 **/
static enum png_chunk_type rpng_read_chunk_header(
      uint8_t *buf, uint32_t chunk_size)
{
   int i;
   char type[4];

   for (i = 0; i &lt; 4; i++)
   {
      uint8_t byte = buf[i + 4];

      /* All four bytes of the chunk type must be
       * ASCII letters (codes 65-90 and 97-122) */
      if ((byte &lt; 65) || ((byte &gt; 90) &amp;&amp; (byte &lt; 97)) || (byte &gt; 122))
         return PNG_CHUNK_ERROR;
      type[i]      = byte;
   }

   if (
            type[0] == 'I'
         &amp;&amp; type[1] == 'H'
         &amp;&amp; type[2] == 'D'
         &amp;&amp; type[3] == 'R'
      )
      return PNG_CHUNK_IHDR;
   else if
      (
          type[0] == 'I'
       &amp;&amp; type[1] == 'D'
       &amp;&amp; type[2] == 'A'
       &amp;&amp; type[3] == 'T'
      )
         return PNG_CHUNK_IDAT;
   else if
      (
          type[0] == 'I'
       &amp;&amp; type[1] == 'E'
       &amp;&amp; type[2] == 'N'
       &amp;&amp; type[3] == 'D'
      )
         return PNG_CHUNK_IEND;
   else if
      (
          type[0] == 'P'
       &amp;&amp; type[1] == 'L'
       &amp;&amp; type[2] == 'T'
       &amp;&amp; type[3] == 'E'
      )
         return PNG_CHUNK_PLTE;
   else if
      (
          type[0] == 't'
       &amp;&amp; type[1] == 'R'
       &amp;&amp; type[2] == 'N'
       &amp;&amp; type[3] == 'S'
      )
         return PNG_CHUNK_tRNS;

   return PNG_CHUNK_NOOP;
}

bool rpng_iterate_image(rpng_t *rpng)
{
   unsigned i;
   uint8_t *buf             = (uint8_t*)rpng-&gt;buff_data;
   uint32_t chunk_size      = 0;

   /* Check whether data buffer pointer is valid */
   if (buf &gt; rpng-&gt;buff_end)
      return false;

   /* Check whether reading the header will overflow
    * the data buffer */
   if (rpng-&gt;buff_end - buf &lt; 8)
      return false;

   chunk_size = rpng_dword_be(buf);

   /* Check whether chunk will overflow the data buffer */
   if (buf + 8 + chunk_size &gt; rpng-&gt;buff_end)
      return false;

   switch (rpng_read_chunk_header(buf, chunk_size))
   {
      case PNG_CHUNK_NOOP:
      default:
         break;

      case PNG_CHUNK_ERROR:
         return false;

      case PNG_CHUNK_IHDR:
         if (     (rpng-&gt;flags &amp; RPNG_FLAG_HAS_IHDR)
               || (rpng-&gt;flags &amp; RPNG_FLAG_HAS_IDAT)
               || (rpng-&gt;flags &amp; RPNG_FLAG_HAS_IEND))
            return false;

         if (chunk_size != 13)
            return false;

         buf                    += 4 + 4;

         rpng-&gt;ihdr.width        = rpng_dword_be(buf + 0);
         rpng-&gt;ihdr.height       = rpng_dword_be(buf + 4);
         rpng-&gt;ihdr.depth        = buf[8];
         rpng-&gt;ihdr.color_type   = buf[9];
         rpng-&gt;ihdr.compression  = buf[10];
         rpng-&gt;ihdr.filter       = buf[11];
         rpng-&gt;ihdr.interlace    = buf[12];

         if (     rpng-&gt;ihdr.width  == 0
               || rpng-&gt;ihdr.height == 0
               /* ensure multiplications don't overflow and wrap around, that'd give buffer overflow crashes */
               || (uint64_t)rpng-&gt;ihdr.width*rpng-&gt;ihdr.height*sizeof(uint32_t) &gt;= 0x80000000)
            return false;

         if (!rpng_process_ihdr(&amp;rpng-&gt;ihdr))
            return false;

         if (rpng-&gt;ihdr.compression != 0)
         {
#if defined(DEBUG) || defined(RPNG_TEST)
            fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
#endif
            return false;
         }

         rpng-&gt;flags   |= RPNG_FLAG_HAS_IHDR;
         break;

      case PNG_CHUNK_PLTE:
         {
            int i;
            unsigned entries = chunk_size / 3;

            if (entries &gt; 256)
               return false;
            if (chunk_size % 3)
               return false;

            if (     !(rpng-&gt;flags &amp; RPNG_FLAG_HAS_IHDR)
                  ||  (rpng-&gt;flags &amp; RPNG_FLAG_HAS_PLTE)
                  ||  (rpng-&gt;flags &amp; RPNG_FLAG_HAS_IEND)
                  ||  (rpng-&gt;flags &amp; RPNG_FLAG_HAS_IDAT)
                  ||  (rpng-&gt;flags &amp; RPNG_FLAG_HAS_TRNS))
               return false;

            buf += 8;

            for (i = 0; i &lt; (int)entries; i++)
            {
               uint32_t r       = buf[3 * i + 0];
               uint32_t g       = buf[3 * i + 1];
               uint32_t b       = buf[3 * i + 2];
               rpng-&gt;palette[i] = (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0) | (0xffu &lt;&lt; 24);
            }

            rpng-&gt;flags        |= RPNG_FLAG_HAS_PLTE;
         }
         break;

      case PNG_CHUNK_tRNS:
         if (rpng-&gt;flags &amp; RPNG_FLAG_HAS_IDAT)
            return false;

         if (rpng-&gt;ihdr.color_type == PNG_IHDR_COLOR_PLT)
         {
            int i;
            uint32_t *palette;
            /* we should compare with the number of palette entries */
            if (chunk_size &gt; 256)
               return false;

            buf    += 8;
            palette = rpng-&gt;palette;

            for (i = 0; i &lt; (int)chunk_size; i++, buf++, palette++)
               *palette = (*palette &amp; 0x00ffffff) | (unsigned)*buf &lt;&lt; 24;
         }
         /* TODO: support colorkey in grayscale and truecolor images */

         rpng-&gt;flags         |= RPNG_FLAG_HAS_TRNS;
         break;

      case PNG_CHUNK_IDAT:
         if (     !(rpng-&gt;flags &amp; RPNG_FLAG_HAS_IHDR)
               ||  (rpng-&gt;flags &amp; RPNG_FLAG_HAS_IEND)
               ||  (rpng-&gt;ihdr.color_type == PNG_IHDR_COLOR_PLT
                  &amp;&amp;
                  !(rpng-&gt;flags &amp; RPNG_FLAG_HAS_PLTE)))
            return false;

         if (!rpng_realloc_idat(&amp;rpng-&gt;idat_buf, chunk_size))
            return false;

         buf += 8;

         for (i = 0; i &lt; chunk_size; i++)
            rpng-&gt;idat_buf.data[i + rpng-&gt;idat_buf.size] = buf[i];

         rpng-&gt;idat_buf.size += chunk_size;

         rpng-&gt;flags         |= RPNG_FLAG_HAS_IDAT;
         break;

      case PNG_CHUNK_IEND:
         if (     !(rpng-&gt;flags &amp; RPNG_FLAG_HAS_IHDR)
               || !(rpng-&gt;flags &amp; RPNG_FLAG_HAS_IDAT))
            return false;

         rpng-&gt;flags         |= RPNG_FLAG_HAS_IEND;
         return false;
   }

   rpng-&gt;buff_data += chunk_size + 12;

   /* Check whether data buffer pointer is valid */
   if (rpng-&gt;buff_data &gt; rpng-&gt;buff_end)
      return false;
   return true;
}

int rpng_process_image(rpng_t *rpng,
      void **_data, size_t len, unsigned *width, unsigned *height)
{
   uint32_t **data = (uint32_t**)_data;

   if (!rpng-&gt;process)
   {
      struct rpng_process *process = rpng_process_init(rpng);

      if (!process)
         goto error;

      rpng-&gt;process = process;
      return IMAGE_PROCESS_NEXT;
   }

   if (!(rpng-&gt;process-&gt;flags &amp; RPNG_PROCESS_FLAG_INFLATE_INITIALIZED))
   {
      if (rpng_load_image_argb_process_inflate_init(rpng, data) == -1)
         goto error;
      return IMAGE_PROCESS_NEXT;
   }

   *width  = rpng-&gt;ihdr.width;
   *height = rpng-&gt;ihdr.height;

   if (rpng-&gt;ihdr.interlace &amp;&amp; rpng-&gt;process)
      return rpng_reverse_filter_adam7(data, &amp;rpng-&gt;ihdr, rpng-&gt;process);
   return rpng_reverse_filter_regular_iterate(data, &amp;rpng-&gt;ihdr, rpng-&gt;process);

error:
   if (rpng-&gt;process)
   {
      if (rpng-&gt;process-&gt;inflate_buf)
         free(rpng-&gt;process-&gt;inflate_buf);
      if (rpng-&gt;process-&gt;stream)
         rpng-&gt;process-&gt;stream_backend-&gt;stream_free(rpng-&gt;process-&gt;stream);
      free(rpng-&gt;process);
      rpng-&gt;process = NULL;
   }
   return IMAGE_PROCESS_ERROR;
}

void rpng_free(rpng_t *rpng)
{
   if (!rpng)
      return;

   if (rpng-&gt;idat_buf.data)
      free(rpng-&gt;idat_buf.data);
   if (rpng-&gt;process)
   {
      if (rpng-&gt;process-&gt;inflate_buf)
         free(rpng-&gt;process-&gt;inflate_buf);
      if (rpng-&gt;process-&gt;stream)
      {
         if (rpng-&gt;process-&gt;stream_backend &amp;&amp; rpng-&gt;process-&gt;stream_backend-&gt;stream_free)
            rpng-&gt;process-&gt;stream_backend-&gt;stream_free(rpng-&gt;process-&gt;stream);
         else
            free(rpng-&gt;process-&gt;stream);
      }
      free(rpng-&gt;process);
   }

   free(rpng);
}

bool rpng_start(rpng_t *rpng)
{
   if (!rpng)
      return false;

   /* Check whether reading the header will overflow
    * the data buffer */
   if (rpng-&gt;buff_end - rpng-&gt;buff_data &lt; 8)
      return false;

   if (memcmp(rpng-&gt;buff_data, png_magic, sizeof(png_magic)) != 0)
      return false;

   rpng-&gt;buff_data += 8;

   return true;
}

/**
 * rpng_is_valid:
 *
 * Check if @rpng is a valid PNG image.
 * Must contain an IHDR chunk, one or more IDAT
 * chunks, and an IEND chunk.
 *
 * Leaf function.
 *
 * @return true if it's a valid PNG image, otherwise false.
 **/
bool rpng_is_valid(rpng_t *rpng)
{
   return (rpng &amp;&amp; ((rpng-&gt;flags &amp; (RPNG_FLAG_HAS_IHDR | RPNG_FLAG_HAS_IDAT |
RPNG_FLAG_HAS_IEND)) &gt; 0));
}

bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len)
{
   if (!rpng || (len &lt; 1))
      return false;

   rpng-&gt;buff_data = (uint8_t*)data;
   rpng-&gt;buff_end  = rpng-&gt;buff_data + (len - 1);

   return true;
}

rpng_t *rpng_alloc(void)
{
   rpng_t *rpng = (rpng_t*)calloc(1, sizeof(*rpng));
   if (!rpng)
      return NULL;
   return rpng;
}</pre>
<h2>./include/libretro-common/formats/png/rpng_encode.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng_encode.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;libretro.h&gt;
#include &lt;encodings/crc32.h&gt;
#include &lt;streams/interface_stream.h&gt;
#include &lt;streams/trans_stream.h&gt;

#include "rpng_internal.h"

#undef GOTO_END_ERROR
#define GOTO_END_ERROR() do { \
   fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__); \
   ret = false; \
   goto end; \
} while (0)

double DEFLATE_PADDING = 1.1;
int PNG_ROUGH_HEADER = 100;

static void dword_write_be(uint8_t *buf, uint32_t val)
{
   *buf++ = (uint8_t)(val &gt;&gt; 24);
   *buf++ = (uint8_t)(val &gt;&gt; 16);
   *buf++ = (uint8_t)(val &gt;&gt;  8);
   *buf++ = (uint8_t)(val &gt;&gt;  0);
}

static bool png_write_crc_string(intfstream_t *intf_s, const uint8_t *data, size_t len)
{
   uint8_t crc_raw[4] = {0};
   uint32_t crc       = encoding_crc32(0, data, len);

   dword_write_be(crc_raw, crc);
   return intfstream_write(intf_s, crc_raw, sizeof(crc_raw)) == sizeof(crc_raw);
}

static bool png_write_ihdr_string(intfstream_t *intf_s, const struct png_ihdr *ihdr)
{
   uint8_t ihdr_raw[21];

   ihdr_raw[0]  = '0';                 /* Size */
   ihdr_raw[1]  = '0';
   ihdr_raw[2]  = '0';
   ihdr_raw[3]  = '0';
   ihdr_raw[4]  = 'I';
   ihdr_raw[5]  = 'H';
   ihdr_raw[6]  = 'D';
   ihdr_raw[7]  = 'R';
   ihdr_raw[8]  =   0;                 /* Width */
   ihdr_raw[9]  =   0;
   ihdr_raw[10] =   0;
   ihdr_raw[11] =   0;
   ihdr_raw[12] =   0;                 /* Height */
   ihdr_raw[13] =   0;
   ihdr_raw[14] =   0;
   ihdr_raw[15] =   0;
   ihdr_raw[16] =   ihdr-&gt;depth;       /* Depth */
   ihdr_raw[17] =   ihdr-&gt;color_type;
   ihdr_raw[18] =   ihdr-&gt;compression;
   ihdr_raw[19] =   ihdr-&gt;filter;
   ihdr_raw[20] =   ihdr-&gt;interlace;

   dword_write_be(ihdr_raw +  0, sizeof(ihdr_raw) - 8);
   dword_write_be(ihdr_raw +  8, ihdr-&gt;width);
   dword_write_be(ihdr_raw + 12, ihdr-&gt;height);
   if (intfstream_write(intf_s, ihdr_raw, sizeof(ihdr_raw)) != sizeof(ihdr_raw))
      return false;

   return png_write_crc_string(intf_s, ihdr_raw + sizeof(uint32_t),
         sizeof(ihdr_raw) - sizeof(uint32_t));
}

static bool png_write_idat_string(intfstream_t* intf_s, const uint8_t *data, size_t len)
{
   if (intfstream_write(intf_s, data, len) != (ssize_t)len)
      return false;
   return png_write_crc_string(intf_s, data + sizeof(uint32_t), len - sizeof(uint32_t));
}

static bool png_write_iend_string(intfstream_t* intf_s)
{
   const uint8_t data[] = {
      0, 0, 0, 0,
      'I', 'E', 'N', 'D',
   };

   if (intfstream_write(intf_s, data, sizeof(data)) != sizeof(data))
      return false;

   return png_write_crc_string(intf_s, data + sizeof(uint32_t),
         sizeof(data) - sizeof(uint32_t));
}

static void copy_argb_line(uint8_t *dst, const uint32_t *src, unsigned width)
{
   unsigned i;
   for (i = 0; i &lt; width; i++)
   {
      uint32_t col = src[i];
      *dst++ = (uint8_t)(col &gt;&gt; 16);
      *dst++ = (uint8_t)(col &gt;&gt;  8);
      *dst++ = (uint8_t)(col &gt;&gt;  0);
      *dst++ = (uint8_t)(col &gt;&gt; 24);
   }
}

static void copy_bgr24_line(uint8_t *dst, const uint8_t *src, unsigned width)
{
   unsigned i;
   for (i = 0; i &lt; width; i++, dst += 3, src += 3)
   {
      dst[2] = src[0];
      dst[1] = src[1];
      dst[0] = src[2];
   }
}

static unsigned count_sad(const uint8_t *data, size_t len)
{
   size_t i;
   unsigned cnt = 0;
   for (i = 0; i &lt; len; i++)
   {
      if (data[i])
         cnt += abs((int8_t)data[i]);
   }
   return cnt;
}

static unsigned filter_up(uint8_t *target, const uint8_t *line,
      const uint8_t *prev, unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i &lt; width; i++)
      target[i] = line[i] - prev[i];

   return count_sad(target, width);
}

static unsigned filter_sub(uint8_t *target, const uint8_t *line,
      unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i &lt; bpp; i++)
      target[i] = line[i];
   for (i = bpp; i &lt; width; i++)
      target[i] = line[i] - line[i - bpp];

   return count_sad(target, width);
}

static unsigned filter_avg(uint8_t *target, const uint8_t *line,
      const uint8_t *prev, unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i &lt; bpp; i++)
      target[i] = line[i] - (prev[i] &gt;&gt; 1);
   for (i = bpp; i &lt; width; i++)
      target[i] = line[i] - ((line[i - bpp] + prev[i]) &gt;&gt; 1);

   return count_sad(target, width);
}

static unsigned filter_paeth(uint8_t *target,
      const uint8_t *line, const uint8_t *prev,
      unsigned width, unsigned bpp)
{
   unsigned i;
   width *= bpp;
   for (i = 0; i &lt; bpp; i++)
      target[i] = line[i] - paeth(0, prev[i], 0);
   for (i = bpp; i &lt; width; i++)
      target[i] = line[i] - paeth(line[i - bpp], prev[i], prev[i - bpp]);

   return count_sad(target, width);
}

bool rpng_save_image_stream(const uint8_t *data, intfstream_t* intf_s,
      unsigned width, unsigned height, signed pitch, unsigned bpp)
{
   unsigned h;
   struct png_ihdr ihdr = {0};
   bool ret = true;
   const struct trans_stream_backend *stream_backend = NULL;
   size_t encode_buf_size  = 0;
   uint8_t *encode_buf     = NULL;
   uint8_t *deflate_buf    = NULL;
   uint8_t *rgba_line      = NULL;
   uint8_t *up_filtered    = NULL;
   uint8_t *sub_filtered   = NULL;
   uint8_t *avg_filtered   = NULL;
   uint8_t *paeth_filtered = NULL;
   uint8_t *prev_encoded   = NULL;
   uint8_t *encode_target  = NULL;
   void *stream            = NULL;
   uint32_t total_in       = 0;
   uint32_t total_out      = 0;

   if (!intf_s)
      GOTO_END_ERROR();

   stream_backend = trans_stream_get_zlib_deflate_backend();

   if (intfstream_write(intf_s, png_magic, sizeof(png_magic)) != sizeof(png_magic))
      GOTO_END_ERROR();

   ihdr.width = width;
   ihdr.height = height;
   ihdr.depth = 8;
   ihdr.color_type = bpp == sizeof(uint32_t) ? 6 : 2; /* RGBA or RGB */
   if (!png_write_ihdr_string(intf_s, &amp;ihdr))
      GOTO_END_ERROR();

   encode_buf_size = (width * bpp + 1) * height;
   encode_buf      = (uint8_t*)malloc(encode_buf_size);
   if (!encode_buf)
      GOTO_END_ERROR();

   prev_encoded = (uint8_t*)calloc(1, width * bpp);
   if (!prev_encoded)
      GOTO_END_ERROR();

   rgba_line      = (uint8_t*)malloc(width * bpp);
   up_filtered    = (uint8_t*)malloc(width * bpp);
   sub_filtered   = (uint8_t*)malloc(width * bpp);
   avg_filtered   = (uint8_t*)malloc(width * bpp);
   paeth_filtered = (uint8_t*)malloc(width * bpp);
   if (!rgba_line || !up_filtered || !sub_filtered || !avg_filtered || !paeth_filtered)
      GOTO_END_ERROR();

   encode_target = encode_buf;
   for (h = 0; h &lt; height;
         h++, encode_target += width * bpp, data += pitch)
   {
      if (bpp == sizeof(uint32_t))
         copy_argb_line(rgba_line, (const uint32_t*)data, width);
      else
         copy_bgr24_line(rgba_line, data, width);

      /* Try every filtering method, and choose the method
       * which has most entries as zero.
       *
       * This is probably not very optimal, but it's very
       * simple to implement.
       */
      {
         unsigned none_score  = count_sad(rgba_line, width * bpp);
         unsigned up_score    = filter_up(up_filtered, rgba_line, prev_encoded, width, bpp);
         unsigned sub_score   = filter_sub(sub_filtered, rgba_line, width, bpp);
         unsigned avg_score   = filter_avg(avg_filtered, rgba_line, prev_encoded, width, bpp);
         unsigned paeth_score = filter_paeth(paeth_filtered, rgba_line, prev_encoded, width, bpp);

         uint8_t filter       = 0;
         unsigned min_sad     = none_score;
         const uint8_t *chosen_filtered = rgba_line;

         if (sub_score &lt; min_sad)
         {
            filter = 1;
            chosen_filtered = sub_filtered;
            min_sad = sub_score;
         }

         if (up_score &lt; min_sad)
         {
            filter = 2;
            chosen_filtered = up_filtered;
            min_sad = up_score;
         }

         if (avg_score &lt; min_sad)
         {
            filter = 3;
            chosen_filtered = avg_filtered;
            min_sad = avg_score;
         }

         if (paeth_score &lt; min_sad)
         {
            filter = 4;
            chosen_filtered = paeth_filtered;
         }

         *encode_target++ = filter;
         memcpy(encode_target, chosen_filtered, width * bpp);

         memcpy(prev_encoded, rgba_line, width * bpp);
      }
   }

   deflate_buf = (uint8_t*)malloc(encode_buf_size * 2); /* Just to be sure. */
   if (!deflate_buf)
      GOTO_END_ERROR();

   stream = stream_backend-&gt;stream_new();

   if (!stream)
      GOTO_END_ERROR();

   stream_backend-&gt;set_in(
         stream,
         encode_buf,
         (unsigned)encode_buf_size);
   stream_backend-&gt;set_out(
         stream,
         deflate_buf + 8,
         (unsigned)(encode_buf_size * 2));

   if (!stream_backend-&gt;trans(stream, true, &amp;total_in, &amp;total_out, NULL))
      GOTO_END_ERROR();

   memcpy(deflate_buf + 4, "IDAT", 4);
   dword_write_be(deflate_buf + 0,        ((uint32_t)total_out));
   if (!png_write_idat_string(intf_s, deflate_buf, ((size_t)total_out + 8)))
      GOTO_END_ERROR();

   if (!png_write_iend_string(intf_s))
      GOTO_END_ERROR();
end:
   free(encode_buf);
   free(deflate_buf);
   free(rgba_line);
   free(prev_encoded);
   free(up_filtered);
   free(sub_filtered);
   free(avg_filtered);
   free(paeth_filtered);

   if (stream_backend)
   {
      if (stream)
      {
         if (stream_backend-&gt;stream_free)
            stream_backend-&gt;stream_free(stream);
      }
   }
   return ret;
}

bool rpng_save_image_argb(const char *path, const uint32_t *data,
      unsigned width, unsigned height, unsigned pitch)
{
   bool ret                      = false;
   intfstream_t* intf_s          = NULL;

   intf_s = intfstream_open_file(path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   ret = rpng_save_image_stream((const uint8_t*) data, intf_s,
                                width, height,
                                (signed) pitch, sizeof(uint32_t));
   intfstream_close(intf_s);
   free(intf_s);
   return ret;
}

bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
      unsigned width, unsigned height, unsigned pitch)
{
   bool ret                      = false;
   intfstream_t* intf_s          = NULL;

   intf_s = intfstream_open_file(path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   ret = rpng_save_image_stream(data, intf_s, width, height,
                                (signed) pitch, 3);
   intfstream_close(intf_s);
   free(intf_s);
   return ret;
}


uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
      unsigned width, unsigned height, signed pitch, uint64_t* bytes)
{
   bool ret             = false;
   uint8_t *output      = NULL;
   intfstream_t *intf_s = NULL;
   size_t _len          = (width * height * 3 * DEFLATE_PADDING) + PNG_ROUGH_HEADER;
   uint8_t *buf         = (uint8_t*)malloc(_len * sizeof(uint8_t));
   if (!buf)
      GOTO_END_ERROR();

   intf_s = intfstream_open_memory(buf,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE,
         _len);

   ret    = rpng_save_image_stream((const uint8_t*)data,
            intf_s, width, height, pitch, 3);
   *bytes = intfstream_get_ptr(intf_s);
   intfstream_rewind(intf_s);
   output = (uint8_t*)malloc((size_t)((*bytes)*sizeof(uint8_t)));
   if (!output)
      GOTO_END_ERROR();
   intfstream_read(intf_s, output, *bytes);

end:
   if (buf)
      free(buf);
   if (intf_s)
   {
      intfstream_close(intf_s);
      free(intf_s);
   }
   if (ret == false)
   {
      if (output)
         free(output);
      return NULL;
   }
   return output;
}</pre>
<h2>./include/libretro-common/formats/png/rpng_internal.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng_internal.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _RPNG_COMMON_H
#define _RPNG_COMMON_H

#include &lt;stdint.h&gt;
#include &lt;filters.h&gt;
#include &lt;formats/rpng.h&gt;

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

static const uint8_t png_magic[8] = {
   0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a,
};

struct png_ihdr
{
   uint32_t width;
   uint32_t height;
   uint8_t depth;
   uint8_t color_type;
   uint8_t compression;
   uint8_t filter;
   uint8_t interlace;
};

#endif</pre>
<h2>./include/libretro-common/formats/tga/rtga.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtga.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Modified version of stb_image's TGA sources. */

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stddef.h&gt; /* ptrdiff_t on osx */
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_inline.h&gt;

#include &lt;formats/image.h&gt;
#include &lt;formats/rtga.h&gt;

#define RTGA_COMPUTE_Y(r, g, b) ((uint8_t)((((r) * 77) + ((g) * 150) +  (29 * (b))) &gt;&gt; 8))

struct rtga
{
   uint8_t *buff_data;
   uint32_t *output_image;
};

typedef struct
{
   uint8_t *img_buffer;
   uint8_t *img_buffer_end;
   uint8_t *img_buffer_original;
   int buflen;
   int img_n, img_out_n;
   uint32_t img_x, img_y;
   uint8_t buffer_start[128];
} rtga_context;

static INLINE uint8_t rtga_get8(rtga_context *s)
{
   if (s-&gt;img_buffer &lt; s-&gt;img_buffer_end)
      return *s-&gt;img_buffer++;
   return 0;
}

static void rtga_skip(rtga_context *s, int n)
{
   if (n &lt; 0)
   {
      s-&gt;img_buffer = s-&gt;img_buffer_end;
      return;
   }
   s-&gt;img_buffer += n;
}

static int rtga_get16le(rtga_context *s)
{
   return rtga_get8(s) + (rtga_get8(s) &lt;&lt; 8);
}

static unsigned char *rtga_convert_format(
      unsigned char *data,
      int img_n,
      int req_comp,
      unsigned int x,
      unsigned int y)
{
   int i,j;
   unsigned char *good = (unsigned char *) malloc(req_comp * x * y);

   if (!good)
   {
      free(data);
      return NULL;
   }

   for (j=0; j &lt; (int) y; ++j)
   {
      unsigned char *src  = data + j * x * img_n   ;
      unsigned char *dest = good + j * x * req_comp;

      switch (((img_n)*8+(req_comp)))
      {
         case ((1)*8+(2)):
            for (i=x-1; i &gt;= 0; --i, src += 1, dest += 2)
            {
               dest[0]=src[0];
               dest[1]=255;
            }
            break;
         case ((1)*8+(3)):
            for (i=x-1; i &gt;= 0; --i, src += 1, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case ((1)*8+(4)):
            for (i=x-1; i &gt;= 0; --i, src += 1, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=255;
            }
            break;
         case ((2)*8+(1)):
            for (i=x-1; i &gt;= 0; --i, src += 2, dest += 1)
               dest[0]=src[0];
            break;
         case ((2)*8+(3)):
            for (i=x-1; i &gt;= 0; --i, src += 2, dest += 3)
               dest[0]=dest[1]=dest[2]=src[0];
            break;
         case ((2)*8+(4)):
            for (i=x-1; i &gt;= 0; --i, src += 2, dest += 4)
            {
               dest[0]=dest[1]=dest[2]=src[0];
               dest[3]=src[1];
            }
            break;
         case ((3)*8+(4)):
            for (i=x-1; i &gt;= 0; --i, src += 3, dest += 4)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
               dest[3]=255;
            }
            break;
         case ((3)*8+(1)):
            for (i=x-1; i &gt;= 0; --i, src += 3, dest += 1)
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case ((3)*8+(2)):
            for (i=x-1; i &gt;= 0; --i, src += 3, dest += 2)
            {
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = 255;
            }
            break;
         case ((4)*8+(1)):
            for (i=x-1; i &gt;= 0; --i, src += 4, dest += 1)
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
            break;
         case ((4)*8+(2)):
            for (i=x-1; i &gt;= 0; --i, src += 4, dest += 2)
            {
               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
               dest[1] = src[3];
            }
            break;
         case ((4)*8+(3)):
            for (i=x-1; i &gt;= 0; --i, src += 4, dest += 3)
            {
               dest[0]=src[0];
               dest[1]=src[1];
               dest[2]=src[2];
            }
            break;
         default:
            break;
      }
   }

   free(data);
   return good;
}

static uint8_t *rtga_tga_load(rtga_context *s,
      unsigned *x, unsigned *y, int *comp, int req_comp)
{
   /* Read in the TGA header stuff */
   int tga_offset          = rtga_get8(s);
   int tga_indexed         = rtga_get8(s);
   int tga_image_type      = rtga_get8(s);
   int tga_is_RLE          = 0;
   int tga_palette_start   = rtga_get16le(s);
   int tga_palette_len     = rtga_get16le(s);
   int tga_palette_bits    = rtga_get8(s);
   int tga_x_origin        = rtga_get16le(s);
   int tga_y_origin        = rtga_get16le(s);
   int tga_width           = rtga_get16le(s);
   int tga_height          = rtga_get16le(s);
   int tga_bits_per_pixel  = rtga_get8(s);
   int tga_comp            = tga_bits_per_pixel / 8;
   int tga_inverted        = rtga_get8(s);

   /*   image data */
   unsigned char *tga_data = NULL;

   (void)tga_palette_start;
   (void)tga_x_origin;
   (void)tga_y_origin;

   /*   do a tiny bit of precessing */
   if (tga_image_type &gt;= 8)
   {
      tga_image_type -= 8;
      tga_is_RLE = 1;
   }

   /* int tga_alpha_bits = tga_inverted &amp; 15; */
   tga_inverted = 1 - ((tga_inverted &gt;&gt; 5) &amp; 1);

   /*   error check */
   if (
         (tga_width &lt; 1) || (tga_height &lt; 1) ||
         (tga_image_type &lt; 1) || (tga_image_type &gt; 3) ||
         (
          (tga_bits_per_pixel != 8)  &amp;&amp; (tga_bits_per_pixel != 16) &amp;&amp;
          (tga_bits_per_pixel != 24) &amp;&amp; (tga_bits_per_pixel != 32)
         )
      )
      return NULL; /* we don't report this as a bad TGA because we don't even know if it's TGA */

   /*   If paletted, then we will use the number of bits from the palette */
   if (tga_indexed)
      tga_comp = tga_palette_bits / 8;

   /*   TGA info */
   *x = tga_width;
   *y = tga_height;
   if (comp)
      *comp = tga_comp;

   tga_data = (unsigned char*)malloc((size_t)tga_width * tga_height * tga_comp);
   if (!tga_data)
      return NULL;

   /* skip to the data's starting position (offset usually = 0) */
   rtga_skip(s, tga_offset );

   if (!tga_indexed &amp;&amp; !tga_is_RLE)
   {
      int i;
      for (i=0; i &lt; tga_height; ++i)
      {
         int _y           = tga_inverted ? (tga_height -i - 1) : i;
         uint8_t *tga_row = tga_data + _y * tga_width * tga_comp;
         int n            = tga_width * tga_comp;

         if (s-&gt;img_buffer + n &lt;= s-&gt;img_buffer_end)
         {
            memcpy(tga_row, s-&gt;img_buffer, n);
            s-&gt;img_buffer += n;
         }
      }
   }
   else
   {
      int i, j;
      int RLE_repeating          = 0;
      int RLE_count              = 0;
      int read_next_pixel        = 1;
      unsigned char raw_data[4] = {0};
      unsigned char *tga_palette = NULL;

      /*   Do I need to load a palette? */
      if (tga_indexed)
      {
         int n;
         /* Any data to skip? (offset usually = 0) */
         rtga_skip(s, tga_palette_start );
         /* Load the palette */
         tga_palette = (unsigned char*)malloc(tga_palette_len * tga_palette_bits / 8);

         if (!tga_palette)
         {
            free(tga_data);
            return NULL;
         }

         n = tga_palette_len * tga_palette_bits / 8;

         if (s-&gt;img_buffer+n &lt;= s-&gt;img_buffer_end)
         {
            memcpy(tga_palette, s-&gt;img_buffer, n);
            s-&gt;img_buffer += n;
         }
         else
         {
            free(tga_data);
            free(tga_palette);
            return NULL;
         }
      }

      /*   load the data */
      for (i=0; i &lt; tga_width * tga_height; ++i)
      {
         /*   if I'm in RLE mode, do I need to get a RLE rtga_png chunk? */
         if (tga_is_RLE)
         {
            if (RLE_count == 0)
            {
               /*   yep, get the next byte as a RLE command */
               int RLE_cmd     = rtga_get8(s);
               RLE_count       = 1 + (RLE_cmd &amp; 127);
               RLE_repeating   = RLE_cmd &gt;&gt; 7;
               read_next_pixel = 1;
            }
            else if (!RLE_repeating)
               read_next_pixel = 1;
         }
         else
            read_next_pixel = 1;

         /*   OK, if I need to read a pixel, do it now */
         if (read_next_pixel)
         {
            /*   load however much data we did have */
            if (tga_indexed)
            {
               /*   read in 1 byte, then perform the lookup */
               int pal_idx = rtga_get8(s);
               if (pal_idx &gt;= tga_palette_len) /* invalid index */
                  pal_idx = 0;
               pal_idx *= tga_bits_per_pixel / 8;
               for (j = 0; j*8 &lt; tga_bits_per_pixel; ++j)
                  raw_data[j] = tga_palette[pal_idx+j];
            }
            else
            {
               /* read in the data raw */
               /* manually unroll, probably GCC bug 92955 */
               j = 0;
               switch (tga_bits_per_pixel)
               {
                  case 32:
                     raw_data[j++] = rtga_get8(s); /* fallthrough */
                  case 24:
                     raw_data[j++] = rtga_get8(s); /* fallthrough */
                  case 16:
                     raw_data[j++] = rtga_get8(s); /* fallthrough */
                  case  8:
                     raw_data[j++] = rtga_get8(s);
               }
            }

            /*   clear the reading flag for the next pixel */
            read_next_pixel = 0;
         } /* end of reading a pixel */

         /* copy data */
         for (j = 0; j &lt; tga_comp; ++j)
            tga_data[i*tga_comp+j] = raw_data[j];

         /*   in case we're in RLE mode, keep counting down */
         --RLE_count;
      }

      /*   do I need to invert the image? */
      if (tga_inverted)
      {
         if (tga_data)
         {
            for (j = 0; j*2 &lt; tga_height; ++j)
            {
               int index1 = j * tga_width * tga_comp;
               int index2 = (tga_height - 1 - j) * tga_width * tga_comp;

               for (i = tga_width * tga_comp; i &gt; 0; --i)
               {
                  unsigned char temp = tga_data[index1];
                  tga_data[index1]   = tga_data[index2];
                  tga_data[index2]   = temp;
                  ++index1;
                  ++index2;
               }
            }
         }
      }

      /* Clear my palette, if I had one */
      if (tga_palette)
         free(tga_palette);
   }

   /* swap RGB */
   if (tga_comp &gt;= 3)
   {
      int i;
      unsigned char* tga_pixel = tga_data;

      for (i = 0; i &lt; tga_width * tga_height; ++i)
      {
         unsigned char temp  = tga_pixel[0];
         tga_pixel[0]        = tga_pixel[2];
         tga_pixel[2]        = temp;
         tga_pixel          += tga_comp;
      }
   }

   /* convert to target component count */
   if (     (req_comp)
         &amp;&amp; (req_comp &gt;= 1 &amp;&amp; req_comp &lt;= 4)
         &amp;&amp; (req_comp != tga_comp))
   {
      tga_data = rtga_convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
   }

   return tga_data;
}

static uint8_t *rtga_load_from_memory(uint8_t const *buffer, int len,
      unsigned *x, unsigned *y, int *comp, int req_comp)
{
   rtga_context s;

   s.img_buffer          = (uint8_t *)buffer;
   s.img_buffer_original = (uint8_t *) buffer;
   s.img_buffer_end      = (uint8_t *) buffer+len;

   return rtga_tga_load(&amp;s,x,y,comp,req_comp);
}

int rtga_process_image(rtga_t *rtga, void **buf_data,
      size_t size, unsigned *width, unsigned *height)
{
   int comp;
   unsigned size_tex     = 0;

   if (!rtga)
      return IMAGE_PROCESS_ERROR;

   rtga-&gt;output_image   = (uint32_t*)rtga_load_from_memory(rtga-&gt;buff_data,
                           (int)size, width, height, &amp;comp, 4);
   *buf_data             = rtga-&gt;output_image;
   size_tex              = (*width) * (*height);

   /* Convert RGBA to ARGB */
   while (size_tex--)
   {
      unsigned int texel = rtga-&gt;output_image[size_tex];
      unsigned int A     = texel &amp; 0xFF000000;
      unsigned int B     = texel &amp; 0x00FF0000;
      unsigned int G     = texel &amp; 0x0000FF00;
      unsigned int R     = texel &amp; 0x000000FF;
      ((unsigned int*)rtga-&gt;output_image)[size_tex] = A | (R &lt;&lt; 16) | G | (B &gt;&gt; 16);
   };

   return IMAGE_PROCESS_END;
}

bool rtga_set_buf_ptr(rtga_t *rtga, void *data)
{
   if (!rtga)
      return false;

   rtga-&gt;buff_data = (uint8_t*)data;

   return true;
}

void rtga_free(rtga_t *rtga)
{
   if (!rtga)
      return;

   free(rtga);
}

rtga_t *rtga_alloc(void)
{
   rtga_t *rtga = (rtga_t*)calloc(1, sizeof(*rtga));
   if (!rtga)
      return NULL;
   return rtga;
}</pre>
<h2>./include/libretro-common/formats/wav/rwav.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rwav.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stddef.h&gt; /* ptrdiff_t on osx */
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;formats/rwav.h&gt;

enum
{
   ITER_BEGIN,
   ITER_COPY_SAMPLES,
   ITER_COPY_SAMPLES_8,
   ITER_COPY_SAMPLES_16
};

struct rwav_iterator
{
   rwav_t *out;
   const uint8_t *data;
   size_t size;
   size_t i, j;
   int step;
};

void rwav_init(rwav_iterator_t* iter, rwav_t* out, const void *s, size_t len)
{
   iter-&gt;out    = out;
   iter-&gt;data   = (const uint8_t*)s;
   iter-&gt;size   = len;
   iter-&gt;step   = ITER_BEGIN;

   out-&gt;samples = NULL;
}

enum rwav_state rwav_iterate(rwav_iterator_t *iter)
{
   size_t s;
   uint16_t *u16       = NULL;
   void *samples       = NULL;
   rwav_t *rwav        = iter-&gt;out;
   const uint8_t *data = iter-&gt;data;

   switch (iter-&gt;step)
   {
      case ITER_BEGIN:
         if (iter-&gt;size &lt; 44)
            return RWAV_ITERATE_ERROR; /* buffer is smaller than an empty wave file */

         if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F')
            return RWAV_ITERATE_ERROR;

         if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E')
            return RWAV_ITERATE_ERROR;

         if (data[12] != 'f' || data[13] != 'm' || data[14] != 't' || data[15] != ' ')
            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */

         if (data[16] != 16 || data[17] != 0 || data[18] != 0 || data[19] != 0)
            return RWAV_ITERATE_ERROR;

         if (data[20] != 1 || data[21] != 0)
            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */

         if (data[36] != 'd' || data[37] != 'a' || data[38] != 't' || data[39] != 'a')
            return RWAV_ITERATE_ERROR;

         rwav-&gt;bitspersample = data[34] | data[35] &lt;&lt; 8;

         if (rwav-&gt;bitspersample != 8 &amp;&amp; rwav-&gt;bitspersample != 16)
            return RWAV_ITERATE_ERROR; /* we only support 8 and 16 bps */

         rwav-&gt;subchunk2size = data[40] | data[41] &lt;&lt; 8 | data[42] &lt;&lt; 16 | data[43] &lt;&lt; 24;

         if ((rwav-&gt;subchunk2size &lt; 1) ||
             (rwav-&gt;subchunk2size &gt; iter-&gt;size - 44))
            return RWAV_ITERATE_ERROR; /* too few bytes in buffer */

         samples = malloc(rwav-&gt;subchunk2size);

         if (!samples)
            return RWAV_ITERATE_ERROR;

         rwav-&gt;numchannels = data[22] | data[23] &lt;&lt; 8;
         rwav-&gt;numsamples  = rwav-&gt;subchunk2size * 8 / rwav-&gt;bitspersample / rwav-&gt;numchannels;
         rwav-&gt;samplerate  = data[24] | data[25] &lt;&lt; 8 | data[26] &lt;&lt; 16 | data[27] &lt;&lt; 24;
         rwav-&gt;samples     = samples;

         iter-&gt;step = ITER_COPY_SAMPLES;
         return RWAV_ITERATE_MORE;

      case ITER_COPY_SAMPLES:
         iter-&gt;i = 0;

         if (rwav-&gt;bitspersample == 8)
         {
            iter-&gt;step = ITER_COPY_SAMPLES_8;

            /* TODO/FIXME - what is going on here? */
            case ITER_COPY_SAMPLES_8:
            s = rwav-&gt;subchunk2size - iter-&gt;i;

            if (s &gt; RWAV_ITERATE_BUF_SIZE)
               s = RWAV_ITERATE_BUF_SIZE;

            memcpy((void*)((uint8_t*)rwav-&gt;samples + iter-&gt;i), (void *)(iter-&gt;data + 44 + iter-&gt;i), s);
            iter-&gt;i += s;
         }
         else
         {
            iter-&gt;step = ITER_COPY_SAMPLES_16;
            iter-&gt;j    = 0;

            /* TODO/FIXME - what is going on here? */
            case ITER_COPY_SAMPLES_16:
            s = rwav-&gt;subchunk2size - iter-&gt;i;

            if (s &gt; RWAV_ITERATE_BUF_SIZE)
               s = RWAV_ITERATE_BUF_SIZE;

            u16 = (uint16_t *)rwav-&gt;samples;

            while (s != 0)
            {
               u16[iter-&gt;j++] = iter-&gt;data[44 + iter-&gt;i] | iter-&gt;data[45 + iter-&gt;i] &lt;&lt; 8;
               iter-&gt;i += 2;
               s -= 2;
            }
         }

         if (iter-&gt;i &lt; rwav-&gt;subchunk2size)
            return RWAV_ITERATE_MORE;
         return RWAV_ITERATE_DONE;
   }

   return RWAV_ITERATE_ERROR;
}

enum rwav_state rwav_load(rwav_t* out, const void *s, size_t len)
{
   enum rwav_state res;
   rwav_iterator_t iter;

   iter.out             = NULL;
   iter.data            = NULL;
   iter.size            = 0;
   iter.i               = 0;
   iter.j               = 0;
   iter.step            = 0;

   rwav_init(&amp;iter, out, s, len);

   do
   {
      res = rwav_iterate(&amp;iter);
   }while (res == RWAV_ITERATE_MORE);

   return res;
}

void rwav_free(rwav_t *rwav)
{
   free((void*)rwav-&gt;samples);
}</pre>
<h2>./include/libretro-common/formats/xml/rxml.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;boolean.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;compat/posix_string.h&gt;
#include &lt;string/stdstring.h&gt;

#include &lt;formats/rxml.h&gt;

#include "../../deps/yxml/yxml.h"

#define BUFSIZE 4096

struct rxml_parse_buffer
{
   rxml_node_t *stack[32];
   char xml[BUFSIZE];
   char val[BUFSIZE];
};

struct rxml_document
{
   struct rxml_node *root_node;
};

struct rxml_node *rxml_root_node(rxml_document_t *doc)
{
   if (doc)
      return doc-&gt;root_node;
   return NULL;
}

static void rxml_free_node(struct rxml_node *node)
{
   struct rxml_node *head = NULL;
   struct rxml_attrib_node *attrib_node_head = NULL;

   if (!node)
      return;

   for (head = node-&gt;children; head; )
   {
      struct rxml_node *next_node = (struct rxml_node*)head-&gt;next;
      rxml_free_node(head);
      head = next_node;
   }

   for (attrib_node_head = node-&gt;attrib; attrib_node_head; )
   {
      struct rxml_attrib_node *next_attrib =
            (struct rxml_attrib_node*)attrib_node_head-&gt;next;

      if (attrib_node_head-&gt;attrib)
         free(attrib_node_head-&gt;attrib);
      if (attrib_node_head-&gt;value)
         free(attrib_node_head-&gt;value);
      if (attrib_node_head)
         free(attrib_node_head);

      attrib_node_head = next_attrib;
   }

   if (node-&gt;name)
      free(node-&gt;name);
   if (node-&gt;data)
      free(node-&gt;data);
   if (node)
      free(node);
}

rxml_document_t *rxml_load_document(const char *path)
{
   rxml_document_t *doc    = NULL;
   char *memory_buffer     = NULL;
   int64_t len             = 0;
   RFILE *file             = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!file)
      return NULL;

   len                     = filestream_get_size(file);
   memory_buffer           = (char*)malloc((size_t)(len + 1));
   if (!memory_buffer)
      goto error;

   memory_buffer[len]      = '\0';
   if (filestream_read(file, memory_buffer, len) != len)
      goto error;

   filestream_close(file);
   file                    = NULL;

   doc                     = rxml_load_document_string(memory_buffer);

   free(memory_buffer);
   return doc;

error:
   free(memory_buffer);
   if (file)
      filestream_close(file);
   return NULL;
}

rxml_document_t *rxml_load_document_string(const char *str)
{
   yxml_t x;
   rxml_document_t *doc          = NULL;
   size_t stack_i                = 0;
   size_t level                  = 0;
   int i                         = 0;
   char *valptr                  = NULL;
   rxml_node_t *node             = NULL;
   struct rxml_attrib_node *attr = NULL;
   struct rxml_parse_buffer *buf = (struct rxml_parse_buffer*)
      malloc(sizeof(*buf));
   if (!buf)
      return NULL;

   valptr                        = buf-&gt;val;
   doc                           = (rxml_document_t*)malloc(sizeof(*doc));
   if (!doc)
      goto error;
   doc-&gt;root_node                = NULL;

   yxml_init(&amp;x, buf-&gt;xml, BUFSIZE);

   for (; *str; ++str)
   {
      yxml_ret_t r = yxml_parse(&amp;x, *str);

      if (r &lt; 0)
         goto error;

      switch (r)
      {

         case YXML_ELEMSTART:
            if (node)
            {
               if (level &gt; stack_i)
               {
                  buf-&gt;stack[stack_i]      = node;
                  ++stack_i;

                  node-&gt;children           = (rxml_node_t*)
                     malloc(sizeof(*node));

                  node-&gt;children-&gt;name     = NULL;
                  node-&gt;children-&gt;data     = NULL;
                  node-&gt;children-&gt;attrib   = NULL;
                  node-&gt;children-&gt;children = NULL;
                  node-&gt;children-&gt;next     = NULL;

                  node                     = node-&gt;children;
               }
               else
               {
                  node-&gt;next               = (rxml_node_t*)
                     malloc(sizeof(*node));

                  node-&gt;next-&gt;name         = NULL;
                  node-&gt;next-&gt;data         = NULL;
                  node-&gt;next-&gt;attrib       = NULL;
                  node-&gt;next-&gt;children     = NULL;
                  node-&gt;next-&gt;next         = NULL;

                  node                     = node-&gt;next;
               }
            }
            else
               node = doc-&gt;root_node       = (rxml_node_t*)
                  calloc(1, sizeof(*node));

            if (node-&gt;name)
               free(node-&gt;name);
            node-&gt;name                     = strdup(x.elem);

            attr                           = NULL;
            valptr                         = buf-&gt;val;

            ++level;
            break;

         case YXML_ELEMEND:
            --level;

            if (valptr &gt; buf-&gt;val)
            {
               *valptr = '\0';

               /* Original code was broken here:
                * &gt; If an element ended on two successive
                *   iterations, on the second iteration
                *   the 'data' for the *previous* node would
                *   get overwritten
                * &gt; This effectively erased the data for the
                *   previous node, *and* caused a memory leak
                *   (due to the double strdup())
                * It seems the correct thing to do here is
                * only copy the data if the current 'level'
                * and 'stack index' are the same... */
               if (level == stack_i)
               {
                  if (node-&gt;data)
                     free(node-&gt;data);
                  node-&gt;data = strdup(buf-&gt;val);
               }

               valptr = buf-&gt;val;
            }

            if (level &lt; stack_i)
            {
               --stack_i;
               node = buf-&gt;stack[stack_i];
            }
            break;

         case YXML_CONTENT:
            for (i = 0; i &lt; (int)sizeof(x.data) &amp;&amp; x.data[i]; i++)
            {
               *valptr = x.data[i];
               ++valptr;
            }
            break;

         case YXML_ATTRSTART:
            if (attr)
               attr = attr-&gt;next   = (struct rxml_attrib_node*)
                     calloc(1, sizeof(*attr));
            else
            {
               attr = (struct rxml_attrib_node*)calloc(1, sizeof(*attr));
               if (node &amp;&amp; attr)
                  node-&gt;attrib = attr;
            }

            if (attr)
            {
               if (attr-&gt;attrib)
                  free(attr-&gt;attrib);
               attr-&gt;attrib = strdup(x.attr);
            }

            valptr       = buf-&gt;val;
            break;

         case YXML_ATTRVAL:
            for (i = 0; i &lt; (int)sizeof(x.data) &amp;&amp; x.data[i]; i++)
            {
               *valptr = x.data[i];
               ++valptr;
            }
            break;

         case YXML_ATTREND:
            if (valptr &gt; buf-&gt;val)
            {
               *valptr = '\0';

               if (attr)
               {
                  if (attr-&gt;value)
                     free(attr-&gt;value);
                  attr-&gt;value = strdup(buf-&gt;val);
               }

               valptr      = buf-&gt;val;
            }
            break;

         default:
            break;
      }
   }

   free(buf);
   return doc;

error:
   rxml_free_document(doc);
   free(buf);
   return NULL;
}

void rxml_free_document(rxml_document_t *doc)
{
   if (!doc)
      return;

   if (doc-&gt;root_node)
      rxml_free_node(doc-&gt;root_node);

   free(doc);
}

const char *rxml_node_attrib(struct rxml_node *node, const char *attrib)
{
   struct rxml_attrib_node *attribs = NULL;
   for (attribs = node-&gt;attrib; attribs; attribs = attribs-&gt;next)
   {
      if (string_is_equal(attrib, attribs-&gt;attrib))
         return attribs-&gt;value;
   }

   return NULL;
}</pre>
<h2>./include/libretro-common/formats/xml/test/Makefile</h2>
<pre>TARGET := rxml

LIBRETRO_XML_DIR  := ..
LIBRETRO_COMM_DIR := ../../..
LIBRETRO_DEPS_DIR := ../../../../deps

SOURCES := \
	rxml_test.c \
	$(LIBRETRO_XML_DIR)/rxml.c \
	$(LIBRETRO_DEPS_DIR)/yxml/yxml.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -DRXML_TEST -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/formats/xml/test/rxml_test.c</h2>
<pre>/* Copyright  (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;formats/rxml.h&gt;
#include &lt;stdio.h&gt;

static void print_siblings(struct rxml_node *node, unsigned level)
{
   fprintf(stderr, "\n%*sName: %s\n", level * 4, "", node-&gt;name);
   if (node-&gt;data)
      fprintf(stderr, "%*sData: %s\n", level * 4, "", node-&gt;data);

   for (const struct rxml_attrib_node *attrib =
         node-&gt;attrib; attrib; attrib = attrib-&gt;next)
      fprintf(stderr, "%*s  Attrib: %s = %s\n", level * 4, "",
            attrib-&gt;attrib, attrib-&gt;value);

   if (node-&gt;children)
      print_siblings(node-&gt;children, level + 1);

   if (node-&gt;next)
      print_siblings(node-&gt;next, level);
}

static void rxml_log_document(const char *path)
{
   rxml_document_t *doc = rxml_load_document(path);
   if (!doc)
   {
      fprintf(stderr, "rxml: Failed to load document: %s\n", path);
      return;
   }

   print_siblings(rxml_root_node(doc), 0);
   rxml_free_document(doc);
}

int main(int argc, char *argv[])
{
   if (argc != 2)
   {
      fprintf(stderr, "Usage: %s &lt;path&gt;\n", argv[0]);
      return 1;
   }

   rxml_log_document(argv[1]);
}</pre>
<h2>./include/libretro-common/gfx/gl_capabilities.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gl_capabilities.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;math.h&gt;
#include &lt;string.h&gt;

#include &lt;boolean.h&gt;

#include &lt;glsym/glsym.h&gt;

#include &lt;gfx/gl_capabilities.h&gt;

static bool gl_core_context       = false;

bool gl_query_core_context_in_use(void)
{
   return gl_core_context;
}

void gl_query_core_context_set(bool set)
{
   gl_core_context     =  set;
}

void gl_query_core_context_unset(void)
{
   gl_core_context = false;
}

bool gl_query_extension(const char *ext)
{
   bool ret = false;

   if (gl_query_core_context_in_use())
   {
#ifdef GL_NUM_EXTENSIONS
      GLint i;
      GLint exts = 0;
      glGetIntegerv(GL_NUM_EXTENSIONS, &amp;exts);
      for (i = 0; i &lt; exts; i++)
      {
         const char *str = (const char*)glGetStringi(GL_EXTENSIONS, i);
         if (str &amp;&amp; strstr(str, ext))
         {
            ret = true;
            break;
         }
      }
#endif
   }
   else
   {
      const char *str = (const char*)glGetString(GL_EXTENSIONS);
      ret = str &amp;&amp; strstr(str, ext);
   }

   return ret;
}

bool gl_check_error(char **err_string)
{
   int err = glGetError();
   switch (err)
   {
      case GL_INVALID_ENUM:
         *err_string = strdup("GL: Invalid enum.");
         break;
      case GL_INVALID_VALUE:
         *err_string = strdup("GL: Invalid value.");
         break;
      case GL_INVALID_OPERATION:
         *err_string = strdup("GL: Invalid operation.");
         break;
      case GL_OUT_OF_MEMORY:
         *err_string = strdup("GL: Out of memory.");
         break;
      case GL_NO_ERROR:
         return true;
      default:
         *err_string = strdup("Non specified GL error.");
         break;
   }

   return false;
}

bool gl_check_capability(enum gl_capability_enum enum_idx)
{
   unsigned major       = 0;
   unsigned minor       = 0;
   const char *vendor   = (const char*)glGetString(GL_VENDOR);
   const char *renderer = (const char*)glGetString(GL_RENDERER);
   const char *version  = (const char*)glGetString(GL_VERSION);
#ifdef HAVE_OPENGLES
   if (version &amp;&amp; sscanf(version, "OpenGL ES %u.%u", &amp;major, &amp;minor) != 2)
#else
   if (version &amp;&amp; sscanf(version, "%u.%u", &amp;major, &amp;minor) != 2)
#endif
      major = minor = 0;

   (void)vendor;
   (void)renderer;

   switch (enum_idx)
   {
      case GL_CAPS_GLES3_SUPPORTED:
#if defined(HAVE_OPENGLES)
         if (major &gt;= 3)
            return true;
#endif
         break;
      case GL_CAPS_EGLIMAGE:
#if defined(HAVE_EGL) &amp;&amp; defined(HAVE_OPENGLES)
         if (glEGLImageTargetTexture2DOES != NULL)
            return true;
#endif
         break;
      case GL_CAPS_SYNC:
#ifdef HAVE_OPENGLES
         if (major &gt;= 3)
            return true;
#else
         if (gl_query_extension("ARB_sync") &amp;&amp;
               glFenceSync &amp;&amp; glDeleteSync &amp;&amp; glClientWaitSync)
            return true;
#endif
         break;
      case GL_CAPS_MIPMAP:
         {
            static bool extension_queried = false;
            static bool extension         = false;

            if (!extension_queried)
            {
               extension         = gl_query_extension("ARB_framebuffer_object");
               extension_queried = true;
            }

            if (extension)
               return true;
         }
         break;
      case GL_CAPS_VAO:
#ifndef HAVE_OPENGLES
         if (!gl_query_core_context_in_use() &amp;&amp; !gl_query_extension("ARB_vertex_array_object"))
            return false;

         if (glGenVertexArrays &amp;&amp; glBindVertexArray &amp;&amp; glDeleteVertexArrays)
            return true;
#endif
         break;
      case GL_CAPS_FBO:
#if defined(HAVE_PSGL) || defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2)
         return true;
#else
         if (     !gl_query_core_context_in_use()
               &amp;&amp; !gl_query_extension("ARB_framebuffer_object")
               &amp;&amp; !gl_query_extension("EXT_framebuffer_object"))
            return false;

         if (gl_query_extension("ARB_framebuffer_object"))
            return true;

         if (gl_query_extension("EXT_framebuffer_object"))
            return true;

         if (major &gt;= 3)
            return true;
         break;
#endif
      case GL_CAPS_ARGB8:
#if defined(HAVE_OPENGLES) &amp;&amp; !defined(EMSCRIPTEN)
         if (gl_query_extension("OES_rgb8_rgba8")
               || gl_query_extension("ARM_rgba8")
                  || major &gt;= 3)
            return true;
#elif defined(HAVE_OPENGLES) &amp;&amp; defined(EMSCRIPTEN)
         if (gl_query_extension("EXT_sRGB")
               || major &gt;= 3)
            return true;
#else
         /* TODO/FIXME - implement this for non-GLES? */
#endif
         break;
      case GL_CAPS_DEBUG:
         if (gl_query_extension("KHR_debug"))
            return true;
#ifndef HAVE_OPENGLES
         if (gl_query_extension("ARB_debug_output"))
            return true;
#endif
         break;
      case GL_CAPS_PACKED_DEPTH_STENCIL:
         if (major &gt;= 3)
            return true;
         if (gl_query_extension("OES_packed_depth_stencil"))
            return true;
         if (gl_query_extension("EXT_packed_depth_stencil"))
            return true;
         break;
      case GL_CAPS_ES2_COMPAT:
#ifndef HAVE_OPENGLES
         /* ATI card detected, skipping check for GL_RGB565 support... */
         if (vendor &amp;&amp; renderer &amp;&amp; (strstr(vendor, "ATI") || strstr(renderer, "ATI")))
            return false;

         if (gl_query_extension("ARB_ES2_compatibility"))
            return true;
#endif
         break;
      case GL_CAPS_UNPACK_ROW_LENGTH:
#ifdef HAVE_OPENGLES
         if (major &gt;= 3)
            return true;

         /* Extension GL_EXT_unpack_subimage, can copy textures faster
          * than using UNPACK_ROW_LENGTH */
         if (gl_query_extension("GL_EXT_unpack_subimage"))
            return true;
#endif
         break;
      case GL_CAPS_FULL_NPOT_SUPPORT:
         if (major &gt;= 3)
            return true;
#ifdef HAVE_OPENGLES
         if (gl_query_extension("ARB_texture_non_power_of_two") ||
               gl_query_extension("OES_texture_npot"))
            return true;
#else
         {
            GLint max_texture_size = 0;
            GLint max_native_instr = 0;
            /* try to detect actual npot support. might fail for older cards. */
            bool  arb_npot         = gl_query_extension("ARB_texture_non_power_of_two");
            bool  arb_frag_program = gl_query_extension("ARB_fragment_program");

            glGetIntegerv(GL_MAX_TEXTURE_SIZE, &amp;max_texture_size);

#ifdef GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB
            if (arb_frag_program &amp;&amp; glGetProgramivARB)
               glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
                     GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &amp;max_native_instr);
#endif

            if (arb_npot &amp;&amp; arb_frag_program &amp;&amp;
                  (max_texture_size &gt;= 8192) &amp;&amp; (max_native_instr &gt;= 4096))
               return true;
         }
#endif
         break;
      case GL_CAPS_SRGB_FBO_ES3:
#ifdef HAVE_OPENGLES
         if (major &gt;= 3)
            return true;
#else
         break;
#endif
      case GL_CAPS_SRGB_FBO:
#if defined(HAVE_OPENGLES)
         if (major &gt;= 3 || gl_query_extension("EXT_sRGB"))
            return true;
#endif
         if (gl_check_capability(GL_CAPS_FBO))
         {
            if (   gl_query_core_context_in_use() ||
                  (gl_query_extension("EXT_texture_sRGB")
                   &amp;&amp; gl_query_extension("ARB_framebuffer_sRGB"))
               )
               return true;
         }
         break;
      case GL_CAPS_FP_FBO:
         if (gl_check_capability(GL_CAPS_FBO))
         {
            /* Float FBO is core in 3.2. */
            if (gl_query_core_context_in_use() || gl_query_extension("ARB_texture_float") || gl_query_extension("OES_texture_float_linear"))
               return true;
         }
         break;
      case GL_CAPS_BGRA8888:
#ifdef HAVE_OPENGLES
         /* There are both APPLE and EXT variants. */
         if (gl_query_extension("BGRA8888"))
            return true;
#else
         return true;
#endif
         break;
      case GL_CAPS_TEX_STORAGE:
#ifdef HAVE_OPENGLES
         if (major &gt;= 3)
            return true;
#else
         if (vendor &amp;&amp; strstr(vendor, "ATI Technologies"))
            return false;
         if (gl_query_extension("ARB_texture_storage"))
            return true;
#endif
         break;
      case GL_CAPS_TEX_STORAGE_EXT:
#ifdef TARGET_OS_IPHONE
           /* Not working on iOS */
           return false;
#else
         if (gl_query_extension("EXT_texture_storage"))
            return true;
#endif
         break;
      case GL_CAPS_NONE:
      default:
         break;
   }

   return false;
}</pre>
<h2>./include/libretro-common/gfx/scaler/pixconv.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (pixconv.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_inline.h&gt;

#include &lt;gfx/scaler/pixconv.h&gt;

#if _MSC_VER &amp;&amp; _MSC_VER &lt;= 1800
#define SCALER_NO_SIMD
#endif

#ifdef SCALER_NO_SIMD
#undef __SSE2__
#endif

#if defined(__SSE2__)
#include &lt;emmintrin.h&gt;
#elif defined(__MMX__)
#include &lt;mmintrin.h&gt;
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
#include &lt;arm_neon.h&gt;
#endif

void conv_rgb565_0rgb1555(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input   = (const uint16_t*)input_;
   uint16_t *output        = (uint16_t*)output_;

#if defined(__SSE2__)
   int max_width           = width - 7;
   const __m128i hi_mask   = _mm_set1_epi16(0x7fe0);
   const __m128i lo_mask   = _mm_set1_epi16(0x1f);
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 1, input += in_stride &gt;&gt; 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w &lt; max_width; w += 8)
      {
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i hi = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);
         __m128i lo = _mm_and_si128(in, lo_mask);
         _mm_storeu_si128((__m128i*)(output + w), _mm_or_si128(hi, lo));
      }
#endif

      for (; w &lt; width; w++)
      {
         uint16_t col = input[w];
         uint16_t hi  = (col &gt;&gt; 1) &amp; 0x7fe0;
         uint16_t lo  = col &amp; 0x1f;
         output[w]    = hi | lo;
      }
   }
}

void conv_0rgb1555_rgb565(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input   = (const uint16_t*)input_;
   uint16_t *output        = (uint16_t*)output_;

#if defined(__SSE2__)
   int max_width           = width - 7;

   const __m128i hi_mask   = _mm_set1_epi16(
         (int16_t)((0x1f &lt;&lt; 11) | (0x1f &lt;&lt; 6)));
   const __m128i lo_mask   = _mm_set1_epi16(0x1f);
   const __m128i glow_mask = _mm_set1_epi16(1 &lt;&lt; 5);
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 1, input += in_stride &gt;&gt; 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w &lt; max_width; w += 8)
      {
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i rg   = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);
         __m128i b    = _mm_and_si128(in, lo_mask);
         __m128i glow = _mm_and_si128(_mm_srli_epi16(in, 4), glow_mask);
         _mm_storeu_si128((__m128i*)(output + w),
               _mm_or_si128(rg, _mm_or_si128(b, glow)));
      }
#endif

      for (; w &lt; width; w++)
      {
         uint16_t col  = input[w];
         uint16_t rg   = (col &lt;&lt; 1) &amp; ((0x1f &lt;&lt; 11) | (0x1f &lt;&lt; 6));
         uint16_t b    = col &amp; 0x1f;
         uint16_t glow = (col &gt;&gt; 4) &amp; (1 &lt;&lt; 5);
         output[w]     = rg | b | glow;
      }
   }
}

void conv_0rgb1555_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input = (const uint16_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

#ifdef __SSE2__
   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f &lt;&lt; 10);
   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f &lt;&lt;  5);
   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);
   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);
   const __m128i a           = _mm_set1_epi16(0x00ff);

   int max_width = width - 7;
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 2, input += in_stride &gt;&gt; 1)
   {
      int w = 0;
#ifdef __SSE2__
      for (; w &lt; max_width; w += 8)
      {
         __m128i res_lo_bg, res_hi_bg;
         __m128i res_lo_ra, res_hi_ra;
         __m128i res_lo, res_hi;
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i r = _mm_and_si128(in, pix_mask_r);
         __m128i g = _mm_and_si128(in, pix_mask_gb);
         __m128i b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_gb);

         r = _mm_mulhi_epi16(r, mul15_hi);
         g = _mm_mulhi_epi16(g, mul15_mid);
         b = _mm_mulhi_epi16(b, mul15_mid);

         res_lo_bg = _mm_unpacklo_epi8(b, g);
         res_hi_bg = _mm_unpackhi_epi8(b, g);
         res_lo_ra = _mm_unpacklo_epi8(r, a);
         res_hi_ra = _mm_unpackhi_epi8(r, a);

         res_lo = _mm_or_si128(res_lo_bg,
               _mm_slli_si128(res_lo_ra, 2));
         res_hi = _mm_or_si128(res_hi_bg,
               _mm_slli_si128(res_hi_ra, 2));

         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
      }
#endif

      for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col &gt;&gt; 10) &amp; 0x1f;
         uint32_t g   = (col &gt;&gt;  5) &amp; 0x1f;
         uint32_t b   = (col &gt;&gt;  0) &amp; 0x1f;
         r            = (r &lt;&lt; 3) | (r &gt;&gt; 2);
         g            = (g &lt;&lt; 3) | (g &gt;&gt; 2);
         b            = (b &lt;&lt; 3) | (b &gt;&gt; 2);

         output[w]    = (0xffu &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);
      }
   }
}

void conv_rgb565_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input    = (const uint16_t*)input_;
   uint32_t *output         = (uint32_t*)output_;

#if defined(__SSE2__)
   const __m128i pix_mask_r = _mm_set1_epi16(0x1f &lt;&lt; 10);
   const __m128i pix_mask_g = _mm_set1_epi16(0x3f &lt;&lt;  5);
   const __m128i pix_mask_b = _mm_set1_epi16(0x1f &lt;&lt;  5);
   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
   const __m128i a          = _mm_set1_epi16(0x00ff);

   int max_width            = width - 7;
#elif defined(__MMX__)
   const __m64 pix_mask_r = _mm_set1_pi16(0x1f &lt;&lt; 10);
   const __m64 pix_mask_g = _mm_set1_pi16(0x3f &lt;&lt; 5);
   const __m64 pix_mask_b = _mm_set1_pi16(0x1f &lt;&lt; 5);
   const __m64 mul16_r    = _mm_set1_pi16(0x0210);
   const __m64 mul16_g    = _mm_set1_pi16(0x2080);
   const __m64 mul16_b    = _mm_set1_pi16(0x4200);
   const __m64 a          = _mm_set1_pi16(0x00ff);

   int max_width            = width - 3;
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
   int max_width            = width - 7;
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 2, input += in_stride &gt;&gt; 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w &lt; max_width; w += 8)
      {
         __m128i res_lo, res_hi;
         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);
         __m128i        g = _mm_and_si128(in, pix_mask_g);
         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);

         r                = _mm_mulhi_epi16(r, mul16_r);
         g                = _mm_mulhi_epi16(g, mul16_g);
         b                = _mm_mulhi_epi16(b, mul16_b);

         res_lo_bg        = _mm_unpacklo_epi8(b, g);
         res_hi_bg        = _mm_unpackhi_epi8(b, g);
         res_lo_ra        = _mm_unpacklo_epi8(r, a);
         res_hi_ra        = _mm_unpackhi_epi8(r, a);

         res_lo           = _mm_or_si128(res_lo_bg,
               _mm_slli_si128(res_lo_ra, 2));
         res_hi           = _mm_or_si128(res_hi_bg,
               _mm_slli_si128(res_hi_ra, 2));

         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
      }
#elif defined(__MMX__)
      for (; w &lt; max_width; w += 4)
      {
         __m64 res_lo, res_hi;
         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m64 in = *((__m64*)(input + w));
         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 1), pix_mask_r);
         __m64          g = _mm_and_si64(in, pix_mask_g);
         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 5), pix_mask_b);

         r                = _mm_mulhi_pi16(r, mul16_r);
         g                = _mm_mulhi_pi16(g, mul16_g);
         b                = _mm_mulhi_pi16(b, mul16_b);

         res_lo_bg        = _mm_unpacklo_pi8(b, g);
         res_hi_bg        = _mm_unpackhi_pi8(b, g);
         res_lo_ra        = _mm_unpacklo_pi8(r, a);
         res_hi_ra        = _mm_unpackhi_pi8(r, a);

         res_lo           = _mm_or_si64(res_lo_bg,
               _mm_slli_si64(res_lo_ra, 16));
         res_hi           = _mm_or_si64(res_hi_bg,
               _mm_slli_si64(res_hi_ra, 16));

         *((__m64*)(output + w + 0)) = res_lo;
         *((__m64*)(output + w + 2)) = res_hi;
      }

      _mm_empty();
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
      for (; w &lt; max_width; w += 8)
      {
         uint16x8_t in = vld1q_u16(input + w);

         uint16x8_t r = vsriq_n_u16(in, in, 5);
         uint16x8_t b = vsliq_n_u16(in, in, 5);
         uint16x8_t g = vsriq_n_u16(b,  b,  6);

         uint8x8x4_t res;
         res.val[3] = vdup_n_u8(0xffu);
         res.val[2] = vshrn_n_u16(r, 8);
         res.val[1] = vshrn_n_u16(g, 8);
         res.val[0] = vshrn_n_u16(b, 2);

         vst4_u8((uint8_t*)(output + w), res);
      }
#endif

      for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col &gt;&gt; 11) &amp; 0x1f;
         uint32_t g   = (col &gt;&gt;  5) &amp; 0x3f;
         uint32_t b   = (col &gt;&gt;  0) &amp; 0x1f;
         r            = (r &lt;&lt; 3) | (r &gt;&gt; 2);
         g            = (g &lt;&lt; 2) | (g &gt;&gt; 4);
         b            = (b &lt;&lt; 3) | (b &gt;&gt; 2);

         output[w]    = (0xffu &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);
      }
   }
}

void conv_rgb565_abgr8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input    = (const uint16_t*)input_;
   uint32_t *output         = (uint32_t*)output_;
 #if defined(__SSE2__)
   const __m128i pix_mask_r = _mm_set1_epi16(0x1f &lt;&lt; 10);
   const __m128i pix_mask_g = _mm_set1_epi16(0x3f &lt;&lt;  5);
   const __m128i pix_mask_b = _mm_set1_epi16(0x1f &lt;&lt;  5);
   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
   const __m128i a          = _mm_set1_epi16(0x00ff);
    int max_width            = width - 7;
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
   int max_width            = width - 7;
#endif
    for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 2, input += in_stride &gt;&gt; 1)
   {
      int w = 0;
#if defined(__SSE2__)
      for (; w &lt; max_width; w += 8)
      {
         __m128i res_lo, res_hi;
         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);
         __m128i        g = _mm_and_si128(in, pix_mask_g);
         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);
         r                = _mm_mulhi_epi16(r, mul16_r);
         g                = _mm_mulhi_epi16(g, mul16_g);
         b                = _mm_mulhi_epi16(b, mul16_b);
         res_lo_bg        = _mm_unpacklo_epi8(b, g);
         res_hi_bg        = _mm_unpackhi_epi8(b, g);
         res_lo_ra        = _mm_unpacklo_epi8(r, a);
         res_hi_ra        = _mm_unpackhi_epi8(r, a);
         res_lo           = _mm_or_si128(res_lo_bg,
               _mm_slli_si128(res_lo_ra, 2));
         res_hi           = _mm_or_si128(res_hi_bg,
               _mm_slli_si128(res_hi_ra, 2));
         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
      }
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
      for (; w &lt; max_width; w += 8)
      {
         uint16x8_t in = vld1q_u16(input + w);

         uint16x8_t r = vsriq_n_u16(in, in, 5);
         uint16x8_t b = vsliq_n_u16(in, in, 5);
         uint16x8_t g = vsriq_n_u16(b,  b,  6);

         uint8x8x4_t res;
         res.val[3] = vdup_n_u8(0xffu);
         res.val[2] = vshrn_n_u16(b, 2);
         res.val[1] = vshrn_n_u16(g, 8);
         res.val[0] = vshrn_n_u16(r, 8);

         vst4_u8((uint8_t*)(output + w), res);
      }
#endif
       for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col &gt;&gt; 11) &amp; 0x1f;
         uint32_t g   = (col &gt;&gt;  5) &amp; 0x3f;
         uint32_t b   = (col &gt;&gt;  0) &amp; 0x1f;
         r            = (r &lt;&lt; 3) | (r &gt;&gt; 2);
         g            = (g &lt;&lt; 2) | (g &gt;&gt; 4);
         b            = (b &lt;&lt; 3) | (b &gt;&gt; 2);
         output[w]    = (0xffu &lt;&lt; 24) | (b &lt;&lt; 16) | (g &lt;&lt; 8) | (r &lt;&lt; 0);
      }
   }
}

void conv_argb8888_rgba4444(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint32_t *input = (const uint32_t*)input_;
   uint16_t *output      = (uint16_t*)output_;

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 2, input += in_stride &gt;&gt; 1)
   {
      for (w = 0; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col &gt;&gt; 16) &amp; 0xf;
         uint32_t g   = (col &gt;&gt;  8) &amp; 0xf;
         uint32_t b   = (col) &amp; 0xf;
         uint32_t a   = (col &gt;&gt;  24) &amp; 0xf;
         r            = (r &gt;&gt; 4) | r;
         g            = (g &gt;&gt; 4) | g;
         b            = (b &gt;&gt; 4) | b;
         a            = (a &gt;&gt; 4) | a;

         output[w]    = (r &lt;&lt; 12) | (g &lt;&lt; 8) | (b &lt;&lt; 4) | a;
      }
   }
}

void conv_rgba4444_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input = (const uint16_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

#if defined(__MMX__)
   const __m64 pix_mask_r = _mm_set1_pi16(0xf &lt;&lt; 10);
   const __m64 pix_mask_g = _mm_set1_pi16(0xf &lt;&lt; 8);
   const __m64 pix_mask_b = _mm_set1_pi16(0xf &lt;&lt; 8);
   const __m64 mul16_r    = _mm_set1_pi16(0x0440);
   const __m64 mul16_g    = _mm_set1_pi16(0x1100);
   const __m64 mul16_b    = _mm_set1_pi16(0x1100);
   const __m64 a          = _mm_set1_pi16(0x00ff);

   int max_width            = width - 3;
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 2, input += in_stride &gt;&gt; 1)
   {
      int w = 0;
#if defined(__MMX__)
      for (; w &lt; max_width; w += 4)
      {
         __m64 res_lo, res_hi;
         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         const __m64 in = *((__m64*)(input + w));
         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 2), pix_mask_r);
         __m64          g = _mm_and_si64(in, pix_mask_g);
         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 4), pix_mask_b);

         r                = _mm_mulhi_pi16(r, mul16_r);
         g                = _mm_mulhi_pi16(g, mul16_g);
         b                = _mm_mulhi_pi16(b, mul16_b);

         res_lo_bg        = _mm_unpacklo_pi8(b, g);
         res_hi_bg        = _mm_unpackhi_pi8(b, g);
         res_lo_ra        = _mm_unpacklo_pi8(r, a);
         res_hi_ra        = _mm_unpackhi_pi8(r, a);

         res_lo           = _mm_or_si64(res_lo_bg,
               _mm_slli_si64(res_lo_ra, 16));
         res_hi           = _mm_or_si64(res_hi_bg,
               _mm_slli_si64(res_hi_ra, 16));

         *((__m64*)(output + w + 0)) = res_lo;
         *((__m64*)(output + w + 2)) = res_hi;
      }

      _mm_empty();
#endif

      for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col &gt;&gt; 12) &amp; 0xf;
         uint32_t g   = (col &gt;&gt;  8) &amp; 0xf;
         uint32_t b   = (col &gt;&gt;  4) &amp; 0xf;
         uint32_t a   = (col &gt;&gt;  0) &amp; 0xf;
         r            = (r &lt;&lt; 4) | r;
         g            = (g &lt;&lt; 4) | g;
         b            = (b &lt;&lt; 4) | b;
         a            = (a &lt;&lt; 4) | a;

         output[w]    = (a &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);
      }
   }
}

void conv_rgba4444_rgb565(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint16_t *input = (const uint16_t*)input_;
   uint16_t *output      = (uint16_t*)output_;

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 1, input += in_stride &gt;&gt; 1)
   {
      for (w = 0; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col &gt;&gt; 12) &amp; 0xf;
         uint32_t g   = (col &gt;&gt;  8) &amp; 0xf;
         uint32_t b   = (col &gt;&gt;  4) &amp; 0xf;

         output[w]    = (r &lt;&lt; 12) | (g &lt;&lt; 7) | (b &lt;&lt; 1);
      }
   }
}

#if defined(__SSE2__)
/* :( TODO: Make this saner. */
static INLINE void store_bgr24_sse2(void *output, __m128i a,
      __m128i b, __m128i c, __m128i d)
{
   const __m128i mask_0 = _mm_set_epi32(0, 0, 0, 0x00ffffff);
   const __m128i mask_1 = _mm_set_epi32(0, 0, 0x00ffffff, 0);
   const __m128i mask_2 = _mm_set_epi32(0, 0x00ffffff, 0, 0);
   const __m128i mask_3 = _mm_set_epi32(0x00ffffff, 0, 0, 0);

   __m128i a0 = _mm_and_si128(a, mask_0);
   __m128i a1 = _mm_srli_si128(_mm_and_si128(a, mask_1),  1);
   __m128i a2 = _mm_srli_si128(_mm_and_si128(a, mask_2),  2);
   __m128i a3 = _mm_srli_si128(_mm_and_si128(a, mask_3),  3);
   __m128i a4 = _mm_slli_si128(_mm_and_si128(b, mask_0), 12);
   __m128i a5 = _mm_slli_si128(_mm_and_si128(b, mask_1), 11);

   __m128i b0 = _mm_srli_si128(_mm_and_si128(b, mask_1), 5);
   __m128i b1 = _mm_srli_si128(_mm_and_si128(b, mask_2), 6);
   __m128i b2 = _mm_srli_si128(_mm_and_si128(b, mask_3), 7);
   __m128i b3 = _mm_slli_si128(_mm_and_si128(c, mask_0), 8);
   __m128i b4 = _mm_slli_si128(_mm_and_si128(c, mask_1), 7);
   __m128i b5 = _mm_slli_si128(_mm_and_si128(c, mask_2), 6);

   __m128i c0 = _mm_srli_si128(_mm_and_si128(c, mask_2), 10);
   __m128i c1 = _mm_srli_si128(_mm_and_si128(c, mask_3), 11);
   __m128i c2 = _mm_slli_si128(_mm_and_si128(d, mask_0),  4);
   __m128i c3 = _mm_slli_si128(_mm_and_si128(d, mask_1),  3);
   __m128i c4 = _mm_slli_si128(_mm_and_si128(d, mask_2),  2);
   __m128i c5 = _mm_slli_si128(_mm_and_si128(d, mask_3),  1);

   __m128i *out = (__m128i*)output;

   _mm_storeu_si128(out + 0,
         _mm_or_si128(a0, _mm_or_si128(a1, _mm_or_si128(a2,
                  _mm_or_si128(a3, _mm_or_si128(a4, a5))))));

   _mm_storeu_si128(out + 1,
         _mm_or_si128(b0, _mm_or_si128(b1, _mm_or_si128(b2,
                  _mm_or_si128(b3, _mm_or_si128(b4, b5))))));

   _mm_storeu_si128(out + 2,
         _mm_or_si128(c0, _mm_or_si128(c1, _mm_or_si128(c2,
                  _mm_or_si128(c3, _mm_or_si128(c4, c5))))));
}
#endif

void conv_0rgb1555_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input     = (const uint16_t*)input_;
   uint8_t *output           = (uint8_t*)output_;

#if defined(__SSE2__)
   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f &lt;&lt; 10);
   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f &lt;&lt;  5);
   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);
   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);
   const __m128i a           = _mm_set1_epi16(0x00ff);

   int max_width             = width - 15;
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride, input += in_stride &gt;&gt; 1)
   {
      uint8_t *out = output;
      int   w = 0;

#if defined(__SSE2__)
      for (; w &lt; max_width; w += 16, out += 48)
      {
         __m128i res_lo_bg0, res_lo_bg1, res_hi_bg0, res_hi_bg1,
                 res_lo_ra0, res_lo_ra1, res_hi_ra0, res_hi_ra1,
                 res_lo0, res_lo1, res_hi0, res_hi1;
         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w + 0));
         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));
         __m128i r0        = _mm_and_si128(in0, pix_mask_r);
         __m128i r1        = _mm_and_si128(in1, pix_mask_r);
         __m128i g0        = _mm_and_si128(in0, pix_mask_gb);
         __m128i g1        = _mm_and_si128(in1, pix_mask_gb);
         __m128i b0        = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_gb);
         __m128i b1        = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_gb);

         r0                = _mm_mulhi_epi16(r0, mul15_hi);
         r1                = _mm_mulhi_epi16(r1, mul15_hi);
         g0                = _mm_mulhi_epi16(g0, mul15_mid);
         g1                = _mm_mulhi_epi16(g1, mul15_mid);
         b0                = _mm_mulhi_epi16(b0, mul15_mid);
         b1                = _mm_mulhi_epi16(b1, mul15_mid);

         res_lo_bg0        = _mm_unpacklo_epi8(b0, g0);
         res_lo_bg1        = _mm_unpacklo_epi8(b1, g1);
         res_hi_bg0        = _mm_unpackhi_epi8(b0, g0);
         res_hi_bg1        = _mm_unpackhi_epi8(b1, g1);
         res_lo_ra0        = _mm_unpacklo_epi8(r0, a);
         res_lo_ra1        = _mm_unpacklo_epi8(r1, a);
         res_hi_ra0        = _mm_unpackhi_epi8(r0, a);
         res_hi_ra1        = _mm_unpackhi_epi8(r1, a);

         res_lo0           = _mm_or_si128(res_lo_bg0,
               _mm_slli_si128(res_lo_ra0, 2));
         res_lo1           = _mm_or_si128(res_lo_bg1,
               _mm_slli_si128(res_lo_ra1, 2));
         res_hi0           = _mm_or_si128(res_hi_bg0,
               _mm_slli_si128(res_hi_ra0, 2));
         res_hi1           = _mm_or_si128(res_hi_bg1,
               _mm_slli_si128(res_hi_ra1, 2));

         /* Non-POT pixel sizes for the loss */
         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);
      }
#endif

      for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t b   = (col &gt;&gt;  0) &amp; 0x1f;
         uint32_t g   = (col &gt;&gt;  5) &amp; 0x1f;
         uint32_t r   = (col &gt;&gt; 10) &amp; 0x1f;
         b            = (b &lt;&lt; 3) | (b &gt;&gt; 2);
         g            = (g &lt;&lt; 3) | (g &gt;&gt; 2);
         r            = (r &lt;&lt; 3) | (r &gt;&gt; 2);

         *out++       = b;
         *out++       = g;
         *out++       = r;
      }
   }
}

void conv_rgb565_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint16_t *input    = (const uint16_t*)input_;
   uint8_t *output          = (uint8_t*)output_;

#if defined(__SSE2__)
   const __m128i pix_mask_r = _mm_set1_epi16(0x1f &lt;&lt; 10);
   const __m128i pix_mask_g = _mm_set1_epi16(0x3f &lt;&lt;  5);
   const __m128i pix_mask_b = _mm_set1_epi16(0x1f &lt;&lt;  5);
   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
   const __m128i a          = _mm_set1_epi16(0x00ff);

   int max_width            = width - 15;
#endif

   for (h = 0; h &lt; height; h++, output += out_stride, input += in_stride &gt;&gt; 1)
   {
      uint8_t *out = output;
      int        w = 0;
#if defined(__SSE2__)
      for (; w &lt; max_width; w += 16, out += 48)
      {
         __m128i res_lo_bg0, res_hi_bg0, res_lo_ra0, res_hi_ra0;
         __m128i res_lo_bg1, res_hi_bg1, res_lo_ra1, res_hi_ra1;
         __m128i res_lo0, res_hi0, res_lo1, res_hi1;
         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w));
         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));
         __m128i r0 = _mm_and_si128(_mm_srli_epi16(in0, 1), pix_mask_r);
         __m128i g0 = _mm_and_si128(in0, pix_mask_g);
         __m128i b0 = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_b);
         __m128i r1 = _mm_and_si128(_mm_srli_epi16(in1, 1), pix_mask_r);
         __m128i g1 = _mm_and_si128(in1, pix_mask_g);
         __m128i b1 = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_b);

         r0         = _mm_mulhi_epi16(r0, mul16_r);
         g0         = _mm_mulhi_epi16(g0, mul16_g);
         b0         = _mm_mulhi_epi16(b0, mul16_b);
         r1         = _mm_mulhi_epi16(r1, mul16_r);
         g1         = _mm_mulhi_epi16(g1, mul16_g);
         b1         = _mm_mulhi_epi16(b1, mul16_b);

         res_lo_bg0 = _mm_unpacklo_epi8(b0, g0);
         res_hi_bg0 = _mm_unpackhi_epi8(b0, g0);
         res_lo_ra0 = _mm_unpacklo_epi8(r0, a);
         res_hi_ra0 = _mm_unpackhi_epi8(r0, a);
         res_lo_bg1 = _mm_unpacklo_epi8(b1, g1);
         res_hi_bg1 = _mm_unpackhi_epi8(b1, g1);
         res_lo_ra1 = _mm_unpacklo_epi8(r1, a);
         res_hi_ra1 = _mm_unpackhi_epi8(r1, a);

         res_lo0    = _mm_or_si128(res_lo_bg0,
               _mm_slli_si128(res_lo_ra0, 2));
         res_hi0    = _mm_or_si128(res_hi_bg0,
               _mm_slli_si128(res_hi_ra0, 2));
         res_lo1    = _mm_or_si128(res_lo_bg1,
               _mm_slli_si128(res_lo_ra1, 2));
         res_hi1    = _mm_or_si128(res_hi_bg1,
               _mm_slli_si128(res_hi_ra1, 2));

         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);
      }
#endif

      for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint32_t r   = (col &gt;&gt; 11) &amp; 0x1f;
         uint32_t g   = (col &gt;&gt;  5) &amp; 0x3f;
         uint32_t b   = (col &gt;&gt;  0) &amp; 0x1f;
         r = (r &lt;&lt; 3) | (r &gt;&gt; 2);
         g = (g &lt;&lt; 2) | (g &gt;&gt; 4);
         b = (b &lt;&lt; 3) | (b &gt;&gt; 2);

         *out++ = b;
         *out++ = g;
         *out++ = r;
      }
   }
}

void conv_bgr24_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint8_t *input = (const uint8_t*)input_;
   uint32_t *output     = (uint32_t*)output_;

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 2, input += in_stride)
   {
      const uint8_t *inp = input;
      for (w = 0; w &lt; width; w++)
      {
         uint32_t b = *inp++;
         uint32_t g = *inp++;
         uint32_t r = *inp++;
         output[w]  = (0xffu &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | (b &lt;&lt; 0);
      }
   }
}

void conv_bgr24_rgb565(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint8_t *input = (const uint8_t*)input_;
   uint16_t *output     = (uint16_t*)output_;
   for (h = 0; h &lt; height;
         h++, output += out_stride, input += in_stride)
   {
      const uint8_t *inp = input;
      for (w = 0; w &lt; width; w++)
      {
         uint16_t b = *inp++;
         uint16_t g = *inp++;
         uint16_t r = *inp++;

         output[w] = ((r &amp; 0x00F8) &lt;&lt; 8) | ((g&amp;0x00FC) &lt;&lt; 3) | ((b&amp;0x00F8) &gt;&gt; 3);
      }
   }
}

void conv_argb8888_0rgb1555(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint32_t *input = (const uint32_t*)input_;
   uint16_t *output      = (uint16_t*)output_;

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 1, input += in_stride &gt;&gt; 2)
   {
      for (w = 0; w &lt; width; w++)
      {
         uint32_t col = input[w];
         uint16_t r   = (col &gt;&gt; 19) &amp; 0x1f;
         uint16_t g   = (col &gt;&gt; 11) &amp; 0x1f;
         uint16_t b   = (col &gt;&gt;  3) &amp; 0x1f;
         output[w]    = (r &lt;&lt; 10) | (g &lt;&lt; 5) | (b &lt;&lt; 0);
      }
   }
}

void conv_argb8888_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint32_t *input = (const uint32_t*)input_;
   uint8_t *output       = (uint8_t*)output_;

#if defined(__SSE2__)
   int max_width = width - 15;
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride, input += in_stride &gt;&gt; 2)
   {
      uint8_t *out = output;
      int        w = 0;
#if defined(__SSE2__)
      for (; w &lt; max_width; w += 16, out += 48)
      {
         __m128i l0 = _mm_loadu_si128((const __m128i*)(input + w +  0));
         __m128i l1 = _mm_loadu_si128((const __m128i*)(input + w +  4));
         __m128i l2 = _mm_loadu_si128((const __m128i*)(input + w +  8));
         __m128i l3 = _mm_loadu_si128((const __m128i*)(input + w + 12));
         store_bgr24_sse2(out, l0, l1, l2, l3);
      }
#endif

      for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         *out++       = (uint8_t)(col &gt;&gt;  0);
         *out++       = (uint8_t)(col &gt;&gt;  8);
         *out++       = (uint8_t)(col &gt;&gt; 16);
      }
   }
}

#if defined(__SSE2__)
static INLINE __m128i conv_shuffle_rb_epi32(__m128i c)
{
   /* SSSE3 plz */
   const __m128i b_mask = _mm_set1_epi32(0x000000ff);
   const __m128i g_mask = _mm_set1_epi32(0x0000ff00);
   const __m128i r_mask = _mm_set1_epi32(0x00ff0000);
   __m128i sl = _mm_and_si128(_mm_slli_epi32(c, 16), r_mask);
   __m128i sr = _mm_and_si128(_mm_srli_epi32(c, 16), b_mask);
   __m128i g  = _mm_and_si128(c, g_mask);
   __m128i rb = _mm_or_si128(sl, sr);
   return _mm_or_si128(g, rb);
}
#endif

void conv_abgr8888_bgr24(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint32_t *input = (const uint32_t*)input_;
   uint8_t *output       = (uint8_t*)output_;

#if defined(__SSE2__)
   int max_width = width - 15;
#endif

   for (h = 0; h &lt; height;
         h++, output += out_stride, input += in_stride &gt;&gt; 2)
   {
      uint8_t *out = output;
      int        w = 0;
#if defined(__SSE2__)
      for (; w &lt; max_width; w += 16, out += 48)
      {
		 __m128i a = _mm_loadu_si128((const __m128i*)(input + w +  0));
		 __m128i b = _mm_loadu_si128((const __m128i*)(input + w +  4));
		 __m128i c = _mm_loadu_si128((const __m128i*)(input + w +  8));
		 __m128i d = _mm_loadu_si128((const __m128i*)(input + w + 12));
         a = conv_shuffle_rb_epi32(a);
         b = conv_shuffle_rb_epi32(b);
         c = conv_shuffle_rb_epi32(c);
         d = conv_shuffle_rb_epi32(d);
         store_bgr24_sse2(out, a, b, c, d);
      }
#endif

      for (; w &lt; width; w++)
      {
         uint32_t col = input[w];
         *out++       = (uint8_t)(col &gt;&gt; 16);
         *out++       = (uint8_t)(col &gt;&gt;  8);
         *out++       = (uint8_t)(col &gt;&gt;  0);
      }
   }
}

void conv_argb8888_abgr8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h, w;
   const uint32_t *input = (const uint32_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

   for (h = 0; h &lt; height;
         h++, output += out_stride &gt;&gt; 2, input += in_stride &gt;&gt; 2)
   {
      for (w = 0; w &lt; width; w++)
      {
         uint32_t col = input[w];
         output[w]    = ((col &lt;&lt; 16) &amp; 0xff0000) |
            ((col &gt;&gt; 16) &amp; 0xff) | (col &amp; 0xff00ff00);
      }
   }
}

#define YUV_SHIFT 6
#define YUV_OFFSET (1 &lt;&lt; (YUV_SHIFT - 1))
#define YUV_MAT_Y (1 &lt;&lt; 6)
#define YUV_MAT_U_G (-22)
#define YUV_MAT_U_B (113)
#define YUV_MAT_V_R (90)
#define YUV_MAT_V_G (-46)

void conv_yuyv_argb8888(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   const uint8_t *input        = (const uint8_t*)input_;
   uint32_t *output            = (uint32_t*)output_;

#if defined(__SSE2__)
   const __m128i mask_y        = _mm_set1_epi16(0xffu);
   const __m128i mask_u        = _mm_set1_epi32(0xffu &lt;&lt; 8);
   const __m128i mask_v        = _mm_set1_epi32(0xffu &lt;&lt; 24);
   const __m128i chroma_offset = _mm_set1_epi16(128);
   const __m128i round_offset  = _mm_set1_epi16(YUV_OFFSET);

   const __m128i yuv_mul       = _mm_set1_epi16(YUV_MAT_Y);
   const __m128i u_g_mul       = _mm_set1_epi16(YUV_MAT_U_G);
   const __m128i u_b_mul       = _mm_set1_epi16(YUV_MAT_U_B);
   const __m128i v_r_mul       = _mm_set1_epi16(YUV_MAT_V_R);
   const __m128i v_g_mul       = _mm_set1_epi16(YUV_MAT_V_G);
   const __m128i a             = _mm_cmpeq_epi16(
         _mm_setzero_si128(), _mm_setzero_si128());
#endif

   for (h = 0; h &lt; height; h++, output += out_stride &gt;&gt; 2, input += in_stride)
   {
      const uint8_t *src = input;
      uint32_t      *dst = output;
      int              w = 0;

#if defined(__SSE2__)
      /* Each loop processes 16 pixels. */
      for (; w + 16 &lt;= width; w += 16, src += 32, dst += 16)
      {
         __m128i u, v, u0_g, u1_g, u0_b, u1_b, v0_r, v1_r, v0_g, v1_g,
                 r0, g0, b0, r1, g1, b1;
         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
         __m128i res0, res1, res2, res3;
         __m128i yuv0 = _mm_loadu_si128((const __m128i*)(src +  0)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */
         __m128i yuv1 = _mm_loadu_si128((const __m128i*)(src + 16)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */

         __m128i _y0 = _mm_and_si128(yuv0, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */
         __m128i u0 = _mm_and_si128(yuv0, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */
         __m128i v0 = _mm_and_si128(yuv0, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */
         __m128i _y1 = _mm_and_si128(yuv1, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */
         __m128i u1 = _mm_and_si128(yuv1, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */
         __m128i v1 = _mm_and_si128(yuv1, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */

         /* Juggle around to get U and V in the same 16-bit format as Y. */
         u0 = _mm_srli_si128(u0, 1);
         v0 = _mm_srli_si128(v0, 3);
         u1 = _mm_srli_si128(u1, 1);
         v1 = _mm_srli_si128(v1, 3);
         u = _mm_packs_epi32(u0, u1);
         v = _mm_packs_epi32(v0, v1);

         /* Apply YUV offsets (U, V) -= (-128, -128). */
         u = _mm_sub_epi16(u, chroma_offset);
         v = _mm_sub_epi16(v, chroma_offset);

         /* Upscale chroma horizontally (nearest). */
         u0 = _mm_unpacklo_epi16(u, u);
         u1 = _mm_unpackhi_epi16(u, u);
         v0 = _mm_unpacklo_epi16(v, v);
         v1 = _mm_unpackhi_epi16(v, v);

         /* Apply transformations. */
         _y0 = _mm_mullo_epi16(_y0, yuv_mul);
         _y1 = _mm_mullo_epi16(_y1, yuv_mul);
         u0_g   = _mm_mullo_epi16(u0, u_g_mul);
         u1_g   = _mm_mullo_epi16(u1, u_g_mul);
         u0_b   = _mm_mullo_epi16(u0, u_b_mul);
         u1_b   = _mm_mullo_epi16(u1, u_b_mul);
         v0_r   = _mm_mullo_epi16(v0, v_r_mul);
         v1_r   = _mm_mullo_epi16(v1, v_r_mul);
         v0_g   = _mm_mullo_epi16(v0, v_g_mul);
         v1_g   = _mm_mullo_epi16(v1, v_g_mul);

         /* Add contibutions from the transformed components. */
         r0 = _mm_srai_epi16(_mm_adds_epi16(_mm_adds_epi16(_y0, v0_r),
                  round_offset), YUV_SHIFT);
         g0 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_mm_adds_epi16(_y0, v0_g), u0_g), round_offset), YUV_SHIFT);
         b0 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_y0, u0_b), round_offset), YUV_SHIFT);

         r1 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_y1, v1_r), round_offset), YUV_SHIFT);
         g1 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_mm_adds_epi16(_y1, v1_g), u1_g), round_offset), YUV_SHIFT);
         b1 = _mm_srai_epi16(_mm_adds_epi16(
                  _mm_adds_epi16(_y1, u1_b), round_offset), YUV_SHIFT);

         /* Saturate into 8-bit. */
         r0 = _mm_packus_epi16(r0, r1);
         g0 = _mm_packus_epi16(g0, g1);
         b0 = _mm_packus_epi16(b0, b1);

         /* Interleave into ARGB. */
         res_lo_bg = _mm_unpacklo_epi8(b0, g0);
         res_hi_bg = _mm_unpackhi_epi8(b0, g0);
         res_lo_ra = _mm_unpacklo_epi8(r0, a);
         res_hi_ra = _mm_unpackhi_epi8(r0, a);
         res0 = _mm_unpacklo_epi16(res_lo_bg, res_lo_ra);
         res1 = _mm_unpackhi_epi16(res_lo_bg, res_lo_ra);
         res2 = _mm_unpacklo_epi16(res_hi_bg, res_hi_ra);
         res3 = _mm_unpackhi_epi16(res_hi_bg, res_hi_ra);

         _mm_storeu_si128((__m128i*)(dst +  0), res0);
         _mm_storeu_si128((__m128i*)(dst +  4), res1);
         _mm_storeu_si128((__m128i*)(dst +  8), res2);
         _mm_storeu_si128((__m128i*)(dst + 12), res3);
      }
#endif

      /* Finish off the rest (if any) in C. */
      for (; w &lt; width; w += 2, src += 4, dst += 2)
      {
         int _y0    = src[0];
         int  u     = src[1] - 128;
         int _y1    = src[2];
         int  v     = src[3] - 128;

         uint8_t r0 = clamp_8bit((YUV_MAT_Y * _y0 +                   YUV_MAT_V_R * v + YUV_OFFSET) &gt;&gt; YUV_SHIFT);
         uint8_t g0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) &gt;&gt; YUV_SHIFT);
         uint8_t b0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_B * u                   + YUV_OFFSET) &gt;&gt; YUV_SHIFT);

         uint8_t r1 = clamp_8bit((YUV_MAT_Y * _y1 +                   YUV_MAT_V_R * v + YUV_OFFSET) &gt;&gt; YUV_SHIFT);
         uint8_t g1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) &gt;&gt; YUV_SHIFT);
         uint8_t b1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_B * u                   + YUV_OFFSET) &gt;&gt; YUV_SHIFT);

         dst[0]     = 0xff000000u | (r0 &lt;&lt; 16) | (g0 &lt;&lt; 8) | (b0 &lt;&lt; 0);
         dst[1]     = 0xff000000u | (r1 &lt;&lt; 16) | (g1 &lt;&lt; 8) | (b1 &lt;&lt; 0);
      }
   }
}

void conv_copy(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride)
{
   int h;
   int copy_len         = abs(out_stride);
   const uint8_t *input = (const uint8_t*)input_;
   uint8_t *output      = (uint8_t*)output_;

   if (abs(in_stride) &lt; copy_len)
      copy_len          = abs(in_stride);

   for (h = 0; h &lt; height;
         h++, output += out_stride, input += in_stride)
      memcpy(output, input, copy_len);
}</pre>
<h2>./include/libretro-common/gfx/scaler/scaler.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;math.h&gt;

#include &lt;gfx/scaler/scaler.h&gt;
#include &lt;gfx/scaler/scaler_int.h&gt;
#include &lt;gfx/scaler/filter.h&gt;
#include &lt;gfx/scaler/pixconv.h&gt;

static bool allocate_frames(struct scaler_ctx *ctx)
{
   uint64_t *scaled_frame = NULL;
   ctx-&gt;scaled.stride     = ((ctx-&gt;out_width + 7) &amp; ~7) * sizeof(uint64_t);
   ctx-&gt;scaled.width      = ctx-&gt;out_width;
   ctx-&gt;scaled.height     = ctx-&gt;in_height;
   scaled_frame           = (uint64_t*)calloc(
            (ctx-&gt;scaled.stride * ctx-&gt;scaled.height) &gt;&gt; 3,
            sizeof(uint64_t));

   if (!scaled_frame)
      return false;

   ctx-&gt;scaled.frame      = scaled_frame;

   if (ctx-&gt;in_fmt != SCALER_FMT_ARGB8888)
   {
      uint32_t *input_frame = NULL;
      ctx-&gt;input.stride     = ((ctx-&gt;in_width + 7) &amp; ~7) * sizeof(uint32_t);
      input_frame           = (uint32_t*)calloc(
               (ctx-&gt;input.stride * ctx-&gt;in_height) &gt;&gt; 2,
               sizeof(uint32_t));

      if (!input_frame)
         return false;

      ctx-&gt;input.frame      = input_frame;
   }

   if (ctx-&gt;out_fmt != SCALER_FMT_ARGB8888)
   {
      uint32_t *output_frame = NULL;
      ctx-&gt;output.stride     = ((ctx-&gt;out_width + 7) &amp; ~7) * sizeof(uint32_t);

      output_frame           = (uint32_t*)calloc(
               (ctx-&gt;output.stride * ctx-&gt;out_height) &gt;&gt; 2,
               sizeof(uint32_t));

      if (!output_frame)
         return false;

      ctx-&gt;output.frame      = output_frame;
   }

   return true;
}

bool scaler_ctx_gen_filter(struct scaler_ctx *ctx)
{
   scaler_ctx_gen_reset(ctx);

   ctx-&gt;scaler_special = NULL;
   ctx-&gt;unscaled       = false;

   if (!allocate_frames(ctx))
      return false;

   if (     ctx-&gt;in_width  == ctx-&gt;out_width
         &amp;&amp; ctx-&gt;in_height == ctx-&gt;out_height)
   {
      ctx-&gt;unscaled     = true; /* Only pixel format conversion ... */

      if (ctx-&gt;in_fmt == ctx-&gt;out_fmt)
         ctx-&gt;direct_pixconv = conv_copy;
      else
      {
         /* Bind a pixel converter callback function to the
          * 'direct_pixconv' function pointer of the scaler context object. */
         switch (ctx-&gt;in_fmt)
         {
            case SCALER_FMT_0RGB1555:
               switch (ctx-&gt;out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx-&gt;direct_pixconv = conv_0rgb1555_argb8888;
                     break;
                  case SCALER_FMT_RGB565:
                     ctx-&gt;direct_pixconv = conv_0rgb1555_rgb565;
                     break;
                  case SCALER_FMT_BGR24:
                     ctx-&gt;direct_pixconv = conv_0rgb1555_bgr24;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_RGB565:
               switch (ctx-&gt;out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx-&gt;direct_pixconv = conv_rgb565_argb8888;
                     break;
                  case SCALER_FMT_ABGR8888:
                     ctx-&gt;direct_pixconv = conv_rgb565_abgr8888;
                     break;
                  case SCALER_FMT_BGR24:
                     ctx-&gt;direct_pixconv = conv_rgb565_bgr24;
                     break;
                  case SCALER_FMT_0RGB1555:
                     ctx-&gt;direct_pixconv = conv_rgb565_0rgb1555;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_BGR24:
               switch (ctx-&gt;out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx-&gt;direct_pixconv = conv_bgr24_argb8888;
                     break;
                  case SCALER_FMT_RGB565:
                     ctx-&gt;direct_pixconv = conv_bgr24_rgb565;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_ARGB8888:
               switch (ctx-&gt;out_fmt)
               {
                  case SCALER_FMT_0RGB1555:
                     ctx-&gt;direct_pixconv = conv_argb8888_0rgb1555;
                     break;
                  case SCALER_FMT_BGR24:
                     ctx-&gt;direct_pixconv = conv_argb8888_bgr24;
                     break;
                  case SCALER_FMT_ABGR8888:
                     ctx-&gt;direct_pixconv = conv_argb8888_abgr8888;
                     break;
                  case SCALER_FMT_RGBA4444:
                     ctx-&gt;direct_pixconv = conv_argb8888_rgba4444;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_YUYV:
               switch (ctx-&gt;out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx-&gt;direct_pixconv = conv_yuyv_argb8888;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_RGBA4444:
               switch (ctx-&gt;out_fmt)
               {
                  case SCALER_FMT_ARGB8888:
                     ctx-&gt;direct_pixconv = conv_rgba4444_argb8888;
                     break;
                  case SCALER_FMT_RGB565:
                     ctx-&gt;direct_pixconv = conv_rgba4444_rgb565;
                     break;
                  default:
                     break;
               }
               break;
            case SCALER_FMT_ABGR8888:
               switch (ctx-&gt;out_fmt)
               {
                  case SCALER_FMT_BGR24:
                     ctx-&gt;direct_pixconv = conv_abgr8888_bgr24;
                     break;
                  default:
                     break;
               }
               break;
         }

         if (!ctx-&gt;direct_pixconv)
            return false;
      }
   }
   else
   {
      ctx-&gt;scaler_horiz = scaler_argb8888_horiz;
      ctx-&gt;scaler_vert  = scaler_argb8888_vert;

      switch (ctx-&gt;in_fmt)
      {
         case SCALER_FMT_ARGB8888:
            /* No need to convert :D */
            break;

         case SCALER_FMT_0RGB1555:
            ctx-&gt;in_pixconv = conv_0rgb1555_argb8888;
            break;

         case SCALER_FMT_RGB565:
            ctx-&gt;in_pixconv = conv_rgb565_argb8888;
            break;

         case SCALER_FMT_BGR24:
            ctx-&gt;in_pixconv = conv_bgr24_argb8888;
            break;

         case SCALER_FMT_RGBA4444:
            ctx-&gt;in_pixconv = conv_rgba4444_argb8888;
            break;

         default:
            return false;
      }

      switch (ctx-&gt;out_fmt)
      {
         case SCALER_FMT_ARGB8888:
            /* No need to convert :D */
            break;

         case SCALER_FMT_RGBA4444:
            ctx-&gt;out_pixconv = conv_argb8888_rgba4444;
            break;

         case SCALER_FMT_0RGB1555:
            ctx-&gt;out_pixconv = conv_argb8888_0rgb1555;
            break;

         case SCALER_FMT_BGR24:
            ctx-&gt;out_pixconv = conv_argb8888_bgr24;
            break;

         case SCALER_FMT_ABGR8888:
            ctx-&gt;out_pixconv = conv_argb8888_abgr8888;
            break;

         default:
            return false;
      }

      if (!scaler_gen_filter(ctx))
         return false;
   }

   return true;
}

void scaler_ctx_gen_reset(struct scaler_ctx *ctx)
{
   if (ctx-&gt;horiz.filter)
      free(ctx-&gt;horiz.filter);
   if (ctx-&gt;horiz.filter_pos)
      free(ctx-&gt;horiz.filter_pos);
   if (ctx-&gt;vert.filter)
      free(ctx-&gt;vert.filter);
   if (ctx-&gt;vert.filter_pos)
      free(ctx-&gt;vert.filter_pos);
   if (ctx-&gt;scaled.frame)
      free(ctx-&gt;scaled.frame);
   if (ctx-&gt;input.frame)
      free(ctx-&gt;input.frame);
   if (ctx-&gt;output.frame)
      free(ctx-&gt;output.frame);

   ctx-&gt;horiz.filter        = NULL;
   ctx-&gt;horiz.filter_len    = 0;
   ctx-&gt;horiz.filter_stride = 0;
   ctx-&gt;horiz.filter_pos    = NULL;

   ctx-&gt;vert.filter         = NULL;
   ctx-&gt;vert.filter_len     = 0;
   ctx-&gt;vert.filter_stride  = 0;
   ctx-&gt;vert.filter_pos     = NULL;

   ctx-&gt;scaled.frame        = NULL;
   ctx-&gt;scaled.width        = 0;
   ctx-&gt;scaled.height       = 0;
   ctx-&gt;scaled.stride       = 0;

   ctx-&gt;input.frame         = NULL;
   ctx-&gt;input.stride        = 0;

   ctx-&gt;output.frame        = NULL;
   ctx-&gt;output.stride       = 0;
}

/**
 * scaler_ctx_scale:
 * @ctx          : pointer to scaler context object.
 * @output       : pointer to output image.
 * @input        : pointer to input image.
 *
 * Scales an input image to an output image.
 **/
void scaler_ctx_scale(struct scaler_ctx *ctx,
      void *output, const void *input)
{
   const void *input_frame = input;
   void *output_frame      = output;
   int input_stride        = ctx-&gt;in_stride;
   int output_stride       = ctx-&gt;out_stride;

   if (ctx-&gt;in_fmt != SCALER_FMT_ARGB8888)
   {
      ctx-&gt;in_pixconv(ctx-&gt;input.frame, input,
            ctx-&gt;in_width, ctx-&gt;in_height,
            ctx-&gt;input.stride, ctx-&gt;in_stride);

      input_frame       = ctx-&gt;input.frame;
      input_stride      = ctx-&gt;input.stride;
   }

   if (ctx-&gt;out_fmt != SCALER_FMT_ARGB8888)
   {
      output_frame  = ctx-&gt;output.frame;
      output_stride = ctx-&gt;output.stride;
   }

   /* Take some special, and (hopefully) more optimized path. */
   if (ctx-&gt;scaler_special)
      ctx-&gt;scaler_special(ctx, output_frame, input_frame,
            ctx-&gt;out_width, ctx-&gt;out_height,
            ctx-&gt;in_width, ctx-&gt;in_height,
            output_stride, input_stride);
   else
   {
      /* Take generic filter path. */
      if (ctx-&gt;scaler_horiz)
         ctx-&gt;scaler_horiz(ctx, input_frame, input_stride);
      if (ctx-&gt;scaler_vert)
         ctx-&gt;scaler_vert (ctx, output, output_stride);
   }

   if (ctx-&gt;out_fmt != SCALER_FMT_ARGB8888)
      ctx-&gt;out_pixconv(output, ctx-&gt;output.frame,
            ctx-&gt;out_width, ctx-&gt;out_height,
            ctx-&gt;out_stride, ctx-&gt;output.stride);
}</pre>
<h2>./include/libretro-common/gfx/scaler/scaler_filter.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler_filter.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#include &lt;gfx/scaler/filter.h&gt;
#include &lt;gfx/scaler/scaler_int.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;filters.h&gt;
#include &lt;retro_math.h&gt;

#define FILTER_UNITY (1 &lt;&lt; 14)

static INLINE void gen_filter_point_sub(struct scaler_filter *filter,
      int len, int pos, int step)
{
   int i;
   for (i = 0; i &lt; len; i++, pos += step)
   {
      filter-&gt;filter_pos[i] = pos &gt;&gt; 16;
      filter-&gt;filter[i]     = FILTER_UNITY;
   }
}

static INLINE void gen_filter_bilinear_sub(struct scaler_filter *filter,
      int len, int pos, int step)
{
   int i;
   for (i = 0; i &lt; len; i++, pos += step)
   {
      filter-&gt;filter_pos[i]     = pos &gt;&gt; 16;
      filter-&gt;filter[i * 2 + 1] = (pos &amp; 0xffff) &gt;&gt; 2;
      filter-&gt;filter[i * 2 + 0] = FILTER_UNITY - filter-&gt;filter[i * 2 + 1];
   }
}

static INLINE void gen_filter_sinc_sub(struct scaler_filter *filter,
      int len, int pos, int step, double phase_mul)
{
   int i, j;
   const int sinc_size = filter-&gt;filter_len;

   for (i = 0; i &lt; len; i++, pos += step)
   {
      filter-&gt;filter_pos[i] = pos &gt;&gt; 16;

      for (j = 0; j &lt; sinc_size; j++)
      {
         double sinc_phase    = M_PI * ((double)((sinc_size &lt;&lt; 15) + (pos &amp; 0xffff)) / 0x10000 - j);
         double lanczos_phase = sinc_phase / ((sinc_size &gt;&gt; 1));
         int16_t sinc_val     = FILTER_UNITY * sinc(sinc_phase * phase_mul) * sinc(lanczos_phase) * phase_mul;

         filter-&gt;filter[i * sinc_size + j] = sinc_val;
      }
   }
}

static bool validate_filter(struct scaler_ctx *ctx)
{
   int i;
   int max_h_pos;
   int max_w_pos = ctx-&gt;in_width - ctx-&gt;horiz.filter_len;

   for (i = 0; i &lt; ctx-&gt;out_width; i++)
   {
      if (ctx-&gt;horiz.filter_pos[i] &gt; max_w_pos || ctx-&gt;horiz.filter_pos[i] &lt; 0)
         return false;
   }

   max_h_pos = ctx-&gt;in_height - ctx-&gt;vert.filter_len;

   for (i = 0; i &lt; ctx-&gt;out_height; i++)
   {
      if (ctx-&gt;vert.filter_pos[i] &gt; max_h_pos || ctx-&gt;vert.filter_pos[i] &lt; 0)
         return false;
   }

   return true;
}

static void fixup_filter_sub(struct scaler_filter *filter,
      int out_len, int in_len)
{
   int i;
   int max_pos = in_len - filter-&gt;filter_len;

   for (i = 0; i &lt; out_len; i++)
   {
      int postsample =  filter-&gt;filter_pos[i] - max_pos;
      int presample  = -filter-&gt;filter_pos[i];

      if (postsample &gt; 0)
      {
         int16_t *base_filter   = NULL;

         filter-&gt;filter_pos[i] -= postsample;

         base_filter            = filter-&gt;filter + i * filter-&gt;filter_stride;

         if (postsample &gt; (int)filter-&gt;filter_len)
            memset(base_filter, 0, filter-&gt;filter_len * sizeof(int16_t));
         else
         {
            memmove(base_filter + postsample, base_filter,
                  (filter-&gt;filter_len - postsample) * sizeof(int16_t));
            memset(base_filter, 0, postsample * sizeof(int16_t));
         }
      }

      if (presample &gt; 0)
      {
         int16_t *base_filter   = NULL;

         filter-&gt;filter_pos[i] += presample;
         base_filter            = filter-&gt;filter + i * filter-&gt;filter_stride;

         if (presample &gt; (int)filter-&gt;filter_len)
            memset(base_filter, 0, filter-&gt;filter_len * sizeof(int16_t));
         else
         {
            memmove(base_filter, base_filter + presample,
                  (filter-&gt;filter_len - presample) * sizeof(int16_t));
            memset(base_filter + (filter-&gt;filter_len - presample),
                  0, presample * sizeof(int16_t));
         }
      }
   }
}

bool scaler_gen_filter(struct scaler_ctx *ctx)
{
   int x_pos, x_step, y_pos, y_step;
   int sinc_size = 0;

   switch (ctx-&gt;scaler_type)
   {
      case SCALER_TYPE_POINT:
         ctx-&gt;horiz.filter_len    = 1;
         ctx-&gt;horiz.filter_stride = 1;
         ctx-&gt;vert.filter_len     = 1;
         ctx-&gt;vert.filter_stride  = 1;
         break;
      case SCALER_TYPE_BILINEAR:
         ctx-&gt;horiz.filter_len    = 2;
         ctx-&gt;horiz.filter_stride = 2;
         ctx-&gt;vert.filter_len     = 2;
         ctx-&gt;vert.filter_stride  = 2;
         break;
      case SCALER_TYPE_SINC:
         sinc_size                = 8 * ((ctx-&gt;in_width &gt; ctx-&gt;out_width)
               ? next_pow2(ctx-&gt;in_width / ctx-&gt;out_width) : 1);
         ctx-&gt;horiz.filter_len    = sinc_size;
         ctx-&gt;horiz.filter_stride = sinc_size;
         ctx-&gt;vert.filter_len     = sinc_size;
         ctx-&gt;vert.filter_stride  = sinc_size;
         break;
      case SCALER_TYPE_UNKNOWN:
      default:
         return false;
   }

   ctx-&gt;horiz.filter     = (int16_t*)calloc(ctx-&gt;horiz.filter_stride * ctx-&gt;out_width, sizeof(int16_t));
   ctx-&gt;horiz.filter_pos = (int*)calloc(ctx-&gt;out_width, sizeof(int));

   ctx-&gt;vert.filter      = (int16_t*)calloc(ctx-&gt;vert.filter_stride * ctx-&gt;out_height, sizeof(int16_t));
   ctx-&gt;vert.filter_pos  = (int*)calloc(ctx-&gt;out_height, sizeof(int));

   if (!ctx-&gt;horiz.filter || !ctx-&gt;vert.filter)
      return false;

   x_step = (1 &lt;&lt; 16) * ctx-&gt;in_width  / ctx-&gt;out_width;
   y_step = (1 &lt;&lt; 16) * ctx-&gt;in_height / ctx-&gt;out_height;
   x_pos  = (1 &lt;&lt; 15) * ctx-&gt;in_width  / ctx-&gt;out_width  - (1 &lt;&lt; 15);
   y_pos  = (1 &lt;&lt; 15) * ctx-&gt;in_height / ctx-&gt;out_height - (1 &lt;&lt; 15);

   switch (ctx-&gt;scaler_type)
   {
      case SCALER_TYPE_POINT:
         gen_filter_point_sub(&amp;ctx-&gt;horiz, ctx-&gt;out_width,  x_pos, x_step);
         gen_filter_point_sub(&amp;ctx-&gt;vert,  ctx-&gt;out_height, y_pos, y_step);

         ctx-&gt;scaler_special = scaler_argb8888_point_special;
         break;

      case SCALER_TYPE_BILINEAR:
         gen_filter_bilinear_sub(&amp;ctx-&gt;horiz, ctx-&gt;out_width,  x_pos, x_step);
         gen_filter_bilinear_sub(&amp;ctx-&gt;vert,  ctx-&gt;out_height, y_pos, y_step);
         break;

      case SCALER_TYPE_SINC:
         /* Need to expand the filter when downsampling
          * to get a proper low-pass effect. */
         x_pos  -= (sinc_size &lt;&lt; 15);
         y_pos  -= (sinc_size &lt;&lt; 15);

         gen_filter_sinc_sub(&amp;ctx-&gt;horiz, ctx-&gt;out_width, x_pos, x_step,
               ctx-&gt;in_width  &gt; ctx-&gt;out_width  ? (double)ctx-&gt;out_width  / ctx-&gt;in_width  : 1.0);
         gen_filter_sinc_sub(&amp;ctx-&gt;vert, ctx-&gt;out_height, y_pos, y_step,
               ctx-&gt;in_height &gt; ctx-&gt;out_height ? (double)ctx-&gt;out_height / ctx-&gt;in_height : 1.0
               );
         break;
      case SCALER_TYPE_UNKNOWN:
         break;
   }

   /* Makes sure that we never sample outside our rectangle */
   fixup_filter_sub(&amp;ctx-&gt;horiz, ctx-&gt;out_width,  ctx-&gt;in_width);
   fixup_filter_sub(&amp;ctx-&gt;vert,  ctx-&gt;out_height, ctx-&gt;in_height);

   return validate_filter(ctx);
}</pre>
<h2>./include/libretro-common/gfx/scaler/scaler_int.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler_int.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;gfx/scaler/scaler_int.h&gt;

#include &lt;retro_inline.h&gt;

#ifdef SCALER_NO_SIMD
#undef __SSE2__
#endif

#if defined(__SSE2__)
#include &lt;emmintrin.h&gt;
#ifdef _WIN32
#include &lt;intrin.h&gt;
#endif
#endif

/* ARGB8888 scaler is split in two:
 *
 * First, horizontal scaler is applied.
 * Here, all 8-bit channels are expanded to 16-bit. Values are then shifted 7
 * to left to occupy 15 bits.
 *
 * The sign bit is kept empty as we have to do signed multiplication for the
 * filter.
 *
 * A mulhi [(a * b) &gt;&gt; 16] is applied which loses some precision, but is
 * very efficient for SIMD.
 * It is accurate enough for 8-bit purposes.
 *
 * The fixed point 1.0 for filter is (1 &lt;&lt; 14). After horizontal scale,
 * the output is kept with 16-bit channels, and will now have 13 bits
 * of precision as [(a * (1 &lt;&lt; 14)) &gt;&gt; 16] is effectively a right shift by 2.
 *
 * Vertical scaler takes the 13 bit channels, and performs the
 * same mulhi steps.
 * Another 2 bits of precision is lost, which ends up as 11 bits.
 * Scaling is now complete. Channels are shifted right by 3, and saturated
 * into 8-bit values.
 *
 * The C version of scalers perform the exact same operations as the
 * SIMD code for testing purposes.
 */

void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)
{
   int h, w, y;
   const uint64_t      *input = ctx-&gt;scaled.frame;
   uint32_t           *output = (uint32_t*)output_;

   const int16_t *filter_vert = ctx-&gt;vert.filter;

   for (h = 0; h &lt; ctx-&gt;out_height; h++,
         filter_vert += ctx-&gt;vert.filter_stride, output += stride &gt;&gt; 2)
   {
      const uint64_t *input_base = input + ctx-&gt;vert.filter_pos[h]
         * (ctx-&gt;scaled.stride &gt;&gt; 3);

      for (w = 0; w &lt; ctx-&gt;out_width; w++)
      {
         const uint64_t *input_base_y = input_base + w;
#if defined(__SSE2__)
         __m128i final;
         __m128i res = _mm_setzero_si128();

         for (y = 0; (y + 1) &lt; ctx-&gt;vert.filter_len; y += 2,
               input_base_y += (ctx-&gt;scaled.stride &gt;&gt; 2))
         {
            __m128i coeff = _mm_set_epi64x(filter_vert[y + 1] * 0x0001000100010001ll, filter_vert[y + 0] * 0x0001000100010001ll);
            __m128i col   = _mm_set_epi64x(input_base_y[ctx-&gt;scaled.stride &gt;&gt; 3], input_base_y[0]);

            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         for (; y &lt; ctx-&gt;vert.filter_len; y++, input_base_y += (ctx-&gt;scaled.stride &gt;&gt; 3))
         {
            __m128i coeff = _mm_set_epi64x(0, filter_vert[y] * 0x0001000100010001ll);
            __m128i col   = _mm_set_epi64x(0, input_base_y[0]);

            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         res       = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
         res       = _mm_srai_epi16(res, (7 - 2 - 2));

         final     = _mm_packus_epi16(res, res);

         output[w] = _mm_cvtsi128_si32(final);
#else
         int16_t res_a = 0;
         int16_t res_r = 0;
         int16_t res_g = 0;
         int16_t res_b = 0;

         for (y = 0; y &lt; ctx-&gt;vert.filter_len; y++,
               input_base_y += (ctx-&gt;scaled.stride &gt;&gt; 3))
         {
            uint64_t col   = *input_base_y;

            int16_t a      = (col &gt;&gt; 48) &amp; 0xffff;
            int16_t r      = (col &gt;&gt; 32) &amp; 0xffff;
            int16_t g      = (col &gt;&gt; 16) &amp; 0xffff;
            int16_t b      = (col &gt;&gt;  0) &amp; 0xffff;

            int16_t coeff  = filter_vert[y];

            res_a         += (a * coeff) &gt;&gt; 16;
            res_r         += (r * coeff) &gt;&gt; 16;
            res_g         += (g * coeff) &gt;&gt; 16;
            res_b         += (b * coeff) &gt;&gt; 16;
         }

         res_a           &gt;&gt;= (7 - 2 - 2);
         res_r           &gt;&gt;= (7 - 2 - 2);
         res_g           &gt;&gt;= (7 - 2 - 2);
         res_b           &gt;&gt;= (7 - 2 - 2);

         output[w]         =
            (clamp_8bit(res_a) &lt;&lt; 24) |
            (clamp_8bit(res_r) &lt;&lt; 16) |
            (clamp_8bit(res_g) &lt;&lt; 8)  |
            (clamp_8bit(res_b) &lt;&lt; 0);
#endif
      }
   }
}

void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)
{
   int h, w, x;
   const uint32_t *input = (uint32_t*)input_;
   uint64_t *output      = ctx-&gt;scaled.frame;

   for (h = 0; h &lt; ctx-&gt;scaled.height; h++, input += stride &gt;&gt; 2,
         output += ctx-&gt;scaled.stride &gt;&gt; 3)
   {
      const int16_t *filter_horiz = ctx-&gt;horiz.filter;

      for (w = 0; w &lt; ctx-&gt;scaled.width; w++,
            filter_horiz += ctx-&gt;horiz.filter_stride)
      {
         const uint32_t *input_base_x = input + ctx-&gt;horiz.filter_pos[w];
#if defined(__SSE2__)
         __m128i res = _mm_setzero_si128();
#ifndef __x86_64__
         union
         {
            uint32_t *u32;
            uint64_t *u64;
         } u;
#endif
         for (x = 0; (x + 1) &lt; ctx-&gt;horiz.filter_len; x += 2)
         {
            __m128i coeff = _mm_set_epi64x(filter_horiz[x + 1] * 0x0001000100010001ll, filter_horiz[x + 0] * 0x0001000100010001ll);

            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi64x(0,
                     ((uint64_t)input_base_x[x + 1] &lt;&lt; 32) | input_base_x[x + 0]), _mm_setzero_si128());

            col           = _mm_slli_epi16(col, 7);
            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         for (; x &lt; ctx-&gt;horiz.filter_len; x++)
         {
            __m128i coeff = _mm_set_epi64x(0, filter_horiz[x] * 0x0001000100010001ll);
            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi32(0, 0, 0, input_base_x[x]), _mm_setzero_si128());

            col           = _mm_slli_epi16(col, 7);
            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
         }

         res              = _mm_adds_epi16(_mm_srli_si128(res, 8), res);

#ifdef __x86_64__
         output[w]        = _mm_cvtsi128_si64(res);
#else /* 32-bit doesn't have si64. Do it in two steps. */
         u.u64    = output + w;
         u.u32[0] = _mm_cvtsi128_si32(res);
         u.u32[1] = _mm_cvtsi128_si32(_mm_srli_si128(res, 4));
#endif
#else
         int16_t res_a = 0;
         int16_t res_r = 0;
         int16_t res_g = 0;
         int16_t res_b = 0;

         for (x = 0; x &lt; ctx-&gt;horiz.filter_len; x++)
         {
            uint32_t col   = input_base_x[x];

            int16_t a      = (col &gt;&gt; (24 - 7)) &amp; (0xff &lt;&lt; 7);
            int16_t r      = (col &gt;&gt; (16 - 7)) &amp; (0xff &lt;&lt; 7);
            int16_t g      = (col &gt;&gt; ( 8 - 7)) &amp; (0xff &lt;&lt; 7);
            int16_t b      = (col &lt;&lt; ( 0 + 7)) &amp; (0xff &lt;&lt; 7);

            int16_t coeff  = filter_horiz[x];

            res_a         += (a * coeff) &gt;&gt; 16;
            res_r         += (r * coeff) &gt;&gt; 16;
            res_g         += (g * coeff) &gt;&gt; 16;
            res_b         += (b * coeff) &gt;&gt; 16;
         }

         output[w]         = (
               (uint64_t)res_a  &lt;&lt; 48)  |
               ((uint64_t)res_r &lt;&lt; 32)  |
               ((uint64_t)res_g &lt;&lt; 16)  |
               ((uint64_t)res_b &lt;&lt; 0);
#endif
      }
   }
}

void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
      void *output_, const void *input_,
      int out_width, int out_height,
      int in_width, int in_height,
      int out_stride, int in_stride)
{
   int h, w;
   int x_pos             = (1 &lt;&lt; 15) * in_width / out_width - (1 &lt;&lt; 15);
   int x_step            = (1 &lt;&lt; 16) * in_width / out_width;
   int y_pos             = (1 &lt;&lt; 15) * in_height / out_height - (1 &lt;&lt; 15);
   int y_step            = (1 &lt;&lt; 16) * in_height / out_height;
   const uint32_t *input = (const uint32_t*)input_;
   uint32_t *output      = (uint32_t*)output_;

   if (x_pos &lt; 0)
      x_pos = 0;
   if (y_pos &lt; 0)
      y_pos = 0;

   for (h = 0; h &lt; out_height; h++, y_pos += y_step, output += out_stride &gt;&gt; 2)
   {
      int               x = x_pos;
      const uint32_t *inp = input + (y_pos &gt;&gt; 16) * (in_stride &gt;&gt; 2);

      for (w = 0; w &lt; out_width; w++, x += x_step)
         output[w] = inp[x &gt;&gt; 16];
   }
}</pre>
<h2>./include/libretro-common/.gitignore</h2>
<pre>glsm/
*.[od]
*.dll
*.so
*.dylib
*.exe</pre>
<h2>./include/libretro-common/glsm/glsm.c</h2>
<pre>/* Copyright (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsm).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;glsym/glsym.h&gt;
#include &lt;glsm/glsm.h&gt;

#ifndef GL_DEPTH_CLAMP
#define GL_DEPTH_CLAMP                    0x864F
#define GL_RASTERIZER_DISCARD             0x8C89
#define GL_SAMPLE_MASK                    0x8E51
#endif

#if 0
extern retro_log_printf_t log_cb;
#define GLSM_DEBUG
#endif

struct gl_cached_state
{
   struct
   {
      GLuint *ids;
   } bind_textures;

   struct
   {
      bool used[MAX_ATTRIB];
      GLint size[MAX_ATTRIB];
      GLenum type[MAX_ATTRIB];
      GLboolean normalized[MAX_ATTRIB];
      GLsizei stride[MAX_ATTRIB];
      const GLvoid *pointer[MAX_ATTRIB];
      GLuint buffer[MAX_ATTRIB];
   } attrib_pointer;

#ifndef HAVE_OPENGLES
   GLenum colorlogicop;
#endif

   struct
   {
      bool enabled[MAX_ATTRIB];
   } vertex_attrib_pointer;

   struct
   {
      GLenum pname;
      GLint param;
   } pixelstore_i;

   struct
   {
      GLuint r;
      GLuint g;
      GLuint b;
      GLuint a;
   } clear_color;

   struct
   {
      bool used;
      GLint x;
      GLint y;
      GLsizei w;
      GLsizei h;
   } scissor;

   struct
   {
      GLint x;
      GLint y;
      GLsizei w;
      GLsizei h;
   } viewport;

   struct
   {
      bool used;
      GLenum sfactor;
      GLenum dfactor;
   } blendfunc;

   struct
   {
      bool used;
      GLenum srcRGB;
      GLenum dstRGB;
      GLenum srcAlpha;
      GLenum dstAlpha;
   } blendfunc_separate;

   struct
   {
      bool used;
      GLboolean red;
      GLboolean green;
      GLboolean blue;
      GLboolean alpha;
   } colormask;

   struct
   {
      bool used;
      GLdouble depth;
   } cleardepth;

   struct
   {
      bool used;
      GLenum func;
   } depthfunc;

   struct
   {
      bool used;
      GLclampd zNear;
      GLclampd zFar;
   } depthrange;

   struct
   {
      bool used;
      GLfloat factor;
      GLfloat units;
   } polygonoffset;

   struct
   {
      bool used;
      GLenum func;
      GLint ref;
      GLuint mask;
   } stencilfunc;

   struct
   {
      bool used;
      GLenum sfail;
      GLenum dpfail;
      GLenum dppass;
   } stencilop;

   struct
   {
      bool used;
      GLenum mode;
   } frontface;

   struct
   {
      bool used;
      GLenum mode;
   } cullface;

   struct
   {
      bool used;
      GLuint mask;
   } stencilmask;

   struct
   {
      bool used;
      GLboolean mask;
   } depthmask;

   struct
   {
      GLenum mode;
   } readbuffer;

   GLuint vao;
   GLuint framebuf;
   GLuint array_buffer;
   GLuint program;
   GLenum active_texture;
   int cap_state[SGL_CAP_MAX];
   int cap_translate[SGL_CAP_MAX];
};

static GLuint default_framebuffer;
static GLint glsm_max_textures;
struct retro_hw_render_callback hw_render;
static struct gl_cached_state gl_state;

/* GL wrapper-side */

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
GLenum rglGetError(void)
{
   return glGetError();
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : N/A
 */

void rglProvokingVertex(	GLenum provokeMode)
{
#if defined(HAVE_OPENGL)
   glProvokingVertex(provokeMode);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglGetInteger64v(	GLenum pname, int64_t *data)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGetInteger64v(pname, (GLint64*)data);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglSamplerParameteri(	GLuint sampler,
 	GLenum pname,
 	GLint param)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glSamplerParameteri(sampler, pname, param);
#endif
}

void rglGenSamplers(	GLsizei n,
 	GLuint *samplers)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGenSamplers(n, samplers);
#endif
}

void rglBindSampler(	GLuint unit,
 	GLuint sampler)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glBindSampler(unit, sampler);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglClear(GLbitfield mask)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClear.\n");
#endif
   glClear(mask);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglValidateProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glValidateProgram.\n");
#endif
   glValidateProgram(program);
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 * OpenGLES  : N/A
 */
void rglPolygonMode(GLenum face, GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glPolygonMode.\n");
#endif
#ifndef HAVE_OPENGLES
   glPolygonMode(face, mode);
#endif
}

void rglTexSubImage2D(
      GLenum target,
  	GLint level,
  	GLint xoffset,
  	GLint yoffset,
  	GLsizei width,
  	GLsizei height,
  	GLenum format,
  	GLenum type,
  	const GLvoid * pixels)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexSubImage2D.\n");
#endif
   glTexSubImage2D(target, level, xoffset, yoffset,
         width, height, format, type, pixels);
}

void rglGetBufferSubData(	GLenum target,
 	GLintptr offset,
 	GLsizeiptr size,
 	GLvoid * data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetBufferSubData.\n");
#endif
#if defined(HAVE_OPENGL)
   glGetBufferSubData(target, offset, size, data);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglLineWidth(GLfloat width)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glLineWidth.\n");
#endif
   glLineWidth(width);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglBlitFramebuffer(
      GLint srcX0, GLint srcY0,
      GLint srcX1, GLint srcY1,
      GLint dstX0, GLint dstY0,
      GLint dstX1, GLint dstY1,
      GLbitfield mask, GLenum filter)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlitFramebuffer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
         dstX0, dstY0, dstX1, dstY1,
         mask, filter);
#endif
}

/*
 *
 * Core in:
 * OpenGLES  : 3.0
 */
void rglReadBuffer(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glReadBuffer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glReadBuffer(mode);
   gl_state.readbuffer.mode = mode;
#endif
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglClearDepth(GLdouble depth)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearDepth.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
#ifdef HAVE_OPENGLES
   glClearDepthf(depth);
#else
   glClearDepth(depth);
#endif
   gl_state.cleardepth.used  = true;
   gl_state.cleardepth.depth = depth;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglPixelStorei(GLenum pname, GLint param)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glPixelStorei.\n");
#endif
   glPixelStorei(pname, param);
   gl_state.pixelstore_i.pname = pname;
   gl_state.pixelstore_i.param = param;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglDepthRange(GLclampd zNear, GLclampd zFar)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDepthRange.\n");
#endif
#ifdef HAVE_OPENGLES
   glDepthRangef(zNear, zFar);
#else
   glDepthRange(zNear, zFar);
#endif
   gl_state.depthrange.used  = true;
   gl_state.depthrange.zNear = zNear;
   gl_state.depthrange.zFar  = zFar;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglFrontFace(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFrontFace.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glFrontFace(mode);
   gl_state.frontface.used = true;
   gl_state.frontface.mode = mode;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglDepthFunc(GLenum func)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDepthFunc.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.depthfunc.used = true;
   gl_state.depthfunc.func = func;
   glDepthFunc(func);
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglColorMask(GLboolean red, GLboolean green,
      GLboolean blue, GLboolean alpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glColorMask.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glColorMask(red, green, blue, alpha);
   gl_state.colormask.red   = red;
   gl_state.colormask.green = green;
   gl_state.colormask.blue  = blue;
   gl_state.colormask.alpha = alpha;
   gl_state.colormask.used  = true;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglCullFace(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCullFace.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glCullFace(mode);
   gl_state.cullface.used = true;
   gl_state.cullface.mode = mode;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glStencilOp.\n");
#endif
   glStencilOp(sfail, dpfail, dppass);
   gl_state.stencilop.used   = true;
   gl_state.stencilop.sfail  = sfail;
   gl_state.stencilop.dpfail = dpfail;
   gl_state.stencilop.dppass = dppass;
}

/*
 *
 * Core in:
 * OpenGLES  : 2.0
 */
void rglStencilFunc(GLenum func, GLint ref, GLuint mask)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glStencilFunc.\n");
#endif
   glStencilFunc(func, ref, mask);
   gl_state.stencilfunc.used = true;
   gl_state.stencilfunc.func = func;
   gl_state.stencilfunc.ref  = ref;
   gl_state.stencilfunc.mask = mask;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
GLboolean rglIsEnabled(GLenum cap)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glIsEnabled.\n");
#endif
   return gl_state.cap_state[cap] ? GL_TRUE : GL_FALSE;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglClearColor(GLclampf red, GLclampf green,
      GLclampf blue, GLclampf alpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearColor.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glClearColor(red, green, blue, alpha);
   gl_state.clear_color.r = red;
   gl_state.clear_color.g = green;
   gl_state.clear_color.b = blue;
   gl_state.clear_color.a = alpha;
}

/*
 *
 * Core in:
 * OpenGLES    : 2.0 (maybe earlier?)
 */
void rglScissor(GLint x, GLint y, GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glScissor.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glScissor(x, y, width, height);
   gl_state.scissor.used = true;
   gl_state.scissor.x    = x;
   gl_state.scissor.y    = y;
   gl_state.scissor.w    = width;
   gl_state.scissor.h    = height;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglViewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glViewport.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glViewport(x, y, width, height);
   gl_state.viewport.x = x;
   gl_state.viewport.y = y;
   gl_state.viewport.w = width;
   gl_state.viewport.h = height;
}

void rglBlendFunc(GLenum sfactor, GLenum dfactor)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendFunc.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.blendfunc.used    = true;
   gl_state.blendfunc.sfactor = sfactor;
   gl_state.blendfunc.dfactor = dfactor;
   glBlendFunc(sfactor, dfactor);
}

/*
 * Category: Blending
 *
 * Core in:
 * OpenGL    : 1.4
 */
void rglBlendFuncSeparate(GLenum sfactor, GLenum dfactor)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendFuncSeparate.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.blendfunc_separate.used     = true;
   gl_state.blendfunc_separate.srcRGB   = sfactor;
   gl_state.blendfunc_separate.dstRGB   = dfactor;
   gl_state.blendfunc_separate.srcAlpha = sfactor;
   gl_state.blendfunc_separate.dstAlpha = dfactor;
   glBlendFunc(sfactor, dfactor);
}

/*
 * Category: Textures
 *
 * Core in:
 * OpenGL    : 1.3
 */
void rglActiveTexture(GLenum texture)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glActiveTexture.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glActiveTexture(texture);
   gl_state.active_texture = texture - GL_TEXTURE0;
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglBindTexture(GLenum target, GLuint texture)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindTexture.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glBindTexture(target, texture);
   gl_state.bind_textures.ids[gl_state.active_texture] = texture;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglDisable(GLenum cap)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDisable.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glDisable(gl_state.cap_translate[cap]);
   gl_state.cap_state[cap] = 0;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglEnable(GLenum cap)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glEnable.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glEnable(gl_state.cap_translate[cap]);
   gl_state.cap_state[cap] = 1;
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUseProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUseProgram.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.program = program;
   glUseProgram(program);
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglDepthMask(GLboolean flag)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDepthMask.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glDepthMask(flag);
   gl_state.depthmask.used = true;
   gl_state.depthmask.mask = flag;
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglStencilMask(GLenum mask)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glStencilMask.\n");
#endif
   glStencilMask(mask);
   gl_state.stencilmask.used = true;
   gl_state.stencilmask.mask = mask;
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglBufferData(GLenum target, GLsizeiptr size,
      const GLvoid *data, GLenum usage)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBufferData.\n");
#endif
   glBufferData(target, size, data, usage);
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglBufferSubData(GLenum target, GLintptr offset,
      GLsizeiptr size, const GLvoid *data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBufferSubData.\n");
#endif
   glBufferSubData(target, offset, size, data);
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglBindBuffer(GLenum target, GLuint buffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindBuffer.\n");
#endif
   if (target == GL_ARRAY_BUFFER)
      gl_state.array_buffer = buffer;
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glBindBuffer(target, buffer);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglLinkProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glLinkProgram.\n");
#endif
   glLinkProgram(program);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 2.0
 */
void rglFramebufferTexture2D(GLenum target, GLenum attachment,
      GLenum textarget, GLuint texture, GLint level)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFramebufferTexture2D.\n");
#endif
   glFramebufferTexture2D(target, attachment, textarget, texture, level);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.2
 */
void rglFramebufferTexture(GLenum target, GLenum attachment,
  	GLuint texture, GLint level)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFramebufferTexture.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3_2)
   glFramebufferTexture(target, attachment, texture, level);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglDrawArrays(GLenum mode, GLint first, GLsizei count)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawArrays.\n");
#endif
   glDrawArrays(mode, first, count);
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglDrawElements(GLenum mode, GLsizei count, GLenum type,
                           const GLvoid * indices)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawElements.\n");
#endif
   glDrawElements(mode, count, type, indices);
}

void rglCompressedTexImage2D(GLenum target, GLint level,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLint border, GLsizei imageSize, const GLvoid *data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCompressedTexImage2D.\n");
#endif
   glCompressedTexImage2D(target, level, internalformat,
         width, height, border, imageSize, data);
}

void rglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteFramebuffers.\n");
#endif
   glDeleteFramebuffers(n, framebuffers);
}

void rglDeleteTextures(GLsizei n, const GLuint *textures)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteTextures.\n");
#endif
   glDeleteTextures(n, textures);
}

/*
 *
 * Core in:
 * OpenGLES    : 2.0
 */
void rglRenderbufferStorage(GLenum target, GLenum internalFormat,
      GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glRenderbufferStorage.\n");
#endif
   glRenderbufferStorage(target, internalFormat, width, height);
}

/*
 *
 * Core in:
 *
 * OpenGL      : 3.0
 * OpenGLES    : 2.0
 */
void rglBindRenderbuffer(GLenum target, GLuint renderbuffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindRenderbuffer.\n");
#endif
   glBindRenderbuffer(target, renderbuffer);
}

/*
 *
 * Core in:
 *
 * OpenGLES    : 2.0
 */
void rglDeleteRenderbuffers(GLsizei n, GLuint *renderbuffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteRenderbuffers.\n");
#endif
   glDeleteRenderbuffers(n, renderbuffers);
}

/*
 *
 * Core in:
 *
 * OpenGL      : 3.0
 * OpenGLES    : 2.0
 */
void rglGenRenderbuffers(GLsizei n, GLuint *renderbuffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenRenderbuffers.\n");
#endif
   glGenRenderbuffers(n, renderbuffers);
}

/*
 *
 * Core in:
 *
 * OpenGL      : 3.0
 * OpenGLES    : 2.0
 */
void rglGenerateMipmap(GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenerateMipmap.\n");
#endif
   glGenerateMipmap(target);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 */
GLenum rglCheckFramebufferStatus(GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCheckFramebufferStatus.\n");
#endif
   return glCheckFramebufferStatus(target);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 2.0
 */
void rglFramebufferRenderbuffer(GLenum target, GLenum attachment,
      GLenum renderbuffertarget, GLuint renderbuffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFramebufferRenderbuffer.\n");
#endif
   glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 3.0
 */
void rglBindFragDataLocation(GLuint program, GLuint colorNumber,
                                   const char * name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindFragDataLocation.\n");
#endif
#if !defined(HAVE_OPENGLES2)
   glBindFragDataLocation(program, colorNumber, name);
#endif
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetProgramiv(GLuint shader, GLenum pname, GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetProgramiv.\n");
#endif
   glGetProgramiv(shader, pname, params);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 4.1
 * OpenGLES  : 3.0
 */
void rglProgramParameteri( 	GLuint program,
  	GLenum pname,
  	GLint value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glProgramParameteri.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) &amp;&amp; (defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1))
   glProgramParameteri(program, pname, value);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
      GLsizei *length, GLint *size, GLenum *type, GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetActiveUniform.\n");
#endif
   glGetActiveUniform(program, index, bufsize, length, size, type, name);
}

void rglGenQueries(	GLsizei n,
 	GLuint * ids)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenQueries.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGenQueries(n, ids);
#endif
}

void rglGetQueryObjectuiv(	GLuint id,
 	GLenum pname,
 	GLuint * params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetQueryObjectuiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGetQueryObjectuiv(id, pname, params);
#endif
}

void rglDeleteQueries(	GLsizei n,
 	const GLuint * ids)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteQueries.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glDeleteQueries(n, ids);
#endif
}

void rglBeginQuery(	GLenum target,
 	GLuint id)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBeginQuery.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glBeginQuery(target, id);
#endif
}

void rglEndQuery(	GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glEndQuery.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glEndQuery(target);
#endif
}

/*
 * Category: UBO
 *
 * Core in:
 *
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglGetActiveUniformBlockiv(GLuint program,
  	GLuint uniformBlockIndex,
  	GLenum pname,
  	GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetActiveUniformBlockiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGetActiveUniformBlockiv(program, uniformBlockIndex,
         pname, params);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglGetActiveUniformsiv( 	GLuint program,
  	GLsizei uniformCount,
  	const GLuint *uniformIndices,
  	GLenum pname,
  	GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetActiveUniformsiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGetActiveUniformsiv(program, uniformCount,
         uniformIndices, pname, params);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglGetUniformIndices(GLuint program,
  	GLsizei uniformCount,
  	const GLchar **uniformNames,
  	GLuint *uniformIndices)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetUniformIndices.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGetUniformIndices(program, uniformCount,
         uniformNames, uniformIndices);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 * Category: UBO
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglBindBufferBase( 	GLenum target,
  	GLuint index,
  	GLuint buffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindBufferBase.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glBindBufferBase(target, index, buffer);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Category: UBO
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
GLuint rglGetUniformBlockIndex( 	GLuint program,
  	const GLchar *uniformBlockName)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetUniformBlockIndex.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   return glGetUniformBlockIndex(program, uniformBlockName);
#else
   printf("WARNING! Not implemented.\n");
   return 0;
#endif
}

/*
 * Category: UBO
 *
 * Core in:
 *
 * OpenGLES  : 3.0
 */
void rglUniformBlockBinding( 	GLuint program,
  	GLuint uniformBlockIndex,
  	GLuint uniformBlockBinding)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniformBlockBinding.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glUniformBlockBinding(program, uniformBlockIndex,
         uniformBlockBinding);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform1ui(GLint location, GLuint v)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glUniform1ui(location ,v);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform2ui(GLint location, GLuint v0, GLuint v1)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glUniform2ui(location, v0, v1);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform3ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glUniform3ui(location, v0, v1, v2);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4ui.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glUniform4ui(location, v0, v1, v2, v3);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
      const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniformMatrix4fv.\n");
#endif
   glUniformMatrix4fv(location, count, transpose, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglDetachShader(GLuint program, GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDetachShader.\n");
#endif
   glDetachShader(program, shader);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetShaderiv(GLuint shader, GLenum pname, GLint *params)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetShaderiv.\n");
#endif
   glGetShaderiv(shader, pname, params);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglAttachShader(GLuint program, GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glAttachShader.\n");
#endif
   glAttachShader(program, shader);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLint rglGetAttribLocation(GLuint program, const GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetAttribLocation.\n");
#endif
   return glGetAttribLocation(program, name);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglShaderSource(GLuint shader, GLsizei count,
      const GLchar **string, const GLint *length)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glShaderSource.\n");
#endif
   return glShaderSource(shader, count, string, length);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglCompileShader(GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCompileShader.\n");
#endif
   glCompileShader(shader);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLuint rglCreateProgram(void)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCreateProgram.\n");
#endif
   return glCreateProgram();
}

/*
 *
 * Core in:
 * OpenGL    : 1.1
 */
void rglGenTextures(GLsizei n, GLuint *textures)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenTextures.\n");
#endif
   glGenTextures(n, textures);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetShaderInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetShaderInfoLog.\n");
#endif
   glGetShaderInfoLog(shader, maxLength, length, infoLog);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglGetProgramInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetProgramInfoLog.\n");
#endif
   glGetProgramInfoLog(shader, maxLength, length, infoLog);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLboolean rglIsProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glIsProgram.\n");
#endif
   return glIsProgram(program);
}

void rglTexCoord2f(GLfloat s, GLfloat t)
{
#ifdef HAVE_LEGACY_GL
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexCoord2f.\n");
#endif
   glTexCoord2f(s, t);
#endif
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 *
 */
void rglDisableVertexAttribArray(GLuint index)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDisableVertexAttribArray.\n");
#endif
   gl_state.vertex_attrib_pointer.enabled[index] = 0;
   glDisableVertexAttribArray(index);
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglEnableVertexAttribArray(GLuint index)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glEnableVertexAttribArray.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   gl_state.vertex_attrib_pointer.enabled[index] = 1;
   glEnableVertexAttribArray(index);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttribIPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttribIPointer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glVertexAttribIPointer(index, size, type, stride, pointer);
#endif
}

void rglVertexAttribLPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttribLPointer.\n");
#endif
#if defined(HAVE_OPENGL)
   glVertexAttribLPointer(index, size, type, stride, pointer);
#endif
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttribPointer(GLuint name, GLint size,
      GLenum type, GLboolean normalized, GLsizei stride,
      const GLvoid* pointer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttribPointer.\n");
#endif
   gl_state.attrib_pointer.used[name] = 1;
   gl_state.attrib_pointer.size[name] = size;
   gl_state.attrib_pointer.type[name] = type;
   gl_state.attrib_pointer.normalized[name] = normalized;
   gl_state.attrib_pointer.stride[name] = stride;
   gl_state.attrib_pointer.pointer[name] = pointer;
   gl_state.attrib_pointer.buffer[name] = gl_state.array_buffer;
   glVertexAttribPointer(name, size, type, normalized, stride, pointer);
}

/*
 * Category: Generic vertex attributes
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglBindAttribLocation(GLuint program, GLuint index, const GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindAttribLocation.\n");
#endif
   glBindAttribLocation(program, index, name);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttrib4f(GLuint name, GLfloat x, GLfloat y,
      GLfloat z, GLfloat w)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttrib4f.\n");
#endif
   glVertexAttrib4f(name, x, y, z, w);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglVertexAttrib4fv(GLuint name, GLfloat* v)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glVertexAttrib4fv.\n");
#endif
   glVertexAttrib4fv(name, v);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLuint rglCreateShader(GLenum shaderType)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCreateShader.\n");
#endif
   return glCreateShader(shaderType);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglDeleteProgram(GLuint program)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteProgram.\n");
#endif
   glDeleteProgram(program);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglDeleteShader(GLuint shader)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteShader.\n");
#endif
   glDeleteShader(shader);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
GLint rglGetUniformLocation(GLuint program, const GLchar *name)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetUniformLocation.\n");
#endif
   return glGetUniformLocation(program, name);
}

/*
 * Category: VBO and PBO
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglDeleteBuffers(GLsizei n, const GLuint *buffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteBuffers.\n");
#endif
   glDeleteBuffers(n, buffers);
}

/*
 * Category: VBO and PBO
 *
 * Core in:
 * OpenGL    : 1.5
 */
void rglGenBuffers(GLsizei n, GLuint *buffers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenBuffers.\n");
#endif
   glGenBuffers(n, buffers);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1f(GLint location, GLfloat v0)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1f.\n");
#endif
   glUniform1f(location, v0);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1fv(GLint location,  GLsizei count,  const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1fv.\n");
#endif
   glUniform1fv(location, count, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1iv(GLint location,  GLsizei count,  const GLint *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1iv.\n");
#endif
   glUniform1iv(location, count, value);
}

void rglClearBufferfv( 	GLenum buffer,
  	GLint drawBuffer,
  	const GLfloat * value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearBufferfv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3)
   glClearBufferfv(buffer, drawBuffer, value);
#endif
}

void rglTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexBuffer.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3_2)
   glTexBuffer(target, internalFormat, buffer);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
const GLubyte* rglGetStringi(GLenum name, GLuint index)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetString.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3)
   return glGetStringi(name, index);
#else
   return NULL;
#endif
}

void rglClearBufferfi( 	GLenum buffer,
  	GLint drawBuffer,
  	GLfloat depth,
  	GLint stencil)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClearBufferfi.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3)
   glClearBufferfi(buffer, drawBuffer, depth, stencil);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglRenderbufferStorageMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glRenderbufferStorageMultisample.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3)
   glRenderbufferStorageMultisample(target, samples, internalformat, width, height);
#endif
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform1i(GLint location, GLint v0)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform1i.\n");
#endif
   glUniform1i(location, v0);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform2f(GLint location, GLfloat v0, GLfloat v1)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2f.\n");
#endif
   glUniform2f(location, v0, v1);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform2i(GLint location, GLint v0, GLint v1)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2i.\n");
#endif
   glUniform2i(location, v0, v1);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform2fv(GLint location, GLsizei count, const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2fv.\n");
#endif
   glUniform2fv(location, count, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform3f.\n");
#endif
   glUniform3f(location, v0, v1, v2);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform3fv(GLint location, GLsizei count, const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform3fv.\n");
#endif
   glUniform3fv(location, count, value);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4i.\n");
#endif
   glUniform4i(location, v0, v1, v2, v3);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4f.\n");
#endif
   glUniform4f(location, v0, v1, v2, v3);
}

/*
 * Category: Shaders
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglUniform4fv(GLint location, GLsizei count, const GLfloat *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform4fv.\n");
#endif
   glUniform4fv(location, count, value);
}

/*
 *
 * Core in:
 * OpenGL    : 1.0
 */
void rglPolygonOffset(GLfloat factor, GLfloat units)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glPolygonOffset.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glPolygonOffset(factor, units);
   gl_state.polygonoffset.used   = true;
   gl_state.polygonoffset.factor = factor;
   gl_state.polygonoffset.units  = units;
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 */
void rglGenFramebuffers(GLsizei n, GLuint *ids)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenFramebuffers.\n");
#endif
   glGenFramebuffers(n, ids);
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 3.0
 */
void rglBindFramebuffer(GLenum target, GLuint framebuffer)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindFramebuffer.\n");
#endif
   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
   glBindFramebuffer(target, framebuffer);
   gl_state.framebuf = framebuffer;
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void rglDrawBuffers(GLsizei n, const GLenum *bufs)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawBuffers.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glDrawBuffers(n, bufs);
#endif
}

/*
 * Category: FBO
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.0
 */
void *rglMapBufferRange( 	GLenum target,
  	GLintptr offset,
  	GLsizeiptr length,
  	GLbitfield access)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glMapBufferRange.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   return glMapBufferRange(target, offset, length, access);
#else
   printf("WARNING! Not implemented.\n");
   return NULL;
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.3
 * OpenGLES  : 3.1
 */
void rglTexStorage2DMultisample(GLenum target, GLsizei samples,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLboolean fixedsamplelocations)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexStorage2DMultisample.\n");
#endif
#if defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3_1)
   glTexStorage2DMultisample(target, samples, internalformat,
         width, height, fixedsamplelocations);
#endif
}

/*
 *
 * Core in:
 * OpenGLES  : 3.0
 */
void rglTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
      GLsizei width, GLsizei height)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexStorage2D.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glTexStorage2D(target, levels, internalFormat, width, height);
#endif
}
/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.2
 */
void rglDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex)
{
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3_2)
   glDrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.2
 * OpenGLES  : 3.1
 */
void rglMemoryBarrier( 	GLbitfield barriers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glMemoryBarrier.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3) &amp;&amp; defined(HAVE_OPENGLES_3_1)
   glMemoryBarrier(barriers);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.2
 * OpenGLES  : 3.1
 */
void rglBindImageTexture( 	GLuint unit,
  	GLuint texture,
  	GLint level,
  	GLboolean layered,
  	GLint layer,
  	GLenum access,
  	GLenum format)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindImageTexture.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3) &amp;&amp; defined(HAVE_OPENGLES_3_1)
   glBindImageTexture(unit, texture, level, layered, layer, access, format);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.1
 * OpenGLES  : 3.1
 */
void rglGetProgramBinary( 	GLuint program,
  	GLsizei bufsize,
  	GLsizei *length,
  	GLenum *binaryFormat,
  	void *binary)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGetProgramBinary.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGetProgramBinary(program, bufsize, length, binaryFormat, binary);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.1
 * OpenGLES  : 3.1
 */
void rglProgramBinary(GLuint program,
  	GLenum binaryFormat,
  	const void *binary,
  	GLsizei length)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glProgramBinary.\n");
#endif
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3_1)
   glProgramBinary(program, binaryFormat, binary, length);
#else
   printf("WARNING! Not implemented.\n");
#endif
}

void rglTexImage2DMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height,
  	GLboolean fixedsamplelocations)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexImage2DMultisample.\n");
#endif
#ifndef HAVE_OPENGLES
   glTexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations);
#endif
}

void rglTexImage3D(	GLenum target,
 	GLint level,
 	GLint internalFormat,
 	GLsizei width,
 	GLsizei height,
 	GLsizei depth,
 	GLint border,
 	GLenum format,
 	GLenum type,
 	const GLvoid * data)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTexImage3D.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, data);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
void * rglMapBuffer(	GLenum target, GLenum access)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glMapBuffer.\n");
#endif
#if defined(HAVE_OPENGLES)
   return glMapBufferOES(target, access);
#else
   return glMapBuffer(target, access);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 1.5
 */
GLboolean rglUnmapBuffer( 	GLenum target)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUnmapBuffer.\n");
#endif
#if defined(HAVE_OPENGLES)
   return glUnmapBufferOES(target);
#else
   return glUnmapBuffer(target);
#endif
}

void rglBlendEquation(GLenum mode)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendEquation.\n");
#endif
   glBlendEquation(mode);
}

void rglBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendColor.\n");
#endif
   glBlendColor(red, green, blue, alpha);
}

/*
 * Category: Blending
 *
 * Core in:
 * OpenGL    : 2.0
 */
void rglBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBlendEquationSeparate.\n");
#endif
   glBlendEquationSeparate(modeRGB, modeAlpha);
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 3.2
 */
void rglCopyImageSubData( 	GLuint srcName,
  	GLenum srcTarget,
  	GLint srcLevel,
  	GLint srcX,
  	GLint srcY,
  	GLint srcZ,
  	GLuint dstName,
  	GLenum dstTarget,
  	GLint dstLevel,
  	GLint dstX,
  	GLint dstY,
  	GLint dstZ,
  	GLsizei srcWidth,
  	GLsizei srcHeight,
  	GLsizei srcDepth)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glCopyImageSubData.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES_3_2)
   glCopyImageSubData(srcName,
         srcTarget,
         srcLevel,
         srcX,
         srcY,
         srcZ,
         dstName,
         dstTarget,
         dstLevel,
         dstX,
         dstY,
         dstZ,
         srcWidth,
         srcHeight,
         srcDepth);
#endif
}

/*
 * Category: VAO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglBindVertexArray(GLuint array)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBindVertexArray.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glBindVertexArray(array);
#endif
}

/*
 * Category: VAO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglGenVertexArrays(GLsizei n, GLuint *arrays)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glGenVertexArrays.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glGenVertexArrays(n, arrays);
#endif
}

/*
 * Category: VAO
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglDeleteVertexArrays(GLsizei n, const GLuint *arrays)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteVertexArrays.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glDeleteVertexArrays(n, arrays);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void *rglFenceSync(GLenum condition, GLbitfield flags)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFenceSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   return (GLsync)glFenceSync(condition, flags);
#else
   return NULL;
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglDeleteSync(void * sync)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDeleteSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
  glDeleteSync((GLsync)sync);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
void rglWaitSync(void *sync, GLbitfield flags, uint64_t timeout)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glWaitSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glWaitSync((GLsync)sync, flags, (GLuint64)timeout);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.4
 * OpenGLES  : Not available
 */
void rglBufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GLbitfield flags)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glBufferStorage.\n");
#endif
#if defined(HAVE_OPENGL)
   glBufferStorage(target, size, data, flags);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 2.0
 * OpenGLES  : 2.0
 */

void rglUniform2iv(	GLint location,
 	GLsizei count,
 	const GLint *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2iv.\n");
#endif
   glUniform2iv(location, count, value);
}

/*
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : ?.?
 */

void rglUniform2uiv(	GLint location,
 	GLsizei count,
 	const GLuint *value)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glUniform2uiv.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
   glUniform2uiv(location, count, value);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 4.3
 * OpenGLES  : ?.?
 */
void rglTextureView(	GLuint texture,
 	GLenum target,
 	GLuint origtexture,
 	GLenum internalformat,
 	GLuint minlevel,
 	GLuint numlevels,
 	GLuint minlayer,
 	GLuint numlayers)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glTextureView.\n");
#endif
#if defined(HAVE_OPENGL)
   glTextureView(texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers);
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.0
 * OpenGLES  : 3.0
 */
void rglFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glFlushMappedBufferRange.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
  glFlushMappedBufferRange(target, offset, length);
#endif
}

#ifndef GL_WAIT_FAILED
#define GL_WAIT_FAILED                                   0x911D
#endif

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : 3.0
 */
GLenum rglClientWaitSync(void *sync, GLbitfield flags, uint64_t timeout)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glClientWaitSync.\n");
#endif
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) &amp;&amp; defined(HAVE_OPENGLES3)
  return glClientWaitSync((GLsync)sync, flags, (GLuint64)timeout);
#else
  return GL_WAIT_FAILED;
#endif
}

/*
 *
 * Core in:
 * OpenGL    : 3.2
 * OpenGLES  : Not available
 */
void rglDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
			       GLvoid *indices, GLint basevertex)
{
#ifdef GLSM_DEBUG
   log_cb(RETRO_LOG_INFO, "glDrawElementsBaseVertex.\n");
#endif
#if defined(HAVE_OPENGL)
   glDrawElementsBaseVertex(mode, count, type, indices, basevertex);
#endif
}

/* GLSM-side */

static void glsm_state_setup(void)
{
   unsigned i;

   gl_state.cap_translate[SGL_DEPTH_TEST]           = GL_DEPTH_TEST;
   gl_state.cap_translate[SGL_BLEND]                = GL_BLEND;
   gl_state.cap_translate[SGL_POLYGON_OFFSET_FILL]  = GL_POLYGON_OFFSET_FILL;
   gl_state.cap_translate[SGL_FOG]                  = GL_FOG;
   gl_state.cap_translate[SGL_CULL_FACE]            = GL_CULL_FACE;
   gl_state.cap_translate[SGL_ALPHA_TEST]           = GL_ALPHA_TEST;
   gl_state.cap_translate[SGL_SCISSOR_TEST]         = GL_SCISSOR_TEST;
   gl_state.cap_translate[SGL_STENCIL_TEST]         = GL_STENCIL_TEST;

#ifndef HAVE_OPENGLES
   gl_state.cap_translate[SGL_COLOR_LOGIC_OP]       = GL_COLOR_LOGIC_OP;
   gl_state.cap_translate[SGL_CLIP_DISTANCE0]       = GL_CLIP_DISTANCE0;
   gl_state.cap_translate[SGL_DEPTH_CLAMP]          = GL_DEPTH_CLAMP;
#endif

   for (i = 0; i &lt; MAX_ATTRIB; i++)
   {
      gl_state.vertex_attrib_pointer.enabled[i] = 0;
      gl_state.attrib_pointer.used[i] = 0;
   }

   glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &amp;glsm_max_textures);

   gl_state.bind_textures.ids           = (GLuint*)calloc(glsm_max_textures, sizeof(GLuint));

   default_framebuffer                  = glsm_get_current_framebuffer();
   gl_state.framebuf                    = default_framebuffer;
   gl_state.cullface.mode               = GL_BACK;
   gl_state.frontface.mode              = GL_CCW;

   gl_state.blendfunc_separate.used     = false;
   gl_state.blendfunc_separate.srcRGB   = GL_ONE;
   gl_state.blendfunc_separate.dstRGB   = GL_ZERO;
   gl_state.blendfunc_separate.srcAlpha = GL_ONE;
   gl_state.blendfunc_separate.dstAlpha = GL_ZERO;

   gl_state.depthfunc.used              = false;

   gl_state.colormask.used              = false;
   gl_state.colormask.red               = GL_TRUE;
   gl_state.colormask.green             = GL_TRUE;
   gl_state.colormask.blue              = GL_TRUE;
   gl_state.colormask.alpha             = GL_TRUE;

   gl_state.polygonoffset.used          = false;

   gl_state.depthfunc.func              = GL_LESS;

#ifndef HAVE_OPENGLES
   gl_state.colorlogicop                = GL_COPY;
#endif

#ifdef CORE
   glGenVertexArrays(1, &amp;gl_state.vao);
#endif
}

static void glsm_state_bind(void)
{
   unsigned i;
#ifdef CORE
   glBindVertexArray(gl_state.vao);
#endif
   glBindBuffer(GL_ARRAY_BUFFER, gl_state.array_buffer);

   for (i = 0; i &lt; MAX_ATTRIB; i++)
   {
      if (gl_state.vertex_attrib_pointer.enabled[i])
         glEnableVertexAttribArray(i);
      else
         glDisableVertexAttribArray(i);

      if (gl_state.attrib_pointer.used[i] &amp;&amp; gl_state.attrib_pointer.buffer[i] == gl_state.array_buffer)
      {
         glVertexAttribPointer(
               i,
               gl_state.attrib_pointer.size[i],
               gl_state.attrib_pointer.type[i],
               gl_state.attrib_pointer.normalized[i],
               gl_state.attrib_pointer.stride[i],
               gl_state.attrib_pointer.pointer[i]);
      }
   }

   glBindFramebuffer(RARCH_GL_FRAMEBUFFER, default_framebuffer);

   if (gl_state.blendfunc.used)
      glBlendFunc(
            gl_state.blendfunc.sfactor,
            gl_state.blendfunc.dfactor);

   if (gl_state.blendfunc_separate.used)
      glBlendFuncSeparate(
            gl_state.blendfunc_separate.srcRGB,
            gl_state.blendfunc_separate.dstRGB,
            gl_state.blendfunc_separate.srcAlpha,
            gl_state.blendfunc_separate.dstAlpha
            );

   glClearColor(
         gl_state.clear_color.r,
         gl_state.clear_color.g,
         gl_state.clear_color.b,
         gl_state.clear_color.a);

   if (gl_state.depthfunc.used)
      glDepthFunc(gl_state.depthfunc.func);

   if (gl_state.colormask.used)
      glColorMask(
            gl_state.colormask.red,
            gl_state.colormask.green,
            gl_state.colormask.blue,
            gl_state.colormask.alpha);

   if (gl_state.cullface.used)
      glCullFace(gl_state.cullface.mode);

   if (gl_state.depthmask.used)
      glDepthMask(gl_state.depthmask.mask);

   if (gl_state.polygonoffset.used)
      glPolygonOffset(
            gl_state.polygonoffset.factor,
            gl_state.polygonoffset.units);

   if (gl_state.scissor.used)
      glScissor(
            gl_state.scissor.x,
            gl_state.scissor.y,
            gl_state.scissor.w,
            gl_state.scissor.h);

   glUseProgram(gl_state.program);

   glViewport(
         gl_state.viewport.x,
         gl_state.viewport.y,
         gl_state.viewport.w,
         gl_state.viewport.h);

   for(i = 0; i &lt; SGL_CAP_MAX; i ++)
   {
      if (gl_state.cap_state[i])
         glEnable(gl_state.cap_translate[i]);
   }

   if (gl_state.frontface.used)
      glFrontFace(gl_state.frontface.mode);

   if (gl_state.stencilmask.used)
      glStencilMask(gl_state.stencilmask.mask);

   if (gl_state.stencilop.used)
      glStencilOp(gl_state.stencilop.sfail,
            gl_state.stencilop.dpfail,
            gl_state.stencilop.dppass);

   if (gl_state.stencilfunc.used)
      glStencilFunc(
            gl_state.stencilfunc.func,
            gl_state.stencilfunc.ref,
            gl_state.stencilfunc.mask);

   for (i = 0; i &lt; glsm_max_textures; i ++)
   {
      glActiveTexture(GL_TEXTURE0 + i);
      glBindTexture(GL_TEXTURE_2D, gl_state.bind_textures.ids[i]);
   }

   glActiveTexture(GL_TEXTURE0 + gl_state.active_texture);
}

static void glsm_state_unbind(void)
{
   unsigned i;
#ifdef CORE
   glBindVertexArray(0);
#endif
   for (i = 0; i &lt; SGL_CAP_MAX; i ++)
   {
      if (gl_state.cap_state[i])
         glDisable(gl_state.cap_translate[i]);
   }

   glBlendFunc(GL_ONE, GL_ZERO);

   if (gl_state.colormask.used)
      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
   if (gl_state.blendfunc_separate.used)
      glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);

   if (gl_state.cullface.used)
      glCullFace(GL_BACK);

   if (gl_state.depthmask.used)
      glDepthMask(GL_TRUE);

   if (gl_state.polygonoffset.used)
      glPolygonOffset(0, 0);

   glUseProgram(0);
   glClearColor(0,0,0,0.0f);

   if (gl_state.depthrange.used)
      rglDepthRange(0, 1);

   glStencilMask(1);
   glFrontFace(GL_CCW);
   if (gl_state.depthfunc.used)
      glDepthFunc(GL_LESS);

   if (gl_state.stencilop.used)
      glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);

   if (gl_state.stencilfunc.used)
      glStencilFunc(GL_ALWAYS,0,1);

   /* Clear textures */
   for (i = 0; i &lt; glsm_max_textures; i ++)
   {
      glActiveTexture(GL_TEXTURE0 + i);
      glBindTexture(GL_TEXTURE_2D, 0);
   }
   glActiveTexture(GL_TEXTURE0);

   for (i = 0; i &lt; MAX_ATTRIB; i ++)
      glDisableVertexAttribArray(i);

   glBindFramebuffer(RARCH_GL_FRAMEBUFFER, 0);
}

static bool glsm_state_ctx_destroy(void *data)
{
   if (gl_state.bind_textures.ids)
      free(gl_state.bind_textures.ids);
   gl_state.bind_textures.ids = NULL;

   return true;
}

static bool glsm_state_ctx_init(glsm_ctx_params_t *params)
{
   if (!params || !params-&gt;environ_cb)
      return false;

#ifdef HAVE_OPENGLES
#if defined(HAVE_OPENGLES_3_1)
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES_VERSION;
   hw_render.version_major      = 3;
   hw_render.version_minor      = 1;
#elif defined(HAVE_OPENGLES3)
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES3;
#else
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES2;
#endif
#else
   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGL;
   if (params-&gt;context_type != RETRO_HW_CONTEXT_NONE)
      hw_render.context_type    = params-&gt;context_type;
   if (params-&gt;major != 0)
      hw_render.version_major   = params-&gt;major;
   if (params-&gt;minor != 0)
      hw_render.version_minor   = params-&gt;minor;
#endif

   hw_render.context_reset      = params-&gt;context_reset;
   hw_render.context_destroy    = params-&gt;context_destroy;
   hw_render.stencil            = params-&gt;stencil;
   hw_render.depth              = true;
   hw_render.bottom_left_origin = true;
   hw_render.cache_context      = false;

   if (!params-&gt;environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &amp;hw_render))
      return false;

   return true;
}

GLuint glsm_get_current_framebuffer(void)
{
   return hw_render.get_current_framebuffer();
}

bool glsm_ctl(enum glsm_state_ctl state, void *data)
{
   switch (state)
   {
      case GLSM_CTL_IMM_VBO_DRAW:
         return false;
      case GLSM_CTL_IMM_VBO_DISABLE:
         return false;
      case GLSM_CTL_IS_IMM_VBO:
         return false;
      case GLSM_CTL_SET_IMM_VBO:
         break;
      case GLSM_CTL_UNSET_IMM_VBO:
         break;
      case GLSM_CTL_PROC_ADDRESS_GET:
         {
            glsm_ctx_proc_address_t *proc = (glsm_ctx_proc_address_t*)data;
            if (!hw_render.get_proc_address)
               return false;
            proc-&gt;addr = hw_render.get_proc_address;
         }
         break;
      case GLSM_CTL_STATE_CONTEXT_RESET:
         rglgen_resolve_symbols(hw_render.get_proc_address);
         break;
      case GLSM_CTL_STATE_CONTEXT_DESTROY:
         glsm_state_ctx_destroy(data);
         break;
      case GLSM_CTL_STATE_CONTEXT_INIT:
         return glsm_state_ctx_init((glsm_ctx_params_t*)data);
      case GLSM_CTL_STATE_SETUP:
         glsm_state_setup();
         break;
      case GLSM_CTL_STATE_UNBIND:
         glsm_state_unbind();
         break;
      case GLSM_CTL_STATE_BIND:
         glsm_state_bind();
         break;
      case GLSM_CTL_NONE:
      default:
         break;
   }

   return true;
}</pre>
<h2>./include/libretro-common/glsym/glgen.py</h2>
<pre>#!/usr/bin/env python3

"""
   License statement applies to this file (glgen.py) only.

   Permission is hereby granted, free of charge,
   to any person obtaining a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import sys
import os
import re

banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]

def noext(sym):
   for ext in banned_ext:
      if sym.endswith(ext):
         return False
   return True

def fix_multiline_functions(lines):
   fixed_lines = []
   temp_lines = []
   for line in lines:
      if line.count('(') &gt; line.count(')'):
         temp_lines.append(line)
      else:
         if len(temp_lines) &gt; 0:
            if line.count(')') &gt; line.count('('):
               temp_lines.append(line)
               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
               fixed_lines.append(fixed_line)
               temp_lines = []
            else:
               temp_lines.append(line)
         else:
            fixed_lines.append(line)
   return fixed_lines

def find_gl_symbols(lines):
   typedefs = []
   syms = []
   for line in lines:
      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
      g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
      if m and noext(m.group(1)):
         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
      if g and noext(g.group(1)):
         syms.append(g.group(1))
   return (typedefs, syms)

def generate_defines(gl_syms):
   res = []
   for line in gl_syms:
      res.append('#define {} __rglgen_{}'.format(line, line))
   return res

def generate_declarations(gl_syms):
   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]

def generate_macros(gl_syms):
   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]

def dump(f, lines):
   f.write('\n'.join(lines))
   f.write('\n\n')

if __name__ == '__main__':

   if len(sys.argv) &gt; 4:
      for banned in sys.argv[4:]:
         banned_ext.append(banned)

   with open(sys.argv[1], 'r') as f:
      lines = fix_multiline_functions(f.readlines())
      typedefs, syms = find_gl_symbols(lines)

      overrides = generate_defines(syms)
      declarations = generate_declarations(syms)
      externs = ['extern ' + x for x in declarations]

      macros = generate_macros(syms)

   with open(sys.argv[2], 'w') as f:
      f.write('#ifndef RGLGEN_DECL_H__\n')
      f.write('#define RGLGEN_DECL_H__\n')

      f.write('#ifdef __cplusplus\n')
      f.write('extern "C" {\n')
      f.write('#endif\n')

      f.write('#ifdef GL_APIENTRY\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#else\n')
      f.write('#ifndef APIENTRY\n')
      f.write('#define APIENTRY\n')
      f.write('#endif\n')
      f.write('#ifndef APIENTRYP\n')
      f.write('#define APIENTRYP APIENTRY *\n')
      f.write('#endif\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#endif\n')

      f.write('#ifndef GL_OES_EGL_image\n')
      f.write('typedef void *GLeglImageOES;\n')
      f.write('#endif\n')

      f.write('#if !defined(GL_OES_fixed_point) &amp;&amp; !defined(HAVE_OPENGLES2)\n')
      f.write('typedef GLint GLfixed;\n')
      f.write('#endif\n')

      f.write('#if defined(OSX) &amp;&amp; !defined(MAC_OS_X_VERSION_10_7)\n')
      f.write('typedef long long int GLint64;\n')
      f.write('typedef unsigned long long int GLuint64;\n')
      f.write('typedef unsigned long long int GLuint64EXT;\n')
      f.write('typedef struct __GLsync *GLsync;\n')
      f.write('#endif\n')

      dump(f, typedefs)
      dump(f, overrides)
      dump(f, externs)

      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')

      f.write('#ifdef __cplusplus\n')
      f.write('}\n')
      f.write('#endif\n')

      f.write('#endif\n')

   with open(sys.argv[3], 'w') as f:
      f.write('#include "glsym/glsym.h"\n')
      f.write('#include &lt;stddef.h&gt;\n')
      f.write('#define SYM(x) { "gl" #x, &amp;(gl##x) }\n')
      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
      dump(f, macros)
      f.write('    { NULL, NULL },\n')
      f.write('};\n')
      dump(f, declarations)</pre>
<h2>./include/libretro-common/glsym/glsym_es2.c</h2>
<pre>#include "glsym/glsym.h"
#include &lt;stddef.h&gt;
#define SYM(x) { "gl" #x, &amp;(gl##x) }
const struct rglgen_sym_map rglgen_symbol_map[] = {
    SYM(BlendBarrierKHR),
    SYM(DebugMessageControlKHR),
    SYM(DebugMessageInsertKHR),
    SYM(DebugMessageCallbackKHR),
    SYM(GetDebugMessageLogKHR),
    SYM(PushDebugGroupKHR),
    SYM(PopDebugGroupKHR),
    SYM(ObjectLabelKHR),
    SYM(GetObjectLabelKHR),
    SYM(ObjectPtrLabelKHR),
    SYM(GetObjectPtrLabelKHR),
    SYM(GetPointervKHR),
    SYM(GetGraphicsResetStatusKHR),
    SYM(ReadnPixelsKHR),
    SYM(GetnUniformfvKHR),
    SYM(GetnUniformivKHR),
    SYM(GetnUniformuivKHR),
    SYM(EGLImageTargetTexture2DOES),
    SYM(EGLImageTargetRenderbufferStorageOES),
    SYM(CopyImageSubDataOES),
    SYM(EnableiOES),
    SYM(DisableiOES),
    SYM(BlendEquationiOES),
    SYM(BlendEquationSeparateiOES),
    SYM(BlendFunciOES),
    SYM(BlendFuncSeparateiOES),
    SYM(ColorMaskiOES),
    SYM(IsEnablediOES),
    SYM(DrawElementsBaseVertexOES),
    SYM(DrawRangeElementsBaseVertexOES),
    SYM(DrawElementsInstancedBaseVertexOES),
    SYM(MultiDrawElementsBaseVertexOES),
    SYM(FramebufferTextureOES),
    SYM(GetProgramBinaryOES),
    SYM(ProgramBinaryOES),
    SYM(MapBufferOES),
    SYM(UnmapBufferOES),
    SYM(GetBufferPointervOES),
    SYM(PrimitiveBoundingBoxOES),
    SYM(MinSampleShadingOES),
    SYM(PatchParameteriOES),
    SYM(TexImage3DOES),
    SYM(TexSubImage3DOES),
    SYM(CopyTexSubImage3DOES),
    SYM(CompressedTexImage3DOES),
    SYM(CompressedTexSubImage3DOES),
    SYM(FramebufferTexture3DOES),
    SYM(TexParameterIivOES),
    SYM(TexParameterIuivOES),
    SYM(GetTexParameterIivOES),
    SYM(GetTexParameterIuivOES),
    SYM(SamplerParameterIivOES),
    SYM(SamplerParameterIuivOES),
    SYM(GetSamplerParameterIivOES),
    SYM(GetSamplerParameterIuivOES),
    SYM(TexBufferOES),
    SYM(TexBufferRangeOES),
    SYM(TexStorage3DMultisampleOES),
    SYM(TextureViewOES),
    SYM(BindVertexArrayOES),
    SYM(DeleteVertexArraysOES),
    SYM(GenVertexArraysOES),
    SYM(IsVertexArrayOES),
    SYM(ViewportArrayvOES),
    SYM(ViewportIndexedfOES),
    SYM(ViewportIndexedfvOES),
    SYM(ScissorArrayvOES),
    SYM(ScissorIndexedOES),
    SYM(ScissorIndexedvOES),
    SYM(DepthRangeArrayfvOES),
    SYM(DepthRangeIndexedfOES),
    SYM(GetFloati_vOES),
    SYM(DrawArraysInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
    SYM(BindFragDataLocationIndexedEXT),
    SYM(BindFragDataLocationEXT),
    SYM(GetProgramResourceLocationIndexEXT),
    SYM(GetFragDataIndexEXT),
    SYM(BufferStorageEXT),
    SYM(ClearTexImageEXT),
    SYM(ClearTexSubImageEXT),
    SYM(CopyImageSubDataEXT),
    SYM(LabelObjectEXT),
    SYM(GetObjectLabelEXT),
    SYM(InsertEventMarkerEXT),
    SYM(PushGroupMarkerEXT),
    SYM(PopGroupMarkerEXT),
    SYM(DiscardFramebufferEXT),
    SYM(GenQueriesEXT),
    SYM(DeleteQueriesEXT),
    SYM(IsQueryEXT),
    SYM(BeginQueryEXT),
    SYM(EndQueryEXT),
    SYM(QueryCounterEXT),
    SYM(GetQueryivEXT),
    SYM(GetQueryObjectivEXT),
    SYM(GetQueryObjectuivEXT),
    SYM(DrawBuffersEXT),
    SYM(EnableiEXT),
    SYM(DisableiEXT),
    SYM(BlendEquationiEXT),
    SYM(BlendEquationSeparateiEXT),
    SYM(BlendFunciEXT),
    SYM(BlendFuncSeparateiEXT),
    SYM(ColorMaskiEXT),
    SYM(IsEnablediEXT),
    SYM(DrawElementsBaseVertexEXT),
    SYM(DrawRangeElementsBaseVertexEXT),
    SYM(DrawElementsInstancedBaseVertexEXT),
    SYM(MultiDrawElementsBaseVertexEXT),
    SYM(DrawArraysInstancedEXT),
    SYM(DrawElementsInstancedEXT),
    SYM(FramebufferTextureEXT),
    SYM(VertexAttribDivisorEXT),
    SYM(MapBufferRangeEXT),
    SYM(FlushMappedBufferRangeEXT),
    SYM(MultiDrawArraysEXT),
    SYM(MultiDrawElementsEXT),
    SYM(MultiDrawArraysIndirectEXT),
    SYM(MultiDrawElementsIndirectEXT),
    SYM(RenderbufferStorageMultisampleEXT),
    SYM(FramebufferTexture2DMultisampleEXT),
    SYM(ReadBufferIndexedEXT),
    SYM(DrawBuffersIndexedEXT),
    SYM(GetIntegeri_vEXT),
    SYM(PolygonOffsetClampEXT),
    SYM(PrimitiveBoundingBoxEXT),
    SYM(RasterSamplesEXT),
    SYM(GetGraphicsResetStatusEXT),
    SYM(ReadnPixelsEXT),
    SYM(GetnUniformfvEXT),
    SYM(GetnUniformivEXT),
    SYM(ActiveShaderProgramEXT),
    SYM(BindProgramPipelineEXT),
    SYM(CreateShaderProgramvEXT),
    SYM(DeleteProgramPipelinesEXT),
    SYM(GenProgramPipelinesEXT),
    SYM(GetProgramPipelineInfoLogEXT),
    SYM(GetProgramPipelineivEXT),
    SYM(IsProgramPipelineEXT),
    SYM(ProgramParameteriEXT),
    SYM(ProgramUniform1fEXT),
    SYM(ProgramUniform1fvEXT),
    SYM(ProgramUniform1iEXT),
    SYM(ProgramUniform1ivEXT),
    SYM(ProgramUniform2fEXT),
    SYM(ProgramUniform2fvEXT),
    SYM(ProgramUniform2iEXT),
    SYM(ProgramUniform2ivEXT),
    SYM(ProgramUniform3fEXT),
    SYM(ProgramUniform3fvEXT),
    SYM(ProgramUniform3iEXT),
    SYM(ProgramUniform3ivEXT),
    SYM(ProgramUniform4fEXT),
    SYM(ProgramUniform4fvEXT),
    SYM(ProgramUniform4iEXT),
    SYM(ProgramUniform4ivEXT),
    SYM(ProgramUniformMatrix2fvEXT),
    SYM(ProgramUniformMatrix3fvEXT),
    SYM(ProgramUniformMatrix4fvEXT),
    SYM(UseProgramStagesEXT),
    SYM(ValidateProgramPipelineEXT),
    SYM(ProgramUniform1uiEXT),
    SYM(ProgramUniform2uiEXT),
    SYM(ProgramUniform3uiEXT),
    SYM(ProgramUniform4uiEXT),
    SYM(ProgramUniform1uivEXT),
    SYM(ProgramUniform2uivEXT),
    SYM(ProgramUniform3uivEXT),
    SYM(ProgramUniform4uivEXT),
    SYM(ProgramUniformMatrix2x3fvEXT),
    SYM(ProgramUniformMatrix3x2fvEXT),
    SYM(ProgramUniformMatrix2x4fvEXT),
    SYM(ProgramUniformMatrix4x2fvEXT),
    SYM(ProgramUniformMatrix3x4fvEXT),
    SYM(ProgramUniformMatrix4x3fvEXT),
    SYM(FramebufferPixelLocalStorageSizeEXT),
    SYM(GetFramebufferPixelLocalStorageSizeEXT),
    SYM(ClearPixelLocalStorageuiEXT),
    SYM(TexPageCommitmentEXT),
    SYM(PatchParameteriEXT),
    SYM(TexParameterIivEXT),
    SYM(TexParameterIuivEXT),
    SYM(GetTexParameterIivEXT),
    SYM(GetTexParameterIuivEXT),
    SYM(SamplerParameterIivEXT),
    SYM(SamplerParameterIuivEXT),
    SYM(GetSamplerParameterIivEXT),
    SYM(GetSamplerParameterIuivEXT),
    SYM(TexBufferEXT),
    SYM(TexBufferRangeEXT),
    SYM(TexStorage1DEXT),
    SYM(TexStorage2DEXT),
    SYM(TexStorage3DEXT),
    SYM(TextureStorage1DEXT),
    SYM(TextureStorage2DEXT),
    SYM(TextureStorage3DEXT),
    SYM(TextureViewEXT),
    SYM(FramebufferTextureMultiviewOVR),
    SYM(FramebufferTextureMultisampleMultiviewOVR),

    { NULL, NULL },
};
RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;</pre>
<h2>./include/libretro-common/glsym/glsym_es3.c</h2>
<pre>#include "glsym/glsym.h"
#include &lt;stddef.h&gt;
#define SYM(x) { "gl" #x, &amp;(gl##x) }
const struct rglgen_sym_map rglgen_symbol_map[] = {
    SYM(BlendBarrierKHR),
    SYM(DebugMessageControlKHR),
    SYM(DebugMessageInsertKHR),
    SYM(DebugMessageCallbackKHR),
    SYM(GetDebugMessageLogKHR),
    SYM(PushDebugGroupKHR),
    SYM(PopDebugGroupKHR),
    SYM(ObjectLabelKHR),
    SYM(GetObjectLabelKHR),
    SYM(ObjectPtrLabelKHR),
    SYM(GetObjectPtrLabelKHR),
    SYM(GetPointervKHR),
    SYM(GetGraphicsResetStatusKHR),
    SYM(ReadnPixelsKHR),
    SYM(GetnUniformfvKHR),
    SYM(GetnUniformivKHR),
    SYM(GetnUniformuivKHR),
    SYM(EGLImageTargetTexture2DOES),
    SYM(EGLImageTargetRenderbufferStorageOES),
    SYM(CopyImageSubDataOES),
    SYM(EnableiOES),
    SYM(DisableiOES),
    SYM(BlendEquationiOES),
    SYM(BlendEquationSeparateiOES),
    SYM(BlendFunciOES),
    SYM(BlendFuncSeparateiOES),
    SYM(ColorMaskiOES),
    SYM(IsEnablediOES),
    SYM(DrawElementsBaseVertexOES),
    SYM(DrawRangeElementsBaseVertexOES),
    SYM(DrawElementsInstancedBaseVertexOES),
    SYM(MultiDrawElementsBaseVertexOES),
    SYM(FramebufferTextureOES),
    SYM(GetProgramBinaryOES),
    SYM(ProgramBinaryOES),
    SYM(MapBufferOES),
    SYM(UnmapBufferOES),
    SYM(GetBufferPointervOES),
    SYM(PrimitiveBoundingBoxOES),
    SYM(MinSampleShadingOES),
    SYM(PatchParameteriOES),
    SYM(TexImage3DOES),
    SYM(TexSubImage3DOES),
    SYM(CopyTexSubImage3DOES),
    SYM(CompressedTexImage3DOES),
    SYM(CompressedTexSubImage3DOES),
    SYM(FramebufferTexture3DOES),
    SYM(TexParameterIivOES),
    SYM(TexParameterIuivOES),
    SYM(GetTexParameterIivOES),
    SYM(GetTexParameterIuivOES),
    SYM(SamplerParameterIivOES),
    SYM(SamplerParameterIuivOES),
    SYM(GetSamplerParameterIivOES),
    SYM(GetSamplerParameterIuivOES),
    SYM(TexBufferOES),
    SYM(TexBufferRangeOES),
    SYM(TexStorage3DMultisampleOES),
    SYM(TextureViewOES),
    SYM(BindVertexArrayOES),
    SYM(DeleteVertexArraysOES),
    SYM(GenVertexArraysOES),
    SYM(IsVertexArrayOES),
    SYM(ViewportArrayvOES),
    SYM(ViewportIndexedfOES),
    SYM(ViewportIndexedfvOES),
    SYM(ScissorArrayvOES),
    SYM(ScissorIndexedOES),
    SYM(ScissorIndexedvOES),
    SYM(DepthRangeArrayfvOES),
    SYM(DepthRangeIndexedfOES),
    SYM(GetFloati_vOES),
    SYM(DrawArraysInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseInstanceEXT),
    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
    SYM(BindFragDataLocationIndexedEXT),
    SYM(BindFragDataLocationEXT),
    SYM(GetProgramResourceLocationIndexEXT),
    SYM(GetFragDataIndexEXT),
    SYM(BufferStorageEXT),
    SYM(ClearTexImageEXT),
    SYM(ClearTexSubImageEXT),
    SYM(CopyImageSubDataEXT),
    SYM(LabelObjectEXT),
    SYM(GetObjectLabelEXT),
    SYM(InsertEventMarkerEXT),
    SYM(PushGroupMarkerEXT),
    SYM(PopGroupMarkerEXT),
    SYM(DiscardFramebufferEXT),
    SYM(GenQueriesEXT),
    SYM(DeleteQueriesEXT),
    SYM(IsQueryEXT),
    SYM(BeginQueryEXT),
    SYM(EndQueryEXT),
    SYM(QueryCounterEXT),
    SYM(GetQueryivEXT),
    SYM(GetQueryObjectivEXT),
    SYM(GetQueryObjectuivEXT),
    SYM(GetQueryObjecti64vEXT),
    SYM(GetQueryObjectui64vEXT),
    SYM(DrawBuffersEXT),
    SYM(EnableiEXT),
    SYM(DisableiEXT),
    SYM(BlendEquationiEXT),
    SYM(BlendEquationSeparateiEXT),
    SYM(BlendFunciEXT),
    SYM(BlendFuncSeparateiEXT),
    SYM(ColorMaskiEXT),
    SYM(IsEnablediEXT),
    SYM(DrawElementsBaseVertexEXT),
    SYM(DrawRangeElementsBaseVertexEXT),
    SYM(DrawElementsInstancedBaseVertexEXT),
    SYM(MultiDrawElementsBaseVertexEXT),
    SYM(DrawArraysInstancedEXT),
    SYM(DrawElementsInstancedEXT),
    SYM(FramebufferTextureEXT),
    SYM(VertexAttribDivisorEXT),
    SYM(MapBufferRangeEXT),
    SYM(FlushMappedBufferRangeEXT),
    SYM(MultiDrawArraysEXT),
    SYM(MultiDrawElementsEXT),
    SYM(MultiDrawArraysIndirectEXT),
    SYM(MultiDrawElementsIndirectEXT),
    SYM(RenderbufferStorageMultisampleEXT),
    SYM(FramebufferTexture2DMultisampleEXT),
    SYM(ReadBufferIndexedEXT),
    SYM(DrawBuffersIndexedEXT),
    SYM(GetIntegeri_vEXT),
    SYM(PolygonOffsetClampEXT),
    SYM(PrimitiveBoundingBoxEXT),
    SYM(RasterSamplesEXT),
    SYM(GetGraphicsResetStatusEXT),
    SYM(ReadnPixelsEXT),
    SYM(GetnUniformfvEXT),
    SYM(GetnUniformivEXT),
    SYM(ActiveShaderProgramEXT),
    SYM(BindProgramPipelineEXT),
    SYM(CreateShaderProgramvEXT),
    SYM(DeleteProgramPipelinesEXT),
    SYM(GenProgramPipelinesEXT),
    SYM(GetProgramPipelineInfoLogEXT),
    SYM(GetProgramPipelineivEXT),
    SYM(IsProgramPipelineEXT),
    SYM(ProgramParameteriEXT),
    SYM(ProgramUniform1fEXT),
    SYM(ProgramUniform1fvEXT),
    SYM(ProgramUniform1iEXT),
    SYM(ProgramUniform1ivEXT),
    SYM(ProgramUniform2fEXT),
    SYM(ProgramUniform2fvEXT),
    SYM(ProgramUniform2iEXT),
    SYM(ProgramUniform2ivEXT),
    SYM(ProgramUniform3fEXT),
    SYM(ProgramUniform3fvEXT),
    SYM(ProgramUniform3iEXT),
    SYM(ProgramUniform3ivEXT),
    SYM(ProgramUniform4fEXT),
    SYM(ProgramUniform4fvEXT),
    SYM(ProgramUniform4iEXT),
    SYM(ProgramUniform4ivEXT),
    SYM(ProgramUniformMatrix2fvEXT),
    SYM(ProgramUniformMatrix3fvEXT),
    SYM(ProgramUniformMatrix4fvEXT),
    SYM(UseProgramStagesEXT),
    SYM(ValidateProgramPipelineEXT),
    SYM(ProgramUniform1uiEXT),
    SYM(ProgramUniform2uiEXT),
    SYM(ProgramUniform3uiEXT),
    SYM(ProgramUniform4uiEXT),
    SYM(ProgramUniform1uivEXT),
    SYM(ProgramUniform2uivEXT),
    SYM(ProgramUniform3uivEXT),
    SYM(ProgramUniform4uivEXT),
    SYM(ProgramUniformMatrix2x3fvEXT),
    SYM(ProgramUniformMatrix3x2fvEXT),
    SYM(ProgramUniformMatrix2x4fvEXT),
    SYM(ProgramUniformMatrix4x2fvEXT),
    SYM(ProgramUniformMatrix3x4fvEXT),
    SYM(ProgramUniformMatrix4x3fvEXT),
    SYM(FramebufferPixelLocalStorageSizeEXT),
    SYM(GetFramebufferPixelLocalStorageSizeEXT),
    SYM(ClearPixelLocalStorageuiEXT),
    SYM(TexPageCommitmentEXT),
    SYM(PatchParameteriEXT),
    SYM(TexParameterIivEXT),
    SYM(TexParameterIuivEXT),
    SYM(GetTexParameterIivEXT),
    SYM(GetTexParameterIuivEXT),
    SYM(SamplerParameterIivEXT),
    SYM(SamplerParameterIuivEXT),
    SYM(GetSamplerParameterIivEXT),
    SYM(GetSamplerParameterIuivEXT),
    SYM(TexBufferEXT),
    SYM(TexBufferRangeEXT),
    SYM(TexStorage1DEXT),
    SYM(TexStorage2DEXT),
    SYM(TexStorage3DEXT),
    SYM(TextureStorage1DEXT),
    SYM(TextureStorage2DEXT),
    SYM(TextureStorage3DEXT),
    SYM(TextureViewEXT),
    SYM(FramebufferTextureMultiviewOVR),
    SYM(FramebufferTextureMultisampleMultiviewOVR),

    { NULL, NULL },
};
RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;
RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;
RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;</pre>
<h2>./include/libretro-common/glsym/glsym_gl.c</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stddef.h&gt;

#include &lt;glsym/glsym.h&gt;

#define SYM(x) { "gl" #x, (void*)&amp;(gl##x) }

const struct rglgen_sym_map rglgen_symbol_map[] = {
#ifdef HAVE_LIBNX
    SYM(ClearIndex),
    SYM(ClearColor),
    SYM(Clear),
    SYM(IndexMask),
    SYM(ColorMask),
    SYM(AlphaFunc),
    SYM(BlendFunc),
    SYM(LogicOp),
    SYM(CullFace),
    SYM(FrontFace),
    SYM(PointSize),
    SYM(LineWidth),
    SYM(LineStipple),
    SYM(PolygonMode),
    SYM(PolygonOffset),
    SYM(PolygonStipple),
    SYM(GetPolygonStipple),
    SYM(EdgeFlag),
    SYM(EdgeFlagv),
    SYM(Scissor),
    SYM(ClipPlane),
    SYM(GetClipPlane),
    SYM(DrawBuffer),
    SYM(ReadBuffer),
    SYM(Enable),
    SYM(Disable),
    SYM(IsEnabled),
    SYM(EnableClientState),
    SYM(DisableClientState),
    SYM(GetBooleanv),
    SYM(GetDoublev),
    SYM(GetFloatv),
    SYM(GetIntegerv),
    SYM(PushAttrib),
    SYM(PopAttrib),
    SYM(PushClientAttrib),
    SYM(PopClientAttrib),
    SYM(RenderMode),
    SYM(GetError),
    SYM(GetString),
    SYM(Finish),
    SYM(Flush),
    SYM(Hint),
    SYM(ClearDepth),
    SYM(DepthFunc),
    SYM(DepthMask),
    SYM(DepthRange),
    SYM(ClearAccum),
    SYM(Accum),
    SYM(MatrixMode),
    SYM(Ortho),
    SYM(Frustum),
    SYM(Viewport),
    SYM(PushMatrix),
    SYM(PopMatrix),
    SYM(LoadIdentity),
    SYM(LoadMatrixd),
    SYM(LoadMatrixf),
    SYM(MultMatrixd),
    SYM(MultMatrixf),
    SYM(Rotated),
    SYM(Rotatef),
    SYM(Scaled),
    SYM(Scalef),
    SYM(Translated),
    SYM(Translatef),
    SYM(IsList),
    SYM(DeleteLists),
    SYM(GenLists),
    SYM(NewList),
    SYM(EndList),
    SYM(CallList),
    SYM(CallLists),
    SYM(ListBase),
    SYM(Begin),
    SYM(End),
    SYM(Vertex2d),
    SYM(Vertex2f),
    SYM(Vertex2i),
    SYM(Vertex2s),
    SYM(Vertex3d),
    SYM(Vertex3f),
    SYM(Vertex3i),
    SYM(Vertex3s),
    SYM(Vertex4d),
    SYM(Vertex4f),
    SYM(Vertex4i),
    SYM(Vertex4s),
    SYM(Vertex2dv),
    SYM(Vertex2fv),
    SYM(Vertex2iv),
    SYM(Vertex2sv),
    SYM(Vertex3dv),
    SYM(Vertex3fv),
    SYM(Vertex3iv),
    SYM(Vertex3sv),
    SYM(Vertex4dv),
    SYM(Vertex4fv),
    SYM(Vertex4iv),
    SYM(Vertex4sv),
    SYM(Normal3b),
    SYM(Normal3d),
    SYM(Normal3f),
    SYM(Normal3i),
    SYM(Normal3s),
    SYM(Normal3bv),
    SYM(Normal3dv),
    SYM(Normal3fv),
    SYM(Normal3iv),
    SYM(Normal3sv),
    SYM(Indexd),
    SYM(Indexf),
    SYM(Indexi),
    SYM(Indexs),
    SYM(Indexub),
    SYM(Indexdv),
    SYM(Indexfv),
    SYM(Indexiv),
    SYM(Indexsv),
    SYM(Indexubv),
    SYM(Color3b),
    SYM(Color3d),
    SYM(Color3f),
    SYM(Color3i),
    SYM(Color3s),
    SYM(Color3ub),
    SYM(Color3ui),
    SYM(Color3us),
    SYM(Color4b),
    SYM(Color4d),
    SYM(Color4f),
    SYM(Color4i),
    SYM(Color4s),
    SYM(Color4ub),
    SYM(Color4ui),
    SYM(Color4us),
    SYM(Color3bv),
    SYM(Color3dv),
    SYM(Color3fv),
    SYM(Color3iv),
    SYM(Color3sv),
    SYM(Color3ubv),
    SYM(Color3uiv),
    SYM(Color3usv),
    SYM(Color4bv),
    SYM(Color4dv),
    SYM(Color4fv),
    SYM(Color4iv),
    SYM(Color4sv),
    SYM(Color4ubv),
    SYM(Color4uiv),
    SYM(Color4usv),
    SYM(TexCoord1d),
    SYM(TexCoord1f),
    SYM(TexCoord1i),
    SYM(TexCoord1s),
    SYM(TexCoord2d),
    SYM(TexCoord2f),
    SYM(TexCoord2i),
    SYM(TexCoord2s),
    SYM(TexCoord3d),
    SYM(TexCoord3f),
    SYM(TexCoord3i),
    SYM(TexCoord3s),
    SYM(TexCoord4d),
    SYM(TexCoord4f),
    SYM(TexCoord4i),
    SYM(TexCoord4s),
    SYM(TexCoord1dv),
    SYM(TexCoord1fv),
    SYM(TexCoord1iv),
    SYM(TexCoord1sv),
    SYM(TexCoord2dv),
    SYM(TexCoord2fv),
    SYM(TexCoord2iv),
    SYM(TexCoord2sv),
    SYM(TexCoord3dv),
    SYM(TexCoord3fv),
    SYM(TexCoord3iv),
    SYM(TexCoord3sv),
    SYM(TexCoord4dv),
    SYM(TexCoord4fv),
    SYM(TexCoord4iv),
    SYM(TexCoord4sv),
    SYM(RasterPos2d),
    SYM(RasterPos2f),
    SYM(RasterPos2i),
    SYM(RasterPos2s),
    SYM(RasterPos3d),
    SYM(RasterPos3f),
    SYM(RasterPos3i),
    SYM(RasterPos3s),
    SYM(RasterPos4d),
    SYM(RasterPos4f),
    SYM(RasterPos4i),
    SYM(RasterPos4s),
    SYM(RasterPos2dv),
    SYM(RasterPos2fv),
    SYM(RasterPos2iv),
    SYM(RasterPos2sv),
    SYM(RasterPos3dv),
    SYM(RasterPos3fv),
    SYM(RasterPos3iv),
    SYM(RasterPos3sv),
    SYM(RasterPos4dv),
    SYM(RasterPos4fv),
    SYM(RasterPos4iv),
    SYM(RasterPos4sv),
    SYM(Rectd),
    SYM(Rectf),
    SYM(Recti),
    SYM(Rects),
    SYM(Rectdv),
    SYM(Rectfv),
    SYM(Rectiv),
    SYM(Rectsv),
    SYM(VertexPointer),
    SYM(NormalPointer),
    SYM(ColorPointer),
    SYM(IndexPointer),
    SYM(TexCoordPointer),
    SYM(EdgeFlagPointer),
    SYM(GetPointerv),
    SYM(ArrayElement),
    SYM(DrawArrays),
    SYM(DrawElements),
    SYM(InterleavedArrays),
    SYM(ShadeModel),
    SYM(Lightf),
    SYM(Lighti),
    SYM(Lightfv),
    SYM(Lightiv),
    SYM(GetLightfv),
    SYM(GetLightiv),
    SYM(LightModelf),
    SYM(LightModeli),
    SYM(LightModelfv),
    SYM(LightModeliv),
    SYM(Materialf),
    SYM(Materiali),
    SYM(Materialfv),
    SYM(Materialiv),
    SYM(GetMaterialfv),
    SYM(GetMaterialiv),
    SYM(ColorMaterial),
    SYM(PixelZoom),
    SYM(PixelStoref),
    SYM(PixelStorei),
    SYM(PixelTransferf),
    SYM(PixelTransferi),
    SYM(PixelMapfv),
    SYM(PixelMapuiv),
    SYM(PixelMapusv),
    SYM(GetPixelMapfv),
    SYM(GetPixelMapuiv),
    SYM(GetPixelMapusv),
    SYM(Bitmap),
    SYM(ReadPixels),
    SYM(DrawPixels),
    SYM(CopyPixels),
    SYM(StencilFunc),
    SYM(StencilMask),
    SYM(StencilOp),
    SYM(ClearStencil),
    SYM(TexGend),
    SYM(TexGenf),
    SYM(TexGeni),
    SYM(TexGendv),
    SYM(TexGenfv),
    SYM(TexGeniv),
    SYM(GetTexGendv),
    SYM(GetTexGenfv),
    SYM(GetTexGeniv),
    SYM(TexEnvf),
    SYM(TexEnvi),
    SYM(TexEnvfv),
    SYM(TexEnviv),
    SYM(GetTexEnvfv),
    SYM(GetTexEnviv),
    SYM(TexParameterf),
    SYM(TexParameteri),
    SYM(TexParameterfv),
    SYM(TexParameteriv),
    SYM(GetTexParameterfv),
    SYM(GetTexParameteriv),
    SYM(GetTexLevelParameterfv),
    SYM(GetTexLevelParameteriv),
    SYM(TexImage1D),
    SYM(TexImage2D),
    SYM(GetTexImage),
    SYM(GenTextures),
    SYM(DeleteTextures),
    SYM(BindTexture),
    SYM(PrioritizeTextures),
    SYM(AreTexturesResident),
    SYM(IsTexture),
    SYM(TexSubImage1D),
    SYM(TexSubImage2D),
    SYM(CopyTexImage1D),
    SYM(CopyTexImage2D),
    SYM(CopyTexSubImage1D),
    SYM(CopyTexSubImage2D),
    SYM(Map1d),
    SYM(Map1f),
    SYM(Map2d),
    SYM(Map2f),
    SYM(GetMapdv),
    SYM(GetMapfv),
    SYM(GetMapiv),
    SYM(EvalCoord1d),
    SYM(EvalCoord1f),
    SYM(EvalCoord1dv),
    SYM(EvalCoord1fv),
    SYM(EvalCoord2d),
    SYM(EvalCoord2f),
    SYM(EvalCoord2dv),
    SYM(EvalCoord2fv),
    SYM(MapGrid1d),
    SYM(MapGrid1f),
    SYM(MapGrid2d),
    SYM(MapGrid2f),
    SYM(EvalPoint1),
    SYM(EvalPoint2),
    SYM(EvalMesh1),
    SYM(EvalMesh2),
    SYM(Fogf),
    SYM(Fogi),
    SYM(Fogfv),
    SYM(Fogiv),
    SYM(FeedbackBuffer),
    SYM(PassThrough),
    SYM(SelectBuffer),
    SYM(InitNames),
    SYM(LoadName),
    SYM(PushName),
    SYM(PopName),
    SYM(DrawRangeElements),
    SYM(TexImage3D),
    SYM(TexSubImage3D),
    SYM(CopyTexSubImage3D),
    SYM(ColorTable),
    SYM(ColorSubTable),
    SYM(ColorTableParameteriv),
    SYM(ColorTableParameterfv),
    SYM(CopyColorSubTable),
    SYM(CopyColorTable),
    SYM(GetColorTable),
    SYM(GetColorTableParameterfv),
    SYM(GetColorTableParameteriv),
    SYM(BlendEquation),
    SYM(BlendColor),
    SYM(Histogram),
    SYM(ResetHistogram),
    SYM(GetHistogram),
    SYM(GetHistogramParameterfv),
    SYM(GetHistogramParameteriv),
    SYM(Minmax),
    SYM(ResetMinmax),
    SYM(GetMinmax),
    SYM(GetMinmaxParameterfv),
    SYM(GetMinmaxParameteriv),
    SYM(ConvolutionFilter1D),
    SYM(ConvolutionFilter2D),
    SYM(ConvolutionParameterf),
    SYM(ConvolutionParameterfv),
    SYM(ConvolutionParameteri),
    SYM(ConvolutionParameteriv),
    SYM(CopyConvolutionFilter1D),
    SYM(CopyConvolutionFilter2D),
    SYM(GetConvolutionFilter),
    SYM(GetConvolutionParameterfv),
    SYM(GetConvolutionParameteriv),
    SYM(SeparableFilter2D),
    SYM(GetSeparableFilter),
    SYM(ActiveTexture),
    SYM(ClientActiveTexture),
    SYM(CompressedTexImage1D),
    SYM(CompressedTexImage2D),
    SYM(CompressedTexImage3D),
    SYM(CompressedTexSubImage1D),
    SYM(CompressedTexSubImage2D),
    SYM(CompressedTexSubImage3D),
    SYM(GetCompressedTexImage),
    SYM(MultiTexCoord1d),
    SYM(MultiTexCoord1dv),
    SYM(MultiTexCoord1f),
    SYM(MultiTexCoord1fv),
    SYM(MultiTexCoord1i),
    SYM(MultiTexCoord1iv),
    SYM(MultiTexCoord1s),
    SYM(MultiTexCoord1sv),
    SYM(MultiTexCoord2d),
    SYM(MultiTexCoord2dv),
    SYM(MultiTexCoord2f),
    SYM(MultiTexCoord2fv),
    SYM(MultiTexCoord2i),
    SYM(MultiTexCoord2iv),
    SYM(MultiTexCoord2s),
    SYM(MultiTexCoord2sv),
    SYM(MultiTexCoord3d),
    SYM(MultiTexCoord3dv),
    SYM(MultiTexCoord3f),
    SYM(MultiTexCoord3fv),
    SYM(MultiTexCoord3i),
    SYM(MultiTexCoord3iv),
    SYM(MultiTexCoord3s),
    SYM(MultiTexCoord3sv),
    SYM(MultiTexCoord4d),
    SYM(MultiTexCoord4dv),
    SYM(MultiTexCoord4f),
    SYM(MultiTexCoord4fv),
    SYM(MultiTexCoord4i),
    SYM(MultiTexCoord4iv),
    SYM(MultiTexCoord4s),
    SYM(MultiTexCoord4sv),
    SYM(LoadTransposeMatrixd),
    SYM(LoadTransposeMatrixf),
    SYM(MultTransposeMatrixd),
    SYM(MultTransposeMatrixf),
    SYM(SampleCoverage),
    SYM(ActiveTextureARB),
    SYM(ClientActiveTextureARB),
    SYM(MultiTexCoord1dARB),
    SYM(MultiTexCoord1dvARB),
    SYM(MultiTexCoord1fARB),
    SYM(MultiTexCoord1fvARB),
    SYM(MultiTexCoord1iARB),
    SYM(MultiTexCoord1ivARB),
    SYM(MultiTexCoord1sARB),
    SYM(MultiTexCoord1svARB),
    SYM(MultiTexCoord2dARB),
    SYM(MultiTexCoord2dvARB),
    SYM(MultiTexCoord2fARB),
    SYM(MultiTexCoord2fvARB),
    SYM(MultiTexCoord2iARB),
    SYM(MultiTexCoord2ivARB),
    SYM(MultiTexCoord2sARB),
    SYM(MultiTexCoord2svARB),
    SYM(MultiTexCoord3dARB),
    SYM(MultiTexCoord3dvARB),
    SYM(MultiTexCoord3fARB),
    SYM(MultiTexCoord3fvARB),
    SYM(MultiTexCoord3iARB),
    SYM(MultiTexCoord3ivARB),
    SYM(MultiTexCoord3sARB),
    SYM(MultiTexCoord3svARB),
    SYM(MultiTexCoord4dARB),
    SYM(MultiTexCoord4dvARB),
    SYM(MultiTexCoord4fARB),
    SYM(MultiTexCoord4fvARB),
    SYM(MultiTexCoord4iARB),
    SYM(MultiTexCoord4ivARB),
    SYM(MultiTexCoord4sARB),
    SYM(MultiTexCoord4svARB),
    SYM(EGLImageTargetTexture2DOES),
    SYM(EGLImageTargetRenderbufferStorageOES),
#endif

    SYM(DrawRangeElements),
    SYM(TexImage3D),
    SYM(TexSubImage3D),
    SYM(CopyTexSubImage3D),
    SYM(ActiveTexture),
    SYM(SampleCoverage),
    SYM(CompressedTexImage3D),
    SYM(CompressedTexImage2D),
    SYM(CompressedTexImage1D),
    SYM(CompressedTexSubImage3D),
    SYM(CompressedTexSubImage2D),
    SYM(CompressedTexSubImage1D),
    SYM(GetCompressedTexImage),
    SYM(ClientActiveTexture),
    SYM(MultiTexCoord1d),
    SYM(MultiTexCoord1dv),
    SYM(MultiTexCoord1f),
    SYM(MultiTexCoord1fv),
    SYM(MultiTexCoord1i),
    SYM(MultiTexCoord1iv),
    SYM(MultiTexCoord1s),
    SYM(MultiTexCoord1sv),
    SYM(MultiTexCoord2d),
    SYM(MultiTexCoord2dv),
    SYM(MultiTexCoord2f),
    SYM(MultiTexCoord2fv),
    SYM(MultiTexCoord2i),
    SYM(MultiTexCoord2iv),
    SYM(MultiTexCoord2s),
    SYM(MultiTexCoord2sv),
    SYM(MultiTexCoord3d),
    SYM(MultiTexCoord3dv),
    SYM(MultiTexCoord3f),
    SYM(MultiTexCoord3fv),
    SYM(MultiTexCoord3i),
    SYM(MultiTexCoord3iv),
    SYM(MultiTexCoord3s),
    SYM(MultiTexCoord3sv),
    SYM(MultiTexCoord4d),
    SYM(MultiTexCoord4dv),
    SYM(MultiTexCoord4f),
    SYM(MultiTexCoord4fv),
    SYM(MultiTexCoord4i),
    SYM(MultiTexCoord4iv),
    SYM(MultiTexCoord4s),
    SYM(MultiTexCoord4sv),
    SYM(LoadTransposeMatrixf),
    SYM(LoadTransposeMatrixd),
    SYM(MultTransposeMatrixf),
    SYM(MultTransposeMatrixd),
    SYM(BlendFuncSeparate),
    SYM(MultiDrawArrays),
    SYM(MultiDrawElements),
    SYM(PointParameterf),
    SYM(PointParameterfv),
    SYM(PointParameteri),
    SYM(PointParameteriv),
    SYM(FogCoordf),
    SYM(FogCoordfv),
    SYM(FogCoordd),
    SYM(FogCoorddv),
    SYM(FogCoordPointer),
    SYM(SecondaryColor3b),
    SYM(SecondaryColor3bv),
    SYM(SecondaryColor3d),
    SYM(SecondaryColor3dv),
    SYM(SecondaryColor3f),
    SYM(SecondaryColor3fv),
    SYM(SecondaryColor3i),
    SYM(SecondaryColor3iv),
    SYM(SecondaryColor3s),
    SYM(SecondaryColor3sv),
    SYM(SecondaryColor3ub),
    SYM(SecondaryColor3ubv),
    SYM(SecondaryColor3ui),
    SYM(SecondaryColor3uiv),
    SYM(SecondaryColor3us),
    SYM(SecondaryColor3usv),
    SYM(SecondaryColorPointer),
    SYM(WindowPos2d),
    SYM(WindowPos2dv),
    SYM(WindowPos2f),
    SYM(WindowPos2fv),
    SYM(WindowPos2i),
    SYM(WindowPos2iv),
    SYM(WindowPos2s),
    SYM(WindowPos2sv),
    SYM(WindowPos3d),
    SYM(WindowPos3dv),
    SYM(WindowPos3f),
    SYM(WindowPos3fv),
    SYM(WindowPos3i),
    SYM(WindowPos3iv),
    SYM(WindowPos3s),
    SYM(WindowPos3sv),
    SYM(BlendColor),
    SYM(BlendEquation),
    SYM(GenQueries),
    SYM(DeleteQueries),
    SYM(IsQuery),
    SYM(BeginQuery),
    SYM(EndQuery),
    SYM(GetQueryiv),
    SYM(GetQueryObjectiv),
    SYM(GetQueryObjectuiv),
    SYM(BindBuffer),
    SYM(DeleteBuffers),
    SYM(GenBuffers),
    SYM(IsBuffer),
    SYM(BufferData),
    SYM(BufferSubData),
    SYM(GetBufferSubData),
    SYM(MapBuffer),
    SYM(UnmapBuffer),
    SYM(GetBufferParameteriv),
    SYM(GetBufferPointerv),
    SYM(BlendEquationSeparate),
    SYM(DrawBuffers),
    SYM(StencilOpSeparate),
    SYM(StencilFuncSeparate),
    SYM(StencilMaskSeparate),
    SYM(AttachShader),
    SYM(BindAttribLocation),
    SYM(CompileShader),
    SYM(CreateProgram),
    SYM(CreateShader),
    SYM(DeleteProgram),
    SYM(DeleteShader),
    SYM(DetachShader),
    SYM(DisableVertexAttribArray),
    SYM(EnableVertexAttribArray),
    SYM(GetActiveAttrib),
    SYM(GetActiveUniform),
    SYM(GetAttachedShaders),
    SYM(GetAttribLocation),
    SYM(GetProgramiv),
    SYM(GetProgramInfoLog),
    SYM(GetShaderiv),
    SYM(GetShaderInfoLog),
    SYM(GetShaderSource),
    SYM(GetUniformLocation),
    SYM(GetUniformfv),
    SYM(GetUniformiv),
    SYM(GetVertexAttribdv),
    SYM(GetVertexAttribfv),
    SYM(GetVertexAttribiv),
    SYM(GetVertexAttribPointerv),
    SYM(IsProgram),
    SYM(IsShader),
    SYM(LinkProgram),
    SYM(ShaderSource),
    SYM(UseProgram),
    SYM(Uniform1f),
    SYM(Uniform2f),
    SYM(Uniform3f),
    SYM(Uniform4f),
    SYM(Uniform1i),
    SYM(Uniform2i),
    SYM(Uniform3i),
    SYM(Uniform4i),
    SYM(Uniform1fv),
    SYM(Uniform2fv),
    SYM(Uniform3fv),
    SYM(Uniform4fv),
    SYM(Uniform1iv),
    SYM(Uniform2iv),
    SYM(Uniform3iv),
    SYM(Uniform4iv),
    SYM(UniformMatrix2fv),
    SYM(UniformMatrix3fv),
    SYM(UniformMatrix4fv),
    SYM(ValidateProgram),
    SYM(VertexAttrib1d),
    SYM(VertexAttrib1dv),
    SYM(VertexAttrib1f),
    SYM(VertexAttrib1fv),
    SYM(VertexAttrib1s),
    SYM(VertexAttrib1sv),
    SYM(VertexAttrib2d),
    SYM(VertexAttrib2dv),
    SYM(VertexAttrib2f),
    SYM(VertexAttrib2fv),
    SYM(VertexAttrib2s),
    SYM(VertexAttrib2sv),
    SYM(VertexAttrib3d),
    SYM(VertexAttrib3dv),
    SYM(VertexAttrib3f),
    SYM(VertexAttrib3fv),
    SYM(VertexAttrib3s),
    SYM(VertexAttrib3sv),
    SYM(VertexAttrib4Nbv),
    SYM(VertexAttrib4Niv),
    SYM(VertexAttrib4Nsv),
    SYM(VertexAttrib4Nub),
    SYM(VertexAttrib4Nubv),
    SYM(VertexAttrib4Nuiv),
    SYM(VertexAttrib4Nusv),
    SYM(VertexAttrib4bv),
    SYM(VertexAttrib4d),
    SYM(VertexAttrib4dv),
    SYM(VertexAttrib4f),
    SYM(VertexAttrib4fv),
    SYM(VertexAttrib4iv),
    SYM(VertexAttrib4s),
    SYM(VertexAttrib4sv),
    SYM(VertexAttrib4ubv),
    SYM(VertexAttrib4uiv),
    SYM(VertexAttrib4usv),
    SYM(VertexAttribPointer),
    SYM(UniformMatrix2x3fv),
    SYM(UniformMatrix3x2fv),
    SYM(UniformMatrix2x4fv),
    SYM(UniformMatrix4x2fv),
    SYM(UniformMatrix3x4fv),
    SYM(UniformMatrix4x3fv),
    SYM(ColorMaski),
    SYM(GetBooleani_v),
    SYM(GetIntegeri_v),
    SYM(Enablei),
    SYM(Disablei),
    SYM(IsEnabledi),
    SYM(BeginTransformFeedback),
    SYM(EndTransformFeedback),
    SYM(BindBufferRange),
    SYM(BindBufferBase),
    SYM(TransformFeedbackVaryings),
    SYM(GetTransformFeedbackVarying),
    SYM(ClampColor),
    SYM(BeginConditionalRender),
    SYM(EndConditionalRender),
    SYM(VertexAttribIPointer),
    SYM(GetVertexAttribIiv),
    SYM(GetVertexAttribIuiv),
    SYM(VertexAttribI1i),
    SYM(VertexAttribI2i),
    SYM(VertexAttribI3i),
    SYM(VertexAttribI4i),
    SYM(VertexAttribI1ui),
    SYM(VertexAttribI2ui),
    SYM(VertexAttribI3ui),
    SYM(VertexAttribI4ui),
    SYM(VertexAttribI1iv),
    SYM(VertexAttribI2iv),
    SYM(VertexAttribI3iv),
    SYM(VertexAttribI4iv),
    SYM(VertexAttribI1uiv),
    SYM(VertexAttribI2uiv),
    SYM(VertexAttribI3uiv),
    SYM(VertexAttribI4uiv),
    SYM(VertexAttribI4bv),
    SYM(VertexAttribI4sv),
    SYM(VertexAttribI4ubv),
    SYM(VertexAttribI4usv),
    SYM(GetUniformuiv),
    SYM(BindFragDataLocation),
    SYM(GetFragDataLocation),
    SYM(Uniform1ui),
    SYM(Uniform2ui),
    SYM(Uniform3ui),
    SYM(Uniform4ui),
    SYM(Uniform1uiv),
    SYM(Uniform2uiv),
    SYM(Uniform3uiv),
    SYM(Uniform4uiv),
    SYM(TexParameterIiv),
    SYM(TexParameterIuiv),
    SYM(GetTexParameterIiv),
    SYM(GetTexParameterIuiv),
    SYM(ClearBufferiv),
    SYM(ClearBufferuiv),
    SYM(ClearBufferfv),
    SYM(ClearBufferfi),
    SYM(GetStringi),
    SYM(IsRenderbuffer),
    SYM(BindRenderbuffer),
    SYM(DeleteRenderbuffers),
    SYM(GenRenderbuffers),
    SYM(RenderbufferStorage),
    SYM(GetRenderbufferParameteriv),
    SYM(IsFramebuffer),
    SYM(BindFramebuffer),
    SYM(DeleteFramebuffers),
    SYM(GenFramebuffers),
    SYM(CheckFramebufferStatus),
    SYM(FramebufferTexture1D),
    SYM(FramebufferTexture2D),
    SYM(FramebufferTexture3D),
    SYM(FramebufferRenderbuffer),
    SYM(GetFramebufferAttachmentParameteriv),
    SYM(GenerateMipmap),
    SYM(BlitFramebuffer),
    SYM(RenderbufferStorageMultisample),
    SYM(FramebufferTextureLayer),
    SYM(MapBufferRange),
    SYM(FlushMappedBufferRange),
    SYM(BindVertexArray),
    SYM(DeleteVertexArrays),
    SYM(GenVertexArrays),
    SYM(IsVertexArray),
    SYM(DrawArraysInstanced),
    SYM(DrawElementsInstanced),
    SYM(TexBuffer),
    SYM(PrimitiveRestartIndex),
    SYM(CopyBufferSubData),
    SYM(GetUniformIndices),
    SYM(GetActiveUniformsiv),
    SYM(GetActiveUniformName),
    SYM(GetUniformBlockIndex),
    SYM(GetActiveUniformBlockiv),
    SYM(GetActiveUniformBlockName),
    SYM(UniformBlockBinding),
    SYM(DrawElementsBaseVertex),
    SYM(DrawRangeElementsBaseVertex),
    SYM(DrawElementsInstancedBaseVertex),
    SYM(MultiDrawElementsBaseVertex),
    SYM(ProvokingVertex),
    SYM(FenceSync),
    SYM(IsSync),
    SYM(DeleteSync),
    SYM(ClientWaitSync),
    SYM(WaitSync),
    SYM(GetInteger64v),
    SYM(GetSynciv),
    SYM(GetInteger64i_v),
    SYM(GetBufferParameteri64v),
    SYM(FramebufferTexture),
    SYM(TexImage2DMultisample),
    SYM(TexImage3DMultisample),
    SYM(GetMultisamplefv),
    SYM(SampleMaski),
    SYM(BindFragDataLocationIndexed),
    SYM(GetFragDataIndex),
    SYM(GenSamplers),
    SYM(DeleteSamplers),
    SYM(IsSampler),
    SYM(BindSampler),
    SYM(SamplerParameteri),
    SYM(SamplerParameteriv),
    SYM(SamplerParameterf),
    SYM(SamplerParameterfv),
    SYM(SamplerParameterIiv),
    SYM(SamplerParameterIuiv),
    SYM(GetSamplerParameteriv),
    SYM(GetSamplerParameterIiv),
    SYM(GetSamplerParameterfv),
    SYM(GetSamplerParameterIuiv),
    SYM(QueryCounter),
    SYM(GetQueryObjecti64v),
    SYM(GetQueryObjectui64v),
    SYM(VertexAttribDivisor),
    SYM(VertexAttribP1ui),
    SYM(VertexAttribP1uiv),
    SYM(VertexAttribP2ui),
    SYM(VertexAttribP2uiv),
    SYM(VertexAttribP3ui),
    SYM(VertexAttribP3uiv),
    SYM(VertexAttribP4ui),
    SYM(VertexAttribP4uiv),
    SYM(VertexP2ui),
    SYM(VertexP2uiv),
    SYM(VertexP3ui),
    SYM(VertexP3uiv),
    SYM(VertexP4ui),
    SYM(VertexP4uiv),
    SYM(TexCoordP1ui),
    SYM(TexCoordP1uiv),
    SYM(TexCoordP2ui),
    SYM(TexCoordP2uiv),
    SYM(TexCoordP3ui),
    SYM(TexCoordP3uiv),
    SYM(TexCoordP4ui),
    SYM(TexCoordP4uiv),
    SYM(MultiTexCoordP1ui),
    SYM(MultiTexCoordP1uiv),
    SYM(MultiTexCoordP2ui),
    SYM(MultiTexCoordP2uiv),
    SYM(MultiTexCoordP3ui),
    SYM(MultiTexCoordP3uiv),
    SYM(MultiTexCoordP4ui),
    SYM(MultiTexCoordP4uiv),
    SYM(NormalP3ui),
    SYM(NormalP3uiv),
    SYM(ColorP3ui),
    SYM(ColorP3uiv),
    SYM(ColorP4ui),
    SYM(ColorP4uiv),
    SYM(SecondaryColorP3ui),
    SYM(SecondaryColorP3uiv),
    SYM(MinSampleShading),
    SYM(BlendEquationi),
    SYM(BlendEquationSeparatei),
    SYM(BlendFunci),
    SYM(BlendFuncSeparatei),
    SYM(DrawArraysIndirect),
    SYM(DrawElementsIndirect),
    SYM(Uniform1d),
    SYM(Uniform2d),
    SYM(Uniform3d),
    SYM(Uniform4d),
    SYM(Uniform1dv),
    SYM(Uniform2dv),
    SYM(Uniform3dv),
    SYM(Uniform4dv),
    SYM(UniformMatrix2dv),
    SYM(UniformMatrix3dv),
    SYM(UniformMatrix4dv),
    SYM(UniformMatrix2x3dv),
    SYM(UniformMatrix2x4dv),
    SYM(UniformMatrix3x2dv),
    SYM(UniformMatrix3x4dv),
    SYM(UniformMatrix4x2dv),
    SYM(UniformMatrix4x3dv),
    SYM(GetUniformdv),
    SYM(GetSubroutineUniformLocation),
    SYM(GetSubroutineIndex),
    SYM(GetActiveSubroutineUniformiv),
    SYM(GetActiveSubroutineUniformName),
    SYM(GetActiveSubroutineName),
    SYM(UniformSubroutinesuiv),
    SYM(GetUniformSubroutineuiv),
    SYM(GetProgramStageiv),
    SYM(PatchParameteri),
    SYM(PatchParameterfv),
    SYM(BindTransformFeedback),
    SYM(DeleteTransformFeedbacks),
    SYM(GenTransformFeedbacks),
    SYM(IsTransformFeedback),
    SYM(PauseTransformFeedback),
    SYM(ResumeTransformFeedback),
    SYM(DrawTransformFeedback),
    SYM(DrawTransformFeedbackStream),
    SYM(BeginQueryIndexed),
    SYM(EndQueryIndexed),
    SYM(GetQueryIndexediv),
    SYM(ReleaseShaderCompiler),
    SYM(ShaderBinary),
    SYM(GetShaderPrecisionFormat),
    SYM(DepthRangef),
    SYM(ClearDepthf),
    SYM(GetProgramBinary),
    SYM(ProgramBinary),
    SYM(ProgramParameteri),
    SYM(UseProgramStages),
    SYM(ActiveShaderProgram),
    SYM(CreateShaderProgramv),
    SYM(BindProgramPipeline),
    SYM(DeleteProgramPipelines),
    SYM(GenProgramPipelines),
    SYM(IsProgramPipeline),
    SYM(GetProgramPipelineiv),
    SYM(ProgramUniform1i),
    SYM(ProgramUniform1iv),
    SYM(ProgramUniform1f),
    SYM(ProgramUniform1fv),
    SYM(ProgramUniform1d),
    SYM(ProgramUniform1dv),
    SYM(ProgramUniform1ui),
    SYM(ProgramUniform1uiv),
    SYM(ProgramUniform2i),
    SYM(ProgramUniform2iv),
    SYM(ProgramUniform2f),
    SYM(ProgramUniform2fv),
    SYM(ProgramUniform2d),
    SYM(ProgramUniform2dv),
    SYM(ProgramUniform2ui),
    SYM(ProgramUniform2uiv),
    SYM(ProgramUniform3i),
    SYM(ProgramUniform3iv),
    SYM(ProgramUniform3f),
    SYM(ProgramUniform3fv),
    SYM(ProgramUniform3d),
    SYM(ProgramUniform3dv),
    SYM(ProgramUniform3ui),
    SYM(ProgramUniform3uiv),
    SYM(ProgramUniform4i),
    SYM(ProgramUniform4iv),
    SYM(ProgramUniform4f),
    SYM(ProgramUniform4fv),
    SYM(ProgramUniform4d),
    SYM(ProgramUniform4dv),
    SYM(ProgramUniform4ui),
    SYM(ProgramUniform4uiv),
    SYM(ProgramUniformMatrix2fv),
    SYM(ProgramUniformMatrix3fv),
    SYM(ProgramUniformMatrix4fv),
    SYM(ProgramUniformMatrix2dv),
    SYM(ProgramUniformMatrix3dv),
    SYM(ProgramUniformMatrix4dv),
    SYM(ProgramUniformMatrix2x3fv),
    SYM(ProgramUniformMatrix3x2fv),
    SYM(ProgramUniformMatrix2x4fv),
    SYM(ProgramUniformMatrix4x2fv),
    SYM(ProgramUniformMatrix3x4fv),
    SYM(ProgramUniformMatrix4x3fv),
    SYM(ProgramUniformMatrix2x3dv),
    SYM(ProgramUniformMatrix3x2dv),
    SYM(ProgramUniformMatrix2x4dv),
    SYM(ProgramUniformMatrix4x2dv),
    SYM(ProgramUniformMatrix3x4dv),
    SYM(ProgramUniformMatrix4x3dv),
    SYM(ValidateProgramPipeline),
    SYM(GetProgramPipelineInfoLog),
    SYM(VertexAttribL1d),
    SYM(VertexAttribL2d),
    SYM(VertexAttribL3d),
    SYM(VertexAttribL4d),
    SYM(VertexAttribL1dv),
    SYM(VertexAttribL2dv),
    SYM(VertexAttribL3dv),
    SYM(VertexAttribL4dv),
    SYM(VertexAttribLPointer),
    SYM(GetVertexAttribLdv),
    SYM(ViewportArrayv),
    SYM(ViewportIndexedf),
    SYM(ViewportIndexedfv),
    SYM(ScissorArrayv),
    SYM(ScissorIndexed),
    SYM(ScissorIndexedv),
    SYM(DepthRangeArrayv),
    SYM(DepthRangeIndexed),
    SYM(GetFloati_v),
    SYM(GetDoublei_v),
    SYM(DrawArraysInstancedBaseInstance),
    SYM(DrawElementsInstancedBaseInstance),
    SYM(DrawElementsInstancedBaseVertexBaseInstance),
    SYM(GetInternalformativ),
    SYM(GetActiveAtomicCounterBufferiv),
    SYM(BindImageTexture),
    SYM(MemoryBarrier),
    SYM(TexStorage1D),
    SYM(TexStorage2D),
    SYM(TexStorage3D),
    SYM(DrawTransformFeedbackInstanced),
    SYM(DrawTransformFeedbackStreamInstanced),
    SYM(ClearBufferData),
    SYM(ClearBufferSubData),
    SYM(DispatchCompute),
    SYM(DispatchComputeIndirect),
    SYM(CopyImageSubData),
    SYM(FramebufferParameteri),
    SYM(GetFramebufferParameteriv),
    SYM(GetInternalformati64v),
    SYM(InvalidateTexSubImage),
    SYM(InvalidateTexImage),
    SYM(InvalidateBufferSubData),
    SYM(InvalidateBufferData),
    SYM(InvalidateFramebuffer),
    SYM(InvalidateSubFramebuffer),
    SYM(MultiDrawArraysIndirect),
    SYM(MultiDrawElementsIndirect),
    SYM(GetProgramInterfaceiv),
    SYM(GetProgramResourceIndex),
    SYM(GetProgramResourceName),
    SYM(GetProgramResourceiv),
    SYM(GetProgramResourceLocation),
    SYM(GetProgramResourceLocationIndex),
    SYM(ShaderStorageBlockBinding),
    SYM(TexBufferRange),
    SYM(TexStorage2DMultisample),
    SYM(TexStorage3DMultisample),
    SYM(TextureView),
    SYM(BindVertexBuffer),
    SYM(VertexAttribFormat),
    SYM(VertexAttribIFormat),
    SYM(VertexAttribLFormat),
    SYM(VertexAttribBinding),
    SYM(VertexBindingDivisor),
    SYM(DebugMessageControl),
    SYM(DebugMessageInsert),
    SYM(DebugMessageCallback),
    SYM(GetDebugMessageLog),
    SYM(PushDebugGroup),
    SYM(PopDebugGroup),
    SYM(ObjectLabel),
    SYM(GetObjectLabel),
    SYM(ObjectPtrLabel),
    SYM(GetObjectPtrLabel),
    SYM(BufferStorage),
    SYM(ClearTexImage),
    SYM(ClearTexSubImage),
    SYM(BindBuffersBase),
    SYM(BindBuffersRange),
    SYM(BindTextures),
    SYM(BindSamplers),
    SYM(BindImageTextures),
    SYM(BindVertexBuffers),
    SYM(GetTextureHandleARB),
    SYM(GetTextureSamplerHandleARB),
    SYM(MakeTextureHandleResidentARB),
    SYM(MakeTextureHandleNonResidentARB),
    SYM(GetImageHandleARB),
    SYM(MakeImageHandleResidentARB),
    SYM(MakeImageHandleNonResidentARB),
    SYM(UniformHandleui64ARB),
    SYM(UniformHandleui64vARB),
    SYM(ProgramUniformHandleui64ARB),
    SYM(ProgramUniformHandleui64vARB),
    SYM(IsTextureHandleResidentARB),
    SYM(IsImageHandleResidentARB),
    SYM(VertexAttribL1ui64ARB),
    SYM(VertexAttribL1ui64vARB),
    SYM(GetVertexAttribLui64vARB),
    SYM(CreateSyncFromCLeventARB),
    SYM(ClampColorARB),
    SYM(DispatchComputeGroupSizeARB),
    SYM(DebugMessageControlARB),
    SYM(DebugMessageInsertARB),
    SYM(DebugMessageCallbackARB),
    SYM(GetDebugMessageLogARB),
    SYM(DrawBuffersARB),
    SYM(BlendEquationiARB),
    SYM(BlendEquationSeparateiARB),
    SYM(BlendFunciARB),
    SYM(BlendFuncSeparateiARB),
    SYM(DrawArraysInstancedARB),
    SYM(DrawElementsInstancedARB),
    SYM(ProgramStringARB),
    SYM(BindProgramARB),
    SYM(DeleteProgramsARB),
    SYM(GenProgramsARB),
    SYM(ProgramEnvParameter4dARB),
    SYM(ProgramEnvParameter4dvARB),
    SYM(ProgramEnvParameter4fARB),
    SYM(ProgramEnvParameter4fvARB),
    SYM(ProgramLocalParameter4dARB),
    SYM(ProgramLocalParameter4dvARB),
    SYM(ProgramLocalParameter4fARB),
    SYM(ProgramLocalParameter4fvARB),
    SYM(GetProgramEnvParameterdvARB),
    SYM(GetProgramEnvParameterfvARB),
    SYM(GetProgramLocalParameterdvARB),
    SYM(GetProgramLocalParameterfvARB),
    SYM(GetProgramivARB),
    SYM(GetProgramStringARB),
    SYM(IsProgramARB),
    SYM(ProgramParameteriARB),
    SYM(FramebufferTextureARB),
    SYM(FramebufferTextureLayerARB),
    SYM(FramebufferTextureFaceARB),
    SYM(ColorTable),
    SYM(ColorTableParameterfv),
    SYM(ColorTableParameteriv),
    SYM(CopyColorTable),
    SYM(GetColorTable),
    SYM(GetColorTableParameterfv),
    SYM(GetColorTableParameteriv),
    SYM(ColorSubTable),
    SYM(CopyColorSubTable),
    SYM(ConvolutionFilter1D),
    SYM(ConvolutionFilter2D),
    SYM(ConvolutionParameterf),
    SYM(ConvolutionParameterfv),
    SYM(ConvolutionParameteri),
    SYM(ConvolutionParameteriv),
    SYM(CopyConvolutionFilter1D),
    SYM(CopyConvolutionFilter2D),
    SYM(GetConvolutionFilter),
    SYM(GetConvolutionParameterfv),
    SYM(GetConvolutionParameteriv),
    SYM(GetSeparableFilter),
    SYM(SeparableFilter2D),
    SYM(GetHistogram),
    SYM(GetHistogramParameterfv),
    SYM(GetHistogramParameteriv),
    SYM(GetMinmax),
    SYM(GetMinmaxParameterfv),
    SYM(GetMinmaxParameteriv),
    SYM(Histogram),
    SYM(Minmax),
    SYM(ResetHistogram),
    SYM(ResetMinmax),
    SYM(MultiDrawArraysIndirectCountARB),
    SYM(MultiDrawElementsIndirectCountARB),
    SYM(VertexAttribDivisorARB),
    SYM(CurrentPaletteMatrixARB),
    SYM(MatrixIndexubvARB),
    SYM(MatrixIndexusvARB),
    SYM(MatrixIndexuivARB),
    SYM(MatrixIndexPointerARB),
    SYM(SampleCoverageARB),
    SYM(ActiveTextureARB),
    SYM(ClientActiveTextureARB),
    SYM(MultiTexCoord1dARB),
    SYM(MultiTexCoord1dvARB),
    SYM(MultiTexCoord1fARB),
    SYM(MultiTexCoord1fvARB),
    SYM(MultiTexCoord1iARB),
    SYM(MultiTexCoord1ivARB),
    SYM(MultiTexCoord1sARB),
    SYM(MultiTexCoord1svARB),
    SYM(MultiTexCoord2dARB),
    SYM(MultiTexCoord2dvARB),
    SYM(MultiTexCoord2fARB),
    SYM(MultiTexCoord2fvARB),
    SYM(MultiTexCoord2iARB),
    SYM(MultiTexCoord2ivARB),
    SYM(MultiTexCoord2sARB),
    SYM(MultiTexCoord2svARB),
    SYM(MultiTexCoord3dARB),
    SYM(MultiTexCoord3dvARB),
    SYM(MultiTexCoord3fARB),
    SYM(MultiTexCoord3fvARB),
    SYM(MultiTexCoord3iARB),
    SYM(MultiTexCoord3ivARB),
    SYM(MultiTexCoord3sARB),
    SYM(MultiTexCoord3svARB),
    SYM(MultiTexCoord4dARB),
    SYM(MultiTexCoord4dvARB),
    SYM(MultiTexCoord4fARB),
    SYM(MultiTexCoord4fvARB),
    SYM(MultiTexCoord4iARB),
    SYM(MultiTexCoord4ivARB),
    SYM(MultiTexCoord4sARB),
    SYM(MultiTexCoord4svARB),
    SYM(GenQueriesARB),
    SYM(DeleteQueriesARB),
    SYM(IsQueryARB),
    SYM(BeginQueryARB),
    SYM(EndQueryARB),
    SYM(GetQueryivARB),
    SYM(GetQueryObjectivARB),
    SYM(GetQueryObjectuivARB),
    SYM(PointParameterfARB),
    SYM(PointParameterfvARB),
    SYM(GetGraphicsResetStatusARB),
    SYM(GetnTexImageARB),
    SYM(ReadnPixelsARB),
    SYM(GetnCompressedTexImageARB),
    SYM(GetnUniformfvARB),
    SYM(GetnUniformivARB),
    SYM(GetnUniformuivARB),
    SYM(GetnUniformdvARB),
    SYM(GetnMapdvARB),
    SYM(GetnMapfvARB),
    SYM(GetnMapivARB),
    SYM(GetnPixelMapfvARB),
    SYM(GetnPixelMapuivARB),
    SYM(GetnPixelMapusvARB),
    SYM(GetnPolygonStippleARB),
    SYM(GetnColorTableARB),
    SYM(GetnConvolutionFilterARB),
    SYM(GetnSeparableFilterARB),
    SYM(GetnHistogramARB),
    SYM(GetnMinmaxARB),
    SYM(MinSampleShadingARB),
    SYM(DeleteObjectARB),
    SYM(GetHandleARB),
    SYM(DetachObjectARB),
    SYM(CreateShaderObjectARB),
    SYM(ShaderSourceARB),
    SYM(CompileShaderARB),
    SYM(CreateProgramObjectARB),
    SYM(AttachObjectARB),
    SYM(LinkProgramARB),
    SYM(UseProgramObjectARB),
    SYM(ValidateProgramARB),
    SYM(Uniform1fARB),
    SYM(Uniform2fARB),
    SYM(Uniform3fARB),
    SYM(Uniform4fARB),
    SYM(Uniform1iARB),
    SYM(Uniform2iARB),
    SYM(Uniform3iARB),
    SYM(Uniform4iARB),
    SYM(Uniform1fvARB),
    SYM(Uniform2fvARB),
    SYM(Uniform3fvARB),
    SYM(Uniform4fvARB),
    SYM(Uniform1ivARB),
    SYM(Uniform2ivARB),
    SYM(Uniform3ivARB),
    SYM(Uniform4ivARB),
    SYM(UniformMatrix2fvARB),
    SYM(UniformMatrix3fvARB),
    SYM(UniformMatrix4fvARB),
    SYM(GetObjectParameterfvARB),
    SYM(GetObjectParameterivARB),
    SYM(GetInfoLogARB),
    SYM(GetAttachedObjectsARB),
    SYM(GetUniformLocationARB),
    SYM(GetActiveUniformARB),
    SYM(GetUniformfvARB),
    SYM(GetUniformivARB),
    SYM(GetShaderSourceARB),
    SYM(NamedStringARB),
    SYM(DeleteNamedStringARB),
    SYM(CompileShaderIncludeARB),
    SYM(IsNamedStringARB),
    SYM(GetNamedStringARB),
    SYM(GetNamedStringivARB),
    SYM(TexPageCommitmentARB),
    SYM(TexBufferARB),
    SYM(CompressedTexImage3DARB),
    SYM(CompressedTexImage2DARB),
    SYM(CompressedTexImage1DARB),
    SYM(CompressedTexSubImage3DARB),
    SYM(CompressedTexSubImage2DARB),
    SYM(CompressedTexSubImage1DARB),
    SYM(GetCompressedTexImageARB),
    SYM(LoadTransposeMatrixfARB),
    SYM(LoadTransposeMatrixdARB),
    SYM(MultTransposeMatrixfARB),
    SYM(MultTransposeMatrixdARB),
    SYM(WeightbvARB),
    SYM(WeightsvARB),
    SYM(WeightivARB),
    SYM(WeightfvARB),
    SYM(WeightdvARB),
    SYM(WeightubvARB),
    SYM(WeightusvARB),
    SYM(WeightuivARB),
    SYM(WeightPointerARB),
    SYM(VertexBlendARB),
    SYM(BindBufferARB),
    SYM(DeleteBuffersARB),
    SYM(GenBuffersARB),
    SYM(IsBufferARB),
    SYM(BufferDataARB),
    SYM(BufferSubDataARB),
    SYM(GetBufferSubDataARB),
    SYM(MapBufferARB),
    SYM(UnmapBufferARB),
    SYM(GetBufferParameterivARB),
    SYM(GetBufferPointervARB),
    SYM(VertexAttrib1dARB),
    SYM(VertexAttrib1dvARB),
    SYM(VertexAttrib1fARB),
    SYM(VertexAttrib1fvARB),
    SYM(VertexAttrib1sARB),
    SYM(VertexAttrib1svARB),
    SYM(VertexAttrib2dARB),
    SYM(VertexAttrib2dvARB),
    SYM(VertexAttrib2fARB),
    SYM(VertexAttrib2fvARB),
    SYM(VertexAttrib2sARB),
    SYM(VertexAttrib2svARB),
    SYM(VertexAttrib3dARB),
    SYM(VertexAttrib3dvARB),
    SYM(VertexAttrib3fARB),
    SYM(VertexAttrib3fvARB),
    SYM(VertexAttrib3sARB),
    SYM(VertexAttrib3svARB),
    SYM(VertexAttrib4NbvARB),
    SYM(VertexAttrib4NivARB),
    SYM(VertexAttrib4NsvARB),
    SYM(VertexAttrib4NubARB),
    SYM(VertexAttrib4NubvARB),
    SYM(VertexAttrib4NuivARB),
    SYM(VertexAttrib4NusvARB),
    SYM(VertexAttrib4bvARB),
    SYM(VertexAttrib4dARB),
    SYM(VertexAttrib4dvARB),
    SYM(VertexAttrib4fARB),
    SYM(VertexAttrib4fvARB),
    SYM(VertexAttrib4ivARB),
    SYM(VertexAttrib4sARB),
    SYM(VertexAttrib4svARB),
    SYM(VertexAttrib4ubvARB),
    SYM(VertexAttrib4uivARB),
    SYM(VertexAttrib4usvARB),
    SYM(VertexAttribPointerARB),
    SYM(EnableVertexAttribArrayARB),
    SYM(DisableVertexAttribArrayARB),
    SYM(GetVertexAttribdvARB),
    SYM(GetVertexAttribfvARB),
    SYM(GetVertexAttribivARB),
    SYM(GetVertexAttribPointervARB),
    SYM(BindAttribLocationARB),
    SYM(GetActiveAttribARB),
    SYM(GetAttribLocationARB),
    SYM(WindowPos2dARB),
    SYM(WindowPos2dvARB),
    SYM(WindowPos2fARB),
    SYM(WindowPos2fvARB),
    SYM(WindowPos2iARB),
    SYM(WindowPos2ivARB),
    SYM(WindowPos2sARB),
    SYM(WindowPos2svARB),
    SYM(WindowPos3dARB),
    SYM(WindowPos3dvARB),
    SYM(WindowPos3fARB),
    SYM(WindowPos3fvARB),
    SYM(WindowPos3iARB),
    SYM(WindowPos3ivARB),
    SYM(WindowPos3sARB),
    SYM(WindowPos3svARB),
    SYM(MultiTexCoord1bOES),
    SYM(MultiTexCoord1bvOES),
    SYM(MultiTexCoord2bOES),
    SYM(MultiTexCoord2bvOES),
    SYM(MultiTexCoord3bOES),
    SYM(MultiTexCoord3bvOES),
    SYM(MultiTexCoord4bOES),
    SYM(MultiTexCoord4bvOES),
    SYM(TexCoord1bOES),
    SYM(TexCoord1bvOES),
    SYM(TexCoord2bOES),
    SYM(TexCoord2bvOES),
    SYM(TexCoord3bOES),
    SYM(TexCoord3bvOES),
    SYM(TexCoord4bOES),
    SYM(TexCoord4bvOES),
    SYM(Vertex2bOES),
    SYM(Vertex2bvOES),
    SYM(Vertex3bOES),
    SYM(Vertex3bvOES),
    SYM(Vertex4bOES),
    SYM(Vertex4bvOES),
    SYM(AlphaFuncxOES),
    SYM(ClearColorxOES),
    SYM(ClearDepthxOES),
    SYM(ClipPlanexOES),
    SYM(Color4xOES),
    SYM(DepthRangexOES),
    SYM(FogxOES),
    SYM(FogxvOES),
    SYM(FrustumxOES),
    SYM(GetClipPlanexOES),
    SYM(GetFixedvOES),
    SYM(GetTexEnvxvOES),
    SYM(GetTexParameterxvOES),
    SYM(LightModelxOES),
    SYM(LightModelxvOES),
    SYM(LightxOES),
    SYM(LightxvOES),
    SYM(LineWidthxOES),
    SYM(LoadMatrixxOES),
    SYM(MaterialxOES),
    SYM(MaterialxvOES),
    SYM(MultMatrixxOES),
    SYM(MultiTexCoord4xOES),
    SYM(Normal3xOES),
    SYM(OrthoxOES),
    SYM(PointParameterxvOES),
    SYM(PointSizexOES),
    SYM(PolygonOffsetxOES),
    SYM(RotatexOES),
    SYM(SampleCoverageOES),
    SYM(ScalexOES),
    SYM(TexEnvxOES),
    SYM(TexEnvxvOES),
    SYM(TexParameterxOES),
    SYM(TexParameterxvOES),
    SYM(TranslatexOES),
    SYM(AccumxOES),
    SYM(BitmapxOES),
    SYM(BlendColorxOES),
    SYM(ClearAccumxOES),
    SYM(Color3xOES),
    SYM(Color3xvOES),
    SYM(Color4xvOES),
    SYM(ConvolutionParameterxOES),
    SYM(ConvolutionParameterxvOES),
    SYM(EvalCoord1xOES),
    SYM(EvalCoord1xvOES),
    SYM(EvalCoord2xOES),
    SYM(EvalCoord2xvOES),
    SYM(FeedbackBufferxOES),
    SYM(GetConvolutionParameterxvOES),
    SYM(GetHistogramParameterxvOES),
    SYM(GetLightxOES),
    SYM(GetMapxvOES),
    SYM(GetMaterialxOES),
    SYM(GetPixelMapxv),
    SYM(GetTexGenxvOES),
    SYM(GetTexLevelParameterxvOES),
    SYM(IndexxOES),
    SYM(IndexxvOES),
    SYM(LoadTransposeMatrixxOES),
    SYM(Map1xOES),
    SYM(Map2xOES),
    SYM(MapGrid1xOES),
    SYM(MapGrid2xOES),
    SYM(MultTransposeMatrixxOES),
    SYM(MultiTexCoord1xOES),
    SYM(MultiTexCoord1xvOES),
    SYM(MultiTexCoord2xOES),
    SYM(MultiTexCoord2xvOES),
    SYM(MultiTexCoord3xOES),
    SYM(MultiTexCoord3xvOES),
    SYM(MultiTexCoord4xvOES),
    SYM(Normal3xvOES),
    SYM(PassThroughxOES),
    SYM(PixelMapx),
    SYM(PixelStorex),
    SYM(PixelTransferxOES),
    SYM(PixelZoomxOES),
    SYM(PrioritizeTexturesxOES),
    SYM(RasterPos2xOES),
    SYM(RasterPos2xvOES),
    SYM(RasterPos3xOES),
    SYM(RasterPos3xvOES),
    SYM(RasterPos4xOES),
    SYM(RasterPos4xvOES),
    SYM(RectxOES),
    SYM(RectxvOES),
    SYM(TexCoord1xOES),
    SYM(TexCoord1xvOES),
    SYM(TexCoord2xOES),
    SYM(TexCoord2xvOES),
    SYM(TexCoord3xOES),
    SYM(TexCoord3xvOES),
    SYM(TexCoord4xOES),
    SYM(TexCoord4xvOES),
    SYM(TexGenxOES),
    SYM(TexGenxvOES),
    SYM(Vertex2xOES),
    SYM(Vertex2xvOES),
    SYM(Vertex3xOES),
    SYM(Vertex3xvOES),
    SYM(Vertex4xOES),
    SYM(Vertex4xvOES),
    SYM(QueryMatrixxOES),
    SYM(ClearDepthfOES),
    SYM(ClipPlanefOES),
    SYM(DepthRangefOES),
    SYM(FrustumfOES),
    SYM(GetClipPlanefOES),
    SYM(OrthofOES),
    SYM(ImageTransformParameteriHP),
    SYM(ImageTransformParameterfHP),
    SYM(ImageTransformParameterivHP),
    SYM(ImageTransformParameterfvHP),
    SYM(GetImageTransformParameterivHP),
    SYM(GetImageTransformParameterfvHP),

    { NULL, NULL },
};
RGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;
RGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;
RGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;
RGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;
RGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;
RGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;
RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;
RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;
RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;
RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;
RGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;
RGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;
RGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;
RGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;
RGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;
RGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;
RGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;
RGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;
RGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;
RGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;
RGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;
RGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;
RGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;
RGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;
RGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;
RGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;
RGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;
RGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;
RGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;
RGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;
RGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;
RGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;
RGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;
RGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;
RGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;
RGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;
RGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;
RGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;
RGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;
RGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;
RGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;
RGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;
RGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;
RGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;
RGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;
RGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;
RGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;
RGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;
RGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;
RGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;
RGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;
RGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;
RGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;
RGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;
RGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;
RGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;
RGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;
RGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;
RGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;
RGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;
RGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;
RGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;
RGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;
RGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;
RGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;
RGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;
RGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;
RGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;
RGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;
RGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;
RGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;
RGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;
RGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;
RGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;
RGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;
RGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;
RGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;
RGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;
RGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;
RGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;
RGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;
RGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;
RGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;
RGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;
RGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;
RGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;
RGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;
RGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;
RGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;
RGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;
RGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;
RGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;
RGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;
RGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;
RGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;
RGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;
RGLSYMGLISQUERYPROC __rglgen_glIsQuery;
RGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;
RGLSYMGLENDQUERYPROC __rglgen_glEndQuery;
RGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;
RGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;
RGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;
RGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;
RGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;
RGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;
RGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;
RGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;
RGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;
RGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;
RGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;
RGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;
RGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;
RGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;
RGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;
RGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;
RGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;
RGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;
RGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;
RGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;
RGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;
RGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;
RGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;
RGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;
RGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;
RGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;
RGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;
RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;
RGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;
RGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;
RGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;
RGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;
RGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;
RGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;
RGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;
RGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;
RGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;
RGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;
RGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;
RGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;
RGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;
RGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;
RGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;
RGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;
RGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;
RGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;
RGLSYMGLISSHADERPROC __rglgen_glIsShader;
RGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;
RGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;
RGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;
RGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;
RGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;
RGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;
RGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;
RGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;
RGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;
RGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;
RGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;
RGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;
RGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;
RGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;
RGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;
RGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;
RGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;
RGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;
RGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;
RGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;
RGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;
RGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;
RGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;
RGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;
RGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;
RGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;
RGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;
RGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;
RGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;
RGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;
RGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;
RGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;
RGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;
RGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;
RGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;
RGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;
RGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;
RGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;
RGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;
RGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;
RGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;
RGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;
RGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;
RGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;
RGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;
RGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;
RGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;
RGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;
RGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;
RGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;
RGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;
RGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;
RGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;
RGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;
RGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;
RGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;
RGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;
RGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;
RGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;
RGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;
RGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;
RGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;
RGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;
RGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;
RGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;
RGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;
RGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;
RGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;
RGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;
RGLSYMGLENABLEIPROC __rglgen_glEnablei;
RGLSYMGLDISABLEIPROC __rglgen_glDisablei;
RGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;
RGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;
RGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;
RGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;
RGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;
RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;
RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;
RGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;
RGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;
RGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;
RGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;
RGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;
RGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;
RGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;
RGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;
RGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;
RGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;
RGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;
RGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;
RGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;
RGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;
RGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;
RGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;
RGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;
RGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;
RGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;
RGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;
RGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;
RGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;
RGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;
RGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;
RGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;
RGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;
RGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;
RGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;
RGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;
RGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;
RGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;
RGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;
RGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;
RGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;
RGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;
RGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;
RGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;
RGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;
RGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;
RGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;
RGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;
RGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;
RGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;
RGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;
RGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;
RGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;
RGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;
RGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;
RGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;
RGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;
RGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;
RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;
RGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;
RGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;
RGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;
RGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;
RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;
RGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;
RGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;
RGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;
RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;
RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;
RGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;
RGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;
RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;
RGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;
RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;
RGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;
RGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;
RGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;
RGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;
RGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;
RGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;
RGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;
RGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;
RGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;
RGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;
RGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;
RGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;
RGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;
RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;
RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;
RGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;
RGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;
RGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;
RGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;
RGLSYMGLISSYNCPROC __rglgen_glIsSync;
RGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;
RGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;
RGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;
RGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;
RGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;
RGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;
RGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;
RGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;
RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;
RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;
RGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;
RGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;
RGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;
RGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;
RGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;
RGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;
RGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;
RGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;
RGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;
RGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;
RGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;
RGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;
RGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;
RGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;
RGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;
RGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;
RGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;
RGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;
RGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;
RGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;
RGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;
RGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;
RGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;
RGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;
RGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;
RGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;
RGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;
RGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;
RGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;
RGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;
RGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;
RGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;
RGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;
RGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;
RGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;
RGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;
RGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;
RGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;
RGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;
RGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;
RGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;
RGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;
RGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;
RGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;
RGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;
RGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;
RGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;
RGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;
RGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;
RGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;
RGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;
RGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;
RGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;
RGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;
RGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;
RGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;
RGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;
RGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;
RGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;
RGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;
RGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;
RGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;
RGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;
RGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;
RGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;
RGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;
RGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;
RGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;
RGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;
RGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;
RGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;
RGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;
RGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;
RGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;
RGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;
RGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;
RGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;
RGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;
RGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;
RGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;
RGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;
RGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;
RGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;
RGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;
RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;
RGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;
RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;
RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;
RGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;
RGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;
RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;
RGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;
RGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;
RGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;
RGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;
RGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;
RGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;
RGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;
RGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;
RGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;
RGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;
RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;
RGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;
RGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;
RGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;
RGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;
RGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;
RGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;
RGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;
RGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;
RGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;
RGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;
RGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;
RGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;
RGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;
RGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;
RGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;
RGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;
RGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;
RGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;
RGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;
RGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;
RGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;
RGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;
RGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;
RGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;
RGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;
RGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;
RGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;
RGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;
RGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;
RGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;
RGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;
RGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;
RGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;
RGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;
RGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;
RGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;
RGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;
RGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;
RGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;
RGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;
RGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;
RGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;
RGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;
RGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;
RGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;
RGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;
RGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;
RGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;
RGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;
RGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;
RGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;
RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;
RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;
RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;
RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;
RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;
RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;
RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;
RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;
RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;
RGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;
RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;
RGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;
RGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;
RGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;
RGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;
RGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;
RGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;
RGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;
RGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;
RGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;
RGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;
RGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;
RGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;
RGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;
RGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;
RGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;
RGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;
RGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;
RGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;
RGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;
RGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;
RGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;
RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;
RGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;
RGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;
RGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;
RGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;
RGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;
RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;
RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;
RGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;
RGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;
RGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;
RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;
RGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;
RGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;
RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;
RGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;
RGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;
RGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;
RGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;
RGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;
RGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;
RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;
RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;
RGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;
RGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;
RGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;
RGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;
RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;
RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;
RGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;
RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;
RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;
RGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;
RGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;
RGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;
RGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;
RGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;
RGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;
RGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;
RGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;
RGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;
RGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;
RGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;
RGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;
RGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;
RGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;
RGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;
RGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;
RGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;
RGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;
RGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;
RGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;
RGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;
RGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;
RGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;
RGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;
RGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;
RGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;
RGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;
RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;
RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;
RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;
RGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;
RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;
RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;
RGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;
RGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;
RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;
RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;
RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;
RGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;
RGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;
RGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;
RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;
RGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;
RGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;
RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;
RGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;
RGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;
RGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;
RGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;
RGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;
RGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;
RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;
RGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;
RGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;
RGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;
RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;
RGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;
RGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;
RGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;
RGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;
RGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;
RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;
RGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;
RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;
RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;
RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;
RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;
RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;
RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;
RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;
RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;
RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;
RGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;
RGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;
RGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;
RGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;
RGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;
RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;
RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;
RGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;
RGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;
RGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;
RGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;
RGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;
RGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;
RGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;
RGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;
RGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;
RGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;
RGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;
RGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;
RGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;
RGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;
RGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;
RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;
RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;
RGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;
RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;
RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;
RGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;
RGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;
RGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;
RGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;
RGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;
RGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;
RGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;
RGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;
RGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;
RGLSYMGLMINMAXPROC __rglgen_glMinmax;
RGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;
RGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;
RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;
RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;
RGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;
RGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;
RGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;
RGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;
RGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;
RGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;
RGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;
RGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;
RGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;
RGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;
RGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;
RGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;
RGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;
RGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;
RGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;
RGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;
RGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;
RGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;
RGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;
RGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;
RGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;
RGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;
RGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;
RGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;
RGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;
RGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;
RGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;
RGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;
RGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;
RGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;
RGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;
RGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;
RGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;
RGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;
RGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;
RGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;
RGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;
RGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;
RGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;
RGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;
RGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;
RGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;
RGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;
RGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;
RGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;
RGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;
RGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;
RGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;
RGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;
RGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;
RGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;
RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;
RGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;
RGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;
RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;
RGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;
RGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;
RGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;
RGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;
RGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;
RGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;
RGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;
RGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;
RGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;
RGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;
RGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;
RGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;
RGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;
RGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;
RGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;
RGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;
RGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;
RGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;
RGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;
RGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;
RGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;
RGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;
RGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;
RGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;
RGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;
RGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;
RGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;
RGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;
RGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;
RGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;
RGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;
RGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;
RGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;
RGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;
RGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;
RGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;
RGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;
RGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;
RGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;
RGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;
RGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;
RGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;
RGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;
RGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;
RGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;
RGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;
RGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;
RGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;
RGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;
RGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;
RGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;
RGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;
RGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;
RGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;
RGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;
RGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;
RGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;
RGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;
RGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;
RGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;
RGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;
RGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;
RGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;
RGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;
RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;
RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;
RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;
RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;
RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;
RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;
RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;
RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;
RGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;
RGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;
RGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;
RGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;
RGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;
RGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;
RGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;
RGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;
RGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;
RGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;
RGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;
RGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;
RGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;
RGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;
RGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;
RGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;
RGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;
RGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;
RGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;
RGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;
RGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;
RGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;
RGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;
RGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;
RGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;
RGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;
RGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;
RGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;
RGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;
RGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;
RGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;
RGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;
RGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;
RGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;
RGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;
RGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;
RGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;
RGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;
RGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;
RGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;
RGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;
RGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;
RGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;
RGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;
RGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;
RGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;
RGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;
RGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;
RGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;
RGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;
RGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;
RGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;
RGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;
RGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;
RGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;
RGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;
RGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;
RGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;
RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;
RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;
RGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;
RGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;
RGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;
RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;
RGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;
RGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;
RGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;
RGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;
RGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;
RGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;
RGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;
RGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;
RGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;
RGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;
RGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;
RGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;
RGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;
RGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;
RGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;
RGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;
RGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;
RGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;
RGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;
RGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;
RGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;
RGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;
RGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;
RGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;
RGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;
RGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;
RGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;
RGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;
RGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;
RGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;
RGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;
RGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;
RGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;
RGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;
RGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;
RGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;
RGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;
RGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;
RGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;
RGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;
RGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;
RGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;
RGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;
RGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;
RGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;
RGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;
RGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;
RGLSYMGLFOGXOESPROC __rglgen_glFogxOES;
RGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;
RGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;
RGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;
RGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;
RGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;
RGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;
RGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;
RGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;
RGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;
RGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;
RGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;
RGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;
RGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;
RGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;
RGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;
RGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;
RGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;
RGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;
RGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;
RGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;
RGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;
RGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;
RGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;
RGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;
RGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;
RGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;
RGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;
RGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;
RGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;
RGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;
RGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;
RGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;
RGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;
RGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;
RGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;
RGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;
RGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;
RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;
RGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;
RGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;
RGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;
RGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;
RGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;
RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;
RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;
RGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;
RGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;
RGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;
RGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;
RGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;
RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;
RGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;
RGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;
RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;
RGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;
RGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;
RGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;
RGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;
RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;
RGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;
RGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;
RGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;
RGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;
RGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;
RGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;
RGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;
RGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;
RGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;
RGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;
RGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;
RGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;
RGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;
RGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;
RGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;
RGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;
RGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;
RGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;
RGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;
RGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;
RGLSYMGLRECTXOESPROC __rglgen_glRectxOES;
RGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;
RGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;
RGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;
RGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;
RGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;
RGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;
RGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;
RGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;
RGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;
RGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;
RGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;
RGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;
RGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;
RGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;
RGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;
RGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;
RGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;
RGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;
RGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;
RGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;
RGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;
RGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;
RGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;
RGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;
RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;
RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;
RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;
RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;
RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;
RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;</pre>
<h2>./include/libretro-common/glsym/README.md</h2>
<pre># Autogenerate GL extension loaders

## OpenGL desktop

Use Khronos' recent [header](www.opengl.org/registry/api/glext.h).

    ./glgen.py /usr/include/GL/glext.h glsym_gl.h glsym_gl.c

## OpenGL ES

    ./glgen.py /usr/include/GLES2/gl2ext.h glsym_es2.h glsym_es2.c</pre>
<h2>./include/libretro-common/glsym/rglgen.c</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;string.h&gt;

#include &lt;glsym/rglgen.h&gt;
#include &lt;glsym/glsym.h&gt;

void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
      const struct rglgen_sym_map *map)
{
   for (; map-&gt;sym; map++)
   {
      rglgen_func_t func = proc(map-&gt;sym);
      memcpy(map-&gt;ptr, &amp;func, sizeof(func));
   }
}

void rglgen_resolve_symbols(rglgen_proc_address_t proc)
{
   if (!proc)
      return;

   rglgen_resolve_symbols_custom(proc, rglgen_symbol_map);
}</pre>
<h2>./include/libretro-common/glsym/rglgen.py</h2>
<pre>#!/usr/bin/env python3

"""
   License statement applies to this file (glgen.py) only.

   Permission is hereby granted, free of charge,
   to any person obtaining a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import sys
import os
import re

banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]

def noext(sym):
   for ext in banned_ext:
      if sym.endswith(ext):
         return False
   return True

def fix_multiline_functions(lines):
   fixed_lines = []
   temp_lines = []
   for line in lines:
      if line.count('(') &gt; line.count(')'):
         temp_lines.append(line)
      else:
         if len(temp_lines) &gt; 0:
            if line.count(')') &gt; line.count('('):
               temp_lines.append(line)
               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
               fixed_lines.append(fixed_line)
               temp_lines = []
            else:
               temp_lines.append(line)
         else:
            fixed_lines.append(line)
   return fixed_lines

def find_gl_symbols(lines):
   typedefs = []
   syms = []
   for line in lines:
      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
      g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
      if m and noext(m.group(1)):
         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
      if g and noext(g.group(1)):
         syms.append(g.group(1))
   return (typedefs, syms)

def generate_defines(gl_syms):
   res = []
   for line in gl_syms:
      res.append('#define {} __rglgen_{}'.format(line, line))
   return res

def generate_declarations(gl_syms):
   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]

def generate_macros(gl_syms):
   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]

def dump(f, lines):
   f.write('\n'.join(lines))
   f.write('\n\n')

if __name__ == '__main__':

   if len(sys.argv) &gt; 4:
      for banned in sys.argv[4:]:
         banned_ext.append(banned)

   with open(sys.argv[1], 'r') as f:
      lines = fix_multiline_functions(f.readlines())
      typedefs, syms = find_gl_symbols(lines)

      overrides = generate_defines(syms)
      declarations = generate_declarations(syms)
      externs = ['extern ' + x for x in declarations]

      macros = generate_macros(syms)

   with open(sys.argv[2], 'w') as f:
      f.write('#ifndef RGLGEN_DECL_H__\n')
      f.write('#define RGLGEN_DECL_H__\n')

      f.write('#ifdef __cplusplus\n')
      f.write('extern "C" {\n')
      f.write('#endif\n')

      f.write('#ifdef GL_APIENTRY\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#else\n')
      f.write('#ifndef APIENTRY\n')
      f.write('#define APIENTRY\n')
      f.write('#endif\n')
      f.write('#ifndef APIENTRYP\n')
      f.write('#define APIENTRYP APIENTRY *\n')
      f.write('#endif\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#endif\n')

      f.write('#ifndef GL_OES_EGL_image\n')
      f.write('typedef void *GLeglImageOES;\n')
      f.write('#endif\n')

      f.write('#if !defined(GL_OES_fixed_point) &amp;&amp; !defined(HAVE_OPENGLES2)\n')
      f.write('typedef GLint GLfixed;\n')
      f.write('#endif\n')

      dump(f, typedefs)
      dump(f, overrides)
      dump(f, externs)

      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')

      f.write('#ifdef __cplusplus\n')
      f.write('}\n')
      f.write('#endif\n')

      f.write('#endif\n')

   with open(sys.argv[3], 'w') as f:
      f.write('#include "glsym/glsym.h"\n')
      f.write('#include &lt;stddef.h&gt;\n')
      f.write('#define SYM(x) { "gl" #x, &amp;(gl##x) }\n')
      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
      dump(f, macros)
      f.write('    { NULL, NULL },\n')
      f.write('};\n')
      dump(f, declarations)</pre>
<h2>./include/libretro-common/glsym/xglgen.py</h2>
<pre>#!/usr/bin/env python3

"""
   License statement applies to this file (xglgen.py) only.

   Permission is hereby granted, free of charge,
   to any person obtaining a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import sys
import os
import re

banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]

def noext(sym):
   for ext in banned_ext:
      if sym.endswith(ext):
         return False
   return True

def fix_multiline_functions(lines):
   fixed_lines = []
   temp_lines = []
   for line in lines:
      if line.count('(') &gt; line.count(')'):
         temp_lines.append(line)
      else:
         if len(temp_lines) &gt; 0:
            if line.count(')') &gt; line.count('('):
               temp_lines.append(line)
               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
               fixed_lines.append(fixed_line)
               temp_lines = []
            else:
               temp_lines.append(line)
         else:
            fixed_lines.append(line)
   return fixed_lines

def find_gl_symbols(lines):
   typedefs = []
   syms = []
   for line in lines:
      # Note this doesn't work automated; this script is designed as a helper
      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
      g = re.search(r'^GLAPI\s(.+)\s(.+)\s(gl\S+)\W*\((.+)\).*', line)
      if g and noext(g.group(3)):
         typedefs.append('typedef ' + g.group(1) + ' (APIENTRYP RGLSYM' + g.group(3).upper() + 'PROC) (' + g.group(4) + ');')
         syms.append(g.group(3))

   return (typedefs, syms)

def generate_defines(gl_syms):
   res = []
   for line in gl_syms:
      res.append('#define {} __rglgen_{}'.format(line, line))
   return res

def generate_declarations(gl_syms):
   return ['RGLSYM' + x.upper() + 'PROC ' + x + ';' for x in gl_syms]

def generate_macros(gl_syms):
   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]

def dump(f, lines):
   f.write('\n'.join(lines))
   f.write('\n\n')

if __name__ == '__main__':

   if len(sys.argv) &gt; 4:
      for banned in sys.argv[4:]:
         banned_ext.append(banned)

   with open(sys.argv[1], 'r') as f:
      lines = fix_multiline_functions(f.readlines())
      typedefs, syms = find_gl_symbols(lines)

      overrides = generate_defines(syms)
      declarations = generate_declarations(syms)
      externs = ['extern ' + x for x in declarations]

      macros = generate_macros(syms)

   with open(sys.argv[2], 'w') as f:
      f.write('#ifndef RGLGEN_DECL_H__\n')
      f.write('#define RGLGEN_DECL_H__\n')

      f.write('#ifdef __cplusplus\n')
      f.write('extern "C" {\n')
      f.write('#endif\n')

      f.write('#ifdef GL_APIENTRY\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#else\n')
      f.write('#ifndef APIENTRY\n')
      f.write('#define APIENTRY\n')
      f.write('#endif\n')
      f.write('#ifndef APIENTRYP\n')
      f.write('#define APIENTRYP APIENTRY *\n')
      f.write('#endif\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
      f.write('#endif\n')

      f.write('#ifndef GL_OES_EGL_image\n')
      f.write('typedef void *GLeglImageOES;\n')
      f.write('#endif\n')

      f.write('#if !defined(GL_OES_fixed_point) &amp;&amp; !defined(HAVE_OPENGLES2)\n')
      f.write('typedef GLint GLfixed;\n')
      f.write('#endif\n')

      f.write('#if defined(OSX) &amp;&amp; !defined(MAC_OS_X_VERSION_10_7)\n')
      f.write('typedef long long int GLint64;\n')
      f.write('typedef unsigned long long int GLuint64;\n')
      f.write('typedef unsigned long long int GLuint64EXT;\n')
      f.write('typedef struct __GLsync *GLsync;\n')
      f.write('#endif\n')

      dump(f, typedefs)
      dump(f, overrides)
      dump(f, externs)

      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')

      f.write('#ifdef __cplusplus\n')
      f.write('}\n')
      f.write('#endif\n')

      f.write('#endif\n')

   with open(sys.argv[3], 'w') as f:
      f.write('#include "glsym/glsym.h"\n')
      f.write('#include &lt;stddef.h&gt;\n')
      f.write('#define SYM(x) { "gl" #x, &amp;(gl##x) }\n')
      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
      dump(f, macros)
      f.write('    { NULL, NULL },\n')
      f.write('};\n')
      dump(f, declarations)</pre>
<h2>./include/libretro-common/hash/lrc_hash.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (lrc_hash.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;string.h&gt;
#include &lt;stdio.h&gt;
#ifdef _WIN32
#include &lt;io.h&gt;
#else
#include &lt;unistd.h&gt;
#endif
#include &lt;lrc_hash.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;retro_endianness.h&gt;
#include &lt;streams/file_stream.h&gt;

#define LSL32(x, n) ((uint32_t)(x) &lt;&lt; (n))
#define LSR32(x, n) ((uint32_t)(x) &gt;&gt; (n))
#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))

/* First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19 */
static const uint32_t T_H[8] = {
   0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
};

/* First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311 */
static const uint32_t T_K[64] = {
   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
};

/* SHA256 implementation from bSNES. Written by valditx. */

struct sha256_ctx
{
   union
   {
      uint8_t u8[64];
      uint32_t u32[16];
   } in;
   unsigned inlen;

   uint32_t w[64];
   uint32_t h[8];
   uint64_t len;
};

static void sha256_init(struct sha256_ctx *p)
{
   memset(p, 0, sizeof(struct sha256_ctx));
   memcpy(p-&gt;h, T_H, sizeof(T_H));
}

static void sha256_block(struct sha256_ctx *p)
{
   unsigned i;
   uint32_t s0, s1;
   uint32_t a, b, c, d, e, f, g, h;

   for (i = 0; i &lt; 16; i++)
      p-&gt;w[i] = load32be(p-&gt;in.u32 + i);

   for (i = 16; i &lt; 64; i++)
   {
      s0 = ROR32(p-&gt;w[i - 15],  7) ^ ROR32(p-&gt;w[i - 15], 18) ^ LSR32(p-&gt;w[i - 15],  3);
      s1 = ROR32(p-&gt;w[i -  2], 17) ^ ROR32(p-&gt;w[i -  2], 19) ^ LSR32(p-&gt;w[i -  2], 10);
      p-&gt;w[i] = p-&gt;w[i - 16] + s0 + p-&gt;w[i - 7] + s1;
   }

   a = p-&gt;h[0]; b = p-&gt;h[1]; c = p-&gt;h[2]; d = p-&gt;h[3];
   e = p-&gt;h[4]; f = p-&gt;h[5]; g = p-&gt;h[6]; h = p-&gt;h[7];

   for (i = 0; i &lt; 64; i++)
   {
      uint32_t t1, t2, maj, ch;

      s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
      maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);
      t2  = s0 + maj;
      s1  = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
      ch  = (e &amp; f) ^ (~e &amp; g);
      t1  = h + s1 + ch + T_K[i] + p-&gt;w[i];

      h   = g;
      g   = f;
      f   = e;
      e   = d + t1;
      d   = c;
      c   = b;
      b   = a;
      a   = t1 + t2;
   }

   p-&gt;h[0] += a; p-&gt;h[1] += b; p-&gt;h[2] += c; p-&gt;h[3] += d;
   p-&gt;h[4] += e; p-&gt;h[5] += f; p-&gt;h[6] += g; p-&gt;h[7] += h;

   /* Next block */
   p-&gt;inlen = 0;
}

static void sha256_chunk(struct sha256_ctx *p,
      const uint8_t *s, size_t len)
{
   p-&gt;len += len;

   while (len)
   {
      size_t l   = 64 - p-&gt;inlen;

      if (len &lt; l)
         l       = len;

      memcpy(p-&gt;in.u8 + p-&gt;inlen, s, l);

      s         += l;
      p-&gt;inlen  += l;
      len       -= l;

      if (p-&gt;inlen == 64)
         sha256_block(p);
   }
}

static void sha256_final(struct sha256_ctx *p)
{
   uint64_t len;
   p-&gt;in.u8[p-&gt;inlen++] = 0x80;

   if (p-&gt;inlen &gt; 56)
   {
      memset(p-&gt;in.u8 + p-&gt;inlen, 0, 64 - p-&gt;inlen);
      sha256_block(p);
   }

   memset(p-&gt;in.u8 + p-&gt;inlen, 0, 56 - p-&gt;inlen);

   len = p-&gt;len &lt;&lt; 3;
   store32be(p-&gt;in.u32 + 14, (uint32_t)(len &gt;&gt; 32));
   store32be(p-&gt;in.u32 + 15, (uint32_t)len);
   sha256_block(p);
}

static void sha256_subhash(struct sha256_ctx *p, uint32_t *t)
{
   unsigned i;
   for (i = 0; i &lt; 8; i++)
      store32be(t++, p-&gt;h[i]);
}

/**
 * sha256_hash:
 * @s                 : Output.
 * @in                : Input.
 * @size              : Size of @s.
 *
 * Hashes SHA256 and outputs a human readable string.
 **/
void sha256_hash(char *s, const uint8_t *in, size_t len)
{
   unsigned i;
   struct sha256_ctx sha;

   union
   {
      uint32_t u32[8];
      uint8_t u8[32];
   } shahash;

   sha256_init(&amp;sha);
   sha256_chunk(&amp;sha, in, len);
   sha256_final(&amp;sha);
   sha256_subhash(&amp;sha, shahash.u32);

   for (i = 0; i &lt; 32; i++)
      snprintf(s + 2 * i, 3, "%02x", (unsigned)shahash.u8[i]);
}

#ifndef HAVE_ZLIB
/* Zlib CRC32. */
static const uint32_t crc32_hash_table[256] = {
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

uint32_t crc32_adjust(uint32_t checksum, uint8_t input)
{
   return ((checksum &gt;&gt; 8) &amp; 0x00ffffff) ^ crc32_hash_table[(checksum ^ input) &amp; 0xff];
}

uint32_t crc32_calculate(const uint8_t *data, size_t len)
{
   size_t i;
   uint32_t checksum = ~0;
   for (i = 0; i &lt; len; i++)
      checksum = crc32_adjust(checksum, data[i]);
   return ~checksum;
}
#endif

/* SHA-1 implementation. */

/*
 *  sha1.c
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones &lt;paulej@packetizer.com&gt;
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This file implements the Secure Hashing Standard as defined
 *      in FIPS PUB 180-1 published April 17, 1995.
 *
 *      The Secure Hashing Standard, which uses the Secure Hashing
 *      Algorithm (SHA), produces a 160-bit message digest for a
 *      given data stream.  In theory, it is highly improbable that
 *      two messages will produce the same message digest.  Therefore,
 *      this algorithm can serve as a means of providing a "fingerprint"
 *      for a message.
 *
 *  Portability Issues:
 *      SHA-1 is defined in terms of 32-bit "words".  This code was
 *      written with the expectation that the processor has at least
 *      a 32-bit machine word size.  If the machine word size is larger,
 *      the code should still function properly.  One caveat to that
 *      is that the input functions taking characters and character
 *      arrays assume that only 8 bits of information are stored in each
 *      character.
 *
 *  Caveats:
 *      SHA-1 is designed to work with messages less than 2^64 bits
 *      long. Although SHA-1 allows a message digest to be generated for
 *      messages of any number of bits less than 2^64, this
 *      implementation only works with messages with a length that is a
 *      multiple of the size of an 8-bit character.
 *
 */

/* Define the circular shift macro */
#define SHA1CircularShift(bits,word) ((((word) &lt;&lt; (bits)) &amp; 0xFFFFFFFF) | ((word) &gt;&gt; (32-(bits))))

struct sha1_context
{
   unsigned Message_Digest[5]; /* Message Digest (output)          */

   unsigned Length_Low;        /* Message length in bits           */
   unsigned Length_High;       /* Message length in bits           */

   unsigned char Message_Block[64]; /* 512-bit message blocks      */
   int Message_Block_Index;    /* Index into message block array   */

   int Computed;               /* Is the digest computed?          */
   int Corrupted;              /* Is the message digest corruped?  */
};


static void SHA1Reset(struct sha1_context *context)
{
   if (!context)
      return;

   context-&gt;Length_Low             = 0;
   context-&gt;Length_High            = 0;
   context-&gt;Message_Block_Index    = 0;

   context-&gt;Message_Digest[0]      = 0x67452301;
   context-&gt;Message_Digest[1]      = 0xEFCDAB89;
   context-&gt;Message_Digest[2]      = 0x98BADCFE;
   context-&gt;Message_Digest[3]      = 0x10325476;
   context-&gt;Message_Digest[4]      = 0xC3D2E1F0;

   context-&gt;Computed   = 0;
   context-&gt;Corrupted  = 0;
}

static void SHA1ProcessMessageBlock(struct sha1_context *context)
{
   const unsigned K[] =            /* Constants defined in SHA-1   */
   {
      0x5A827999,
      0x6ED9EBA1,
      0x8F1BBCDC,
      0xCA62C1D6
   };
   int         t;                  /* Loop counter                 */
   unsigned    temp;               /* Temporary word value         */
   unsigned    W[80];              /* Word sequence                */
   unsigned    A, B, C, D, E;      /* Word buffers                 */

   /* Initialize the first 16 words in the array W */
   for (t = 0; t &lt; 16; t++)
   {
      W[t] = ((unsigned) context-&gt;Message_Block[t * 4]) &lt;&lt; 24;
      W[t] |= ((unsigned) context-&gt;Message_Block[t * 4 + 1]) &lt;&lt; 16;
      W[t] |= ((unsigned) context-&gt;Message_Block[t * 4 + 2]) &lt;&lt; 8;
      W[t] |= ((unsigned) context-&gt;Message_Block[t * 4 + 3]);
   }

   for (t = 16; t &lt; 80; t++)
      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);

   A = context-&gt;Message_Digest[0];
   B = context-&gt;Message_Digest[1];
   C = context-&gt;Message_Digest[2];
   D = context-&gt;Message_Digest[3];
   E = context-&gt;Message_Digest[4];

   for (t = 0; t &lt; 20; t++)
   {
      temp  =  SHA1CircularShift(5,A) +
         ((B &amp; C) | ((~B) &amp; D)) + E + W[t] + K[0];
      temp &amp;= 0xFFFFFFFF;
      E     = D;
      D     = C;
      C     = SHA1CircularShift(30,B);
      B     = A;
      A     = temp;
   }

   for (t = 20; t &lt; 40; t++)
   {
      temp  = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
      temp &amp;= 0xFFFFFFFF;
      E     = D;
      D     = C;
      C     = SHA1CircularShift(30,B);
      B     = A;
      A     = temp;
   }

   for (t = 40; t &lt; 60; t++)
   {
      temp  = SHA1CircularShift(5,A) +
         ((B &amp; C) | (B &amp; D) | (C &amp; D)) + E + W[t] + K[2];
      temp &amp;= 0xFFFFFFFF;
      E     = D;
      D     = C;
      C     = SHA1CircularShift(30,B);
      B     = A;
      A     = temp;
   }

   for (t = 60; t &lt; 80; t++)
   {
      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
      temp &amp;= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   context-&gt;Message_Digest[0] =
      (context-&gt;Message_Digest[0] + A) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[1] =
      (context-&gt;Message_Digest[1] + B) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[2] =
      (context-&gt;Message_Digest[2] + C) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[3] =
      (context-&gt;Message_Digest[3] + D) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[4] =
      (context-&gt;Message_Digest[4] + E) &amp; 0xFFFFFFFF;

   context-&gt;Message_Block_Index = 0;
}

static void SHA1PadMessage(struct sha1_context *context)
{
   if (!context)
      return;

   /*
    *  Check to see if the current message block is too small to hold
    *  the initial padding bits and length.  If so, we will pad the
    *  block, process it, and then continue padding into a second
    *  block.
    */
   context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0x80;

   if (context-&gt;Message_Block_Index &gt; 55)
   {
      while (context-&gt;Message_Block_Index &lt; 64)
         context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0;

      SHA1ProcessMessageBlock(context);
   }

   while (context-&gt;Message_Block_Index &lt; 56)
      context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0;

   /*  Store the message length as the last 8 octets */
   context-&gt;Message_Block[56] = (context-&gt;Length_High &gt;&gt; 24) &amp; 0xFF;
   context-&gt;Message_Block[57] = (context-&gt;Length_High &gt;&gt; 16) &amp; 0xFF;
   context-&gt;Message_Block[58] = (context-&gt;Length_High &gt;&gt; 8) &amp; 0xFF;
   context-&gt;Message_Block[59] = (context-&gt;Length_High) &amp; 0xFF;
   context-&gt;Message_Block[60] = (context-&gt;Length_Low &gt;&gt; 24) &amp; 0xFF;
   context-&gt;Message_Block[61] = (context-&gt;Length_Low &gt;&gt; 16) &amp; 0xFF;
   context-&gt;Message_Block[62] = (context-&gt;Length_Low &gt;&gt; 8) &amp; 0xFF;
   context-&gt;Message_Block[63] = (context-&gt;Length_Low) &amp; 0xFF;

   SHA1ProcessMessageBlock(context);
}

static int SHA1Result(struct sha1_context *context)
{
   if (context-&gt;Corrupted)
      return 0;

   if (!context-&gt;Computed)
   {
      SHA1PadMessage(context);
      context-&gt;Computed = 1;
   }

   return 1;
}

static void SHA1Input(struct sha1_context *context,
      const unsigned char *message_array,
      unsigned len)
{
   if (!len)
      return;

   if (context-&gt;Computed || context-&gt;Corrupted)
   {
      context-&gt;Corrupted = 1;
      return;
   }

   while (len-- &amp;&amp; !context-&gt;Corrupted)
   {
      context-&gt;Message_Block[context-&gt;Message_Block_Index++] =
         (*message_array &amp; 0xFF);

      context-&gt;Length_Low += 8;
      /* Force it to 32 bits */
      context-&gt;Length_Low &amp;= 0xFFFFFFFF;
      if (context-&gt;Length_Low == 0)
      {
         context-&gt;Length_High++;
         /* Force it to 32 bits */
         context-&gt;Length_High &amp;= 0xFFFFFFFF;
         if (context-&gt;Length_High == 0)
            context-&gt;Corrupted = 1; /* Message is too long */
      }

      if (context-&gt;Message_Block_Index == 64)
         SHA1ProcessMessageBlock(context);

      message_array++;
   }
}

int sha1_calculate(const char *path, char *result)
{
   struct sha1_context sha;
   unsigned char buff[4096];
   int rv    = 1;
   RFILE *fd = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fd)
      goto error;

   buff[0] = '\0';

   SHA1Reset(&amp;sha);

   do
   {
      rv = (int)filestream_read(fd, buff, 4096);
      if (rv &lt; 0)
         goto error;

      SHA1Input(&amp;sha, buff, rv);
   } while (rv);

   if (!SHA1Result(&amp;sha))
      goto error;

   sprintf(result, "%08X%08X%08X%08X%08X",
         sha.Message_Digest[0],
         sha.Message_Digest[1],
         sha.Message_Digest[2],
         sha.Message_Digest[3], sha.Message_Digest[4]);

   filestream_close(fd);
   return 0;

error:
   if (fd)
      filestream_close(fd);
   return -1;
}

uint32_t djb2_calculate(const char *str)
{
   const unsigned char *aux = (const unsigned char*)str;
   uint32_t            hash = 5381;

   while ( *aux )
      hash = ( hash &lt;&lt; 5 ) + hash + *aux++;

   return hash;
}</pre>
<h2>./include/libretro-common/include/array/rbuf.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbuf.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ARRAY_RBUF_H__
#define __LIBRETRO_SDK_ARRAY_RBUF_H__

/*
 * This file implements stretchy buffers as invented (?) by Sean Barrett.
 * Based on the implementation from the public domain Bitwise project
 * by Per Vognsen - https://github.com/pervognsen/bitwise
 *
 * It's a super simple type safe dynamic array for C with no need
 * to predeclare any type or anything.
 * The first time an element is added, memory for 16 elements are allocated.
 * Then every time length is about to exceed capacity, capacity is doubled.
 *
 * Be careful not to supply modifying statements to the macro arguments.
 * Something like RBUF_REMOVE(buf, i--); would have unintended results.
 *
 * Sample usage:
 *
 * mytype_t* buf = NULL;
 * RBUF_PUSH(buf, some_element);
 * RBUF_PUSH(buf, other_element);
 * -- now RBUF_LEN(buf) == 2, buf[0] == some_element, buf[1] == other_element
 *
 * -- Free allocated memory:
 * RBUF_FREE(buf);
 * -- now buf == NULL, RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 0
 *
 * -- Explicitly increase allocated memory and set capacity:
 * RBUF_FIT(buf, 100);
 * -- now RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 100
 *
 * -- Resize buffer (does not initialize or zero memory!)
 * RBUF_RESIZE(buf, 200);
 * -- now RBUF_LEN(buf) == 200, RBUF_CAP(buf) == 200
 *
 * -- To handle running out of memory:
 * bool ran_out_of_memory = !RBUF_TRYFIT(buf, 1000);
 * -- before RESIZE or PUSH. When out of memory, buf will stay unmodified.
 */

#include &lt;retro_math.h&gt; /* for MAX */
#include &lt;stdlib.h&gt; /* for malloc, realloc */

#define RBUF__HDR(b) (((struct rbuf__hdr *)(b))-1)

#define RBUF_LEN(b) ((b) ? RBUF__HDR(b)-&gt;len : 0)
#define RBUF_CAP(b) ((b) ? RBUF__HDR(b)-&gt;cap : 0)
#define RBUF_END(b) ((b) + RBUF_LEN(b))
#define RBUF_SIZEOF(b) ((b) ? RBUF_LEN(b)*sizeof(*b) : 0)

#define RBUF_FREE(b) ((b) ? (free(RBUF__HDR(b)), (b) = NULL) : 0)
#define RBUF_FIT(b, n) ((size_t)(n) &lt;= RBUF_CAP(b) ? 0 : (*(void**)(&amp;(b)) = rbuf__grow((b), (n), sizeof(*(b)))))
#define RBUF_PUSH(b, val) (RBUF_FIT((b), 1 + RBUF_LEN(b)), (b)[RBUF__HDR(b)-&gt;len++] = (val))
#define RBUF_POP(b) (b)[--RBUF__HDR(b)-&gt;len]
#define RBUF_RESIZE(b, sz) (RBUF_FIT((b), (sz)), ((b) ? RBUF__HDR(b)-&gt;len = (sz) : 0))
#define RBUF_CLEAR(b) ((b) ? RBUF__HDR(b)-&gt;len = 0 : 0)
#define RBUF_TRYFIT(b, n) (RBUF_FIT((b), (n)), (((b) &amp;&amp; RBUF_CAP(b) &gt;= (size_t)(n)) || !(n)))
#define RBUF_REMOVE(b, idx) memmove((b) + (idx), (b) + (idx) + 1, (--RBUF__HDR(b)-&gt;len - (idx)) * sizeof(*(b)))

struct rbuf__hdr
{
   size_t len;
   size_t cap;
};

#ifdef __GNUC__
__attribute__((__unused__))
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505) /* Unreferenced local function has been removed */
#endif
static void *rbuf__grow(void *buf,
      size_t new_len, size_t elem_size)
{
   struct rbuf__hdr *new_hdr;
   size_t new_cap  = MAX(2 * RBUF_CAP(buf), MAX(new_len, 16));
   size_t new_size = sizeof(struct rbuf__hdr) + new_cap*elem_size;
   if (buf)
   {
      new_hdr      = (struct rbuf__hdr *)realloc(RBUF__HDR(buf), new_size);
      if (!new_hdr)
         return buf; /* out of memory, return unchanged */
   }
   else
   {
      new_hdr      = (struct rbuf__hdr *)malloc(new_size);
      if (!new_hdr)
         return NULL; /* out of memory */
      new_hdr-&gt;len = 0;
   }
   new_hdr-&gt;cap    = new_cap;
   return new_hdr + 1;
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

#endif</pre>
<h2>./include/libretro-common/include/array/rhmap.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rhmap.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ARRAY_RHMAP_H__
#define __LIBRETRO_SDK_ARRAY_RHMAP_H__

/*
 * This file implements a hash map with 32-bit keys.
 * Based on the implementation from the public domain Bitwise project
 * by Per Vognsen - https://github.com/pervognsen/bitwise
 *
 * It's a super simple type safe hash map for C with no need
 * to predeclare any type or anything.
 * Will always allocate memory for twice the amount of max elements
 * so larger structs should be stored as pointers or indices to an array.
 * Can be used in C++ with POD types (without any constructor/destructor).
 *
 * Be careful not to supply modifying statements to the macro arguments.
 * Something like RHMAP_FIT(map, i++); would have unintended results.
 *
 * Sample usage:
 *
 * -- Set 2 elements with string keys and mytype_t values:
 * mytype_t* map = NULL;
 * RHMAP_SET_STR(map, "foo", foo_element);
 * RHMAP_SET_STR(map, "bar", bar_element);
 * -- now RHMAP_LEN(map) == 2, RHMAP_GET_STR(map, "foo") == foo_element
 *
 * -- Check if keys exist:
 * bool has_foo = RHMAP_HAS_STR(map, "foo");
 * bool has_baz = RHMAP_HAS_STR(map, "baz");
 * -- now has_foo == true, has_baz == false
 *
 * -- Removing a key:
 * bool removed = RHMAP_DEL_STR(map, "bar");
 * bool removed_again = RHMAP_DEL_STR(map, "bar");
 * -- now RHMAP_LEN(map) == 1, removed == true, removed_again == false
 *
 * -- Add/modify via pointer:
 * mytype_t* p_elem = RHMAP_PTR_STR(map, "qux");
 * p_elem-&gt;a = 123;
 * -- New keys initially have memory uninitialized
 * -- Pointers can get invalidated when a key is added/removed
 *
 * -- Looking up the index for a given key:
 * ptrdiff_t idx_foo = RHMAP_IDX_STR(map, "foo");
 * ptrdiff_t idx_invalid = RHMAP_IDX_STR(map, "invalid");
 * -- now idx_foo &gt;= 0, idx_invalid == -1, map[idx_foo] == foo_element
 * -- Indices can change when a key is added/removed
 *
 * -- Clear all elements (keep memory allocated):
 * RHMAP_CLEAR(map);
 * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 16
 *
 * -- Reserve memory for at least N elements:
 * RHMAP_FIT(map, 30);
 * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 64
 *
 * -- Add elements with custom hash keys:
 * RHMAP_SET(map, my_uint32_hash(key1), some_element);
 * RHMAP_SET(map, my_uint32_hash(key2), other_element);
 * -- now RHMAP_LEN(map) == 2, _GET/_HAS/_DEL/_PTR/_IDX also exist
 *
 * -- Iterate elements (random order, order can change on insert):
 * for (size_t i = 0, cap = RHMAP_CAP(map); i != cap, i++)
 *   if (RHMAP_KEY(map, i))
 * ------ here map[i] is the value of key RHMAP_KEY(map, i)
 *
 * -- Set a custom null value (is zeroed by default):
 * RHMAP_SETNULLVAL(map, map_null);
 * -- now RHMAP_GET_STR(map, "invalid") == map_null
 *
 * -- Free allocated memory:
 * RHMAP_FREE(map);
 * -- now map == NULL, RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 0
 *
 * -- To handle running out of memory:
 * bool ran_out_of_memory = !RHMAP_TRYFIT(map, 1000);
 * -- before setting an element (with SET, PTR or NULLVAL).
 * -- When out of memory, map will stay unmodified.
 *
 */

#include &lt;stdlib.h&gt; /* for malloc, realloc */
#include &lt;string.h&gt; /* for memcpy, memset */
#include &lt;stddef.h&gt; /* for ptrdiff_t, size_t */
#include &lt;stdint.h&gt; /* for uint32_t */

#define RHMAP_LEN(b) ((b) ? RHMAP__HDR(b)-&gt;len : 0)
#define RHMAP_MAX(b) ((b) ? RHMAP__HDR(b)-&gt;maxlen : 0)
#define RHMAP_CAP(b) ((b) ? RHMAP__HDR(b)-&gt;maxlen + 1 : 0)
#define RHMAP_KEY(b, idx) (RHMAP__HDR(b)-&gt;keys[idx])
#define RHMAP_KEY_STR(b, idx) (RHMAP__HDR(b)-&gt;key_strs[idx])
#define RHMAP_SETNULLVAL(b, val) (RHMAP__FIT1(b), b[-1] = (val))
#define RHMAP_CLEAR(b) ((b) ? (memset(RHMAP__HDR(b)-&gt;keys, 0, RHMAP_CAP(b) * sizeof(uint32_t)), RHMAP__HDR(b)-&gt;len = 0) : 0)
#define RHMAP_FREE(b) ((b) ? (rhmap__free(RHMAP__HDR(b)), (b) = NULL) : 0)
#define RHMAP_FIT(b, n) ((!(n) || ((b) &amp;&amp; (size_t)(n) * 2 &lt;= RHMAP_MAX(b))) ? 0 : RHMAP__GROW(b, n))
#define RHMAP_TRYFIT(b, n) (RHMAP_FIT((b), (n)), (!(n) || ((b) &amp;&amp; (size_t)(n) * 2 &lt;= RHMAP_MAX(b))))

#define RHMAP_SET(b, key, val) RHMAP_SET_FULL(b, key, NULL, val)
#define RHMAP_GET(b, key)      RHMAP_GET_FULL(b, key, NULL)
#define RHMAP_HAS(b, key)      RHMAP_HAS_FULL(b, key, NULL)
#define RHMAP_DEL(b, key)      RHMAP_DEL_FULL(b, key, NULL)
#define RHMAP_PTR(b, key)      RHMAP_PTR_FULL(b, key, NULL)
#define RHMAP_IDX(b, key)      RHMAP_IDX_FULL(b, key, NULL)

#ifdef __GNUC__
#define RHMAP__UNUSED __attribute__((__unused__))
#else
#define RHMAP__UNUSED
#endif

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505) /* Unreferenced local function has been removed */
#endif

#define RHMAP_SET_FULL(b, key, str, val) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)] = (val))
#define RHMAP_GET_FULL(b, key, str) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0)])
#define RHMAP_HAS_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) != -1 : 0)
#define RHMAP_DEL_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, sizeof(*(b))) != -1 : 0)
#define RHMAP_PTR_FULL(b, key, str) (RHMAP__FIT1(b), &amp;b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)])
#define RHMAP_IDX_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) : -1)

#define RHMAP_SET_STR(b, string_key, val) RHMAP_SET_FULL(b, rhmap_hash_string(string_key), string_key, val)
#define RHMAP_GET_STR(b, string_key)      RHMAP_GET_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_HAS_STR(b, string_key)      RHMAP_HAS_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_DEL_STR(b, string_key)      RHMAP_DEL_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_PTR_STR(b, string_key)      RHMAP_PTR_FULL(b, rhmap_hash_string(string_key), string_key)
#define RHMAP_IDX_STR(b, string_key)      RHMAP_IDX_FULL(b, rhmap_hash_string(string_key), string_key)

RHMAP__UNUSED static uint32_t rhmap_hash_string(const char* str)
{
   unsigned char c;
   uint32_t hash = (uint32_t)0x811c9dc5;
   while ((c = (unsigned char)*(str++)) != '\0')
      hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);
   return (hash ? hash : 1);
}

struct rhmap__hdr { size_t len, maxlen; uint32_t *keys; char** key_strs; };
#define RHMAP__HDR(b) (((struct rhmap__hdr *)&amp;(b)[-1])-1)
#define RHMAP__GROW(b, n) (*(void**)(&amp;(b)) = rhmap__grow((void*)(b), sizeof(*(b)), (size_t)(n)))
#define RHMAP__FIT1(b) ((b) &amp;&amp; RHMAP_LEN(b) * 2 &lt;= RHMAP_MAX(b) ? 0 : RHMAP__GROW(b, 0))

RHMAP__UNUSED static void* rhmap__grow(void* old_ptr, size_t elem_size, size_t reserve)
{
   struct rhmap__hdr *old_hdr = (old_ptr ? ((struct rhmap__hdr *)((char*)old_ptr-elem_size))-1 : NULL);
   struct rhmap__hdr *new_hdr;
   char *new_vals;
   size_t new_max = (old_ptr ? old_hdr-&gt;maxlen * 2 + 1 : 15);
   for (; new_max / 2 &lt;= reserve; new_max = new_max * 2 + 1)
      if (new_max == (size_t)-1)
         return old_ptr; /* overflow */

   new_hdr = (struct rhmap__hdr *)malloc(sizeof(struct rhmap__hdr) + (new_max + 2) * elem_size);
   if (!new_hdr)
      return old_ptr; /* out of memory */

   new_hdr-&gt;maxlen = new_max;
   new_hdr-&gt;keys = (uint32_t *)calloc(new_max + 1, sizeof(uint32_t));
   if (!new_hdr-&gt;keys)
   {
      /* out of memory */
      free(new_hdr);
      return old_ptr;
   }
   new_hdr-&gt;key_strs = (char**)calloc(new_max + 1, sizeof(char*));
   if (!new_hdr-&gt;key_strs)
   {
      /* out of memory */
      free(new_hdr-&gt;keys);
      free(new_hdr);
      return old_ptr;
   }

   new_vals = ((char*)(new_hdr + 1)) + elem_size;
   if (old_ptr)
   {
      size_t i;
      char* old_vals = ((char*)(old_hdr + 1)) + elem_size;
      for (i = 0; i &lt;= old_hdr-&gt;maxlen; i++)
      {
         uint32_t key, j;
         if (!old_hdr-&gt;keys[i])
            continue;
         for (key = old_hdr-&gt;keys[i], j = key;; j++)
         {
            if (!new_hdr-&gt;keys[j &amp;= new_hdr-&gt;maxlen])
            {
               new_hdr-&gt;keys[j] = key;
               new_hdr-&gt;key_strs[j] = old_hdr-&gt;key_strs[i];
               memcpy(new_vals + j * elem_size, old_vals + i * elem_size, elem_size);
               break;
            }
         }
      }
      memcpy(new_vals - elem_size, old_vals - elem_size, elem_size);
      new_hdr-&gt;len = old_hdr-&gt;len;
      free(old_hdr-&gt;keys);
      free(old_hdr-&gt;key_strs);
      free(old_hdr);
   }
   else
   {
      memset(new_vals - elem_size, 0, elem_size);
      new_hdr-&gt;len = 0;
   }
   return new_vals;
}

/* This is just a custom version of strdup so we don't have an inherent
 * dependency on strdup for this file. It is functionally equivalent to
 * a system-provided strdup */
static char *rhmap_strdup(const char *s)
{
    char *out;
    int count = 0;
    while (s[count])
        ++count;
    ++count;
    out = (char*)malloc(sizeof(char) * count);
    out[--count] = 0;
    while (--count &gt;= 0)
        out[count] = s[count];
    return out;
}

RHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key, const char * str, int add, size_t del)
{
   uint32_t i;

   if (!key)
      return (ptrdiff_t)-1;

   for (i = key;; i++)
   {
      if (hdr-&gt;keys[i &amp;= hdr-&gt;maxlen] == key &amp;&amp; (!hdr-&gt;key_strs[i] || !str || !strcmp(hdr-&gt;key_strs[i], str)))
      {
         if (del)
         {
            hdr-&gt;len--;
            hdr-&gt;keys[i] = 0;
            free(hdr-&gt;key_strs[i]);
            hdr-&gt;key_strs[i] = NULL;
            while ((key = hdr-&gt;keys[i = (i + 1) &amp; hdr-&gt;maxlen]) != 0)
            {
               if ((key = (uint32_t)rhmap__idx(hdr, key, hdr-&gt;key_strs[i], 1, 0)) == i) continue;
               hdr-&gt;len--;
               hdr-&gt;keys[i] = 0;
               free(hdr-&gt;key_strs[i]);
               hdr-&gt;key_strs[i] = NULL;
               memcpy(((char*)(hdr + 1)) + (key + 1) * del,
                     ((char*)(hdr + 1)) + (i + 1) * del, del);
            }
         }
         return (ptrdiff_t)i;
      }
      if (!hdr-&gt;keys[i])
      {
         if (add)
         {
            hdr-&gt;len++;
            hdr-&gt;keys[i] = key;
            if (str)
               hdr-&gt;key_strs[i] = rhmap_strdup(str);
            return (ptrdiff_t)i;
         }
         return (ptrdiff_t)-1;
      }
   }
}

RHMAP__UNUSED static void rhmap__free(struct rhmap__hdr* hdr)
{
   size_t i;
   for (i=0;i&lt;hdr-&gt;maxlen+1;i++)
   {
      free(hdr-&gt;key_strs[i]);
   }
   free(hdr-&gt;key_strs);
   free(hdr-&gt;keys);
   free(hdr);
}

#if defined(_MSC_VER)
#pragma warning(pop)
#endif

#endif</pre>
<h2>./include/libretro-common/include/audio/audio_mixer.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mixer.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_MIXER__H
#define __LIBRETRO_SDK_AUDIO_MIXER__H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include &lt;boolean.h&gt;
#include &lt;retro_common_api.h&gt;

#include &lt;audio/audio_resampler.h&gt;

RETRO_BEGIN_DECLS

enum audio_mixer_type
{
   AUDIO_MIXER_TYPE_NONE = 0,
   AUDIO_MIXER_TYPE_WAV,
   AUDIO_MIXER_TYPE_OGG,
   AUDIO_MIXER_TYPE_MOD,
   AUDIO_MIXER_TYPE_FLAC,
   AUDIO_MIXER_TYPE_MP3
};

typedef struct audio_mixer_sound audio_mixer_sound_t;
typedef struct audio_mixer_voice audio_mixer_voice_t;

typedef void (*audio_mixer_stop_cb_t)(audio_mixer_sound_t* sound, unsigned reason);

/* Reasons passed to the stop callback. */
#define AUDIO_MIXER_SOUND_FINISHED 0
#define AUDIO_MIXER_SOUND_STOPPED  1
#define AUDIO_MIXER_SOUND_REPEATED 2

void audio_mixer_init(unsigned rate);

void audio_mixer_done(void);

audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,
      const char *resampler_ident, enum resampler_quality quality);
audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size);
audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size);
audio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size);
audio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size);

void audio_mixer_destroy(audio_mixer_sound_t* sound);

audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
      bool repeat, float volume,
      const char *resampler_ident,
      enum resampler_quality quality,
      audio_mixer_stop_cb_t stop_cb);

void audio_mixer_stop(audio_mixer_voice_t* voice);

float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice);

void audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val);

void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bool override);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/audio/audio_mix.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_mix.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_MIX_H__
#define __LIBRETRO_SDK_AUDIO_MIX_H__

#include &lt;retro_common_api.h&gt;

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#ifdef _WIN32
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt;
#endif

#include &lt;formats/rwav.h&gt;
#include &lt;audio/audio_resampler.h&gt;

RETRO_BEGIN_DECLS

typedef struct
{
   double ratio;
   void *buf;
   int16_t *upsample_buf;
   float *float_buf;
   float *float_resample_buf;
   int16_t *resample_buf;
   const retro_resampler_t *resampler;
   void *resampler_data;
   rwav_t *rwav;
   ssize_t len;
   size_t resample_len;
   int sample_rate;
   bool resample;
} audio_chunk_t;

#if defined(__SSE2__)
#define audio_mix_volume           audio_mix_volume_SSE2

void audio_mix_volume_SSE2(float *out,
      const float *in, float vol, size_t samples);
#else
#define audio_mix_volume           audio_mix_volume_C
#endif

void audio_mix_volume_C(float *dst, const float *src, float vol, size_t samples);

void audio_mix_free_chunk(audio_chunk_t *chunk);

audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,
      const char *resampler_ident, enum resampler_quality quality);

size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk);

/**
 * audio_mix_get_chunk_sample:
 * @chunk              : audio chunk instance
 * @channel            : channel of the sample (0=left, 1=right)
 * @index              : index of the sample
 *
 * Get a sample from an audio chunk.
 *
 * Returns: A signed 16-bit audio sample, (if necessary) resampled into the desired output rate.
 **/
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t sample);

int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk);

int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/audio/audio_resampler.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (audio_resampler.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H
#define __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;boolean.h&gt;
#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#define RESAMPLER_SIMD_SSE      (1 &lt;&lt; 0)
#define RESAMPLER_SIMD_SSE2     (1 &lt;&lt; 1)
#define RESAMPLER_SIMD_VMX      (1 &lt;&lt; 2)
#define RESAMPLER_SIMD_VMX128   (1 &lt;&lt; 3)
#define RESAMPLER_SIMD_AVX      (1 &lt;&lt; 4)
#define RESAMPLER_SIMD_NEON     (1 &lt;&lt; 5)
#define RESAMPLER_SIMD_SSE3     (1 &lt;&lt; 6)
#define RESAMPLER_SIMD_SSSE3    (1 &lt;&lt; 7)
#define RESAMPLER_SIMD_MMX      (1 &lt;&lt; 8)
#define RESAMPLER_SIMD_MMXEXT   (1 &lt;&lt; 9)
#define RESAMPLER_SIMD_SSE4     (1 &lt;&lt; 10)
#define RESAMPLER_SIMD_SSE42    (1 &lt;&lt; 11)
#define RESAMPLER_SIMD_AVX2     (1 &lt;&lt; 12)
#define RESAMPLER_SIMD_VFPU     (1 &lt;&lt; 13)
#define RESAMPLER_SIMD_PS       (1 &lt;&lt; 14)

enum resampler_quality
{
   RESAMPLER_QUALITY_DONTCARE = 0,
   RESAMPLER_QUALITY_LOWEST,
   RESAMPLER_QUALITY_LOWER,
   RESAMPLER_QUALITY_NORMAL,
   RESAMPLER_QUALITY_HIGHER,
   RESAMPLER_QUALITY_HIGHEST
};

/* A bit-mask of all supported SIMD instruction sets.
 * Allows an implementation to pick different
 * resampler_implementation structs.
 */
typedef unsigned resampler_simd_mask_t;

#define RESAMPLER_API_VERSION 1

/**
 * A struct that groups the input and output of a resampler.
 */
struct resampler_data
{
   /**
    * The buffer containing the data to be resampled.
    */
   const float *data_in;

   /**
    * The buffer that will be used to store resampled output.
    * Must be allocated in advance, and must not be the same as data_in.
    */
   float *data_out;

   /**
    * The size of ::data_in, in frames (\em not bytes or samples).
    * For example, 32-bit stereo frames would consist of 8 bytes
    * (two 4-byte floats per frame).
    */
   size_t input_frames;

   /**
    * The number of frames (\em not bytes or samples) that the resampler produced.
    * This value is set by the resampler.
    * The resampler may not provide the same number of frames with each use,
    * so be sure to check this value.
    */
   size_t output_frames;

   /**
    * The desired ratio of output_frames to input_frames.
    * This value is used to determine the number of frames written to \c data_out.
    * If this value is (almost) equal to 1,
    * then resampling may be skipped.
    */
   double ratio;
};

/* Returns true if config key was found. Otherwise,
 * returns false, and sets value to default value.
 */
typedef int (*resampler_config_get_float_t)(void *userdata,
      const char *key, float *value, float default_value);

typedef int (*resampler_config_get_int_t)(void *userdata,
      const char *key, int *value, int default_value);

/* Allocates an array with values. free() with resampler_config_free_t. */
typedef int (*resampler_config_get_float_array_t)(void *userdata,
      const char *key, float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values);

typedef int (*resampler_config_get_int_array_t)(void *userdata,
      const char *key, int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values);

typedef int (*resampler_config_get_string_t)(void *userdata,
      const char *key, char **output, const char *default_output);

/* Calls free() in host runtime. Sometimes needed on Windows.
 * free() on NULL is fine. */
typedef void (*resampler_config_free_t)(void *ptr);

struct resampler_config
{
   resampler_config_get_float_t get_float;
   resampler_config_get_int_t get_int;

   resampler_config_get_float_array_t get_float_array;
   resampler_config_get_int_array_t get_int_array;

   resampler_config_get_string_t get_string;
   /* Avoid problems where resampler plug and host are
    * linked against different C runtimes. */
   resampler_config_free_t free;
};

/* Bandwidth factor. Will be &lt; 1.0 for downsampling, &gt; 1.0 for upsampling.
 * Corresponds to expected resampling ratio. */
typedef void *(*resampler_init_t)(const struct resampler_config *config,
      double bandwidth_mod, enum resampler_quality quality,
      resampler_simd_mask_t mask);

/* Frees the handle. */
typedef void (*resampler_free_t)(void *data);

/* Processes input data. */
typedef void (*resampler_process_t)(void *_data, struct resampler_data *data);

typedef struct retro_resampler
{
   resampler_init_t     init;
   resampler_process_t  process;
   resampler_free_t     free;

   /* Must be RESAMPLER_API_VERSION */
   unsigned api_version;

   /* Human readable identifier of implementation. */
   const char *ident;

   /* Computer-friendly short version of ident.
    * Lower case, no spaces and special characters, etc. */
   const char *short_ident;
} retro_resampler_t;

typedef struct audio_frame_float
{
   float l;
   float r;
} audio_frame_float_t;

extern retro_resampler_t sinc_resampler;
#ifdef HAVE_CC_RESAMPLER
extern retro_resampler_t CC_resampler;
#endif
extern retro_resampler_t nearest_resampler;

/**
 * audio_resampler_driver_find_handle:
 * @index              : index of driver to get handle to.
 *
 * Returns: handle to audio resampler driver at index. Can be NULL
 * if nothing found.
 **/
const void *audio_resampler_driver_find_handle(int index);

/**
 * audio_resampler_driver_find_ident:
 * @index              : index of driver to get handle to.
 *
 * Returns: Human-readable identifier of audio resampler driver at index.
 * Can be NULL if nothing found.
 **/
const char *audio_resampler_driver_find_ident(int index);

/**
 * retro_resampler_realloc:
 * @re                         : Resampler handle
 * @backend                    : Resampler backend that is about to be set.
 * @ident                      : Identifier name for resampler we want.
 * @bw_ratio                   : Bandwidth ratio.
 *
 * Reallocates resampler. Will free previous handle before
 * allocating a new one. If ident is NULL, first resampler will be used.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
      const char *ident, enum resampler_quality quality, double bw_ratio);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/audio/conversion/dual_mono.h</h2>
<pre>/* Copyright  (C) 2010-2023 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_CONVERSION_DUAL_MONO__
#define __LIBRETRO_SDK_CONVERSION_DUAL_MONO__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/**
 * Duplicates 1-channel (mono) frames into 2-channel (stereo) frames.
 * The resulting array is suitable for use in the resampler,
 * or for any use case that demands stereo input.
 * This version operates on 32-bit floating-point samples.
 *
 * May use SIMD intrinsics on supported platforms,
 * but will work without them.
 *
 * Will do nothing if \c out or \c in are \c NULL.
 *
 * @param[out] out The location in which the converted frames will be stored.
 * Must have enough room for twice the value of \c frames.
 * @param[in] in The location of the frames to convert.
 * @param[in] frames The number of frames to convert.
 */
void convert_to_dual_mono_float(float *out, const float *in, size_t frames);

/**
 * Downmixes 2-channel (stereo) frames into 1-channel (mono) frames.
 * This is intended for dual-mono audio (i.e. where both channels are identical),
 * but it will work if both channels are different.
 *
 * This version operates on 32-bit floating-point samples.
 * It preserves the left channel and ignores the right channel.
 *
 * Will do nothing if \c out or \c in are \c NULL.
 *
 * @param[out] out The location in which the converted frames will be stored.
 * Must have enough room for half the value of &lt;code&gt;frames * sizeof(float)&lt;/code&gt;.
 * @param[in] in The location of the frames to convert.
 * @param[in] frames The number of frames to convert.
 */
void convert_to_mono_float_left(float *out, const float *in, size_t frames);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/audio/conversion/float_to_s16.h</h2>
<pre>/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_to_s16.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__
#define __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

/**
 * Converts an array of floating-point audio samples
 * to signed integer 16-bit audio samples,
 * possibly using SIMD intrinsics.
 *
 * @param out The buffer that will be used to store the converted samples.
 * @param in The buffer containing the samples to convert.
 * Any number of channels is supported.
 * @param samples The length of \c in in samples, \em not bytes or frames.
 * \c out must be as large as &lt;tt&gt;sizeof(int16_t) * samples&lt;/tt&gt;.
 * @see convert_s16_to_float
 **/
void convert_float_to_s16(int16_t *out,
      const float *in, size_t samples);

/**
 * Initializes any prerequisites for
 * using SIMD implementations of \c convert_float_to_s16.
 *
 * If SIMD intrinsics are not available or no initialization is required,
 * this function does nothing.
 *
 * @see convert_float_to_s16
 **/
void convert_float_to_s16_init_simd(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/audio/conversion/s16_to_float.h</h2>
<pre>/* Copyright  (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (s16_to_float.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__
#define __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/**
 * Converts an array of signed integer 16-bit audio samples
 * to floating-point format,
 * possibly using SIMD intrinsics.
 *
 * @param out The buffer that will be used to store the converted samples.
 * @param in The buffer containing the samples to convert.
 * Any number of channels is supported.
 * @param samples The length of \c in in samples, \em not bytes or frames.
 * \c out must be as large as &lt;tt&gt;sizeof(float) * samples&lt;/tt&gt;.
 * @param gain The gain (audio volume) to apply to the samples.
 * Pass a value of 1.0 to not apply any gain.
 * @see convert_float_to_s16
 **/
void convert_s16_to_float(float *out,
      const int16_t *in, size_t samples, float gain);

/**
 * Initializes any prerequisites for
 * using SIMD implementations of \c convert_s16_to_float.
 *
 * If SIMD intrinsics are not available or no initialization is required,
 * this function does nothing.
 *
 * @see convert_s16_to_float
 **/
void convert_s16_to_float_init_simd(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/audio/dsp_filter.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dsp_filter.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_AUDIO_DSP_FILTER_H
#define __LIBRETRO_SDK_AUDIO_DSP_FILTER_H

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

typedef struct retro_dsp_filter retro_dsp_filter_t;

retro_dsp_filter_t *retro_dsp_filter_new(const char *filter_config,
      void *string_data, float sample_rate);

void retro_dsp_filter_free(retro_dsp_filter_t *dsp);

/**
 * A struct that groups the input and output of a DSP filter.
 */
struct retro_dsp_data
{
   float *input;
   unsigned input_frames;

   /* Set by retro_dsp_filter_process(). */
   float *output;
   unsigned output_frames;
};

void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
      struct retro_dsp_data *data);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/boolean.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (boolean.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_BOOLEAN_H
#define __LIBRETRO_SDK_BOOLEAN_H

#ifndef __cplusplus

#if defined(_MSC_VER) &amp;&amp; _MSC_VER &lt; 1800 &amp;&amp; !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include &lt;stdbool.h&gt;
#endif

#endif

#endif</pre>
<h2>./include/libretro-common/include/cdrom/cdrom.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (cdrom.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_CDROM_H
#define __LIBRETRO_SDK_CDROM_H

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;sys/types.h&gt;

#include &lt;vfs/vfs.h&gt;
#include &lt;libretro.h&gt;
#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;

#include &lt;boolean.h&gt;

struct string_list;

RETRO_BEGIN_DECLS

typedef struct
{
   unsigned short g1_timeout;
   unsigned short g2_timeout;
   unsigned short g3_timeout;
} cdrom_group_timeouts_t;

typedef struct
{
   unsigned lba_start; /* start of pregap */
   unsigned lba; /* start of data */
   unsigned track_size; /* in LBAs */
   unsigned track_bytes;
   unsigned char track_num;
   unsigned char min; /* start of data */
   unsigned char sec;
   unsigned char frame;
   unsigned char mode;
   bool audio;
} cdrom_track_t;

typedef struct
{
   cdrom_track_t track[99];         /* unsigned alignment */
   cdrom_group_timeouts_t timeouts; /* unsigned short alignment */
   unsigned char num_tracks;
   char drive;
} cdrom_toc_t;

void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);

unsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame);

void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame);

int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *s, size_t len);

int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc);

/* needs 32 bytes for full vendor, product and version */
int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *s, size_t len, bool *is_cdrom);

int cdrom_read(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip);

int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed);

int cdrom_stop(libretro_vfs_implementation_file *stream);

int cdrom_unlock(libretro_vfs_implementation_file *stream);

int cdrom_open_tray(libretro_vfs_implementation_file *stream);

int cdrom_close_tray(libretro_vfs_implementation_file *stream);

/* must be freed by the caller */
struct string_list* cdrom_get_available_drives(void);

bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream);

bool cdrom_drive_has_media(const char drive);

void cdrom_get_current_config_core(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream);

void cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream);

int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len);

bool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled);

bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts);

bool cdrom_has_atip(libretro_vfs_implementation_file *stream);

size_t cdrom_device_fillpath(char *s, size_t len, char drive, unsigned char track, bool is_cue);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/clamping.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (clamping.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_CLAMPING_H
#define _LIBRETRO_SDK_CLAMPING_H

#include &lt;stdint.h&gt;
#include &lt;retro_inline.h&gt;

/**
 * Clamps a floating-point value to the specified range.
 *
 * @param val The value to clamp.
 * @param lower The minimum possible value.
 * @param upper The maximum possible value.
 *
 * @returns \c val clamped to between \c lower and \c upper (inclusive).
 */
static INLINE float clamp_float(float val, float lower, float upper)
{
   if (val &lt; lower)
      return lower;
   if (val &gt; upper)
      return upper;
   return val;
}

/**
 * Clamps an integer to fit in 8 bits.
 *
 * @param val The value to clamp.
 * @return \c val clamped to between 0 and 255 (inclusive).
 */
static INLINE uint8_t clamp_8bit(int val)
{
   if (val &gt; 255)
      return 255;
   if (val &lt; 0)
      return 0;
   return (uint8_t)val;
}

#endif</pre>
<h2>./include/libretro-common/include/compat/apple_compat.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (apple_compat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __APPLE_COMPAT_H
#define __APPLE_COMPAT_H

#ifdef __APPLE__
#include &lt;AvailabilityMacros.h&gt;
#endif

#ifdef __OBJC__

#if (MAC_OS_X_VERSION_MAX_ALLOWED &lt;= MAC_OS_X_VERSION_10_4)
typedef int NSInteger;
typedef unsigned NSUInteger;
typedef float CGFloat;
#endif

#ifndef __has_feature
/* Compatibility with non-Clang compilers. */
#define __has_feature(x) 0
#endif

#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif

#ifndef NS_INLINE
#define NS_INLINE inline
#endif

NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X)
{
#if __has_feature(objc_arc)
   return (__bridge_retained CFTypeRef)X;
#else
   return X;
#endif
}

#endif

#ifdef IOS
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

#ifdef __OBJC__
#import &lt;UIKit/UIKit.h&gt;
#import &lt;GLKit/GLKit.h&gt;
#import &lt;Foundation/Foundation.h&gt;
#endif

#else

#ifdef __OBJC__
#include &lt;objc/objc-runtime.h&gt;
#endif
#endif

#endif</pre>
<h2>./include/libretro-common/include/compat/fnmatch.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fnmatch.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_FNMATCH_H__
#define __LIBRETRO_SDK_COMPAT_FNMATCH_H__

#define	FNM_NOMATCH	1

/**
 * Portable implementation of \c fnmatch(3),
 * except \c flags is not implemented.
 * @see https://man7.org/linux/man-pages/man3/fnmatch.3.html
 */
int rl_fnmatch(const char *pattern, const char *string, int flags);

#endif</pre>
<h2>./include/libretro-common/include/compat/fopen_utf8.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fopen_utf8.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H

#ifdef _WIN32
/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */
/* TODO: enable */
/* #define fopen (use fopen_utf8 instead) */
void *fopen_utf8(const char * filename, const char * mode);
#else
#define fopen_utf8 fopen
#endif
#endif</pre>
<h2>./include/libretro-common/include/compat/getopt.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (getopt.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_GETOPT_H
#define __LIBRETRO_SDK_COMPAT_GETOPT_H

#if defined(RARCH_INTERNAL) &amp;&amp; defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif

/**
 * @file getopt.h
 *
 * Portable reimplementation of a subset of libc's \c getopt_long.
 * Not designed to be fully compatible,
 * but it's enough for RetroArch's purposes.
 *
 * If \c getopt_long is available (as determined by \c HAVE_GETOPT_LONG), it will be used instead.
 *
 * @see https://man7.org/linux/man-pages/man3/getopt.3.html
 */

#ifdef HAVE_GETOPT_LONG
#include &lt;getopt.h&gt;
#else
/* Avoid possible naming collisions during link since we
 * prefer to use the actual name. */
#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex)

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

struct option
{
   const char *name;
   int has_arg;
   int *flag;
   int val;
};

/* argv[] is declared with char * const argv[] in GNU,
 * but this makes no sense, as non-POSIX getopt_long
 * mutates argv (non-opts are moved to the end). */
int getopt_long(int argc, char *argv[],
      const char *optstring, const struct option *longopts, int *longindex);
extern char *optarg;
extern int optind, opterr, optopt;

RETRO_END_DECLS

/* If these are variously #defined, then we have bigger problems */
#ifndef no_argument
   #define no_argument 0
   #define required_argument 1
   #define optional_argument 2
#endif

/* HAVE_GETOPT_LONG */
#endif

/* pragma once */
#endif</pre>
<h2>./include/libretro-common/include/compat/ifaddrs.h</h2>
<pre>/*
 * Copyright (c) 1995, 1999
 *	Berkeley Software Design, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
 */

#ifndef	_IFADDRS_H_
#define	_IFADDRS_H_

struct ifaddrs
{
   struct ifaddrs  *ifa_next;
   char		*ifa_name;
   unsigned int	 ifa_flags;
   struct sockaddr	*ifa_addr;
   struct sockaddr	*ifa_netmask;
   struct sockaddr	*ifa_dstaddr;
   void		*ifa_data;
};

/*
 * This may have been defined in &lt;net/if.h&gt;.  Note that if &lt;net/if.h&gt; is
 * to be included it must be included before this header file.
 */
#ifndef	ifa_broadaddr
#define	ifa_broadaddr	ifa_dstaddr	/* broadcast address interface */
#endif

#include &lt;sys/cdefs.h&gt;

/**
 * Portable reimplementation of \c getifaddrs().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/getifaddrs.3.html
 */
extern int getifaddrs(struct ifaddrs **ifap);

/**
 * Portable reimplementation of \c freeifaddrs().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/getifaddrs.3.html
 */
extern void freeifaddrs(struct ifaddrs *ifa);

#endif</pre>
<h2>./include/libretro-common/include/compat/intrinsics.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (intrinsics.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_INTRINSICS_H
#define __LIBRETRO_SDK_COMPAT_INTRINSICS_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;

#if defined(_MSC_VER) &amp;&amp; !defined(_XBOX)
#if (_MSC_VER &gt; 1310)
#include &lt;intrin.h&gt;
#endif
#endif

RETRO_BEGIN_DECLS

/**
 * Counts the leading zero bits in a \c uint16_t.
 * Uses compiler intrinsics if available, or a standard C implementation if not.
 *
 * @param val Value to count leading zeroes in.
 * @return Number of leading zeroes in \c val.
 */
static INLINE unsigned compat_clz_u16(uint16_t val)
{
#if defined(__GNUC__)
   return __builtin_clz(val &lt;&lt; 16 | 0x8000);
#else
   unsigned ret = 0;

   while(!(val &amp; 0x8000) &amp;&amp; ret &lt; 16)
   {
      val &lt;&lt;= 1;
      ret++;
   }

   return ret;
#endif
}

/**
 * Counts the trailing zero bits in a \c uint16_t.
 * Uses compiler intrinsics if available, or a standard C implementation if not.
 *
 * @param val Value to count trailing zeroes in.
 * @return Number of trailing zeroes in \c val.
 */
static INLINE int compat_ctz(unsigned x)
{
#if defined(__GNUC__) &amp;&amp; !defined(RARCH_CONSOLE)
   return __builtin_ctz(x);
#elif _MSC_VER &gt;= 1400 &amp;&amp; !defined(_XBOX) &amp;&amp; !defined(__WINRT__)
   unsigned long r = 0;
   _BitScanForward((unsigned long*)&amp;r, x);
   return (int)r;
#else
   int count = 0;
   if (!(x &amp; 0xffff))
   {
      x &gt;&gt;= 16;
      count |= 16;
   }
   if (!(x &amp; 0xff))
   {
      x &gt;&gt;= 8;
      count |= 8;
   }
   if (!(x &amp; 0xf))
   {
      x &gt;&gt;= 4;
      count |= 4;
   }
   if (!(x &amp; 0x3))
   {
      x &gt;&gt;= 2;
      count |= 2;
   }
   if (!(x &amp; 0x1))
      count |= 1;

   return count;
#endif
}

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/compat/msvc.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (msvc.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_MSVC_H
#define __LIBRETRO_SDK_COMPAT_MSVC_H

#ifdef _MSC_VER

#ifdef __cplusplus
extern "C"  {
#endif

/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
#if _MSC_VER &lt; 1900
   #include &lt;stdio.h&gt;
   #include &lt;stdarg.h&gt;
   #include &lt;stdlib.h&gt;

   #ifndef snprintf
      #define snprintf c99_snprintf_retro__
   #endif
   int c99_snprintf_retro__(char *s, size_t len, const char *format, ...);

   #ifndef vsnprintf
      #define vsnprintf c99_vsnprintf_retro__
   #endif
   int c99_vsnprintf_retro__(char *s, size_t len, const char *format, va_list ap);
#endif

#ifdef __cplusplus
}
#endif

#undef UNICODE /* Do not bother with UNICODE at this time. */
#include &lt;direct.h&gt;
#include &lt;stddef.h&gt;

#define _USE_MATH_DEFINES
#include &lt;math.h&gt;

/* Python headers defines ssize_t and sets HAVE_SSIZE_T.
 * Cannot duplicate these efforts.
 */
#ifndef HAVE_SSIZE_T
#if defined(_WIN64)
typedef __int64 ssize_t;
#elif defined(_WIN32)
typedef int ssize_t;
#endif
#endif

#define mkdir(dirname, unused) _mkdir(dirname)
#define strtoull _strtoui64
#undef strcasecmp
#define strcasecmp _stricmp
#undef strncasecmp
#define strncasecmp _strnicmp

/* Disable some of the annoying warnings. */
#pragma warning(disable : 4800)
#pragma warning(disable : 4805)
#pragma warning(disable : 4244)
#pragma warning(disable : 4305)
#pragma warning(disable : 4146)
#pragma warning(disable : 4267)
#pragma warning(disable : 4723)
#pragma warning(disable : 4996)

/* roundf and va_copy is available since MSVC 2013 */
#if _MSC_VER &lt; 1800
#define roundf(in) (in &gt;= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
#define va_copy(x, y) ((x) = (y))
#endif

#if _MSC_VER &lt;= 1310
   #ifndef __cplusplus
      /* VC6 math.h doesn't define some functions when in C mode.
       * Trying to define a prototype gives "undefined reference".
       * But providing an implementation then gives "function already has body".
       * So the equivalent of the implementations from math.h are used as
       * defines here instead, and it seems to work.
       */
      #define cosf(x) ((float)cos((double)x))
      #define powf(x, y) ((float)pow((double)x, (double)y))
      #define sinf(x) ((float)sin((double)x))
      #define ceilf(x) ((float)ceil((double)x))
      #define floorf(x) ((float)floor((double)x))
      #define sqrtf(x) ((float)sqrt((double)x))
      #define fabsf(x)    ((float)fabs((double)(x)))
   #endif

   #ifndef _strtoui64
      #define _strtoui64(x, y, z) (_atoi64(x))
   #endif

#endif

#ifndef PATH_MAX
#define PATH_MAX _MAX_PATH
#endif

#ifndef SIZE_MAX
#define SIZE_MAX _UI32_MAX
#endif

#endif
#endif</pre>
<h2>./include/libretro-common/include/compat/msvc/stdint.h</h2>
<pre>/* ISO C9x  compliant stdint.h for Microsoft Visual Studio
 * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
 *
 * Copyright (c) 2006-2008 Alexander Chemeris
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __RARCH_STDINT_H
#define __RARCH_STDINT_H

#if _MSC_VER &amp;&amp; (_MSC_VER &lt; 1600)
/* Pre-MSVC 2010 needs an implementation of stdint.h. */

#if _MSC_VER &gt; 1000
#pragma once
#endif

#include &lt;limits.h&gt;

/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when
 * compiling for ARM we should wrap &lt;wchar.h&gt; include with 'extern "C++" {}'
 * or compiler give many errors like this:
 *
 * error C2733: second C linkage of overloaded function 'wmemchr' not allowed
 */
#ifdef __cplusplus
#if _MSC_VER &lt;= 1200
extern "C++" {
#else
extern "C" {
#endif
#endif
#  include &lt;wchar.h&gt;
#ifdef __cplusplus
}
#endif

/* Define _W64 macros to mark types changing their size, like intptr_t. */
#ifndef _W64
#  if !defined(__midl) &amp;&amp; (defined(_X86_) || defined(_M_IX86)) &amp;&amp; _MSC_VER &gt;= 1300
#     define _W64 __w64
#  else
#     define _W64
#  endif
#endif

/* 7.18.1 Integer types. */

/* 7.18.1.1 Exact-width integer types. */

/* Visual Studio 6 and Embedded Visual C++ 4 doesn't
 * realize that, e.g. char has the same size as __int8
 * so we give up on __intX for them.
 */
#if (_MSC_VER &lt; 1300)
   typedef signed char       int8_t;
   typedef signed short      int16_t;
   typedef signed int        int32_t;
   typedef unsigned char     uint8_t;
   typedef unsigned short    uint16_t;
   typedef unsigned int      uint32_t;
#else
   typedef signed __int8     int8_t;
   typedef signed __int16    int16_t;
   typedef signed __int32    int32_t;
   typedef unsigned __int8   uint8_t;
   typedef unsigned __int16  uint16_t;
   typedef unsigned __int32  uint32_t;
#endif
typedef signed __int64       int64_t;
typedef unsigned __int64     uint64_t;

/* 7.18.1.2 Minimum-width integer types. */
typedef int8_t    int_least8_t;
typedef int16_t   int_least16_t;
typedef int32_t   int_least32_t;
typedef int64_t   int_least64_t;
typedef uint8_t   uint_least8_t;
typedef uint16_t  uint_least16_t;
typedef uint32_t  uint_least32_t;
typedef uint64_t  uint_least64_t;

/* 7.18.1.3 Fastest minimum-width integer types. */
typedef int8_t    int_fast8_t;
typedef int16_t   int_fast16_t;
typedef int32_t   int_fast32_t;
typedef int64_t   int_fast64_t;
typedef uint8_t   uint_fast8_t;
typedef uint16_t  uint_fast16_t;
typedef uint32_t  uint_fast32_t;
typedef uint64_t  uint_fast64_t;

/* 7.18.1.4 Integer types capable of holding object pointers. */
#ifdef _WIN64 /* [ */
   typedef signed __int64    intptr_t;
   typedef unsigned __int64  uintptr_t;
#else /* _WIN64 ][ */
   typedef _W64 signed int   intptr_t;
   typedef _W64 unsigned int uintptr_t;
#endif /* _WIN64 ] */

/* 7.18.1.5 Greatest-width integer types. */
typedef int64_t   intmax_t;
typedef uint64_t  uintmax_t;

/* 7.18.2 Limits of specified-width integer types. */

#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
/* [   See footnote 220 at page 257 and footnote 221 at page 259. */

/* 7.18.2.1 Limits of exact-width integer types. */
#define INT8_MIN     ((int8_t)_I8_MIN)
#define INT8_MAX     _I8_MAX
#define INT16_MIN    ((int16_t)_I16_MIN)
#define INT16_MAX    _I16_MAX
#define INT32_MIN    ((int32_t)_I32_MIN)
#define INT32_MAX    _I32_MAX
#define INT64_MIN    ((int64_t)_I64_MIN)
#define INT64_MAX    _I64_MAX
#define UINT8_MAX    _UI8_MAX
#define UINT16_MAX   _UI16_MAX
#define UINT32_MAX   _UI32_MAX
#define UINT64_MAX   _UI64_MAX

/* 7.18.2.2 Limits of minimum-width integer types. */
#define INT_LEAST8_MIN    INT8_MIN
#define INT_LEAST8_MAX    INT8_MAX
#define INT_LEAST16_MIN   INT16_MIN
#define INT_LEAST16_MAX   INT16_MAX
#define INT_LEAST32_MIN   INT32_MIN
#define INT_LEAST32_MAX   INT32_MAX
#define INT_LEAST64_MIN   INT64_MIN
#define INT_LEAST64_MAX   INT64_MAX
#define UINT_LEAST8_MAX   UINT8_MAX
#define UINT_LEAST16_MAX  UINT16_MAX
#define UINT_LEAST32_MAX  UINT32_MAX
#define UINT_LEAST64_MAX  UINT64_MAX

/* 7.18.2.3 Limits of fastest minimum-width integer types. */
#define INT_FAST8_MIN    INT8_MIN
#define INT_FAST8_MAX    INT8_MAX
#define INT_FAST16_MIN   INT16_MIN
#define INT_FAST16_MAX   INT16_MAX
#define INT_FAST32_MIN   INT32_MIN
#define INT_FAST32_MAX   INT32_MAX
#define INT_FAST64_MIN   INT64_MIN
#define INT_FAST64_MAX   INT64_MAX
#define UINT_FAST8_MAX   UINT8_MAX
#define UINT_FAST16_MAX  UINT16_MAX
#define UINT_FAST32_MAX  UINT32_MAX
#define UINT_FAST64_MAX  UINT64_MAX

/* 7.18.2.4 Limits of integer types capable of holding object pointers. */
#ifdef _WIN64 /* [ */
#  define INTPTR_MIN   INT64_MIN
#  define INTPTR_MAX   INT64_MAX
#  define UINTPTR_MAX  UINT64_MAX
#else /* _WIN64 ][ */
#  define INTPTR_MIN   INT32_MIN
#  define INTPTR_MAX   INT32_MAX
#  define UINTPTR_MAX  UINT32_MAX
#endif /* _WIN64 ] */

/* 7.18.2.5 Limits of greatest-width integer types */
#define INTMAX_MIN   INT64_MIN
#define INTMAX_MAX   INT64_MAX
#define UINTMAX_MAX  UINT64_MAX

/* 7.18.3 Limits of other integer types */

#ifdef _WIN64 /* [ */
#  define PTRDIFF_MIN  _I64_MIN
#  define PTRDIFF_MAX  _I64_MAX
#else  /* _WIN64 ][ */
#  define PTRDIFF_MIN  _I32_MIN
#  define PTRDIFF_MAX  _I32_MAX
#endif  /* _WIN64 ] */

#define SIG_ATOMIC_MIN  INT_MIN
#define SIG_ATOMIC_MAX  INT_MAX

#ifndef SIZE_MAX /* [ */
#  ifdef _WIN64 /* [ */
#     define SIZE_MAX  _UI64_MAX
#  else /* _WIN64 ][ */
#     define SIZE_MAX  _UI32_MAX
#  endif /* _WIN64 ] */
#endif /* SIZE_MAX ] */

/* WCHAR_MIN and WCHAR_MAX are also defined in &lt;wchar.h&gt; */
#ifndef WCHAR_MIN /* [ */
#  define WCHAR_MIN  0
#endif  /* WCHAR_MIN ] */
#ifndef WCHAR_MAX // [
#  define WCHAR_MAX  _UI16_MAX
#endif  /* WCHAR_MAX ] */

#define WINT_MIN  0
#define WINT_MAX  _UI16_MAX

#endif /* __STDC_LIMIT_MACROS ] */

/* 7.18.4 Limits of other integer types */

#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
/* [   See footnote 224 at page 260 */

/* 7.18.4.1 Macros for minimum-width integer constants */

#define INT8_C(val)  val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64

#define UINT8_C(val)  val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64

/* 7.18.4.2 Macros for greatest-width integer constants */
#define INTMAX_C   INT64_C
#define UINTMAX_C  UINT64_C

#endif
/* __STDC_CONSTANT_MACROS ] */

#else
/* Sanity for everything else. */
#include &lt;stdint.h&gt;
#endif

#endif</pre>
<h2>./include/libretro-common/include/compat/posix_string.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (posix_string.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H

#include &lt;retro_common_api.h&gt;

/**
 * @file posix_string.h
 *
 * Portable reimplementations of various string functions
 * that are normally provided by libc or POSIX.
 */

#ifdef _MSC_VER
#include &lt;compat/msvc.h&gt;
#endif

RETRO_BEGIN_DECLS

#if defined(_WIN32) || defined(DOXYGEN)
#undef strtok_r
#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)

/**
 * Portable reimplementation of \c strtok_r().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/strtok.3.html
 */
char *strtok_r(char *str, const char *delim, char **saveptr);
#endif

#if defined(_MSC_VER) || defined(DOXYGEN)
#undef strcasecmp
#undef strdup

#define strcasecmp(a, b) retro_strcasecmp__(a, b)
#define strdup(orig)     retro_strdup__(orig)
/**
 * Portable reimplementation of \c strcasecmp().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/strcasecmp.3.html
 */
int strcasecmp(const char *a, const char *b);

/**
 * Portable reimplementation of \c strdup().
 * The original function will be used if it's available.
 *
 * @see https://man7.org/linux/man-pages/man3/strdup.3.html
 */
char *strdup(const char *orig);

/* isblank is available since MSVC 2013 */
#if _MSC_VER &lt; 1800
#undef isblank
#define isblank(c)       retro_isblank__(c)
/**
 * Portable reimplementation of \c isblank().
 * The original function will be used if it's available.
 *
 * @see https://en.cppreference.com/w/c/string/byte/isblank
 */
int isblank(int c);
#endif

#endif

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/compat/strcasestr.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (strcasestr.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H
#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H

#include &lt;string.h&gt;

#if defined(RARCH_INTERNAL) &amp;&amp; defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif

#ifndef HAVE_STRCASESTR

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/* Avoid possible naming collisions during link
 * since we prefer to use the actual name. */
#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)

/**
 * Portable reimplementation of \c strcasestr(3).
 * If the original function is available
 * (as determined by the presence of \c HAVE_STRCASESTR),
 * it will be used instead.
 *
 * @see https://man7.org/linux/man-pages/man3/strstr.3.html
 */
char *strcasestr(const char *haystack, const char *needle);

RETRO_END_DECLS

#endif

#endif</pre>
<h2>./include/libretro-common/include/compat/strl.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (strl.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
#define __LIBRETRO_SDK_COMPAT_STRL_H

/**
 * @file strl.h
 *
 * Portable implementation of \c strlcpy(3) and \c strlcat(3).
 * If these functions are available on the target platform,
 * then the originals should be imported instead.
 *
 * @see https://linux.die.net/man/3/strlcpy
 */
#include &lt;string.h&gt;
#include &lt;stddef.h&gt;

#if defined(RARCH_INTERNAL) &amp;&amp; defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#ifdef __MACH__
#ifndef HAVE_STRL
#define HAVE_STRL
#endif
#endif

#ifndef HAVE_STRL
/* Avoid possible naming collisions during link since
 * we prefer to use the actual name. */
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)

#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)

/**
 * @brief Portable implementation of \c strlcpy(3).
 * @see https://linux.die.net/man/3/strlcpy
 */
size_t strlcpy(char *s, const char *source, size_t len);

/**
 * @brief Portable implementation of \c strlcat(3).
 * @see https://linux.die.net/man/3/strlcpy
 */
size_t strlcat(char *s, const char *source, size_t len);

#endif

/**
 * A version of \c strndup(3) that guarantees the result will be null-terminated.
 *
 * @param s The string to duplicate.
 * @param n The maximum number of characters to copy from \c s.
 * The result will allocate one more byte than this value.
 * @return Pointer to the cloned string.
 * Must be freed with \c free().
 */
char *strldup(const char *s, size_t n);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/compat/zconf.h</h2>
<pre>/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) &amp;&amp; !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) &amp;&amp; !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) &amp;&amp; !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) &amp;&amp; !defined(WIN32)
#  if !defined(__GNUC__) &amp;&amp; !defined(__FLAT__) &amp;&amp; !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ &gt;= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) &amp;&amp; (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) &amp;&amp; !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) &amp;&amp; !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) &amp;&amp; !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 &lt;&lt; (windowBits+2)) +  (1 &lt;&lt; (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 &lt;&lt; windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) &amp;&amp; (!defined(__BORLANDC__) || (__BORLANDC__ &gt;= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include &lt;windows.h&gt;
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) &amp;&amp; !defined(Z_SOLO) &amp;&amp; defined(STDC)
#  include &lt;limits.h&gt;
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include &lt;sys/types.h&gt;      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include &lt;stdarg.h&gt;         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include &lt;stddef.h&gt;         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) &amp;&amp; -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) &amp;&amp; !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include &lt;unistd.h&gt;         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include &lt;unixio.h&gt;       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) &amp;&amp; _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) &amp;&amp; defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) &amp;&amp; _FILE_OFFSET_BITS-0 == 64 &amp;&amp; defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) &amp;&amp; !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) &amp;&amp; defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) &amp;&amp; !defined(__GNUC__) &amp;&amp; !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */</pre>
<h2>./include/libretro-common/include/compat/zconf.h.in</h2>
<pre>/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) &amp;&amp; !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) &amp;&amp; !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) &amp;&amp; !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) &amp;&amp; !defined(WIN32)
#  if !defined(__GNUC__) &amp;&amp; !defined(__FLAT__) &amp;&amp; !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ &gt;= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) &amp;&amp; (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) &amp;&amp; !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) &amp;&amp; !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) &amp;&amp; !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 &lt;&lt; (windowBits+2)) +  (1 &lt;&lt; (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 &lt;&lt; windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) &amp;&amp; (!defined(__BORLANDC__) || (__BORLANDC__ &gt;= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include &lt;windows.h&gt;
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) &amp;&amp; !defined(Z_SOLO) &amp;&amp; defined(STDC)
#  include &lt;limits.h&gt;
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include &lt;sys/types.h&gt;      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include &lt;stdarg.h&gt;         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include &lt;stddef.h&gt;         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) &amp;&amp; -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) &amp;&amp; !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include &lt;unistd.h&gt;         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include &lt;unixio.h&gt;       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) &amp;&amp; _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) &amp;&amp; defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) &amp;&amp; _FILE_OFFSET_BITS-0 == 64 &amp;&amp; defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) &amp;&amp; !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) &amp;&amp; defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) &amp;&amp; !defined(__GNUC__) &amp;&amp; !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */</pre>
<h2>./include/libretro-common/include/compat/zlib.h</h2>
<pre>#ifndef _COMPAT_ZLIB_H
#define _COMPAT_ZLIB_H

#ifdef WANT_ZLIB

#ifdef RARCH_INTERNAL
#include "zconf.h.in"
#endif

/* zlib.h -- interface of the 'zlib' general purpose compression library
  version 1.2.8, April 28th, 2013

  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly        Mark Adler
  jloup@gzip.org          madler@alumni.caltech.edu

  The data format used by the zlib library is described by RFCs (Request for
  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
*/

#ifndef ZLIB_H
#define ZLIB_H

#include &lt;stdint.h&gt;
#include "zconf.h"

#ifdef __cplusplus
extern "C" {
#endif

#define ZLIB_VERSION "1.2.8"
#define ZLIB_VERNUM 0x1280
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
#define ZLIB_VER_REVISION 8
#define ZLIB_VER_SUBREVISION 0

/*
    The 'zlib' compression library provides in-memory compression and
  decompression functions, including integrity checks of the uncompressed data.
  This version of the library supports only one compression method (deflation)
  but other algorithms will be added later and will have the same stream
  interface.

    Compression can be done in a single step if the buffers are large enough,
  or can be done by repeated calls of the compression function.  In the latter
  case, the application must provide more input and/or consume the output
  (providing more output space) before each call.

    The compressed data format used by default by the in-memory functions is
  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
  around a deflate stream, which is itself documented in RFC 1951.

    The library also supports reading and writing files in gzip (.gz) format
  with an interface similar to that of stdio using the functions that start
  with "gz".  The gzip format is different from the zlib format.  gzip is a
  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.

    This library can optionally read and write gzip streams in memory as well.

    The zlib format was designed to be compact and fast for use in memory
  and on communications channels.  The gzip format was designed for single-
  file compression on file systems, has a larger header than zlib to maintain
  directory information, and uses a different, slower check method than zlib.

    The library does not install any signal handler.  The decoder checks
  the consistency of the compressed data, so the library should never crash
  even in case of corrupted input.
*/

typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);
typedef void   (*free_func)  (voidpf opaque, voidpf address);

struct internal_state;

typedef struct z_stream_s {
    z_const Bytef *next_in;     /* next input byte */
    uInt     avail_in;  /* number of bytes available at next_in */
    uLong    total_in;  /* total number of input bytes read so far */

    Bytef    *next_out; /* next output byte should be put there */
    uInt     avail_out; /* remaining free space at next_out */
    uLong    total_out; /* total number of bytes output so far */

    z_const char *msg;  /* last error message, NULL if no error */
    void *state; /* not visible by applications */

    alloc_func zalloc;  /* used to allocate the internal state */
    free_func  zfree;   /* used to free the internal state */
    voidpf     opaque;  /* private data object passed to zalloc and zfree */

    int     data_type;  /* best guess about the data type: binary or text */
    uLong   adler;      /* adler32 value of the uncompressed data */
    uLong   reserved;   /* reserved for future use */
} z_stream;

typedef z_stream FAR *z_streamp;

/*
     gzip header information passed to and from zlib routines.  See RFC 1952
  for more details on the meanings of these fields.
*/
typedef struct gz_header_s {
    int     text;       /* true if compressed data believed to be text */
    uLong   time;       /* modification time */
    int     xflags;     /* extra flags (not used when writing a gzip file) */
    int     os;         /* operating system */
    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
    uInt    extra_max;  /* space at extra (only when reading header) */
    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
    uInt    name_max;   /* space at name (only when reading header) */
    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
    uInt    comm_max;   /* space at comment (only when reading header) */
    int     hcrc;       /* true if there was or will be a header crc */
    int     done;       /* true when done reading gzip header (not used
                           when writing a gzip file) */
} gz_header;

typedef gz_header FAR *gz_headerp;

/*
     The application must update next_in and avail_in when avail_in has dropped
   to zero.  It must update next_out and avail_out when avail_out has dropped
   to zero.  The application must initialize zalloc, zfree and opaque before
   calling the init function.  All other fields are set by the compression
   library and must not be updated by the application.

     The opaque value provided by the application will be passed as the first
   parameter for calls of zalloc and zfree.  This can be useful for custom
   memory management.  The compression library attaches no meaning to the
   opaque value.

     zalloc must return Z_NULL if there is not enough memory for the object.
   If zlib is used in a multi-threaded application, zalloc and zfree must be
   thread safe.

     On 16-bit systems, the functions zalloc and zfree must be able to allocate
   exactly 65536 bytes, but will not be required to allocate more than this if
   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
   returned by zalloc for objects of exactly 65536 bytes *must* have their
   offset normalized to zero.  The default allocation function provided by this
   library ensures this (see zutil.c).  To reduce memory requirements and avoid
   any allocation of 64K objects, at the expense of compression ratio, compile
   the library with -DMAX_WBITS=14 (see zconf.h).

     The fields total_in and total_out can be used for statistics or progress
   reports.  After compression, total_in holds the total size of the
   uncompressed data and may be saved for use in the decompressor (particularly
   if the decompressor wants to decompress everything in a single step).
*/

                        /* constants */

#define Z_NO_FLUSH      0
#define Z_PARTIAL_FLUSH 1
#define Z_SYNC_FLUSH    2
#define Z_FULL_FLUSH    3
#define Z_FINISH        4
#define Z_BLOCK         5
#define Z_TREES         6
/* Allowed flush values; see deflate() and inflate() below for details */

#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative values
 * are errors, positive values are used for special but normal events.
 */

#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
/* compression levels */

#define Z_FILTERED            1
#define Z_HUFFMAN_ONLY        2
#define Z_RLE                 3
#define Z_FIXED               4
#define Z_DEFAULT_STRATEGY    0
/* compression strategy; see deflateInit2() below for details */

#define Z_BINARY   0
#define Z_TEXT     1
#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
#define Z_UNKNOWN  2
/* Possible values of the data_type field (though see inflate()) */

#define Z_DEFLATED   8
/* The deflate compression method (the only one supported in this version) */

#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */

#define zlib_version zlibVersion()
/* for compatibility with versions &lt; 1.0.2 */

                        /* basic functions */

 const char * zlibVersion (void);
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
   If the first character differs, the library code actually used is not
   compatible with the zlib.h header file used by the application.  This check
   is automatically made by deflateInit and inflateInit.
 */

/*
 int deflateInit (z_streamp strm, int level);

     Initializes the internal stream state for compression.  The fields
   zalloc, zfree and opaque must be initialized before by the caller.  If
   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
   allocation functions.

     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
   1 gives best speed, 9 gives best compression, 0 gives no compression at all
   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
   requests a default compromise between speed and compression (currently
   equivalent to level 6).

     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if level is not a valid compression level, or
   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
   if there is no error message.  deflateInit does not perform any compression:
   this will be done by deflate().
*/

 int deflate (z_streamp strm, int flush);
/*
    deflate compresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

    The detailed semantics are as follows.  deflate performs one or both of the
  following actions:

  - Compress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in and avail_in are updated and
    processing will resume at this point for the next call of deflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  This action is forced if the parameter flush is non zero.
    Forcing flush frequently degrades the compression ratio, so this parameter
    should be set only when necessary (in interactive applications).  Some
    output may be provided even if flush is not set.

    Before the call of deflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating avail_in or avail_out accordingly; avail_out should
  never be zero before the call.  The application can consume the compressed
  output when it wants, for example when the output buffer is full (avail_out
  == 0), or after each call of deflate().  If deflate returns Z_OK and with
  zero avail_out, it must be called again after making room in the output
  buffer because there might be more output pending.

    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
  decide how much data to accumulate before producing output, in order to
  maximize compression.

    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
  flushed to the output buffer and the output is aligned on a byte boundary, so
  that the decompressor can get all input data available so far.  (In
  particular avail_in is zero after the call if enough output space has been
  provided before the call.) Flushing may degrade compression for some
  compression algorithms and so it should be used only when necessary.  This
  completes the current deflate block and follows it with an empty stored block
  that is three bits plus filler bits to the next byte, followed by four bytes
  (00 00 ff ff).

    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
  output buffer, but the output is not aligned to a byte boundary.  All of the
  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
  This completes the current deflate block and follows it with an empty fixed
  codes block that is 10 bits long.  This assures that enough bytes are output
  in order for the decompressor to finish the block before the empty fixed code
  block.

    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
  seven bits of the current block are held to be written as the next byte after
  the next deflate block is completed.  In this case, the decompressor may not
  be provided enough bits at this point in order to complete decompression of
  the data provided so far to the compressor.  It may need to wait for the next
  block to be emitted.  This is for advanced applications that need to control
  the emission of deflate blocks.

    If flush is set to Z_FULL_FLUSH, all output is flushed as with
  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
  restart from this point if previous compressed data has been damaged or if
  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
  compression.

    If deflate returns with avail_out == 0, this function must be called again
  with the same value of the flush parameter and more output space (updated
  avail_out), until the flush is complete (deflate returns with non-zero
  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
  avail_out is greater than six to avoid repeated flush markers due to
  avail_out == 0 on return.

    If the parameter flush is set to Z_FINISH, pending input is processed,
  pending output is flushed and deflate returns with Z_STREAM_END if there was
  enough output space; if deflate returns with Z_OK, this function must be
  called again with Z_FINISH and more output space (updated avail_out) but no
  more input data, until it returns with Z_STREAM_END or an error.  After
  deflate has returned Z_STREAM_END, the only possible operations on the stream
  are deflateReset or deflateEnd.

    Z_FINISH can be used immediately after deflateInit if all the compression
  is to be done in a single step.  In this case, avail_out must be at least the
  value returned by deflateBound (see below).  Then deflate is guaranteed to
  return Z_STREAM_END.  If not enough output space is provided, deflate will
  not return Z_STREAM_END, and it must be called again as described above.

    deflate() sets strm-&gt;adler to the adler32 checksum of all input read
  so far (that is, total_in bytes).

    deflate() may update strm-&gt;data_type if it can make a good guess about
  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
  binary.  This field is only for information purposes and does not affect the
  compression algorithm in any manner.

    deflate() returns Z_OK if some progress has been made (more input
  processed or more output produced), Z_STREAM_END if all input has been
  consumed and all output has been produced (only when flush is set to
  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
  fatal, and deflate() can be called again with more input and more output
  space to continue compressing.
*/

 int deflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
   prematurely (some input or output was discarded).  In the error case, msg
   may be set but then points to a static string (which must not be
   deallocated).
*/

/*
 int inflateInit (z_streamp strm);

     Initializes the internal stream state for decompression.  The fields
   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
   exact value depends on the compression method), inflateInit determines the
   compression method from the zlib header and allocates all data structures
   accordingly; otherwise the allocation will be deferred to the first call of
   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
   use default allocation functions.

     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit() does not process any header information -- that is deferred
   until inflate() is called.
*/

 int inflate (z_streamp strm, int flush);
/*
    inflate decompresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

  The detailed semantics are as follows.  inflate performs one or both of the
  following actions:

  - Decompress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in is updated and processing will
    resume at this point for the next call of inflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  inflate() provides as much output as possible, until there is
    no more input data or no more space in the output buffer (see below about
    the flush parameter).

    Before the call of inflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating the next_* and avail_* values accordingly.  The
  application can consume the uncompressed output when it wants, for example
  when the output buffer is full (avail_out == 0), or after each call of
  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
  called again after making room in the output buffer because there might be
  more output pending.

    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
  output as possible to the output buffer.  Z_BLOCK requests that inflate()
  stop if and when it gets to the next deflate block boundary.  When decoding
  the zlib or gzip format, this will cause inflate() to return immediately
  after the header and before the first block.  When doing a raw inflate,
  inflate() will go ahead and process the first block, and will return when it
  gets to the end of that block, or when it runs out of data.

    The Z_BLOCK option assists in appending to or combining deflate streams.
  Also to assist in this, on return inflate() will set strm-&gt;data_type to the
  number of unused bits in the last byte taken from strm-&gt;next_in, plus 64 if
  inflate() is currently decoding the last block in the deflate stream, plus
  128 if inflate() returned immediately after decoding an end-of-block code or
  decoding the complete header up to just before the first byte of the deflate
  stream.  The end-of-block will not be indicated until all of the uncompressed
  data from that block has been written to strm-&gt;next_out.  The number of
  unused bits may in general be greater than seven, except when bit 7 of
  data_type is set, in which case the number of unused bits will be less than
  eight.  data_type is set as noted here every time inflate() returns for all
  flush options, and so can be used to determine the amount of currently
  consumed input in bits.

    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
  end of each deflate block header is reached, before any actual data in that
  block is decoded.  This allows the caller to determine the length of the
  deflate block header for later use in random access within a deflate block.
  256 is added to the value of strm-&gt;data_type when inflate() returns
  immediately after reaching the end of the deflate block header.

    inflate() should normally be called until it returns Z_STREAM_END or an
  error.  However if all decompression is to be performed in a single step (a
  single call of inflate), the parameter flush should be set to Z_FINISH.  In
  this case all pending input is processed and all pending output is flushed;
  avail_out must be large enough to hold all of the uncompressed data for the
  operation to complete.  (The size of the uncompressed data may have been
  saved by the compressor for this purpose.) The use of Z_FINISH is not
  required to perform an inflation in one step.  However it may be used to
  inform inflate that a faster approach can be used for the single inflate()
  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
  stream completes, which reduces inflate's memory footprint.  If the stream
  does not complete, either because not all of the stream is provided or not
  enough output space is provided, then a sliding window will be allocated and
  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
  been used.

     In this implementation, inflate() always flushes as much output as
  possible to the output buffer, and always uses the faster approach on the
  first call.  So the effects of the flush parameter in this implementation are
  on the return value of inflate() as noted below, when inflate() returns early
  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
  memory for a sliding window when Z_FINISH is used.

     If a preset dictionary is needed after this call (see inflateSetDictionary
  below), inflate sets strm-&gt;adler to the Adler-32 checksum of the dictionary
  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
  strm-&gt;adler to the Adler-32 checksum of all output produced so far (that is,
  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
  below.  At the end of the stream, inflate() checks that its computed adler32
  checksum is equal to that saved by the compressor and returns Z_STREAM_END
  only if the checksum is correct.

    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
  deflate data.  The header type is detected automatically, if requested when
  initializing with inflateInit2().  Any information contained in the gzip
  header is not retained, so applications that need that information should
  instead use raw inflate, see inflateInit2() below, or inflateBack() and
  perform their own processing of the gzip header and trailer.  When processing
  gzip-wrapped deflate data, strm-&gt;adler32 is set to the CRC-32 of the output
  producted so far.  The CRC-32 is checked against the gzip trailer.

    inflate() returns Z_OK if some progress has been made (more input processed
  or more output produced), Z_STREAM_END if the end of the compressed data has
  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
  corrupted (input stream not conforming to the zlib format or incorrect check
  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
  inflate() can be called again with more input and more output space to
  continue decompressing.  If Z_DATA_ERROR is returned, the application may
  then call inflateSync() to look for a good compression block if a partial
  recovery of the data is desired.
*/

 int inflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
   was inconsistent.  In the error case, msg may be set but then points to a
   static string (which must not be deallocated).
*/

                        /* Advanced functions */

/*
    The following functions are needed only in some special applications.
*/

/*
 int deflateInit2 (z_streamp strm,
                                     int  level,
                                     int  method,
                                     int  windowBits,
                                     int  memLevel,
                                     int  strategy);

     This is another version of deflateInit with more compression options.  The
   fields next_in, zalloc, zfree and opaque must be initialized before by the
   caller.

     The method parameter is the compression method.  It must be Z_DEFLATED in
   this version of the library.

     The windowBits parameter is the base two logarithm of the window size
   (the size of the history buffer).  It should be in the range 8..15 for this
   version of the library.  Larger values of this parameter result in better
   compression at the expense of memory usage.  The default value is 15 if
   deflateInit is used instead.

     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
   determines the window size.  deflate() will then generate raw deflate data
   with no zlib header or trailer, and will not compute an adler32 check value.

     windowBits can also be greater than 15 for optional gzip encoding.  Add
   16 to windowBits to write a simple gzip header and trailer around the
   compressed data instead of a zlib wrapper.  The gzip header will have no
   file name, no extra data, no comment, no modification time (set to zero), no
   header crc, and the operating system will be set to 255 (unknown).  If a
   gzip stream is being written, strm-&gt;adler is a crc32 instead of an adler32.

     The memLevel parameter specifies how much memory should be allocated
   for the internal compression state.  memLevel=1 uses minimum memory but is
   slow and reduces compression ratio; memLevel=9 uses maximum memory for
   optimal speed.  The default value is 8.  See zconf.h for total memory usage
   as a function of windowBits and memLevel.

     The strategy parameter is used to tune the compression algorithm.  Use the
   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
   string match), or Z_RLE to limit match distances to one (run-length
   encoding).  Filtered data consists mostly of small values with a somewhat
   random distribution.  In this case, the compression algorithm is tuned to
   compress them better.  The effect of Z_FILTERED is to force more Huffman
   coding and less string matching; it is somewhat intermediate between
   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
   strategy parameter only affects the compression ratio but not the
   correctness of the compressed output even if it is not set appropriately.
   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
   decoder for special applications.

     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
   set to null if there is no error message.  deflateInit2 does not perform any
   compression: this will be done by deflate().
*/

 int deflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the compression dictionary from the given byte sequence
   without producing any compressed output.  When using the zlib format, this
   function must be called immediately after deflateInit, deflateInit2 or
   deflateReset, and before any call of deflate.  When doing raw deflate, this
   function must be called either before any call of deflate, or immediately
   after the completion of a deflate block, i.e. after all input has been
   consumed and all output has been delivered when using any of the flush
   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
   compressor and decompressor must use exactly the same dictionary (see
   inflateSetDictionary).

     The dictionary should consist of strings (byte sequences) that are likely
   to be encountered later in the data to be compressed, with the most commonly
   used strings preferably put towards the end of the dictionary.  Using a
   dictionary is most useful when the data to be compressed is short and can be
   predicted with good accuracy; the data can then be compressed better than
   with the default empty dictionary.

     Depending on the size of the compression data structures selected by
   deflateInit or deflateInit2, a part of the dictionary may in effect be
   discarded, for example if the dictionary is larger than the window size
   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
   useful should be put at the end of the dictionary, not at the front.  In
   addition, the current implementation of deflate will use at most the window
   size minus 262 bytes of the provided dictionary.

     Upon return of this function, strm-&gt;adler is set to the adler32 value
   of the dictionary; the decompressor may later use this value to determine
   which dictionary has been used by the compressor.  (The adler32 value
   applies to the whole dictionary even if only a subset of the dictionary is
   actually used by the compressor.) If a raw deflate was requested, then the
   adler32 value is not computed and strm-&gt;adler is not set.

     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent (for example if deflate has already been called for this stream
   or if not at a block boundary for raw deflate).  deflateSetDictionary does
   not perform any compression: this will be done by deflate().
*/

 int deflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when several compression strategies will be
   tried, for example when there are several ways of pre-processing the input
   data with a filter.  The streams that will be discarded should then be freed
   by calling deflateEnd.  Note that deflateCopy duplicates the internal
   compression state which can be quite large, so this strategy is slow and can
   consume lots of memory.

     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int deflateReset (z_streamp strm);
/*
     This function is equivalent to deflateEnd followed by deflateInit,
   but does not free and reallocate all the internal compression state.  The
   stream will keep the same compression level and any other attributes that
   may have been set by deflateInit2.

     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int deflateParams (z_streamp strm,
                                      int level,
                                      int strategy);
/*
     Dynamically update the compression level and compression strategy.  The
   interpretation of level and strategy is as in deflateInit2.  This can be
   used to switch between compression and straight copy of the input data, or
   to switch to a different kind of input data requiring a different strategy.
   If the compression level is changed, the input available so far is
   compressed with the old level (and may be flushed); the new level will take
   effect only at the next call of deflate().

     Before the call of deflateParams, the stream state must be set as for
   a call of deflate(), since the currently available input may have to be
   compressed and flushed.  In particular, strm-&gt;avail_out must be non-zero.

     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
   strm-&gt;avail_out was zero.
*/

 int deflateTune (z_streamp strm,
                                    int good_length,
                                    int max_lazy,
                                    int nice_length,
                                    int max_chain);
/*
     Fine tune deflate's internal compression parameters.  This should only be
   used by someone who understands the algorithm used by zlib's deflate for
   searching for the best matching string, and even then only by the most
   fanatic optimizer trying to squeeze out the last compressed bit for their
   specific input data.  Read the deflate.c source code for the meaning of the
   max_lazy, good_length, nice_length, and max_chain parameters.

     deflateTune() can be called after deflateInit() or deflateInit2(), and
   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
 */

 uLong deflateBound (z_streamp strm,
                                       uLong sourceLen);
/*
     deflateBound() returns an upper bound on the compressed size after
   deflation of sourceLen bytes.  It must be called after deflateInit() or
   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
   to allocate an output buffer for deflation in a single pass, and so would be
   called before deflate().  If that first deflate() call is provided the
   sourceLen input bytes, an output buffer allocated to the size returned by
   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
   to return Z_STREAM_END.  Note that it is possible for the compressed size to
   be larger than the value returned by deflateBound() if flush options other
   than Z_FINISH or Z_NO_FLUSH are used.
*/

 int deflatePending (z_streamp strm,
                                       unsigned *pending,
                                       int *bits);
/*
     deflatePending() returns the number of bytes and bits of output that have
   been generated, but not yet provided in the available output.  The bytes not
   provided would be due to the available output space having being consumed.
   The number of bits of output not provided are between 0 and 7, where they
   await more bits to join them in order to fill out a full byte.  If pending
   or bits are Z_NULL, then those values are not set.

     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
 */

 int deflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     deflatePrime() inserts bits in the deflate output stream.  The intent
   is that this function is used to start off the deflate output with the bits
   leftover from a previous deflate stream when appending to it.  As such, this
   function can only be used for raw deflate, and must be used before the first
   deflate() call after a deflateInit2() or deflateReset().  bits must be less
   than or equal to 16, and that many of the least significant bits of value
   will be inserted in the output.

     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
   source stream state was inconsistent.
*/

 int deflateSetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     deflateSetHeader() provides gzip header information for when a gzip
   stream is requested by deflateInit2().  deflateSetHeader() may be called
   after deflateInit2() or deflateReset() and before the first call of
   deflate().  The text, time, os, extra field, name, and comment information
   in the provided gz_header structure are written to the gzip header (xflag is
   ignored -- the extra flags are set according to the compression level).  The
   caller must assure that, if not Z_NULL, name and comment are terminated with
   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
   available there.  If hcrc is true, a gzip header crc is included.  Note that
   the current versions of the command-line version of gzip (up through version
   1.3.x) do not support header crc's, and will report that it is a "multi-part
   gzip file" and give up.

     If deflateSetHeader is not used, the default gzip header has text false,
   the time set to zero, and os set to 255, with no extra, name, or comment
   fields.  The gzip header is returned to the default state by deflateReset().

     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int inflateInit2 (z_streamp strm,
                                     int  windowBits);

     This is another version of inflateInit with an extra parameter.  The
   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
   before by the caller.

     The windowBits parameter is the base two logarithm of the maximum window
   size (the size of the history buffer).  It should be in the range 8..15 for
   this version of the library.  The default value is 15 if inflateInit is used
   instead.  windowBits must be greater than or equal to the windowBits value
   provided to deflateInit2() while compressing, or it must be equal to 15 if
   deflateInit2() was not used.  If a compressed stream with a larger window
   size is given as input, inflate() will return with the error code
   Z_DATA_ERROR instead of trying to allocate a larger window.

     windowBits can also be zero to request that inflate use the window size in
   the zlib header of the compressed stream.

     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
   determines the window size.  inflate() will then process raw deflate data,
   not looking for a zlib or gzip header, not generating a check value, and not
   looking for any check values for comparison at the end of the stream.  This
   is for use with other formats that use the deflate compressed data format
   such as zip.  Those formats provide their own check values.  If a custom
   format is developed using the raw deflate format for compressed data, it is
   recommended that a check value such as an adler32 or a crc32 be applied to
   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
   most applications, the zlib format should be used as is.  Note that comments
   above on the use in deflateInit2() applies to the magnitude of windowBits.

     windowBits can also be greater than 15 for optional gzip decoding.  Add
   32 to windowBits to enable zlib and gzip decoding with automatic header
   detection, or add 16 to decode only the gzip format (the zlib format will
   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm-&gt;adler is a
   crc32 instead of an adler32.

     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit2 does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit2() does not process any header information -- that is
   deferred until inflate() is called.
*/

 int inflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the decompression dictionary from the given uncompressed byte
   sequence.  This function must be called immediately after a call of inflate,
   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
   can be determined from the adler32 value returned by that call of inflate.
   The compressor and decompressor must use exactly the same dictionary (see
   deflateSetDictionary).  For raw inflate, this function can be called at any
   time to set the dictionary.  If the provided dictionary is smaller than the
   window and there is already data in the window, then the provided dictionary
   will amend what's there.  The application must insure that the dictionary
   that was used for compression is provided.

     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
   expected one (incorrect adler32 value).  inflateSetDictionary does not
   perform any decompression: this will be done by subsequent calls of
   inflate().
*/

 int inflateGetDictionary (z_streamp strm,
                                             Bytef *dictionary,
                                             uInt  *dictLength);
/*
     Returns the sliding dictionary being maintained by inflate.  dictLength is
   set to the number of bytes in the dictionary, and that many bytes are copied
   to dictionary.  dictionary must have enough space, where 32768 bytes is
   always enough.  If inflateGetDictionary() is called with dictionary equal to
   Z_NULL, then only the dictionary length is returned, and nothing is copied.
   Similary, if dictLength is Z_NULL, then it is not set.

     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
   stream state is inconsistent.
*/

 int inflateSync (z_streamp strm);
/*
     Skips invalid compressed data until a possible full flush point (see above
   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
   available input is skipped.  No output is provided.

     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
   All full flush points have this pattern, but not all occurrences of this
   pattern are full flush points.

     inflateSync returns Z_OK if a possible full flush point has been found,
   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
   In the success case, the application may save the current current value of
   total_in which indicates where valid compressed data was found.  In the
   error case, the application may repeatedly call inflateSync, providing more
   input each time, until success or end of the input data.
*/

 int inflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when randomly accessing a large stream.  The
   first pass through the stream can periodically record the inflate state,
   allowing restarting inflate at those points when randomly accessing the
   stream.

     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int inflateReset (z_streamp strm);
/*
     This function is equivalent to inflateEnd followed by inflateInit,
   but does not free and reallocate all the internal decompression state.  The
   stream will keep attributes that may have been set by inflateInit2.

     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int inflateReset2 (z_streamp strm,
                                      int windowBits);
/*
     This function is the same as inflateReset, but it also permits changing
   the wrap and window size requests.  The windowBits parameter is interpreted
   the same as it is for inflateInit2.

     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
   the windowBits parameter is invalid.
*/

 int inflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     This function inserts bits in the inflate input stream.  The intent is
   that this function is used to start inflating at a bit position in the
   middle of a byte.  The provided bits will be used before any bytes are used
   from next_in.  This function should only be used with raw inflate, and
   should be used before the first inflate() call after inflateInit2() or
   inflateReset().  bits must be less than or equal to 16, and that many of the
   least significant bits of value will be inserted in the input.

     If bits is negative, then the input stream bit buffer is emptied.  Then
   inflatePrime() can be called again to put bits in the buffer.  This is used
   to clear out bits leftover after feeding inflate a block description prior
   to feeding inflate codes.

     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

 long  inflateMark (z_streamp strm);
/*
     This function returns two values, one in the lower 16 bits of the return
   value, and the other in the remaining upper bits, obtained by shifting the
   return value down 16 bits.  If the upper value is -1 and the lower value is
   zero, then inflate() is currently decoding information outside of a block.
   If the upper value is -1 and the lower value is non-zero, then inflate is in
   the middle of a stored block, with the lower value equaling the number of
   bytes from the input remaining to copy.  If the upper value is not -1, then
   it is the number of bits back from the current bit position in the input of
   the code (literal or length/distance pair) currently being processed.  In
   that case the lower value is the number of bytes already emitted for that
   code.

     A code is being processed if inflate is waiting for more input to complete
   decoding of the code, or if it has completed decoding but is waiting for
   more output space to write the literal or match data.

     inflateMark() is used to mark locations in the input data for random
   access, which may be at bit positions, and to note those cases where the
   output of a code may span boundaries of random access blocks.  The current
   location in the input stream can be determined from avail_in and data_type
   as noted in the description for the Z_BLOCK flush parameter for inflate.

     inflateMark returns the value noted above or -1 &lt;&lt; 16 if the provided
   source stream state was inconsistent.
*/

 int  inflateGetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     inflateGetHeader() requests that gzip header information be stored in the
   provided gz_header structure.  inflateGetHeader() may be called after
   inflateInit2() or inflateReset(), and before the first call of inflate().
   As inflate() processes the gzip stream, head-&gt;done is zero until the header
   is completed, at which time head-&gt;done is set to one.  If a zlib stream is
   being decoded, then head-&gt;done is set to -1 to indicate that there will be
   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
   used to force inflate() to return immediately after header processing is
   complete and before any actual data is decompressed.

     The text, time, xflags, and os fields are filled in with the gzip header
   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
   contains the maximum number of bytes to write to extra.  Once done is true,
   extra_len contains the actual extra field length, and extra contains the
   extra field, or that field truncated if extra_max is less than extra_len.
   If name is not Z_NULL, then up to name_max characters are written there,
   terminated with a zero unless the length is greater than name_max.  If
   comment is not Z_NULL, then up to comm_max characters are written there,
   terminated with a zero unless the length is greater than comm_max.  When any
   of extra, name, or comment are not Z_NULL and the respective field is not
   present in the header, then that field is set to Z_NULL to signal its
   absence.  This allows the use of deflateSetHeader() with the returned
   structure to duplicate the header.  However if those fields are set to
   allocated memory, then the application will need to save those pointers
   elsewhere so that they can be eventually freed.

     If inflateGetHeader is not used, then the header information is simply
   discarded.  The header is always checked for validity, including the header
   CRC if present.  inflateReset() will reset the process to discard the header
   information.  The application would need to call inflateGetHeader() again to
   retrieve the header from the next gzip stream.

     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int  inflateBackInit (z_streamp strm, int windowBits,
                                        unsigned char FAR *window);

     Initialize the internal stream state for decompression using inflateBack()
   calls.  The fields zalloc, zfree and opaque in strm must be initialized
   before the call.  If zalloc and zfree are Z_NULL, then the default library-
   derived memory allocation routines are used.  windowBits is the base two
   logarithm of the window size, in the range 8..15.  window is a caller
   supplied buffer of that size.  Except for special applications where it is
   assured that deflate was used with small window sizes, windowBits must be 15
   and a 32K byte window must be supplied to be able to decompress general
   deflate streams.

     See inflateBack() for the usage of these routines.

     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
   allocated, or Z_VERSION_ERROR if the version of the library does not match
   the version of the header file.
*/

typedef unsigned (*in_func) (void FAR *,
                                z_const unsigned char FAR * FAR *);
typedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);

 int  inflateBack (z_streamp strm,
                                    in_func in, void FAR *in_desc,
                                    out_func out, void FAR *out_desc);
/*
     inflateBack() does a raw inflate with a single call using a call-back
   interface for input and output.  This is potentially more efficient than
   inflate() for file i/o applications, in that it avoids copying between the
   output and the sliding window by simply making the window itself the output
   buffer.  inflate() can be faster on modern CPUs when used with large
   buffers.  inflateBack() trusts the application to not change the output
   buffer passed by the output function, at least until inflateBack() returns.

     inflateBackInit() must be called first to allocate the internal state
   and to initialize the state with the user-provided window buffer.
   inflateBack() may then be used multiple times to inflate a complete, raw
   deflate stream with each call.  inflateBackEnd() is then called to free the
   allocated state.

     A raw deflate stream is one with no zlib or gzip header or trailer.
   This routine would normally be used in a utility that reads zip or gzip
   files and writes out uncompressed files.  The utility would decode the
   header and process the trailer on its own, hence this routine expects only
   the raw deflate stream to decompress.  This is different from the normal
   behavior of inflate(), which expects either a zlib or gzip header and
   trailer around the deflate stream.

     inflateBack() uses two subroutines supplied by the caller that are then
   called by inflateBack() for input and output.  inflateBack() calls those
   routines until it reads a complete deflate stream and writes out all of the
   uncompressed data, or until it encounters an error.  The function's
   parameters and return types are defined above in the in_func and out_func
   typedefs.  inflateBack() will call in(in_desc, &amp;buf) which should return the
   number of bytes of provided input, and a pointer to that input in buf.  If
   there is no input available, in() must return zero--buf is ignored in that
   case--and inflateBack() will return a buffer error.  inflateBack() will call
   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
   should return zero on success, or non-zero on failure.  If out() returns
   non-zero, inflateBack() will return with an error.  Neither in() nor out()
   are permitted to change the contents of the window provided to
   inflateBackInit(), which is also the buffer that out() uses to write from.
   The length written by out() will be at most the window size.  Any non-zero
   amount of input may be provided by in().

     For convenience, inflateBack() can be provided input on the first call by
   setting strm-&gt;next_in and strm-&gt;avail_in.  If that input is exhausted, then
   in() will be called.  Therefore strm-&gt;next_in must be initialized before
   calling inflateBack().  If strm-&gt;next_in is Z_NULL, then in() will be called
   immediately for input.  If strm-&gt;next_in is not Z_NULL, then strm-&gt;avail_in
   must also be initialized, and then if strm-&gt;avail_in is not zero, input will
   initially be taken from strm-&gt;next_in[0 ..  strm-&gt;avail_in - 1].

     The in_desc and out_desc parameters of inflateBack() is passed as the
   first parameter of in() and out() respectively when they are called.  These
   descriptors can be optionally used to pass any information that the caller-
   supplied in() and out() functions need to do their job.

     On return, inflateBack() will set strm-&gt;next_in and strm-&gt;avail_in to
   pass back any unused input that was provided by the last in() call.  The
   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
   in the deflate stream (in which case strm-&gt;msg is set to indicate the nature
   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
   In the case of Z_BUF_ERROR, an input or output error can be distinguished
   using strm-&gt;next_in which will be Z_NULL only if in() returned an error.  If
   strm-&gt;next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
   non-zero.  (in() will always be called before out(), so strm-&gt;next_in is
   assured to be defined if out() returns non-zero.) Note that inflateBack()
   cannot return Z_OK.
*/

 int  inflateBackEnd (z_streamp strm);
/*
     All memory allocated by inflateBackInit() is freed.

     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
   state was inconsistent.
*/

 uLong  zlibCompileFlags (void);
/* Return flags indicating compile-time options.

    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
     1.0: size of uInt
     3.2: size of uLong
     5.4: size of voidpf (pointer)
     7.6: size of z_off_t

    Compiler, assembler, and debug options:
     8: DEBUG
     9: ASMV or ASMINF -- use ASM code
     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
     11: 0 (reserved)

    One-time table building (smaller code, but not thread-safe if true):
     12: BUILDFIXED -- build static block decoding tables when needed
     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
     14,15: 0 (reserved)

    Library content (indicates missing functionality):
     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
                          deflate code when not needed)
     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
                    and decode gzip streams (to avoid linking crc code)
     18-19: 0 (reserved)

    Operation variations (changes in library functionality):
     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
     21: FASTEST -- deflate algorithm with only one, lowest compression level
     22,23: 0 (reserved)

    The sprintf variant used by gzprintf (zero is best):
     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
     26: 0 = returns value, 1 = void -- 1 means inferred string length returned

    Remainder:
     27-31: 0 (reserved)
 */

#ifndef Z_SOLO

                        /* utility functions */

/*
     The following utility functions are implemented on top of the basic
   stream-oriented functions.  To simplify the interface, some default options
   are assumed (compression level and memory usage, standard memory allocation
   functions).  The source code of these utility functions can be modified if
   you need special options.
*/

 int  compress (Bytef *dest,   uLongf *destLen,
                                 const Bytef *source, uLong sourceLen);
/*
     Compresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer.
*/

 int  compress2 (Bytef *dest,   uLongf *destLen,
                                  const Bytef *source, uLong sourceLen,
                                  int level);
/*
     Compresses the source buffer into the destination buffer.  The level
   parameter has the same meaning as in deflateInit.  sourceLen is the byte
   length of the source buffer.  Upon entry, destLen is the total size of the
   destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
   Z_STREAM_ERROR if the level parameter is invalid.
*/

 uLong  compressBound (uLong sourceLen);
/*
     compressBound() returns an upper bound on the compressed size after
   compress() or compress2() on sourceLen bytes.  It would be used before a
   compress() or compress2() call to allocate the destination buffer.
*/

 int  uncompress (Bytef *dest,   uLongf *destLen,
       const Bytef *source, uLongf sourceLen);
/*
     Decompresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be large enough to hold the entire
   uncompressed data.  (The size of the uncompressed data must have been saved
   previously by the compressor and transmitted to the decompressor by some
   mechanism outside the scope of this compression library.) Upon exit, destLen
   is the actual size of the uncompressed buffer.

     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
   the case where there is not enough room, uncompress() will fill the output
   buffer with the uncompressed data up to that point.
*/

                        /* gzip file access functions */

/*
     This library supports reading and writing files in gzip (.gz) format with
   an interface similar to that of stdio, using the functions that start with
   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
   wrapper, documented in RFC 1952, wrapped around a deflate stream.
*/

typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */

/*
 gzFile  gzopen (const char *path, const char *mode);

     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
   for fixed code compression as in "wb9F".  (See the description of
   deflateInit2 for more information about the strategy parameter.)  'T' will
   request transparent writing or appending with no compression and not using
   the gzip format.

     "a" can be used instead of "w" to request that the gzip stream that will
   be written be appended to the file.  "+" will result in an error, since
   reading and writing to the same gzip file is not supported.  The addition of
   "x" when writing will create the file exclusively, which fails if the file
   already exists.  On systems that support it, the addition of "e" when
   reading or writing will set the flag to close the file on an execve() call.

     These functions, as well as gzip, will read and decode a sequence of gzip
   streams in a file.  The append function of gzopen() can be used to create
   such a file.  (Also see gzflush() for another way to do this.)  When
   appending, gzopen does not test whether the file begins with a gzip stream,
   nor does it look for the end of the gzip streams to begin appending.  gzopen
   will simply append a gzip stream to the existing file.

     gzopen can be used to read a file which is not in gzip format; in this
   case gzread will directly read from the file without decompression.  When
   reading, this will be detected automatically by looking for the magic two-
   byte gzip header.

     gzopen returns NULL if the file could not be opened, if there was
   insufficient memory to allocate the gzFile state, or if an invalid mode was
   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
   errno can be checked to determine if the reason gzopen failed was that the
   file could not be opened.
*/

 gzFile  gzdopen (int fd, const char *mode);
/*
     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
   are obtained from calls like open, dup, creat, pipe or fileno (if the file
   has been previously opened with fopen).  The mode parameter is as in gzopen.

     The next call of gzclose on the returned gzFile will also close the file
   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
   mode);.  The duplicated descriptor should be saved to avoid a leak, since
   gzdopen does not close fd if it fails.  If you are using fileno() to get the
   file descriptor from a FILE *, then you will have to use dup() to avoid
   double-close()ing the file descriptor.  Both gzclose() and fclose() will
   close the associated file descriptor, so they need to have different file
   descriptors.

     gzdopen returns NULL if there was insufficient memory to allocate the
   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
   used until the next gz* read, write, seek, or close operation, so gzdopen
   will not detect if fd is invalid (unless fd is -1).
*/

 int  gzbuffer (gzFile file, unsigned size);
/*
     Set the internal buffer size used by this library's functions.  The
   default buffer size is 8192 bytes.  This function must be called after
   gzopen() or gzdopen(), and before any other calls that read or write the
   file.  The buffer memory allocation is always deferred to the first read or
   write.  Two buffers are allocated, either both of the specified size when
   writing, or one of the specified size and the other twice that size when
   reading.  A larger buffer size of, for example, 64K or 128K bytes will
   noticeably increase the speed of decompression (reading).

     The new buffer size also affects the maximum length for gzprintf().

     gzbuffer() returns 0 on success, or -1 on failure, such as being called
   too late.
*/

 int  gzsetparams (gzFile file, int level, int strategy);
/*
     Dynamically update the compression level or strategy.  See the description
   of deflateInit2 for the meaning of these parameters.

     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
   opened for writing.
*/

 int  gzread (gzFile file, voidp buf, unsigned len);
/*
     Reads the given number of uncompressed bytes from the compressed file.  If
   the input file is not in gzip format, gzread copies the given number of
   bytes into the buffer directly from the file.

     After reaching the end of a gzip stream in the input, gzread will continue
   to read, looking for another gzip stream.  Any number of gzip streams may be
   concatenated in the input file, and will all be decompressed by gzread().
   If something other than a gzip stream is encountered after a gzip stream,
   that remaining trailing garbage is ignored (and no error is returned).

     gzread can be used to read a gzip file that is being concurrently written.
   Upon reaching the end of the input, gzread will return with the available
   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
   gzclearerr can be used to clear the end of file indicator in order to permit
   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
   middle of a gzip stream.  Note that gzread does not return -1 in the event
   of an incomplete gzip stream.  This error is deferred until gzclose(), which
   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
   stream.  Alternatively, gzerror can be used before gzclose to detect this
   case.

     gzread returns the number of uncompressed bytes actually read, less than
   len for end of file, or -1 for error.
*/

 int  gzwrite (gzFile file,
                                voidpc buf, unsigned len);
/*
     Writes the given number of uncompressed bytes into the compressed file.
   gzwrite returns the number of uncompressed bytes written or 0 in case of
   error.
*/

 int gzprintf Z_ARG((gzFile file, const char *format, ...));
/*
     Converts, formats, and writes the arguments to the compressed file under
   control of the format string, as in fprintf.  gzprintf returns the number of
   uncompressed bytes actually written, or 0 in case of error.  The number of
   uncompressed bytes written is limited to 8191, or one less than the buffer
   size given to gzbuffer().  The caller should assure that this limit is not
   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
   nothing written.  In this case, there may also be a buffer overflow with
   unpredictable consequences, which is possible only if zlib was compiled with
   the insecure functions sprintf() or vsprintf() because the secure snprintf()
   or vsnprintf() functions were not available.  This can be determined using
   zlibCompileFlags().
*/

 int  gzputs (gzFile file, const char *s);
/*
     Writes the given null-terminated string to the compressed file, excluding
   the terminating null character.

     gzputs returns the number of characters written, or -1 in case of error.
*/

 char *  gzgets (gzFile file, char *buf, int len);
/*
     Reads bytes from the compressed file until len-1 characters are read, or a
   newline character is read and transferred to buf, or an end-of-file
   condition is encountered.  If any characters are read or if len == 1, the
   string is terminated with a null character.  If no characters are read due
   to an end-of-file or len &lt; 1, then the buffer is left untouched.

     gzgets returns buf which is a null-terminated string, or it returns NULL
   for end-of-file or in case of error.  If there was an error, the contents at
   buf are indeterminate.
*/

 int  gzputc (gzFile file, int c);
/*
     Writes c, converted to an unsigned char, into the compressed file.  gzputc
   returns the value that was written, or -1 in case of error.
*/

 int  gzgetc (gzFile file);
/*
     Reads one byte from the compressed file.  gzgetc returns this byte or -1
   in case of end of file or error.  This is implemented as a macro for speed.
   As such, it does not do all of the checking the other functions do.  I.e.
   it does not check to see if file is NULL, nor whether the structure file
   points to has been clobbered or not.
*/

 int  gzungetc (int c, gzFile file);
/*
     Push one character back onto the stream to be read as the first character
   on the next read.  At least one character of push-back is allowed.
   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
   fail if c is -1, and may fail if a character has been pushed but not read
   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
   The pushed character will be discarded if the stream is repositioned with
   gzseek() or gzrewind().
*/

 int  gzflush (gzFile file, int flush);
/*
     Flushes all pending output into the compressed file.  The parameter flush
   is as in the deflate() function.  The return value is the zlib error number
   (see function gzerror below).  gzflush is only permitted when writing.

     If the flush parameter is Z_FINISH, the remaining data is written and the
   gzip stream is completed in the output.  If gzwrite() is called again, a new
   gzip stream will be started in the output.  gzread() is able to read such
   concatented gzip streams.

     gzflush should be called only when strictly necessary because it will
   degrade compression if called too often.
*/

/*
 z_off_t  gzseek (gzFile file,
                                   z_off_t offset, int whence);

     Sets the starting position for the next gzread or gzwrite on the given
   compressed file.  The offset represents a number of bytes in the
   uncompressed data stream.  The whence parameter is defined as in lseek(2);
   the value SEEK_END is not supported.

     If the file is opened for reading, this function is emulated but can be
   extremely slow.  If the file is opened for writing, only forward seeks are
   supported; gzseek then compresses a sequence of zeroes up to the new
   starting position.

     gzseek returns the resulting offset location as measured in bytes from
   the beginning of the uncompressed stream, or -1 in case of error, in
   particular if the file is opened for writing and the new starting position
   would be before the current position.
*/

 int     gzrewind (gzFile file);
/*
     Rewinds the given file. This function is supported only for reading.

     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
*/

/*
 z_off_t     gztell (gzFile file);

     Returns the starting position for the next gzread or gzwrite on the given
   compressed file.  This position represents a number of bytes in the
   uncompressed data stream, and is zero when starting, even if appending or
   reading a gzip stream from the middle of a file using gzdopen().

     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
*/

/*
 z_off_t  gzoffset (gzFile file);

     Returns the current offset in the file being read or written.  This offset
   includes the count of bytes that precede the gzip stream, for example when
   appending or when using gzdopen() for reading.  When reading, the offset
   does not include as yet unused buffered input.  This information can be used
   for a progress indicator.  On error, gzoffset() returns -1.
*/

 int  gzeof (gzFile file);
/*
     Returns true (1) if the end-of-file indicator has been set while reading,
   false (0) otherwise.  Note that the end-of-file indicator is set only if the
   read tried to go past the end of the input, but came up short.  Therefore,
   just like feof(), gzeof() may return false even if there is no more data to
   read, in the event that the last read request was for the exact number of
   bytes remaining in the input file.  This will happen if the input file size
   is an exact multiple of the buffer size.

     If gzeof() returns true, then the read functions will return no more data,
   unless the end-of-file indicator is reset by gzclearerr() and the input file
   has grown since the previous end of file was detected.
*/

 int  gzdirect (gzFile file);
/*
     Returns true (1) if file is being copied directly while reading, or false
   (0) if file is a gzip stream being decompressed.

     If the input file is empty, gzdirect() will return true, since the input
   does not contain a gzip stream.

     If gzdirect() is used immediately after gzopen() or gzdopen() it will
   cause buffers to be allocated to allow reading the file to determine if it
   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
   gzdirect().

     When writing, gzdirect() returns true (1) if transparent writing was
   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
   gzdirect() is not needed when writing.  Transparent writing must be
   explicitly requested, so the application already knows the answer.  When
   linking statically, using gzdirect() will include all of the zlib code for
   gzip file reading and decompression, which may not be desired.)
*/

 int     gzclose (gzFile file);
/*
     Flushes all pending output if necessary, closes the compressed file and
   deallocates the (de)compression state.  Note that once file is closed, you
   cannot call gzerror with file, since its structures have been deallocated.
   gzclose must not be called more than once on the same file, just as free
   must not be called more than once on the same allocation.

     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
   last read ended in the middle of a gzip stream, or Z_OK on success.
*/

 int  gzclose_r (gzFile file);
 int  gzclose_w (gzFile file);
/*
     Same as gzclose(), but gzclose_r() is only for use when reading, and
   gzclose_w() is only for use when writing or appending.  The advantage to
   using these instead of gzclose() is that they avoid linking in zlib
   compression or decompression code that is not used when only reading or only
   writing respectively.  If gzclose() is used, then both compression and
   decompression code will be included the application when linking to a static
   zlib library.
*/

 const char *  gzerror (gzFile file, int *errnum);
/*
     Returns the error message for the last error which occurred on the given
   compressed file.  errnum is set to zlib error number.  If an error occurred
   in the file system and not in the compression library, errnum is set to
   Z_ERRNO and the application may consult errno to get the exact error code.

     The application must not modify the returned string.  Future calls to
   this function may invalidate the previously returned string.  If file is
   closed, then the string previously returned by gzerror will no longer be
   available.

     gzerror() should be used to distinguish errors from end-of-file for those
   functions above that do not distinguish those cases in their return values.
*/

 void  gzclearerr (gzFile file);
/*
     Clears the error and end-of-file flags for file.  This is analogous to the
   clearerr() function in stdio.  This is useful for continuing to read a gzip
   file that is being written concurrently.
*/

#endif /* !Z_SOLO */

                        /* checksum functions */

/*
     These functions are not related to compression but are exported
   anyway because they might be useful in applications using the compression
   library.
*/

uint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);
/*
     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
   return the updated checksum.  If buf is Z_NULL, this function returns the
   required initial value for the checksum.

     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
   much faster.

   Usage example:

     uLong adler = adler32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       adler = adler32(adler, buffer, length);
     }
     if (adler != original_adler) error();
*/

/*
 uLong  adler32_combine (uLong adler1, uLong adler2,
                                          z_off_t len2);

     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
   that the z_off_t type (like off_t) is a signed integer.  If len2 is
   negative, the result has no meaning or utility.
*/

 uLong  crc32   (uLong crc, const Bytef *buf, uInt len);
/*
     Update a running CRC-32 with the bytes buf[0..len-1] and return the
   updated CRC-32.  If buf is Z_NULL, this function returns the required
   initial value for the crc.  Pre- and post-conditioning (one's complement) is
   performed within this function so it shouldn't be done by the application.

   Usage example:

     uLong crc = crc32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       crc = crc32(crc, buffer, length);
     }
     if (crc != original_crc) error();
*/

/*
 uLong  crc32_combine (uLong crc1, uLong crc2, z_off_t len2);

     Combine two CRC-32 check values into one.  For two sequences of bytes,
   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
   len2.
*/

                        /* various hacks, don't look :) */

/* deflateInit and inflateInit are macros to allow checking the zlib version
 * and the compiler's view of z_stream:
 */
 int  deflateInit_ (z_streamp strm, int level,
                                     const char *version, int stream_size);
 int  inflateInit_ (z_streamp strm,
                                     const char *version, int stream_size);
 int  deflateInit2_ (z_streamp strm, int  level, int  method,
                                      int windowBits, int memLevel,
                                      int strategy, const char *version,
                                      int stream_size);
 int  inflateInit2_ (z_streamp strm, int  windowBits,
                                      const char *version, int stream_size);
 int  inflateBackInit_ (z_streamp strm, int windowBits,
                                         unsigned char FAR *window,
                                         const char *version,
                                         int stream_size);
#define deflateInit(strm, level) \
        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit(strm) \
        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit2(strm, windowBits) \
        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
                      (int)sizeof(z_stream))
#define inflateBackInit(strm, windowBits, window) \
        inflateBackInit_((strm), (windowBits), (window), \
                      ZLIB_VERSION, (int)sizeof(z_stream))

#ifndef Z_SOLO

/* gzgetc() macro and its supporting function and exposed data structure.  Note
 * that the real internal state is much larger than the exposed structure.
 * This abbreviated structure exposes just enough for the gzgetc() macro.  The
 * user should not mess with these exposed elements, since their names or
 * behavior could change in the future, perhaps even capriciously.  They can
 * only be used by the gzgetc() macro.  You have been warned.
 */
 int  gzgetc_ (gzFile file);  /* backward compatibility */
#ifdef Z_PREFIX_SET
#  undef z_gzgetc
#  define z_gzgetc(g) \
          ((g)-&gt;have ? ((g)-&gt;have--, (g)-&gt;pos++, *((g)-&gt;next)++) : gzgetc(g))
#else
#  define gzgetc(g) \
          ((g)-&gt;have ? ((g)-&gt;have--, (g)-&gt;pos++, *((g)-&gt;next)++) : gzgetc(g))
#endif

/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
 * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
 * both are true, the application gets the *64 functions, and the regular
 * functions are changed to 64 bits) -- in case these are set on systems
 * without large file support, _LFS64_LARGEFILE must also be true
 */
#ifdef Z_LARGE64
    gzFile  gzopen64 (const char *, const char *);
    z_off64_t  gzseek64 (gzFile, z_off64_t, int);
    z_off64_t  gztell64 (gzFile);
    z_off64_t  gzoffset64 (gzFile);
    uLong  adler32_combine64 (uLong, uLong, z_off64_t);
    uLong  crc32_combine64 (uLong, uLong, z_off64_t);
#endif

#if !defined(ZLIB_INTERNAL) &amp;&amp; defined(Z_WANT64)
#  ifdef Z_PREFIX_SET
#    define z_gzopen z_gzopen64
#    define z_gzseek z_gzseek64
#    define z_gztell z_gztell64
#    define z_gzoffset z_gzoffset64
#    define z_adler32_combine z_adler32_combine64
#    define z_crc32_combine z_crc32_combine64
#  else
#    define gzopen gzopen64
#    define gzseek gzseek64
#    define gztell gztell64
#    define gzoffset gzoffset64
#    define adler32_combine adler32_combine64
#    define crc32_combine crc32_combine64
#  endif
#  ifndef Z_LARGE64
      gzFile  gzopen64 (const char *, const char *);
      z_off_t  gzseek64 (gzFile, z_off_t, int);
      z_off_t  gztell64 (gzFile);
      z_off_t  gzoffset64 (gzFile);
      uLong  adler32_combine64 (uLong, uLong, z_off_t);
      uLong  crc32_combine64 (uLong, uLong, z_off_t);
#  endif
#else
    gzFile  gzopen (const char *, const char *);
    z_off_t  gzseek (gzFile, z_off_t, int);
    z_off_t  gztell (gzFile);
    z_off_t  gzoffset (gzFile);
    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);
#endif

#else /* Z_SOLO */

    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);

#endif /* !Z_SOLO */

/* hack for buggy compilers */
#if !defined(ZUTIL_H) &amp;&amp; !defined(NO_DUMMY_DECL)
    struct internal_state {int dummy;};
#endif

/* undocumented functions */
 const char   *  zError           (int);
 int             inflateSyncPoint (z_streamp);

 const uint32_t * get_crc_table(void);
 int             inflateUndermine (z_streamp, int);
 int             inflateValidate  (z_streamp, int);
 int             inflateResetKeep (z_streamp);
 int             deflateResetKeep (z_streamp);
#if defined(_WIN32) &amp;&amp; !defined(Z_SOLO)
 gzFile          gzopen_w (const wchar_t *path,
                                            const char *mode);
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
 int            gzvprintf Z_ARG((gzFile file,
                                                  const char *format,
                                                  va_list va));
#  endif
#endif

#ifdef __cplusplus
}
#endif

#endif /* ZLIB_H */

#else
#include &lt;zlib.h&gt;
#endif

#endif</pre>
<h2>./include/libretro-common/include/compat/zlib/zconf.h</h2>
<pre>/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) &amp;&amp; !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) &amp;&amp; !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) &amp;&amp; !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) &amp;&amp; !defined(WIN32)
#  if !defined(__GNUC__) &amp;&amp; !defined(__FLAT__) &amp;&amp; !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ &gt;= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) &amp;&amp; (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) &amp;&amp; !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) &amp;&amp; !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) &amp;&amp; !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 &lt;&lt; (windowBits+2)) +  (1 &lt;&lt; (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 &lt;&lt; windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) &amp;&amp; (!defined(__BORLANDC__) || (__BORLANDC__ &gt;= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include &lt;windows.h&gt;
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) &amp;&amp; !defined(Z_SOLO) &amp;&amp; defined(STDC)
#  include &lt;limits.h&gt;
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include &lt;sys/types.h&gt;      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include &lt;stdarg.h&gt;         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include &lt;stddef.h&gt;         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) &amp;&amp; -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) &amp;&amp; !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include &lt;unistd.h&gt;         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include &lt;unixio.h&gt;       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) &amp;&amp; _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) &amp;&amp; defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) &amp;&amp; _FILE_OFFSET_BITS-0 == 64 &amp;&amp; defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) &amp;&amp; !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) &amp;&amp; defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) &amp;&amp; !defined(__GNUC__) &amp;&amp; !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */</pre>
<h2>./include/libretro-common/include/compat/zlib/zconf.h.in</h2>
<pre>/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) &amp;&amp; !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) &amp;&amp; !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) &amp;&amp; !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) &amp;&amp; !defined(WIN32)
#  if !defined(__GNUC__) &amp;&amp; !defined(__FLAT__) &amp;&amp; !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ &gt;= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) &amp;&amp; (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) &amp;&amp; (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) &amp;&amp; !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) &amp;&amp; !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) &amp;&amp; !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 &lt;&lt; (windowBits+2)) +  (1 &lt;&lt; (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 &lt;&lt; windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) &amp;&amp; (!defined(__BORLANDC__) || (__BORLANDC__ &gt;= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include &lt;windows.h&gt;
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#  endif
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) &amp;&amp; !defined(Z_SOLO) &amp;&amp; defined(STDC)
#  include &lt;limits.h&gt;
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include &lt;sys/types.h&gt;      /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include &lt;stdarg.h&gt;         /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include &lt;stddef.h&gt;         /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) &amp;&amp; -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) &amp;&amp; !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include &lt;unistd.h&gt;         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include &lt;unixio.h&gt;       /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) &amp;&amp; _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) &amp;&amp; defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) &amp;&amp; _FILE_OFFSET_BITS-0 == 64 &amp;&amp; defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) &amp;&amp; !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) &amp;&amp; defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) &amp;&amp; !defined(__GNUC__) &amp;&amp; !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */</pre>
<h2>./include/libretro-common/include/compat/zlib/zlib.h</h2>
<pre>#ifndef _COMPAT_ZLIB_H
#define _COMPAT_ZLIB_H

/* zlib.h -- interface of the 'zlib' general purpose compression library
  version 1.2.8, April 28th, 2013

  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly        Mark Adler
  jloup@gzip.org          madler@alumni.caltech.edu

  The data format used by the zlib library is described by RFCs (Request for
  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
*/

#ifndef ZLIB_H
#define ZLIB_H

#include &lt;stdint.h&gt;
#include "zconf.h"

#ifdef __cplusplus
extern "C" {
#endif

#define ZLIB_VERSION "1.2.8"
#define ZLIB_VERNUM 0x1280
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
#define ZLIB_VER_REVISION 8
#define ZLIB_VER_SUBREVISION 0

/*
    The 'zlib' compression library provides in-memory compression and
  decompression functions, including integrity checks of the uncompressed data.
  This version of the library supports only one compression method (deflation)
  but other algorithms will be added later and will have the same stream
  interface.

    Compression can be done in a single step if the buffers are large enough,
  or can be done by repeated calls of the compression function.  In the latter
  case, the application must provide more input and/or consume the output
  (providing more output space) before each call.

    The compressed data format used by default by the in-memory functions is
  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
  around a deflate stream, which is itself documented in RFC 1951.

    The library also supports reading and writing files in gzip (.gz) format
  with an interface similar to that of stdio using the functions that start
  with "gz".  The gzip format is different from the zlib format.  gzip is a
  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.

    This library can optionally read and write gzip streams in memory as well.

    The zlib format was designed to be compact and fast for use in memory
  and on communications channels.  The gzip format was designed for single-
  file compression on file systems, has a larger header than zlib to maintain
  directory information, and uses a different, slower check method than zlib.

    The library does not install any signal handler.  The decoder checks
  the consistency of the compressed data, so the library should never crash
  even in case of corrupted input.
*/

typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);
typedef void   (*free_func)  (voidpf opaque, voidpf address);

struct internal_state;

typedef struct z_stream_s {
    z_const Bytef *next_in;     /* next input byte */
    uInt     avail_in;  /* number of bytes available at next_in */
    uLong    total_in;  /* total number of input bytes read so far */

    Bytef    *next_out; /* next output byte should be put there */
    uInt     avail_out; /* remaining free space at next_out */
    uLong    total_out; /* total number of bytes output so far */

    z_const char *msg;  /* last error message, NULL if no error */
    void *state; /* not visible by applications */

    alloc_func zalloc;  /* used to allocate the internal state */
    free_func  zfree;   /* used to free the internal state */
    voidpf     opaque;  /* private data object passed to zalloc and zfree */

    int     data_type;  /* best guess about the data type: binary or text */
    uLong   adler;      /* adler32 value of the uncompressed data */
    uLong   reserved;   /* reserved for future use */
} z_stream;

typedef z_stream FAR *z_streamp;

/*
     gzip header information passed to and from zlib routines.  See RFC 1952
  for more details on the meanings of these fields.
*/
typedef struct gz_header_s {
    int     text;       /* true if compressed data believed to be text */
    uLong   time;       /* modification time */
    int     xflags;     /* extra flags (not used when writing a gzip file) */
    int     os;         /* operating system */
    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
    uInt    extra_max;  /* space at extra (only when reading header) */
    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
    uInt    name_max;   /* space at name (only when reading header) */
    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
    uInt    comm_max;   /* space at comment (only when reading header) */
    int     hcrc;       /* true if there was or will be a header crc */
    int     done;       /* true when done reading gzip header (not used
                           when writing a gzip file) */
} gz_header;

typedef gz_header FAR *gz_headerp;

/*
     The application must update next_in and avail_in when avail_in has dropped
   to zero.  It must update next_out and avail_out when avail_out has dropped
   to zero.  The application must initialize zalloc, zfree and opaque before
   calling the init function.  All other fields are set by the compression
   library and must not be updated by the application.

     The opaque value provided by the application will be passed as the first
   parameter for calls of zalloc and zfree.  This can be useful for custom
   memory management.  The compression library attaches no meaning to the
   opaque value.

     zalloc must return Z_NULL if there is not enough memory for the object.
   If zlib is used in a multi-threaded application, zalloc and zfree must be
   thread safe.

     On 16-bit systems, the functions zalloc and zfree must be able to allocate
   exactly 65536 bytes, but will not be required to allocate more than this if
   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
   returned by zalloc for objects of exactly 65536 bytes *must* have their
   offset normalized to zero.  The default allocation function provided by this
   library ensures this (see zutil.c).  To reduce memory requirements and avoid
   any allocation of 64K objects, at the expense of compression ratio, compile
   the library with -DMAX_WBITS=14 (see zconf.h).

     The fields total_in and total_out can be used for statistics or progress
   reports.  After compression, total_in holds the total size of the
   uncompressed data and may be saved for use in the decompressor (particularly
   if the decompressor wants to decompress everything in a single step).
*/

                        /* constants */

#define Z_NO_FLUSH      0
#define Z_PARTIAL_FLUSH 1
#define Z_SYNC_FLUSH    2
#define Z_FULL_FLUSH    3
#define Z_FINISH        4
#define Z_BLOCK         5
#define Z_TREES         6
/* Allowed flush values; see deflate() and inflate() below for details */

#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative values
 * are errors, positive values are used for special but normal events.
 */

#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
/* compression levels */

#define Z_FILTERED            1
#define Z_HUFFMAN_ONLY        2
#define Z_RLE                 3
#define Z_FIXED               4
#define Z_DEFAULT_STRATEGY    0
/* compression strategy; see deflateInit2() below for details */

#define Z_BINARY   0
#define Z_TEXT     1
#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
#define Z_UNKNOWN  2
/* Possible values of the data_type field (though see inflate()) */

#define Z_DEFLATED   8
/* The deflate compression method (the only one supported in this version) */

#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */

#define zlib_version zlibVersion()
/* for compatibility with versions &lt; 1.0.2 */

                        /* basic functions */

 const char * zlibVersion (void);
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
   If the first character differs, the library code actually used is not
   compatible with the zlib.h header file used by the application.  This check
   is automatically made by deflateInit and inflateInit.
 */

/*
 int deflateInit (z_streamp strm, int level);

     Initializes the internal stream state for compression.  The fields
   zalloc, zfree and opaque must be initialized before by the caller.  If
   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
   allocation functions.

     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
   1 gives best speed, 9 gives best compression, 0 gives no compression at all
   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
   requests a default compromise between speed and compression (currently
   equivalent to level 6).

     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if level is not a valid compression level, or
   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
   if there is no error message.  deflateInit does not perform any compression:
   this will be done by deflate().
*/

 int deflate (z_streamp strm, int flush);
/*
    deflate compresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

    The detailed semantics are as follows.  deflate performs one or both of the
  following actions:

  - Compress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in and avail_in are updated and
    processing will resume at this point for the next call of deflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  This action is forced if the parameter flush is non zero.
    Forcing flush frequently degrades the compression ratio, so this parameter
    should be set only when necessary (in interactive applications).  Some
    output may be provided even if flush is not set.

    Before the call of deflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating avail_in or avail_out accordingly; avail_out should
  never be zero before the call.  The application can consume the compressed
  output when it wants, for example when the output buffer is full (avail_out
  == 0), or after each call of deflate().  If deflate returns Z_OK and with
  zero avail_out, it must be called again after making room in the output
  buffer because there might be more output pending.

    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
  decide how much data to accumulate before producing output, in order to
  maximize compression.

    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
  flushed to the output buffer and the output is aligned on a byte boundary, so
  that the decompressor can get all input data available so far.  (In
  particular avail_in is zero after the call if enough output space has been
  provided before the call.) Flushing may degrade compression for some
  compression algorithms and so it should be used only when necessary.  This
  completes the current deflate block and follows it with an empty stored block
  that is three bits plus filler bits to the next byte, followed by four bytes
  (00 00 ff ff).

    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
  output buffer, but the output is not aligned to a byte boundary.  All of the
  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
  This completes the current deflate block and follows it with an empty fixed
  codes block that is 10 bits long.  This assures that enough bytes are output
  in order for the decompressor to finish the block before the empty fixed code
  block.

    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
  seven bits of the current block are held to be written as the next byte after
  the next deflate block is completed.  In this case, the decompressor may not
  be provided enough bits at this point in order to complete decompression of
  the data provided so far to the compressor.  It may need to wait for the next
  block to be emitted.  This is for advanced applications that need to control
  the emission of deflate blocks.

    If flush is set to Z_FULL_FLUSH, all output is flushed as with
  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
  restart from this point if previous compressed data has been damaged or if
  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
  compression.

    If deflate returns with avail_out == 0, this function must be called again
  with the same value of the flush parameter and more output space (updated
  avail_out), until the flush is complete (deflate returns with non-zero
  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
  avail_out is greater than six to avoid repeated flush markers due to
  avail_out == 0 on return.

    If the parameter flush is set to Z_FINISH, pending input is processed,
  pending output is flushed and deflate returns with Z_STREAM_END if there was
  enough output space; if deflate returns with Z_OK, this function must be
  called again with Z_FINISH and more output space (updated avail_out) but no
  more input data, until it returns with Z_STREAM_END or an error.  After
  deflate has returned Z_STREAM_END, the only possible operations on the stream
  are deflateReset or deflateEnd.

    Z_FINISH can be used immediately after deflateInit if all the compression
  is to be done in a single step.  In this case, avail_out must be at least the
  value returned by deflateBound (see below).  Then deflate is guaranteed to
  return Z_STREAM_END.  If not enough output space is provided, deflate will
  not return Z_STREAM_END, and it must be called again as described above.

    deflate() sets strm-&gt;adler to the adler32 checksum of all input read
  so far (that is, total_in bytes).

    deflate() may update strm-&gt;data_type if it can make a good guess about
  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
  binary.  This field is only for information purposes and does not affect the
  compression algorithm in any manner.

    deflate() returns Z_OK if some progress has been made (more input
  processed or more output produced), Z_STREAM_END if all input has been
  consumed and all output has been produced (only when flush is set to
  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
  fatal, and deflate() can be called again with more input and more output
  space to continue compressing.
*/

 int deflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
   prematurely (some input or output was discarded).  In the error case, msg
   may be set but then points to a static string (which must not be
   deallocated).
*/

/*
 int inflateInit (z_streamp strm);

     Initializes the internal stream state for decompression.  The fields
   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
   exact value depends on the compression method), inflateInit determines the
   compression method from the zlib header and allocates all data structures
   accordingly; otherwise the allocation will be deferred to the first call of
   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
   use default allocation functions.

     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit() does not process any header information -- that is deferred
   until inflate() is called.
*/

 int inflate (z_streamp strm, int flush);
/*
    inflate decompresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

  The detailed semantics are as follows.  inflate performs one or both of the
  following actions:

  - Decompress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in is updated and processing will
    resume at this point for the next call of inflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  inflate() provides as much output as possible, until there is
    no more input data or no more space in the output buffer (see below about
    the flush parameter).

    Before the call of inflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating the next_* and avail_* values accordingly.  The
  application can consume the uncompressed output when it wants, for example
  when the output buffer is full (avail_out == 0), or after each call of
  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
  called again after making room in the output buffer because there might be
  more output pending.

    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
  output as possible to the output buffer.  Z_BLOCK requests that inflate()
  stop if and when it gets to the next deflate block boundary.  When decoding
  the zlib or gzip format, this will cause inflate() to return immediately
  after the header and before the first block.  When doing a raw inflate,
  inflate() will go ahead and process the first block, and will return when it
  gets to the end of that block, or when it runs out of data.

    The Z_BLOCK option assists in appending to or combining deflate streams.
  Also to assist in this, on return inflate() will set strm-&gt;data_type to the
  number of unused bits in the last byte taken from strm-&gt;next_in, plus 64 if
  inflate() is currently decoding the last block in the deflate stream, plus
  128 if inflate() returned immediately after decoding an end-of-block code or
  decoding the complete header up to just before the first byte of the deflate
  stream.  The end-of-block will not be indicated until all of the uncompressed
  data from that block has been written to strm-&gt;next_out.  The number of
  unused bits may in general be greater than seven, except when bit 7 of
  data_type is set, in which case the number of unused bits will be less than
  eight.  data_type is set as noted here every time inflate() returns for all
  flush options, and so can be used to determine the amount of currently
  consumed input in bits.

    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
  end of each deflate block header is reached, before any actual data in that
  block is decoded.  This allows the caller to determine the length of the
  deflate block header for later use in random access within a deflate block.
  256 is added to the value of strm-&gt;data_type when inflate() returns
  immediately after reaching the end of the deflate block header.

    inflate() should normally be called until it returns Z_STREAM_END or an
  error.  However if all decompression is to be performed in a single step (a
  single call of inflate), the parameter flush should be set to Z_FINISH.  In
  this case all pending input is processed and all pending output is flushed;
  avail_out must be large enough to hold all of the uncompressed data for the
  operation to complete.  (The size of the uncompressed data may have been
  saved by the compressor for this purpose.) The use of Z_FINISH is not
  required to perform an inflation in one step.  However it may be used to
  inform inflate that a faster approach can be used for the single inflate()
  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
  stream completes, which reduces inflate's memory footprint.  If the stream
  does not complete, either because not all of the stream is provided or not
  enough output space is provided, then a sliding window will be allocated and
  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
  been used.

     In this implementation, inflate() always flushes as much output as
  possible to the output buffer, and always uses the faster approach on the
  first call.  So the effects of the flush parameter in this implementation are
  on the return value of inflate() as noted below, when inflate() returns early
  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
  memory for a sliding window when Z_FINISH is used.

     If a preset dictionary is needed after this call (see inflateSetDictionary
  below), inflate sets strm-&gt;adler to the Adler-32 checksum of the dictionary
  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
  strm-&gt;adler to the Adler-32 checksum of all output produced so far (that is,
  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
  below.  At the end of the stream, inflate() checks that its computed adler32
  checksum is equal to that saved by the compressor and returns Z_STREAM_END
  only if the checksum is correct.

    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
  deflate data.  The header type is detected automatically, if requested when
  initializing with inflateInit2().  Any information contained in the gzip
  header is not retained, so applications that need that information should
  instead use raw inflate, see inflateInit2() below, or inflateBack() and
  perform their own processing of the gzip header and trailer.  When processing
  gzip-wrapped deflate data, strm-&gt;adler32 is set to the CRC-32 of the output
  produced so far.  The CRC-32 is checked against the gzip trailer.

    inflate() returns Z_OK if some progress has been made (more input processed
  or more output produced), Z_STREAM_END if the end of the compressed data has
  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
  corrupted (input stream not conforming to the zlib format or incorrect check
  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
  inflate() can be called again with more input and more output space to
  continue decompressing.  If Z_DATA_ERROR is returned, the application may
  then call inflateSync() to look for a good compression block if a partial
  recovery of the data is desired.
*/

 int inflateEnd (z_streamp strm);
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
   was inconsistent.  In the error case, msg may be set but then points to a
   static string (which must not be deallocated).
*/

                        /* Advanced functions */

/*
    The following functions are needed only in some special applications.
*/

/*
 int deflateInit2 (z_streamp strm,
                                     int  level,
                                     int  method,
                                     int  windowBits,
                                     int  memLevel,
                                     int  strategy);

     This is another version of deflateInit with more compression options.  The
   fields next_in, zalloc, zfree and opaque must be initialized before by the
   caller.

     The method parameter is the compression method.  It must be Z_DEFLATED in
   this version of the library.

     The windowBits parameter is the base two logarithm of the window size
   (the size of the history buffer).  It should be in the range 8..15 for this
   version of the library.  Larger values of this parameter result in better
   compression at the expense of memory usage.  The default value is 15 if
   deflateInit is used instead.

     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
   determines the window size.  deflate() will then generate raw deflate data
   with no zlib header or trailer, and will not compute an adler32 check value.

     windowBits can also be greater than 15 for optional gzip encoding.  Add
   16 to windowBits to write a simple gzip header and trailer around the
   compressed data instead of a zlib wrapper.  The gzip header will have no
   file name, no extra data, no comment, no modification time (set to zero), no
   header crc, and the operating system will be set to 255 (unknown).  If a
   gzip stream is being written, strm-&gt;adler is a crc32 instead of an adler32.

     The memLevel parameter specifies how much memory should be allocated
   for the internal compression state.  memLevel=1 uses minimum memory but is
   slow and reduces compression ratio; memLevel=9 uses maximum memory for
   optimal speed.  The default value is 8.  See zconf.h for total memory usage
   as a function of windowBits and memLevel.

     The strategy parameter is used to tune the compression algorithm.  Use the
   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
   string match), or Z_RLE to limit match distances to one (run-length
   encoding).  Filtered data consists mostly of small values with a somewhat
   random distribution.  In this case, the compression algorithm is tuned to
   compress them better.  The effect of Z_FILTERED is to force more Huffman
   coding and less string matching; it is somewhat intermediate between
   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
   strategy parameter only affects the compression ratio but not the
   correctness of the compressed output even if it is not set appropriately.
   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
   decoder for special applications.

     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
   set to null if there is no error message.  deflateInit2 does not perform any
   compression: this will be done by deflate().
*/

 int deflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the compression dictionary from the given byte sequence
   without producing any compressed output.  When using the zlib format, this
   function must be called immediately after deflateInit, deflateInit2 or
   deflateReset, and before any call of deflate.  When doing raw deflate, this
   function must be called either before any call of deflate, or immediately
   after the completion of a deflate block, i.e. after all input has been
   consumed and all output has been delivered when using any of the flush
   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
   compressor and decompressor must use exactly the same dictionary (see
   inflateSetDictionary).

     The dictionary should consist of strings (byte sequences) that are likely
   to be encountered later in the data to be compressed, with the most commonly
   used strings preferably put towards the end of the dictionary.  Using a
   dictionary is most useful when the data to be compressed is short and can be
   predicted with good accuracy; the data can then be compressed better than
   with the default empty dictionary.

     Depending on the size of the compression data structures selected by
   deflateInit or deflateInit2, a part of the dictionary may in effect be
   discarded, for example if the dictionary is larger than the window size
   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
   useful should be put at the end of the dictionary, not at the front.  In
   addition, the current implementation of deflate will use at most the window
   size minus 262 bytes of the provided dictionary.

     Upon return of this function, strm-&gt;adler is set to the adler32 value
   of the dictionary; the decompressor may later use this value to determine
   which dictionary has been used by the compressor.  (The adler32 value
   applies to the whole dictionary even if only a subset of the dictionary is
   actually used by the compressor.) If a raw deflate was requested, then the
   adler32 value is not computed and strm-&gt;adler is not set.

     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent (for example if deflate has already been called for this stream
   or if not at a block boundary for raw deflate).  deflateSetDictionary does
   not perform any compression: this will be done by deflate().
*/

 int deflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when several compression strategies will be
   tried, for example when there are several ways of pre-processing the input
   data with a filter.  The streams that will be discarded should then be freed
   by calling deflateEnd.  Note that deflateCopy duplicates the internal
   compression state which can be quite large, so this strategy is slow and can
   consume lots of memory.

     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int deflateReset (z_streamp strm);
/*
     This function is equivalent to deflateEnd followed by deflateInit,
   but does not free and reallocate all the internal compression state.  The
   stream will keep the same compression level and any other attributes that
   may have been set by deflateInit2.

     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int deflateParams (z_streamp strm,
                                      int level,
                                      int strategy);
/*
     Dynamically update the compression level and compression strategy.  The
   interpretation of level and strategy is as in deflateInit2.  This can be
   used to switch between compression and straight copy of the input data, or
   to switch to a different kind of input data requiring a different strategy.
   If the compression level is changed, the input available so far is
   compressed with the old level (and may be flushed); the new level will take
   effect only at the next call of deflate().

     Before the call of deflateParams, the stream state must be set as for
   a call of deflate(), since the currently available input may have to be
   compressed and flushed.  In particular, strm-&gt;avail_out must be non-zero.

     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
   strm-&gt;avail_out was zero.
*/

 int deflateTune (z_streamp strm,
                                    int good_length,
                                    int max_lazy,
                                    int nice_length,
                                    int max_chain);
/*
     Fine tune deflate's internal compression parameters.  This should only be
   used by someone who understands the algorithm used by zlib's deflate for
   searching for the best matching string, and even then only by the most
   fanatic optimizer trying to squeeze out the last compressed bit for their
   specific input data.  Read the deflate.c source code for the meaning of the
   max_lazy, good_length, nice_length, and max_chain parameters.

     deflateTune() can be called after deflateInit() or deflateInit2(), and
   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
 */

 uLong deflateBound (z_streamp strm,
                                       uLong sourceLen);
/*
     deflateBound() returns an upper bound on the compressed size after
   deflation of sourceLen bytes.  It must be called after deflateInit() or
   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
   to allocate an output buffer for deflation in a single pass, and so would be
   called before deflate().  If that first deflate() call is provided the
   sourceLen input bytes, an output buffer allocated to the size returned by
   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
   to return Z_STREAM_END.  Note that it is possible for the compressed size to
   be larger than the value returned by deflateBound() if flush options other
   than Z_FINISH or Z_NO_FLUSH are used.
*/

 int deflatePending (z_streamp strm,
                                       unsigned *pending,
                                       int *bits);
/*
     deflatePending() returns the number of bytes and bits of output that have
   been generated, but not yet provided in the available output.  The bytes not
   provided would be due to the available output space having being consumed.
   The number of bits of output not provided are between 0 and 7, where they
   await more bits to join them in order to fill out a full byte.  If pending
   or bits are Z_NULL, then those values are not set.

     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
 */

 int deflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     deflatePrime() inserts bits in the deflate output stream.  The intent
   is that this function is used to start off the deflate output with the bits
   leftover from a previous deflate stream when appending to it.  As such, this
   function can only be used for raw deflate, and must be used before the first
   deflate() call after a deflateInit2() or deflateReset().  bits must be less
   than or equal to 16, and that many of the least significant bits of value
   will be inserted in the output.

     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
   source stream state was inconsistent.
*/

 int deflateSetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     deflateSetHeader() provides gzip header information for when a gzip
   stream is requested by deflateInit2().  deflateSetHeader() may be called
   after deflateInit2() or deflateReset() and before the first call of
   deflate().  The text, time, os, extra field, name, and comment information
   in the provided gz_header structure are written to the gzip header (xflag is
   ignored -- the extra flags are set according to the compression level).  The
   caller must assure that, if not Z_NULL, name and comment are terminated with
   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
   available there.  If hcrc is true, a gzip header crc is included.  Note that
   the current versions of the command-line version of gzip (up through version
   1.3.x) do not support header crc's, and will report that it is a "multi-part
   gzip file" and give up.

     If deflateSetHeader is not used, the default gzip header has text false,
   the time set to zero, and os set to 255, with no extra, name, or comment
   fields.  The gzip header is returned to the default state by deflateReset().

     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int inflateInit2 (z_streamp strm,
                                     int  windowBits);

     This is another version of inflateInit with an extra parameter.  The
   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
   before by the caller.

     The windowBits parameter is the base two logarithm of the maximum window
   size (the size of the history buffer).  It should be in the range 8..15 for
   this version of the library.  The default value is 15 if inflateInit is used
   instead.  windowBits must be greater than or equal to the windowBits value
   provided to deflateInit2() while compressing, or it must be equal to 15 if
   deflateInit2() was not used.  If a compressed stream with a larger window
   size is given as input, inflate() will return with the error code
   Z_DATA_ERROR instead of trying to allocate a larger window.

     windowBits can also be zero to request that inflate use the window size in
   the zlib header of the compressed stream.

     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
   determines the window size.  inflate() will then process raw deflate data,
   not looking for a zlib or gzip header, not generating a check value, and not
   looking for any check values for comparison at the end of the stream.  This
   is for use with other formats that use the deflate compressed data format
   such as zip.  Those formats provide their own check values.  If a custom
   format is developed using the raw deflate format for compressed data, it is
   recommended that a check value such as an adler32 or a crc32 be applied to
   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
   most applications, the zlib format should be used as is.  Note that comments
   above on the use in deflateInit2() applies to the magnitude of windowBits.

     windowBits can also be greater than 15 for optional gzip decoding.  Add
   32 to windowBits to enable zlib and gzip decoding with automatic header
   detection, or add 16 to decode only the gzip format (the zlib format will
   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm-&gt;adler is a
   crc32 instead of an adler32.

     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit2 does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit2() does not process any header information -- that is
   deferred until inflate() is called.
*/

 int inflateSetDictionary (z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength);
/*
     Initializes the decompression dictionary from the given uncompressed byte
   sequence.  This function must be called immediately after a call of inflate,
   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
   can be determined from the adler32 value returned by that call of inflate.
   The compressor and decompressor must use exactly the same dictionary (see
   deflateSetDictionary).  For raw inflate, this function can be called at any
   time to set the dictionary.  If the provided dictionary is smaller than the
   window and there is already data in the window, then the provided dictionary
   will amend what's there.  The application must insure that the dictionary
   that was used for compression is provided.

     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
   expected one (incorrect adler32 value).  inflateSetDictionary does not
   perform any decompression: this will be done by subsequent calls of
   inflate().
*/

 int inflateGetDictionary (z_streamp strm,
                                             Bytef *dictionary,
                                             uInt  *dictLength);
/*
     Returns the sliding dictionary being maintained by inflate.  dictLength is
   set to the number of bytes in the dictionary, and that many bytes are copied
   to dictionary.  dictionary must have enough space, where 32768 bytes is
   always enough.  If inflateGetDictionary() is called with dictionary equal to
   Z_NULL, then only the dictionary length is returned, and nothing is copied.
   Similarly, if dictLength is Z_NULL, then it is not set.

     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
   stream state is inconsistent.
*/

 int inflateSync (z_streamp strm);
/*
     Skips invalid compressed data until a possible full flush point (see above
   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
   available input is skipped.  No output is provided.

     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
   All full flush points have this pattern, but not all occurrences of this
   pattern are full flush points.

     inflateSync returns Z_OK if a possible full flush point has been found,
   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
   In the success case, the application may save the current current value of
   total_in which indicates where valid compressed data was found.  In the
   error case, the application may repeatedly call inflateSync, providing more
   input each time, until success or end of the input data.
*/

 int inflateCopy (z_streamp dest,
                                    z_streamp source);
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when randomly accessing a large stream.  The
   first pass through the stream can periodically record the inflate state,
   allowing restarting inflate at those points when randomly accessing the
   stream.

     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

 int inflateReset (z_streamp strm);
/*
     This function is equivalent to inflateEnd followed by inflateInit,
   but does not free and reallocate all the internal decompression state.  The
   stream will keep attributes that may have been set by inflateInit2.

     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

 int inflateReset2 (z_streamp strm,
                                      int windowBits);
/*
     This function is the same as inflateReset, but it also permits changing
   the wrap and window size requests.  The windowBits parameter is interpreted
   the same as it is for inflateInit2.

     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
   the windowBits parameter is invalid.
*/

 int inflatePrime (z_streamp strm,
                                     int bits,
                                     int value);
/*
     This function inserts bits in the inflate input stream.  The intent is
   that this function is used to start inflating at a bit position in the
   middle of a byte.  The provided bits will be used before any bytes are used
   from next_in.  This function should only be used with raw inflate, and
   should be used before the first inflate() call after inflateInit2() or
   inflateReset().  bits must be less than or equal to 16, and that many of the
   least significant bits of value will be inserted in the input.

     If bits is negative, then the input stream bit buffer is emptied.  Then
   inflatePrime() can be called again to put bits in the buffer.  This is used
   to clear out bits leftover after feeding inflate a block description prior
   to feeding inflate codes.

     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

 long  inflateMark (z_streamp strm);
/*
     This function returns two values, one in the lower 16 bits of the return
   value, and the other in the remaining upper bits, obtained by shifting the
   return value down 16 bits.  If the upper value is -1 and the lower value is
   zero, then inflate() is currently decoding information outside of a block.
   If the upper value is -1 and the lower value is non-zero, then inflate is in
   the middle of a stored block, with the lower value equaling the number of
   bytes from the input remaining to copy.  If the upper value is not -1, then
   it is the number of bits back from the current bit position in the input of
   the code (literal or length/distance pair) currently being processed.  In
   that case the lower value is the number of bytes already emitted for that
   code.

     A code is being processed if inflate is waiting for more input to complete
   decoding of the code, or if it has completed decoding but is waiting for
   more output space to write the literal or match data.

     inflateMark() is used to mark locations in the input data for random
   access, which may be at bit positions, and to note those cases where the
   output of a code may span boundaries of random access blocks.  The current
   location in the input stream can be determined from avail_in and data_type
   as noted in the description for the Z_BLOCK flush parameter for inflate.

     inflateMark returns the value noted above or -1 &lt;&lt; 16 if the provided
   source stream state was inconsistent.
*/

 int  inflateGetHeader (z_streamp strm,
                                         gz_headerp head);
/*
     inflateGetHeader() requests that gzip header information be stored in the
   provided gz_header structure.  inflateGetHeader() may be called after
   inflateInit2() or inflateReset(), and before the first call of inflate().
   As inflate() processes the gzip stream, head-&gt;done is zero until the header
   is completed, at which time head-&gt;done is set to one.  If a zlib stream is
   being decoded, then head-&gt;done is set to -1 to indicate that there will be
   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
   used to force inflate() to return immediately after header processing is
   complete and before any actual data is decompressed.

     The text, time, xflags, and os fields are filled in with the gzip header
   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
   contains the maximum number of bytes to write to extra.  Once done is true,
   extra_len contains the actual extra field length, and extra contains the
   extra field, or that field truncated if extra_max is less than extra_len.
   If name is not Z_NULL, then up to name_max characters are written there,
   terminated with a zero unless the length is greater than name_max.  If
   comment is not Z_NULL, then up to comm_max characters are written there,
   terminated with a zero unless the length is greater than comm_max.  When any
   of extra, name, or comment are not Z_NULL and the respective field is not
   present in the header, then that field is set to Z_NULL to signal its
   absence.  This allows the use of deflateSetHeader() with the returned
   structure to duplicate the header.  However if those fields are set to
   allocated memory, then the application will need to save those pointers
   elsewhere so that they can be eventually freed.

     If inflateGetHeader is not used, then the header information is simply
   discarded.  The header is always checked for validity, including the header
   CRC if present.  inflateReset() will reset the process to discard the header
   information.  The application would need to call inflateGetHeader() again to
   retrieve the header from the next gzip stream.

     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
 int  inflateBackInit (z_streamp strm, int windowBits,
                                        unsigned char FAR *window);

     Initialize the internal stream state for decompression using inflateBack()
   calls.  The fields zalloc, zfree and opaque in strm must be initialized
   before the call.  If zalloc and zfree are Z_NULL, then the default library-
   derived memory allocation routines are used.  windowBits is the base two
   logarithm of the window size, in the range 8..15.  window is a caller
   supplied buffer of that size.  Except for special applications where it is
   assured that deflate was used with small window sizes, windowBits must be 15
   and a 32K byte window must be supplied to be able to decompress general
   deflate streams.

     See inflateBack() for the usage of these routines.

     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
   allocated, or Z_VERSION_ERROR if the version of the library does not match
   the version of the header file.
*/

typedef unsigned (*in_func) (void FAR *,
                                z_const unsigned char FAR * FAR *);
typedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);

 int  inflateBack (z_streamp strm,
                                    in_func in, void FAR *in_desc,
                                    out_func out, void FAR *out_desc);
/*
     inflateBack() does a raw inflate with a single call using a call-back
   interface for input and output.  This is potentially more efficient than
   inflate() for file i/o applications, in that it avoids copying between the
   output and the sliding window by simply making the window itself the output
   buffer.  inflate() can be faster on modern CPUs when used with large
   buffers.  inflateBack() trusts the application to not change the output
   buffer passed by the output function, at least until inflateBack() returns.

     inflateBackInit() must be called first to allocate the internal state
   and to initialize the state with the user-provided window buffer.
   inflateBack() may then be used multiple times to inflate a complete, raw
   deflate stream with each call.  inflateBackEnd() is then called to free the
   allocated state.

     A raw deflate stream is one with no zlib or gzip header or trailer.
   This routine would normally be used in a utility that reads zip or gzip
   files and writes out uncompressed files.  The utility would decode the
   header and process the trailer on its own, hence this routine expects only
   the raw deflate stream to decompress.  This is different from the normal
   behavior of inflate(), which expects either a zlib or gzip header and
   trailer around the deflate stream.

     inflateBack() uses two subroutines supplied by the caller that are then
   called by inflateBack() for input and output.  inflateBack() calls those
   routines until it reads a complete deflate stream and writes out all of the
   uncompressed data, or until it encounters an error.  The function's
   parameters and return types are defined above in the in_func and out_func
   typedefs.  inflateBack() will call in(in_desc, &amp;buf) which should return the
   number of bytes of provided input, and a pointer to that input in buf.  If
   there is no input available, in() must return zero--buf is ignored in that
   case--and inflateBack() will return a buffer error.  inflateBack() will call
   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
   should return zero on success, or non-zero on failure.  If out() returns
   non-zero, inflateBack() will return with an error.  Neither in() nor out()
   are permitted to change the contents of the window provided to
   inflateBackInit(), which is also the buffer that out() uses to write from.
   The length written by out() will be at most the window size.  Any non-zero
   amount of input may be provided by in().

     For convenience, inflateBack() can be provided input on the first call by
   setting strm-&gt;next_in and strm-&gt;avail_in.  If that input is exhausted, then
   in() will be called.  Therefore strm-&gt;next_in must be initialized before
   calling inflateBack().  If strm-&gt;next_in is Z_NULL, then in() will be called
   immediately for input.  If strm-&gt;next_in is not Z_NULL, then strm-&gt;avail_in
   must also be initialized, and then if strm-&gt;avail_in is not zero, input will
   initially be taken from strm-&gt;next_in[0 ..  strm-&gt;avail_in - 1].

     The in_desc and out_desc parameters of inflateBack() is passed as the
   first parameter of in() and out() respectively when they are called.  These
   descriptors can be optionally used to pass any information that the caller-
   supplied in() and out() functions need to do their job.

     On return, inflateBack() will set strm-&gt;next_in and strm-&gt;avail_in to
   pass back any unused input that was provided by the last in() call.  The
   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
   in the deflate stream (in which case strm-&gt;msg is set to indicate the nature
   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
   In the case of Z_BUF_ERROR, an input or output error can be distinguished
   using strm-&gt;next_in which will be Z_NULL only if in() returned an error.  If
   strm-&gt;next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
   non-zero.  (in() will always be called before out(), so strm-&gt;next_in is
   assured to be defined if out() returns non-zero.) Note that inflateBack()
   cannot return Z_OK.
*/

 int  inflateBackEnd (z_streamp strm);
/*
     All memory allocated by inflateBackInit() is freed.

     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
   state was inconsistent.
*/

 uLong  zlibCompileFlags (void);
/* Return flags indicating compile-time options.

    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
     1.0: size of uInt
     3.2: size of uLong
     5.4: size of voidpf (pointer)
     7.6: size of z_off_t

    Compiler, assembler, and debug options:
     8: DEBUG
     9: ASMV or ASMINF -- use ASM code
     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
     11: 0 (reserved)

    One-time table building (smaller code, but not thread-safe if true):
     12: BUILDFIXED -- build static block decoding tables when needed
     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
     14,15: 0 (reserved)

    Library content (indicates missing functionality):
     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
                          deflate code when not needed)
     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
                    and decode gzip streams (to avoid linking crc code)
     18-19: 0 (reserved)

    Operation variations (changes in library functionality):
     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
     21: FASTEST -- deflate algorithm with only one, lowest compression level
     22,23: 0 (reserved)

    The sprintf variant used by gzprintf (zero is best):
     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
     26: 0 = returns value, 1 = void -- 1 means inferred string length returned

    Remainder:
     27-31: 0 (reserved)
 */

#ifndef Z_SOLO

                        /* utility functions */

/*
     The following utility functions are implemented on top of the basic
   stream-oriented functions.  To simplify the interface, some default options
   are assumed (compression level and memory usage, standard memory allocation
   functions).  The source code of these utility functions can be modified if
   you need special options.
*/

 int  compress (Bytef *dest,   uLongf *destLen,
                                 const Bytef *source, uLong sourceLen);
/*
     Compresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer.
*/

 int  compress2 (Bytef *dest,   uLongf *destLen,
                                  const Bytef *source, uLong sourceLen,
                                  int level);
/*
     Compresses the source buffer into the destination buffer.  The level
   parameter has the same meaning as in deflateInit.  sourceLen is the byte
   length of the source buffer.  Upon entry, destLen is the total size of the
   destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
   Z_STREAM_ERROR if the level parameter is invalid.
*/

 uLong  compressBound (uLong sourceLen);
/*
     compressBound() returns an upper bound on the compressed size after
   compress() or compress2() on sourceLen bytes.  It would be used before a
   compress() or compress2() call to allocate the destination buffer.
*/

 int  uncompress (unsigned char *dest,   uint32_t *destLen,
       const unsigned char *source, uint32_t sourceLen);
/*
     Decompresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be large enough to hold the entire
   uncompressed data.  (The size of the uncompressed data must have been saved
   previously by the compressor and transmitted to the decompressor by some
   mechanism outside the scope of this compression library.) Upon exit, destLen
   is the actual size of the uncompressed buffer.

     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
   the case where there is not enough room, uncompress() will fill the output
   buffer with the uncompressed data up to that point.
*/

                        /* gzip file access functions */

/*
     This library supports reading and writing files in gzip (.gz) format with
   an interface similar to that of stdio, using the functions that start with
   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
   wrapper, documented in RFC 1952, wrapped around a deflate stream.
*/

typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */

/*
 gzFile  gzopen (const char *path, const char *mode);

     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
   for fixed code compression as in "wb9F".  (See the description of
   deflateInit2 for more information about the strategy parameter.)  'T' will
   request transparent writing or appending with no compression and not using
   the gzip format.

     "a" can be used instead of "w" to request that the gzip stream that will
   be written be appended to the file.  "+" will result in an error, since
   reading and writing to the same gzip file is not supported.  The addition of
   "x" when writing will create the file exclusively, which fails if the file
   already exists.  On systems that support it, the addition of "e" when
   reading or writing will set the flag to close the file on an execve() call.

     These functions, as well as gzip, will read and decode a sequence of gzip
   streams in a file.  The append function of gzopen() can be used to create
   such a file.  (Also see gzflush() for another way to do this.)  When
   appending, gzopen does not test whether the file begins with a gzip stream,
   nor does it look for the end of the gzip streams to begin appending.  gzopen
   will simply append a gzip stream to the existing file.

     gzopen can be used to read a file which is not in gzip format; in this
   case gzread will directly read from the file without decompression.  When
   reading, this will be detected automatically by looking for the magic two-
   byte gzip header.

     gzopen returns NULL if the file could not be opened, if there was
   insufficient memory to allocate the gzFile state, or if an invalid mode was
   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
   errno can be checked to determine if the reason gzopen failed was that the
   file could not be opened.
*/

 gzFile  gzdopen (int fd, const char *mode);
/*
     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
   are obtained from calls like open, dup, creat, pipe or fileno (if the file
   has been previously opened with fopen).  The mode parameter is as in gzopen.

     The next call of gzclose on the returned gzFile will also close the file
   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
   mode);.  The duplicated descriptor should be saved to avoid a leak, since
   gzdopen does not close fd if it fails.  If you are using fileno() to get the
   file descriptor from a FILE *, then you will have to use dup() to avoid
   double-close()ing the file descriptor.  Both gzclose() and fclose() will
   close the associated file descriptor, so they need to have different file
   descriptors.

     gzdopen returns NULL if there was insufficient memory to allocate the
   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
   used until the next gz* read, write, seek, or close operation, so gzdopen
   will not detect if fd is invalid (unless fd is -1).
*/

 int  gzbuffer (gzFile file, unsigned size);
/*
     Set the internal buffer size used by this library's functions.  The
   default buffer size is 8192 bytes.  This function must be called after
   gzopen() or gzdopen(), and before any other calls that read or write the
   file.  The buffer memory allocation is always deferred to the first read or
   write.  Two buffers are allocated, either both of the specified size when
   writing, or one of the specified size and the other twice that size when
   reading.  A larger buffer size of, for example, 64K or 128K bytes will
   noticeably increase the speed of decompression (reading).

     The new buffer size also affects the maximum length for gzprintf().

     gzbuffer() returns 0 on success, or -1 on failure, such as being called
   too late.
*/

 int  gzsetparams (gzFile file, int level, int strategy);
/*
     Dynamically update the compression level or strategy.  See the description
   of deflateInit2 for the meaning of these parameters.

     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
   opened for writing.
*/

 int  gzread (gzFile file, voidp buf, unsigned len);
/*
     Reads the given number of uncompressed bytes from the compressed file.  If
   the input file is not in gzip format, gzread copies the given number of
   bytes into the buffer directly from the file.

     After reaching the end of a gzip stream in the input, gzread will continue
   to read, looking for another gzip stream.  Any number of gzip streams may be
   concatenated in the input file, and will all be decompressed by gzread().
   If something other than a gzip stream is encountered after a gzip stream,
   that remaining trailing garbage is ignored (and no error is returned).

     gzread can be used to read a gzip file that is being concurrently written.
   Upon reaching the end of the input, gzread will return with the available
   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
   gzclearerr can be used to clear the end of file indicator in order to permit
   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
   middle of a gzip stream.  Note that gzread does not return -1 in the event
   of an incomplete gzip stream.  This error is deferred until gzclose(), which
   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
   stream.  Alternatively, gzerror can be used before gzclose to detect this
   case.

     gzread returns the number of uncompressed bytes actually read, less than
   len for end of file, or -1 for error.
*/

 int  gzwrite (gzFile file,
                                voidpc buf, unsigned len);
/*
     Writes the given number of uncompressed bytes into the compressed file.
   gzwrite returns the number of uncompressed bytes written or 0 in case of
   error.
*/

 int gzprintf Z_ARG((gzFile file, const char *format, ...));
/*
     Converts, formats, and writes the arguments to the compressed file under
   control of the format string, as in fprintf.  gzprintf returns the number of
   uncompressed bytes actually written, or 0 in case of error.  The number of
   uncompressed bytes written is limited to 8191, or one less than the buffer
   size given to gzbuffer().  The caller should assure that this limit is not
   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
   nothing written.  In this case, there may also be a buffer overflow with
   unpredictable consequences, which is possible only if zlib was compiled with
   the insecure functions sprintf() or vsprintf() because the secure snprintf()
   or vsnprintf() functions were not available.  This can be determined using
   zlibCompileFlags().
*/

 int  gzputs (gzFile file, const char *s);
/*
     Writes the given null-terminated string to the compressed file, excluding
   the terminating null character.

     gzputs returns the number of characters written, or -1 in case of error.
*/

 char *  gzgets (gzFile file, char *buf, int len);
/*
     Reads bytes from the compressed file until len-1 characters are read, or a
   newline character is read and transferred to buf, or an end-of-file
   condition is encountered.  If any characters are read or if len == 1, the
   string is terminated with a null character.  If no characters are read due
   to an end-of-file or len &lt; 1, then the buffer is left untouched.

     gzgets returns buf which is a null-terminated string, or it returns NULL
   for end-of-file or in case of error.  If there was an error, the contents at
   buf are indeterminate.
*/

 int  gzputc (gzFile file, int c);
/*
     Writes c, converted to an unsigned char, into the compressed file.  gzputc
   returns the value that was written, or -1 in case of error.
*/

 int  gzgetc (gzFile file);
/*
     Reads one byte from the compressed file.  gzgetc returns this byte or -1
   in case of end of file or error.  This is implemented as a macro for speed.
   As such, it does not do all of the checking the other functions do.  I.e.
   it does not check to see if file is NULL, nor whether the structure file
   points to has been clobbered or not.
*/

 int  gzungetc (int c, gzFile file);
/*
     Push one character back onto the stream to be read as the first character
   on the next read.  At least one character of push-back is allowed.
   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
   fail if c is -1, and may fail if a character has been pushed but not read
   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
   The pushed character will be discarded if the stream is repositioned with
   gzseek() or gzrewind().
*/

 int  gzflush (gzFile file, int flush);
/*
     Flushes all pending output into the compressed file.  The parameter flush
   is as in the deflate() function.  The return value is the zlib error number
   (see function gzerror below).  gzflush is only permitted when writing.

     If the flush parameter is Z_FINISH, the remaining data is written and the
   gzip stream is completed in the output.  If gzwrite() is called again, a new
   gzip stream will be started in the output.  gzread() is able to read such
   concatenated gzip streams.

     gzflush should be called only when strictly necessary because it will
   degrade compression if called too often.
*/

/*
 z_off_t  gzseek (gzFile file,
                                   z_off_t offset, int whence);

     Sets the starting position for the next gzread or gzwrite on the given
   compressed file.  The offset represents a number of bytes in the
   uncompressed data stream.  The whence parameter is defined as in lseek(2);
   the value SEEK_END is not supported.

     If the file is opened for reading, this function is emulated but can be
   extremely slow.  If the file is opened for writing, only forward seeks are
   supported; gzseek then compresses a sequence of zeroes up to the new
   starting position.

     gzseek returns the resulting offset location as measured in bytes from
   the beginning of the uncompressed stream, or -1 in case of error, in
   particular if the file is opened for writing and the new starting position
   would be before the current position.
*/

 int     gzrewind (gzFile file);
/*
     Rewinds the given file. This function is supported only for reading.

     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
*/

/*
 z_off_t     gztell (gzFile file);

     Returns the starting position for the next gzread or gzwrite on the given
   compressed file.  This position represents a number of bytes in the
   uncompressed data stream, and is zero when starting, even if appending or
   reading a gzip stream from the middle of a file using gzdopen().

     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
*/

/*
 z_off_t  gzoffset (gzFile file);

     Returns the current offset in the file being read or written.  This offset
   includes the count of bytes that precede the gzip stream, for example when
   appending or when using gzdopen() for reading.  When reading, the offset
   does not include as yet unused buffered input.  This information can be used
   for a progress indicator.  On error, gzoffset() returns -1.
*/

 int  gzeof (gzFile file);
/*
     Returns true (1) if the end-of-file indicator has been set while reading,
   false (0) otherwise.  Note that the end-of-file indicator is set only if the
   read tried to go past the end of the input, but came up short.  Therefore,
   just like feof(), gzeof() may return false even if there is no more data to
   read, in the event that the last read request was for the exact number of
   bytes remaining in the input file.  This will happen if the input file size
   is an exact multiple of the buffer size.

     If gzeof() returns true, then the read functions will return no more data,
   unless the end-of-file indicator is reset by gzclearerr() and the input file
   has grown since the previous end of file was detected.
*/

 int  gzdirect (gzFile file);
/*
     Returns true (1) if file is being copied directly while reading, or false
   (0) if file is a gzip stream being decompressed.

     If the input file is empty, gzdirect() will return true, since the input
   does not contain a gzip stream.

     If gzdirect() is used immediately after gzopen() or gzdopen() it will
   cause buffers to be allocated to allow reading the file to determine if it
   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
   gzdirect().

     When writing, gzdirect() returns true (1) if transparent writing was
   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
   gzdirect() is not needed when writing.  Transparent writing must be
   explicitly requested, so the application already knows the answer.  When
   linking statically, using gzdirect() will include all of the zlib code for
   gzip file reading and decompression, which may not be desired.)
*/

 int     gzclose (gzFile file);
/*
     Flushes all pending output if necessary, closes the compressed file and
   deallocates the (de)compression state.  Note that once file is closed, you
   cannot call gzerror with file, since its structures have been deallocated.
   gzclose must not be called more than once on the same file, just as free
   must not be called more than once on the same allocation.

     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
   last read ended in the middle of a gzip stream, or Z_OK on success.
*/

 int  gzclose_r (gzFile file);
 int  gzclose_w (gzFile file);
/*
     Same as gzclose(), but gzclose_r() is only for use when reading, and
   gzclose_w() is only for use when writing or appending.  The advantage to
   using these instead of gzclose() is that they avoid linking in zlib
   compression or decompression code that is not used when only reading or only
   writing respectively.  If gzclose() is used, then both compression and
   decompression code will be included the application when linking to a static
   zlib library.
*/

 const char *  gzerror (gzFile file, int *errnum);
/*
     Returns the error message for the last error which occurred on the given
   compressed file.  errnum is set to zlib error number.  If an error occurred
   in the file system and not in the compression library, errnum is set to
   Z_ERRNO and the application may consult errno to get the exact error code.

     The application must not modify the returned string.  Future calls to
   this function may invalidate the previously returned string.  If file is
   closed, then the string previously returned by gzerror will no longer be
   available.

     gzerror() should be used to distinguish errors from end-of-file for those
   functions above that do not distinguish those cases in their return values.
*/

 void  gzclearerr (gzFile file);
/*
     Clears the error and end-of-file flags for file.  This is analogous to the
   clearerr() function in stdio.  This is useful for continuing to read a gzip
   file that is being written concurrently.
*/

#endif /* !Z_SOLO */

                        /* checksum functions */

/*
     These functions are not related to compression but are exported
   anyway because they might be useful in applications using the compression
   library.
*/

uint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);
/*
     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
   return the updated checksum.  If buf is Z_NULL, this function returns the
   required initial value for the checksum.

     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
   much faster.

   Usage example:

     uLong adler = adler32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       adler = adler32(adler, buffer, length);
     }
     if (adler != original_adler) error();
*/

/*
 uLong  adler32_combine (uLong adler1, uLong adler2,
                                          z_off_t len2);

     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
   that the z_off_t type (like off_t) is a signed integer.  If len2 is
   negative, the result has no meaning or utility.
*/

 uLong  crc32   (uLong crc, const Bytef *buf, uInt len);
/*
     Update a running CRC-32 with the bytes buf[0..len-1] and return the
   updated CRC-32.  If buf is Z_NULL, this function returns the required
   initial value for the crc.  Pre- and post-conditioning (one's complement) is
   performed within this function so it shouldn't be done by the application.

   Usage example:

     uLong crc = crc32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       crc = crc32(crc, buffer, length);
     }
     if (crc != original_crc) error();
*/

/*
 uLong  crc32_combine (uLong crc1, uLong crc2, z_off_t len2);

     Combine two CRC-32 check values into one.  For two sequences of bytes,
   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
   len2.
*/

                        /* various hacks, don't look :) */

/* deflateInit and inflateInit are macros to allow checking the zlib version
 * and the compiler's view of z_stream:
 */
 int  deflateInit_ (z_streamp strm, int level,
                                     const char *version, int stream_size);
 int  inflateInit_ (z_streamp strm,
                                     const char *version, int stream_size);
 int  deflateInit2_ (z_streamp strm, int  level, int  method,
                                      int windowBits, int memLevel,
                                      int strategy, const char *version,
                                      int stream_size);
 int  inflateInit2_ (z_streamp strm, int  windowBits,
                                      const char *version, int stream_size);
 int  inflateBackInit_ (z_streamp strm, int windowBits,
                                         unsigned char FAR *window,
                                         const char *version,
                                         int stream_size);
#define deflateInit(strm, level) \
        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit(strm) \
        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit2(strm, windowBits) \
        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
                      (int)sizeof(z_stream))
#define inflateBackInit(strm, windowBits, window) \
        inflateBackInit_((strm), (windowBits), (window), \
                      ZLIB_VERSION, (int)sizeof(z_stream))

#ifndef Z_SOLO

/* gzgetc() macro and its supporting function and exposed data structure.  Note
 * that the real internal state is much larger than the exposed structure.
 * This abbreviated structure exposes just enough for the gzgetc() macro.  The
 * user should not mess with these exposed elements, since their names or
 * behavior could change in the future, perhaps even capriciously.  They can
 * only be used by the gzgetc() macro.  You have been warned.
 */
 int  gzgetc_ (gzFile file);  /* backward compatibility */
#ifdef Z_PREFIX_SET
#  undef z_gzgetc
#  define z_gzgetc(g) \
          ((g)-&gt;have ? ((g)-&gt;have--, (g)-&gt;pos++, *((g)-&gt;next)++) : gzgetc(g))
#else
#  define gzgetc(g) \
          ((g)-&gt;have ? ((g)-&gt;have--, (g)-&gt;pos++, *((g)-&gt;next)++) : gzgetc(g))
#endif

/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
 * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
 * both are true, the application gets the *64 functions, and the regular
 * functions are changed to 64 bits) -- in case these are set on systems
 * without large file support, _LFS64_LARGEFILE must also be true
 */
#ifdef Z_LARGE64
    gzFile  gzopen64 (const char *, const char *);
    z_off64_t  gzseek64 (gzFile, z_off64_t, int);
    z_off64_t  gztell64 (gzFile);
    z_off64_t  gzoffset64 (gzFile);
    uLong  adler32_combine64 (uLong, uLong, z_off64_t);
    uLong  crc32_combine64 (uLong, uLong, z_off64_t);
#endif

#if !defined(ZLIB_INTERNAL) &amp;&amp; defined(Z_WANT64)
#  ifdef Z_PREFIX_SET
#    define z_gzopen z_gzopen64
#    define z_gzseek z_gzseek64
#    define z_gztell z_gztell64
#    define z_gzoffset z_gzoffset64
#    define z_adler32_combine z_adler32_combine64
#    define z_crc32_combine z_crc32_combine64
#  else
#    define gzopen gzopen64
#    define gzseek gzseek64
#    define gztell gztell64
#    define gzoffset gzoffset64
#    define adler32_combine adler32_combine64
#    define crc32_combine crc32_combine64
#  endif
#  ifndef Z_LARGE64
      gzFile  gzopen64 (const char *, const char *);
      z_off_t  gzseek64 (gzFile, z_off_t, int);
      z_off_t  gztell64 (gzFile);
      z_off_t  gzoffset64 (gzFile);
      uLong  adler32_combine64 (uLong, uLong, z_off_t);
      uLong  crc32_combine64 (uLong, uLong, z_off_t);
#  endif
#else
    gzFile  gzopen (const char *, const char *);
    z_off_t  gzseek (gzFile, z_off_t, int);
    z_off_t  gztell (gzFile);
    z_off_t  gzoffset (gzFile);
    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);
#endif

#else /* Z_SOLO */

    uLong  adler32_combine (uLong, uLong, z_off_t);
    uLong  crc32_combine (uLong, uLong, z_off_t);

#endif /* !Z_SOLO */

/* hack for buggy compilers */
#if !defined(ZUTIL_H) &amp;&amp; !defined(NO_DUMMY_DECL)
    struct internal_state {int dummy;};
#endif

/* undocumented functions */
 const char   *  zError           (int);
 int             inflateSyncPoint (z_streamp);

const uint32_t * get_crc_table(void);
 int             inflateUndermine (z_streamp, int);
 int             inflateResetKeep (z_streamp);
 int             deflateResetKeep (z_streamp);
#if defined(_WIN32) &amp;&amp; !defined(Z_SOLO)
 gzFile          gzopen_w (const wchar_t *path,
                                            const char *mode);
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
 int            gzvprintf Z_ARG((gzFile file,
                                                  const char *format,
                                                  va_list va));
#  endif
#endif

#ifdef __cplusplus
}
#endif

#endif /* ZLIB_H */

#endif</pre>
<h2>./include/libretro-common/include/compat/zlib/zutil.h</h2>
<pre>#ifndef _COMPAT_ZUTIL_H
#define _COMPAT_ZUTIL_H

#ifdef WANT_ZLIB

/* zutil.h -- internal interface and configuration of the compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* @(#) $Id$ */

#ifndef ZUTIL_H
#define ZUTIL_H

#ifdef HAVE_HIDDEN
#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
#  define ZLIB_INTERNAL
#endif

#include &lt;zlib.h&gt;

#if defined(STDC) &amp;&amp; !defined(Z_SOLO)
#  if !(defined(_WIN32_WCE) &amp;&amp; defined(_MSC_VER))
#    include &lt;stddef.h&gt;
#  endif
#  include &lt;string.h&gt;
#  include &lt;stdlib.h&gt;
#endif

#ifdef Z_SOLO
   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
#endif

#ifndef local
#  define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */

typedef unsigned char  uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long  ulg;

extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
/* (array size given to avoid silly warnings with Visual C++) */
/* (array entry size given to avoid silly string cast warnings) */

#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]

#define ERR_RETURN(strm,err) \
  return (strm-&gt;msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */

        /* common constants */

#ifndef DEF_WBITS
#  define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */

#if MAX_MEM_LEVEL &gt;= 8
#  define DEF_MEM_LEVEL 8
#else
#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
#endif
/* default memLevel */

#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES    2
/* The three kinds of block type */

#define MIN_MATCH  3
#define MAX_MATCH  258
/* The minimum and maximum match lengths */

#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */

        /* target dependencies */

#if defined(MSDOS) || (defined(WINDOWS) &amp;&amp; !defined(WIN32))
#  define OS_CODE  0x00
#  ifndef Z_SOLO
#    if defined(__TURBOC__) || defined(__BORLANDC__)
#      if (__STDC__ == 1) &amp;&amp; (defined(__LARGE__) || defined(__COMPACT__))
         /* Allow compilation with ANSI keywords only enabled */
         void _Cdecl farfree( void *block );
         void *_Cdecl farmalloc( unsigned long nbytes );
#      else
#        include &lt;alloc.h&gt;
#      endif
#    else /* MSC or DJGPP */
#      include &lt;malloc.h&gt;
#    endif
#  endif
#endif

#ifdef AMIGA
#  define OS_CODE  0x01
#endif

#if defined(VAXC) || defined(VMS)
#  define OS_CODE  0x02
#  define F_OPEN(name, mode) \
     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif

#if defined(ATARI) || defined(atarist)
#  define OS_CODE  0x05
#endif

#ifdef OS2
#  define OS_CODE  0x06
#  if defined(M_I86) &amp;&amp; !defined(Z_SOLO)
#    include &lt;malloc.h&gt;
#  endif
#endif

#if defined(MACOS) || defined(TARGET_OS_MAC)
#  define OS_CODE  0x07
#  ifndef Z_SOLO
#    if defined(__MWERKS__) &amp;&amp; __dest_os != __be_os &amp;&amp; __dest_os != __win32_os
#      include &lt;unix.h&gt; /* for fdopen */
#    else
#      ifndef fdopen
#        define fdopen(fd,mode) NULL /* No fdopen() */
#      endif
#    endif
#  endif
#endif

#ifdef TOPS20
#  define OS_CODE  0x0a
#endif

#ifdef WIN32
#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
#    define OS_CODE  0x0b
#  endif
#endif

#ifdef __50SERIES /* Prime/PRIMOS */
#  define OS_CODE  0x0f
#endif

#if defined(_BEOS_) || defined(RISCOS)
#  define fdopen(fd,mode) NULL /* No fdopen() */
#endif

#if (defined(_MSC_VER) &amp;&amp; (_MSC_VER &gt; 600)) &amp;&amp; !defined __INTERIX
#  if defined(_WIN32_WCE)
#    define fdopen(fd,mode) NULL /* No fdopen() */
#    ifndef _PTRDIFF_T_DEFINED
       typedef int ptrdiff_t;
#      define _PTRDIFF_T_DEFINED
#    endif
#  else
#    define fdopen(fd,type)  _fdopen(fd,type)
#  endif
#endif

#if defined(__BORLANDC__) &amp;&amp; !defined(MSDOS)
  #pragma warn -8004
  #pragma warn -8008
  #pragma warn -8066
#endif

/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) &amp;&amp; \
    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
    uLong adler32_combine64 (uLong, uLong, z_off_t);
    uLong crc32_combine64 (uLong, uLong, z_off_t);
#endif

        /* common defaults */

#ifndef OS_CODE
#  define OS_CODE  0x03  /* assume Unix */
#endif

#ifndef F_OPEN
#  define F_OPEN(name, mode) fopen((name), (mode))
#endif

         /* functions */

#if defined(pyr) || defined(Z_SOLO)
#  define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) &amp;&amp; !defined(_MSC_VER) &amp;&amp; !defined(__SC__)
 /* Use our own functions for small and medium model with MSC &lt;= 5.0.
  * You may have to use the same strategy for Borland C (untested).
  * The __SC__ check is for Symantec.
  */
#  define NO_MEMCPY
#endif
#if defined(STDC) &amp;&amp; !defined(HAVE_MEMCPY) &amp;&amp; !defined(NO_MEMCPY)
#  define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
#    define zmemcpy _fmemcpy
#    define zmemcmp _fmemcmp
#    define zmemzero(dest, len) _fmemset(dest, 0, len)
#  else
#    define zmemcpy memcpy
#    define zmemcmp memcmp
#    define zmemzero(dest, len) memset(dest, 0, len)
#  endif
#else
   void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
   int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
   void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
#endif

/* Diagnostic functions */
#  define Assert(cond,msg)
#  define Trace(x)
#  define Tracev(x)
#  define Tracevv(x)
#  define Tracec(c,x)
#  define Tracecv(c,x)

#ifndef Z_SOLO
   voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
                                    unsigned size);
   void ZLIB_INTERNAL zcfree  (voidpf opaque, voidpf ptr);
#endif

#define ZALLOC(strm, items, size) \
           (*((strm)-&gt;zalloc))((strm)-&gt;opaque, (items), (size))
#define ZFREE(strm, addr)  (*((strm)-&gt;zfree))((strm)-&gt;opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}

/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) &gt;&gt; 24) &amp; 0xff) + (((q) &gt;&gt; 8) &amp; 0xff00) + \
                    (((q) &amp; 0xff00) &lt;&lt; 8) + (((q) &amp; 0xff) &lt;&lt; 24))

#endif /* ZUTIL_H */

#else
#include &lt;zutil.h&gt;
#endif

#endif</pre>
<h2>./include/libretro-common/include/compat/zutil.h</h2>
<pre>#ifndef _COMPAT_ZUTIL_H
#define _COMPAT_ZUTIL_H

#ifdef WANT_ZLIB

/* zutil.h -- internal interface and configuration of the compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* @(#) $Id$ */

#ifndef ZUTIL_H
#define ZUTIL_H

#ifdef HAVE_HIDDEN
#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
#  define ZLIB_INTERNAL
#endif

#include &lt;compat/zlib.h&gt;

#if defined(STDC) &amp;&amp; !defined(Z_SOLO)
#  if !(defined(_WIN32_WCE) &amp;&amp; defined(_MSC_VER))
#    include &lt;stddef.h&gt;
#  endif
#  include &lt;string.h&gt;
#  include &lt;stdlib.h&gt;
#endif

#ifdef Z_SOLO
   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
#endif

#ifndef local
#  define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */

typedef unsigned char  uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long  ulg;

extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
/* (array size given to avoid silly warnings with Visual C++) */
/* (array entry size given to avoid silly string cast warnings) */

#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]

#define ERR_RETURN(strm,err) \
  return (strm-&gt;msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */

        /* common constants */

#ifndef DEF_WBITS
#  define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */

#if MAX_MEM_LEVEL &gt;= 8
#  define DEF_MEM_LEVEL 8
#else
#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
#endif
/* default memLevel */

#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES    2
/* The three kinds of block type */

#define MIN_MATCH  3
#define MAX_MATCH  258
/* The minimum and maximum match lengths */

#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */

        /* target dependencies */

#if defined(MSDOS) || (defined(WINDOWS) &amp;&amp; !defined(WIN32))
#  define OS_CODE  0x00
#  ifndef Z_SOLO
#    if defined(__TURBOC__) || defined(__BORLANDC__)
#      if (__STDC__ == 1) &amp;&amp; (defined(__LARGE__) || defined(__COMPACT__))
         /* Allow compilation with ANSI keywords only enabled */
         void _Cdecl farfree( void *block );
         void *_Cdecl farmalloc( unsigned long nbytes );
#      else
#        include &lt;alloc.h&gt;
#      endif
#    else /* MSC or DJGPP */
#      include &lt;malloc.h&gt;
#    endif
#  endif
#endif

#ifdef AMIGA
#  define OS_CODE  0x01
#endif

#if defined(VAXC) || defined(VMS)
#  define OS_CODE  0x02
#  define F_OPEN(name, mode) \
     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif

#if defined(ATARI) || defined(atarist)
#  define OS_CODE  0x05
#endif

#ifdef OS2
#  define OS_CODE  0x06
#  if defined(M_I86) &amp;&amp; !defined(Z_SOLO)
#    include &lt;malloc.h&gt;
#  endif
#endif

#if defined(MACOS) || defined(TARGET_OS_MAC)
#  define OS_CODE  0x07
#  ifndef Z_SOLO
#    if defined(__MWERKS__) &amp;&amp; __dest_os != __be_os &amp;&amp; __dest_os != __win32_os
#      include &lt;unix.h&gt; /* for fdopen */
#    else
#      ifndef fdopen
#        define fdopen(fd,mode) NULL /* No fdopen() */
#      endif
#    endif
#  endif
#endif

#ifdef TOPS20
#  define OS_CODE  0x0a
#endif

#ifdef WIN32
#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
#    define OS_CODE  0x0b
#  endif
#endif

#ifdef __50SERIES /* Prime/PRIMOS */
#  define OS_CODE  0x0f
#endif

#if defined(_BEOS_) || defined(RISCOS)
#  define fdopen(fd,mode) NULL /* No fdopen() */
#endif

#if (defined(_MSC_VER) &amp;&amp; (_MSC_VER &gt; 600)) &amp;&amp; !defined __INTERIX
#  if defined(_WIN32_WCE)
#    define fdopen(fd,mode) NULL /* No fdopen() */
#    ifndef _PTRDIFF_T_DEFINED
       typedef int ptrdiff_t;
#      define _PTRDIFF_T_DEFINED
#    endif
#  else
#    define fdopen(fd,type)  _fdopen(fd,type)
#  endif
#endif

#if defined(__BORLANDC__) &amp;&amp; !defined(MSDOS)
  #pragma warn -8004
  #pragma warn -8008
  #pragma warn -8066
#endif

/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) &amp;&amp; \
    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
    uLong adler32_combine64 (uLong, uLong, z_off_t);
    uLong crc32_combine64 (uLong, uLong, z_off_t);
#endif

        /* common defaults */

#ifndef OS_CODE
#  define OS_CODE  0x03  /* assume Unix */
#endif

#ifndef F_OPEN
#  define F_OPEN(name, mode) fopen((name), (mode))
#endif

         /* functions */

#if defined(pyr) || defined(Z_SOLO)
#  define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) &amp;&amp; !defined(_MSC_VER) &amp;&amp; !defined(__SC__)
 /* Use our own functions for small and medium model with MSC &lt;= 5.0.
  * You may have to use the same strategy for Borland C (untested).
  * The __SC__ check is for Symantec.
  */
#  define NO_MEMCPY
#endif
#if defined(STDC) &amp;&amp; !defined(HAVE_MEMCPY) &amp;&amp; !defined(NO_MEMCPY)
#  define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
#    define zmemcpy _fmemcpy
#    define zmemcmp _fmemcmp
#    define zmemzero(dest, len) _fmemset(dest, 0, len)
#  else
#    define zmemcpy memcpy
#    define zmemcmp memcmp
#    define zmemzero(dest, len) memset(dest, 0, len)
#  endif
#else
   void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
   int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
   void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
#endif

/* Diagnostic functions */
#  define Assert(cond,msg)
#  define Trace(x)
#  define Tracev(x)
#  define Tracevv(x)
#  define Tracec(c,x)
#  define Tracecv(c,x)

#ifndef Z_SOLO
   voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
                                    unsigned size);
   void ZLIB_INTERNAL zcfree  (voidpf opaque, voidpf ptr);
#endif

#define ZALLOC(strm, items, size) \
           (*((strm)-&gt;zalloc))((strm)-&gt;opaque, (items), (size))
#define ZFREE(strm, addr)  (*((strm)-&gt;zfree))((strm)-&gt;opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}

/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) &gt;&gt; 24) &amp; 0xff) + (((q) &gt;&gt; 8) &amp; 0xff00) + \
                    (((q) &amp; 0xff00) &lt;&lt; 8) + (((q) &amp; 0xff) &lt;&lt; 24))

#endif /* ZUTIL_H */

#else
#include &lt;zutil.h&gt;
#endif

#endif</pre>
<h2>./include/libretro-common/include/defines/cocoa_defines.h</h2>
<pre>/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (cocoa_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __COCOA_COMMON_DEFINES_H
#define __COCOA_COMMON_DEFINES_H

#include &lt;AvailabilityMacros.h&gt;

#ifndef MAC_OS_X_VERSION_10_12
#define MAC_OS_X_VERSION_10_12 101200
#endif

#if MAC_OS_X_VERSION_MAX_ALLOWED &lt; MAC_OS_X_VERSION_10_12
#define HAS_MACOSX_10_12 0
#define NSEventModifierFlagCommand NSCommandKeyMask
#define NSEventModifierFlagControl NSControlKeyMask
#define NSEventModifierFlagHelp NSHelpKeyMask
#define NSEventModifierFlagNumericPad NSNumericPadKeyMask
#define NSEventModifierFlagOption NSAlternateKeyMask
#define NSEventModifierFlagShift NSShiftKeyMask
#define NSCompositingOperationSourceOver NSCompositeSourceOver
#define NSEventMaskApplicationDefined NSApplicationDefinedMask
#define NSEventTypeApplicationDefined NSApplicationDefined
#define NSEventTypeCursorUpdate NSCursorUpdate
#define NSEventTypeMouseMoved NSMouseMoved
#define NSEventTypeMouseEntered NSMouseEntered
#define NSEventTypeMouseExited NSMouseExited
#define NSEventTypeLeftMouseDown NSLeftMouseDown
#define NSEventTypeRightMouseDown NSRightMouseDown
#define NSEventTypeOtherMouseDown NSOtherMouseDown
#define NSEventTypeLeftMouseUp NSLeftMouseUp
#define NSEventTypeRightMouseUp NSRightMouseUp
#define NSEventTypeOtherMouseUp NSOtherMouseUp
#define NSEventTypeLeftMouseDragged NSLeftMouseDragged
#define NSEventTypeRightMouseDragged NSRightMouseDragged
#define NSEventTypeOtherMouseDragged NSOtherMouseDragged
#define NSEventTypeScrollWheel NSScrollWheel
#define NSEventTypeKeyDown NSKeyDown
#define NSEventTypeKeyUp NSKeyUp
#define NSEventTypeFlagsChanged NSFlagsChanged
#define NSEventMaskAny NSAnyEventMask
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
#define NSWindowStyleMaskClosable NSClosableWindowMask
#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
#define NSWindowStyleMaskResizable NSResizableWindowMask
#define NSWindowStyleMaskTitled NSTitledWindowMask
#define NSAlertStyleCritical NSCriticalAlertStyle
#define NSAlertStyleInformational NSInformationalAlertStyle
#define NSAlertStyleWarning  NSWarningAlertStyle
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
#define NSControlSizeRegular NSRegularControlSize
#else
#define HAS_MACOSX_10_12 1
#endif

#endif
</pre>
<h2>./include/libretro-common/include/defines/d3d_defines.h</h2>
<pre>/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (d3d_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef D3DVIDEO_DEFINES_H
#define D3DVIDEO_DEFINES_H

#if defined(DEBUG) || defined(_DEBUG)
#define D3D_DEBUG_INFO
#endif

#if defined(HAVE_D3D9)
/* Direct3D 9 */

#ifndef D3DCREATE_SOFTWARE_VERTEXPROCESSING
#define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0
#endif

#elif defined(HAVE_D3D8)

/* Direct3D 8 */

#if !defined(D3DLOCK_NOSYSLOCK) &amp;&amp; defined(_XBOX)
#define D3DLOCK_NOSYSLOCK (0)
#endif

#endif

#endif</pre>
<h2>./include/libretro-common/include/defines/gx_defines.h</h2>
<pre>/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gx_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _GX_DEFINES_H
#define _GX_DEFINES_H

#ifdef GEKKO

#define SYSMEM1_SIZE 0x01800000

#ifndef _SHIFTL
#define _SHIFTL(v, s, w)	((uint32_t) (((uint32_t)(v) &amp; ((0x01 &lt;&lt; (w)) - 1)) &lt;&lt; (s)))
#define _SHIFTR(v, s, w)	((uint32_t)(((uint32_t)(v) &gt;&gt; (s)) &amp; ((0x01 &lt;&lt; (w)) - 1)))
#endif

#define OSThread lwp_t
#define OSCond lwpq_t
#define OSThreadQueue lwpq_t

#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
#define OSLockMutex(mutex) LWP_MutexLock(mutex)
#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)

#define OSInitCond(cond) LWP_CondInit(cond)
#define OSSignalCond(cond) LWP_ThreadSignal(cond)
#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)

#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
#define OSCloseThreadQueue(queue) LWP_CloseQueue(queue)
#define OSSleepThread(queue) LWP_ThreadSleep(queue)
#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)

#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)

#define BLIT_LINE_16(off) \
{ \
   const uint32_t *tmp_src = src; \
   uint32_t       *tmp_dst = dst; \
   for (unsigned x = 0; x &lt; width2 &gt;&gt; 1; x++, tmp_src += 2, tmp_dst += 8) \
   { \
      tmp_dst[ 0 + off] = BLIT_LINE_16_CONV(tmp_src[0]); \
      tmp_dst[ 1 + off] = BLIT_LINE_16_CONV(tmp_src[1]); \
   } \
   src += tmp_pitch; \
}

#define BLIT_LINE_32(off) \
{ \
   const uint16_t *tmp_src = src; \
   uint16_t       *tmp_dst = dst; \
   for (unsigned x = 0; x &lt; width2 &gt;&gt; 3; x++, tmp_src += 8, tmp_dst += 32) \
   { \
      tmp_dst[  0 + off] = tmp_src[0] | 0xFF00; \
      tmp_dst[ 16 + off] = tmp_src[1]; \
      tmp_dst[  1 + off] = tmp_src[2] | 0xFF00; \
      tmp_dst[ 17 + off] = tmp_src[3]; \
      tmp_dst[  2 + off] = tmp_src[4] | 0xFF00; \
      tmp_dst[ 18 + off] = tmp_src[5]; \
      tmp_dst[  3 + off] = tmp_src[6] | 0xFF00; \
      tmp_dst[ 19 + off] = tmp_src[7]; \
   } \
   src += tmp_pitch; \
}

#define AIInit AUDIO_Init
#define AIInitDMA AUDIO_InitDMA
#define AIStartDMA AUDIO_StartDMA
#define AIStopDMA AUDIO_StopDMA
#define AIRegisterDMACallback AUDIO_RegisterDMACallback
#define AISetDSPSampleRate AUDIO_SetDSPSampleRate

#endif

#endif</pre>
<h2>./include/libretro-common/include/defines/ps3_defines.h</h2>
<pre>/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (ps3_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _PS3_DEFINES_H
#define _PS3_DEFINES_H

/*============================================================
	AUDIO PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;audio/audio.h&gt;
#include &lt;sys/thread.h&gt;

#include &lt;sys/event_queue.h&gt;
#include &lt;lv2/mutex.h&gt;
#include &lt;lv2/cond.h&gt;

/*forward decl. for audioAddData */
extern int audioAddData(uint32_t portNum, float *data,
      uint32_t frames, float volume);

#define PS3_SYS_NO_TIMEOUT 0
#define param_attrib attrib

#else
#include &lt;sdk_version.h&gt;
#include &lt;cell/audio.h&gt;
#include &lt;sys/event.h&gt;
#include &lt;sys/synchronization.h&gt;

#define numChannels nChannel
#define numBlocks nBlock
#define param_attrib attr

#define audioQuit cellAudioQuit 
#define audioInit cellAudioInit
#define audioPortStart cellAudioPortStart
#define audioPortOpen cellAudioPortOpen
#define audioPortClose cellAudioPortClose
#define audioPortStop cellAudioPortStop
#define audioPortParam CellAudioPortParam
#define audioPortOpen cellAudioPortOpen
#define audioAddData cellAudioAddData

/* event queue functions */
#define sysEventQueueReceive sys_event_queue_receive
#define audioSetNotifyEventQueue cellAudioSetNotifyEventQueue
#define audioRemoveNotifyEventQueue cellAudioRemoveNotifyEventQueue
#define audioCreateNotifyEventQueue cellAudioCreateNotifyEventQueue

#define sysLwCondCreate sys_lwcond_create
#define sysLwCondDestroy sys_lwcond_destroy
#define sysLwCondWait sys_lwcond_wait
#define sysLwCondSignal sys_lwcond_signal

#define sysLwMutexDestroy sys_lwmutex_destroy
#define sysLwMutexLock sys_lwmutex_lock
#define sysLwMutexUnlock sys_lwmutex_unlock
#define sysLwMutexCreate sys_lwmutex_create

#define AUDIO_BLOCK_SAMPLES CELL_AUDIO_BLOCK_SAMPLES
#define SYSMODULE_NET CELL_SYSMODULE_NET
#define PS3_SYS_NO_TIMEOUT SYS_NO_TIMEOUT

#define sys_lwmutex_attr_t sys_lwmutex_attribute_t 
#define sys_lwcond_attr_t sys_lwcond_attribute_t 
#define sys_sem_t sys_semaphore_t

#define sysGetSystemTime sys_time_get_system_time
#define sysModuleLoad cellSysmoduleLoadModule
#define sysModuleUnload cellSysmoduleUnloadModule

#define netInitialize sys_net_initialize_network

#endif

/*============================================================
	INPUT PAD PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;io/pad.h&gt;
#define CELL_PAD_CAPABILITY_SENSOR_MODE      4
#define CELL_PAD_SETTING_SENSOR_ON           4
#define CELL_PAD_STATUS_ASSIGN_CHANGES       2
#define CELL_PAD_BTN_OFFSET_DIGITAL1         2
#define CELL_PAD_BTN_OFFSET_DIGITAL2         3
#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X   4
#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y   5
#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X    6
#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y    7
#define CELL_PAD_BTN_OFFSET_PRESS_RIGHT      8
#define CELL_PAD_BTN_OFFSET_PRESS_LEFT       9
#define CELL_PAD_BTN_OFFSET_PRESS_UP         10
#define CELL_PAD_BTN_OFFSET_PRESS_DOWN       11
#define CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE   12
#define CELL_PAD_BTN_OFFSET_PRESS_CIRCLE     13
#define CELL_PAD_BTN_OFFSET_PRESS_CROSS      14
#define CELL_PAD_BTN_OFFSET_PRESS_SQUARE     15
#define CELL_PAD_BTN_OFFSET_PRESS_L1         16
#define CELL_PAD_BTN_OFFSET_PRESS_R1         17
#define CELL_PAD_BTN_OFFSET_PRESS_L2         18
#define CELL_PAD_BTN_OFFSET_PRESS_R2         19
#define CELL_PAD_BTN_OFFSET_SENSOR_X         20
#define CELL_PAD_BTN_OFFSET_SENSOR_Y         21
#define CELL_PAD_BTN_OFFSET_SENSOR_Z         22
#define CELL_PAD_BTN_OFFSET_SENSOR_G         23
#define CELL_PAD_CTRL_LEFT          (128)
#define CELL_PAD_CTRL_DOWN          (64)
#define CELL_PAD_CTRL_RIGHT         (32)
#define CELL_PAD_CTRL_UP            (16)
#define CELL_PAD_CTRL_START         (8)
#define CELL_PAD_CTRL_R3            (4)
#define CELL_PAD_CTRL_L3            (2)
#define CELL_PAD_CTRL_SELECT        (1)
#define CELL_PAD_CTRL_SQUARE        (128)
#define CELL_PAD_CTRL_CROSS         (64)
#define CELL_PAD_CTRL_CIRCLE        (32)
#define CELL_PAD_CTRL_TRIANGLE      (16)
#define CELL_PAD_CTRL_R1            (8)
#define CELL_PAD_CTRL_L1            (4)
#define CELL_PAD_CTRL_R2            (2)
#define CELL_PAD_CTRL_L2            (1)
#define CELL_PAD_CTRL_LDD_PS        (1)
#define CELL_PAD_STATUS_CONNECTED   (1)
#define CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN
#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CROSS  (1)
#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CIRCLE (0)
#define now_connect connected
#define CellPadActParam padActParam
#define cellPadSetPortSetting ioPadSetPortSetting
#define cellSysutilGetSystemParamInt sysUtilGetSystemParamInt
#define cellPadSetActDirect ioPadSetActDirect
#define CellPadInfo2 padInfo2
#define cellPadGetInfo2 ioPadGetInfo2
#define CellPadData padData
#define cellPadGetData ioPadGetData
#define cellPadInit ioPadInit 
#define cellPadEnd ioPadEnd
#else
#include &lt;cell/pad.h&gt;
#define padInfo2 CellPadInfo2
#define padData CellPadData
#define ioPadGetInfo2 cellPadGetInfo2 
#define ioPadGetData cellPadGetData
#define ioPadInit cellPadInit
#define ioPadEnd cellPadEnd
#define ioPadSetPortSetting cellPadSetPortSetting 
#endif

/*============================================================
	INPUT MOUSE PROTOTYPES
============================================================ */

#ifdef HAVE_MOUSE

#ifdef __PSL1GHT__
#include &lt;io/mouse.h&gt;

/* define ps3 mouse structs */
#define CellMouseInfo mouseInfo
#define CellMouseData mouseData

/* define all the ps3 mouse functions */
#define cellMouseInit ioMouseInit
#define cellMouseGetData ioMouseGetData
#define cellMouseEnd ioMouseEnd
#define cellMouseGetInfo ioMouseGetInfo

/* PSL1GHT does not define these in its header */
#define CELL_MOUSE_BUTTON_1 (UINT64_C(1) &lt;&lt; 0) /* Button 1 */
#define CELL_MOUSE_BUTTON_2 (UINT64_C(1) &lt;&lt; 1) /* Button 2 */
#define CELL_MOUSE_BUTTON_3 (UINT64_C(1) &lt;&lt; 2) /* Button 3 */
#define CELL_MOUSE_BUTTON_4 (UINT64_C(1) &lt;&lt; 3) /* Button 4 */
#define CELL_MOUSE_BUTTON_5 (UINT64_C(1) &lt;&lt; 4) /* Button 5 */
#define CELL_MOUSE_BUTTON_6 (UINT64_C(1) &lt;&lt; 5) /* Button 6 */
#define CELL_MOUSE_BUTTON_7 (UINT64_C(1) &lt;&lt; 6) /* Button 7 */
#define CELL_MOUSE_BUTTON_8 (UINT64_C(1) &lt;&lt; 7) /* Button 8 */

#else
#include &lt;cell/mouse.h&gt;
#define mouseInfo CellMouseInfo
#define mouseData CellMouseData

#define ioMouseInit cellMouseInit
#define ioMouseGetData cellMouseGetData
#define ioMouseEnd cellMouseEnd
#define ioMouseGetInfo cellMouseGetInfo
#endif

#endif

/*============================================================
	INPUT KEYBOARD PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;io/kb.h&gt;

#define CELL_KB_RMODE_INPUTCHAR KB_RMODE_INPUTCHAR
#define CELL_KB_CODETYPE_RAW    KB_CODETYPE_RAW

#define cellKbData KbData
#define cellKbInfo KbInfo

#define cellKbSetCodeType ioKbSetCodeType
#define cellKbSetReadMode ioKbSetReadMode
#define cellKbInit ioKbInit
#define cellKbGetInfo ioKbGetInfo
#define cellKbRead ioKbRead
#else
#include &lt;cell/keyboard.h&gt;

#define KB_RMODE_INPUTCHAR CELL_KB_RMODE_INPUTCHAR
#define KB_CODETYPE_RAW    CELL_KB_CODETYPE_RAW

#define KbInfo cellKbInfo

#define ioKbSetCodeType cellKbSetCodeType
#define ioKbSetReadMode cellKbSetReadMode
#define ioKbInit cellKbInit
#define ioKbGetInfo cellKbGetInfo
#define ioKbRead cellKbRead

/* Keyboard RAWDAT Key code (can't be converted to ASCII codes) */
#define KB_RAWKEY_NO_EVENT			0x00
#define KB_RAWKEY_E_ROLLOVER			0x01
#define KB_RAWKEY_E_POSTFAIL			0x02
#define KB_RAWKEY_E_UNDEF			0x03
#define KB_RAWKEY_ESCAPE			0x29
#define KB_RAWKEY_106_KANJI			0x35	/* The half-width/full width Kanji key code */
#define KB_RAWKEY_CAPS_LOCK			0x39
#define KB_RAWKEY_F1				0x3a
#define KB_RAWKEY_F2				0x3b
#define KB_RAWKEY_F3				0x3c
#define KB_RAWKEY_F4				0x3d
#define KB_RAWKEY_F5				0x3e
#define KB_RAWKEY_F6				0x3f
#define KB_RAWKEY_F7				0x40
#define KB_RAWKEY_F8				0x41
#define KB_RAWKEY_F9				0x42
#define KB_RAWKEY_F10				0x43
#define KB_RAWKEY_F11				0x44
#define KB_RAWKEY_F12				0x45
#define KB_RAWKEY_PRINTSCREEN			0x46
#define KB_RAWKEY_SCROLL_LOCK			0x47
#define KB_RAWKEY_PAUSE				0x48
#define KB_RAWKEY_INSERT			0x49
#define KB_RAWKEY_HOME				0x4a
#define KB_RAWKEY_PAGE_UP			0x4b
#define KB_RAWKEY_DELETE			0x4c
#define KB_RAWKEY_END				0x4d
#define KB_RAWKEY_PAGE_DOWN			0x4e
#define KB_RAWKEY_RIGHT_ARROW			0x4f
#define KB_RAWKEY_LEFT_ARROW			0x50
#define KB_RAWKEY_DOWN_ARROW			0x51
#define KB_RAWKEY_UP_ARROW			0x52
#define KB_RAWKEY_NUM_LOCK			0x53
#define KB_RAWKEY_APPLICATION			0x65	/* Application key code */
#define KB_RAWKEY_KANA				0x88	/* Katakana/Hiragana/Romaji key code */
#define KB_RAWKEY_HENKAN			0x8a	/* Conversion key code */
#define KB_RAWKEY_MUHENKAN			0x8b	/* No Conversion key code */

/* Keyboard RAW Key Code definition */
#define KB_RAWKEY_A				0x04
#define KB_RAWKEY_B				0x05
#define KB_RAWKEY_C				0x06
#define KB_RAWKEY_D				0x07
#define KB_RAWKEY_E				0x08
#define KB_RAWKEY_F				0x09
#define KB_RAWKEY_G				0x0A
#define KB_RAWKEY_H				0x0B
#define KB_RAWKEY_I				0x0C
#define KB_RAWKEY_J				0x0D
#define KB_RAWKEY_K				0x0E
#define KB_RAWKEY_L				0x0F
#define KB_RAWKEY_M				0x10
#define KB_RAWKEY_N				0x11
#define KB_RAWKEY_O				0x12
#define KB_RAWKEY_P				0x13
#define KB_RAWKEY_Q				0x14
#define KB_RAWKEY_R				0x15
#define KB_RAWKEY_S				0x16
#define KB_RAWKEY_T				0x17
#define KB_RAWKEY_U				0x18
#define KB_RAWKEY_V				0x19
#define KB_RAWKEY_W				0x1A
#define KB_RAWKEY_X				0x1B
#define KB_RAWKEY_Y				0x1C
#define KB_RAWKEY_Z				0x1D
#define KB_RAWKEY_1				0x1E
#define KB_RAWKEY_2				0x1F
#define KB_RAWKEY_3				0x20
#define KB_RAWKEY_4				0x21
#define KB_RAWKEY_5				0x22
#define KB_RAWKEY_6				0x23
#define KB_RAWKEY_7				0x24
#define KB_RAWKEY_8				0x25
#define KB_RAWKEY_9				0x26
#define KB_RAWKEY_0				0x27
#define KB_RAWKEY_ENTER				0x28
#define KB_RAWKEY_ESC				0x29
#define KB_RAWKEY_BS				0x2A
#define KB_RAWKEY_TAB				0x2B
#define KB_RAWKEY_SPACE				0x2C
#define KB_RAWKEY_MINUS				0x2D
#define KB_RAWKEY_EQUAL_101			0x2E	/* = and + */
#define KB_RAWKEY_ACCENT_CIRCONFLEX_106 	0x2E	/* ^ and ~ */
#define KB_RAWKEY_LEFT_BRACKET_101		0x2F	/* [ */
#define KB_RAWKEY_ATMARK_106			0x2F	/* @ */
#define KB_RAWKEY_RIGHT_BRACKET_101		0x30	/* ] */
#define KB_RAWKEY_LEFT_BRACKET_106		0x30	/* [ */
#define KB_RAWKEY_BACKSLASH_101			0x31	/* \ and | */
#define KB_RAWKEY_RIGHT_BRACKET_106		0x32	/* ] */
#define KB_RAWKEY_SEMICOLON			0x33	/* ; */
#define KB_RAWKEY_QUOTATION_101			0x34	/* ' and " */
#define KB_RAWKEY_COLON_106			0x34	/* : and * */
#define KB_RAWKEY_COMMA		    		0x36
#define KB_RAWKEY_PERIOD			0x37
#define KB_RAWKEY_SLASH		    		0x38
#define KB_RAWKEY_CAPS_LOCK			0x39
#define KB_RAWKEY_KPAD_NUMLOCK			0x53
#define KB_RAWKEY_KPAD_SLASH			0x54
#define KB_RAWKEY_KPAD_ASTERISK			0x55
#define KB_RAWKEY_KPAD_MINUS			0x56
#define KB_RAWKEY_KPAD_PLUS			0x57
#define KB_RAWKEY_KPAD_ENTER			0x58
#define KB_RAWKEY_KPAD_1			0x59
#define KB_RAWKEY_KPAD_2			0x5A
#define KB_RAWKEY_KPAD_3			0x5B
#define KB_RAWKEY_KPAD_4			0x5C
#define KB_RAWKEY_KPAD_5			0x5D
#define KB_RAWKEY_KPAD_6			0x5E
#define KB_RAWKEY_KPAD_7			0x5F
#define KB_RAWKEY_KPAD_8			0x60
#define KB_RAWKEY_KPAD_9			0x61
#define KB_RAWKEY_KPAD_0			0x62
#define KB_RAWKEY_KPAD_PERIOD			0x63
#define KB_RAWKEY_BACKSLASH_106			0x87
#define KB_RAWKEY_YEN_106			0x89

#define KB_CODETYPE_RAW CELL_KB_CODETYPE_RAW

/*! \brief Keyboard Led State. */
typedef struct KbLed
{
	union
   {
      uint32_t leds;
      struct
      {
         uint32_t reserved	   : 27;	/*!&lt; \brief Reserved MSB */
         uint32_t kana		   : 1;	/*!&lt; \brief LED Kana 0:OFF 1:ON Bit4 */
         uint32_t compose		: 1;	/*!&lt; \brief LED Compose 0:OFF 1:ON Bit3 */
         uint32_t scroll_lock	: 1;	/*!&lt; \brief LED Scroll Lock 0:OFF 1:ON Bit2 */
         uint32_t caps_lock	: 1;	/*!&lt; \brief LED Caps Lock 0:OFF 1:ON Bit1 */
         uint32_t num_lock	   : 1;	/*!&lt; \brief LED Num Lock 0:OFF 1:ON Bit0 LSB */
      }_KbLedS;
   }_KbLedU;
} KbLed;


/*! \brief Keyboard Modifier Key State. */
typedef struct KbMkey
{
   union
   {
      uint32_t mkeys;
      struct
      {
         uint32_t reserved	   : 24;	/*!&lt; \brief Reserved MSB */
         uint32_t r_win		   : 1;	/*!&lt; \brief Modifier Key Right WIN 0:OFF 1:ON Bit7 */
         uint32_t r_alt		   : 1;	/*!&lt; \brief Modifier Key Right ALT 0:OFF 1:ON Bit6 */
         uint32_t r_shift		: 1;	/*!&lt; \brief Modifier Key Right SHIFT 0:OFF 1:ON Bit5 */		
         uint32_t r_ctrl		: 1;	/*!&lt; \brief Modifier Key Right CTRL 0:OFF 1:ON Bit4 */
         uint32_t l_win		   : 1;	/*!&lt; \brief Modifier Key Left WIN 0:OFF 1:ON Bit3 */
         uint32_t l_alt		   : 1;	/*!&lt; \brief Modifier Key Left ALT 0:OFF 1:ON Bit2 */
         uint32_t l_shift		: 1;	/*!&lt; \brief Modifier Key Left SHIFT 0:OFF 1:ON Bit1 */
         uint32_t l_ctrl		: 1;	/*!&lt; \brief Modifier Key Left CTRL 0:OFF 1:ON Bit0 LSB */
         /* For Macintosh Keyboard ALT &amp; WIN correspond respectively to OPTION &amp; APPLE keys */
      }_KbMkeyS;
   }_KbMkeyU;
} KbMkey;

/*! \brief Keyboard input data data structure. */
typedef struct KbData
{
	KbLed led;					/*!&lt; \brief Keyboard Led State */
	KbMkey mkey;				/*!&lt; \brief Keyboard Modifier Key State */
	int32_t  nb_keycode;				/*!&lt; \brief Number of key codes (0 equal no data) */
	uint16_t keycode[MAX_KEYCODES];	/*!&lt; \brief Keycode values */
} KbData;
#endif

/*============================================================
	OSK PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;sysutil/osk.h&gt;
/* define all the OSK functions */
#define pOskLoadAsync oskLoadAsync
#define pOskSetLayoutMode oskSetLayoutMode
#define pOskSetKeyLayoutOption oskSetKeyLayoutOption
#define pOskGetSize oskGetSize
#define pOskDisableDimmer oskDisableDimmer
#define pOskAbort oskAbort
#define pOskUnloadAsync oskUnloadAsync

/* define OSK structs / types */
#define sys_memory_container_t sys_mem_container_t
#define CellOskDialogPoint oskPoint
#define CellOskDialogInputFieldInfo oskInputFieldInfo
#define CellOskDialogCallbackReturnParam oskCallbackReturnParam
#define CellOskDialogParam oskParam

#define osk_allowed_panels allowedPanels
#define osk_prohibit_flags prohibitFlags

#define osk_inputfield_message message
#define osk_inputfield_starttext startText
#define osk_inputfield_max_length maxLength
#define osk_callback_return_param res
#define osk_callback_num_chars len
#define osk_callback_return_string str

/* define the OSK defines */
#define CELL_OSKDIALOG_10KEY_PANEL OSK_10KEY_PANEL
#define CELL_OSKDIALOG_FULLKEY_PANEL OSK_FULLKEY_PANEL
#define CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_CENTER OSK_LAYOUTMODE_HORIZONTAL_ALIGN_CENTER
#define CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_TOP OSK_LAYOUTMODE_VERTICAL_ALIGN_TOP
#define CELL_OSKDIALOG_PANELMODE_NUMERAL OSK_PANEL_TYPE_NUMERAL
#define CELL_OSKDIALOG_PANELMODE_NUMERAL_FULL_WIDTH OSK_PANEL_TYPE_NUMERAL_FULL_WIDTH
#define CELL_OSKDIALOG_PANELMODE_ALPHABET OSK_PANEL_TYPE_ALPHABET
#define CELL_OSKDIALOG_PANELMODE_ENGLISH OSK_PANEL_TYPE_ENGLISH
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK (0)
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED (1)
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT (2)
#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT (3)
#define CELL_OSKDIALOG_STRING_SIZE (512)
#else
#include &lt;sysutil/sysutil_oskdialog.h&gt;
/* define all the OSK functions */
#define pOskLoadAsync cellOskDialogLoadAsync
#define pOskSetLayoutMode cellOskDialogSetLayoutMode
#define pOskSetKeyLayoutOption cellOskDialogSetKeyLayoutOption
#define pOskGetSize cellOskDialogGetSize
#define pOskDisableDimmer cellOskDialogDisableDimmer
#define pOskAbort cellOskDialogAbort
#define pOskUnloadAsync cellOskDialogUnloadAsync

/* define OSK structs / types */
#define osk_allowed_panels allowOskPanelFlg
#define osk_prohibit_flags prohibitFlgs
#define osk_inputfield_message message
#define osk_inputfield_starttext init_text
#define osk_inputfield_max_length limit_length
#define osk_callback_return_param result
#define osk_callback_num_chars numCharsResultString
#define osk_callback_return_string pResultString
#endif

/*============================================================
	JPEG/PNG DECODING/ENCODING PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__

#define spu_enable enable
#define stream_select stream
#define color_alpha alpha
#define color_space space
#define output_mode mode
#define output_bytes_per_line bytes_per_line
#define output_width width
#define output_height height

#define CELL_OK 0
#define PTR_NULL 0

#else
/* define the JPEG/PNG struct member names */
#define spu_enable spuThreadEnable
#define ppu_prio ppuThreadPriority
#define spu_prio spuThreadPriority
#define malloc_func cbCtrlMallocFunc
#define malloc_arg cbCtrlMallocArg
#define free_func cbCtrlFreeFunc
#define free_arg cbCtrlFreeArg
#define stream_select srcSelect
#define file_name fileName
#define file_offset fileOffset
#define file_size fileSize
#define stream_ptr streamPtr
#define stream_size streamSize
#define down_scale downScale
#define color_alpha outputColorAlpha
#define color_space outputColorSpace
#define cmd_ptr commandPtr
#define quality method
#define output_mode outputMode
#define output_bytes_per_line outputBytesPerLine
#define output_width outputWidth
#define output_height outputHeight
#define bit_depth outputBitDepth
#define pack_flag outputPackFlag
#define alpha_select outputAlphaSelect

#define PTR_NULL NULL

#endif

/*============================================================
	TIMER PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#define sys_timer_usleep usleep
#endif

/*============================================================
	THREADING PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;sys/thread.h&gt;

/* FIXME - not sure if this is correct -&gt; FIXED! 1 and not 0 */
#define SYS_THREAD_CREATE_JOINABLE THREAD_JOINABLE

#else
#include &lt;sys/ppu_thread.h&gt;

#define SYS_PROCESS_SPAWN_STACK_SIZE_1M SYS_PROCESS_PRIMARY_STACK_SIZE_1M 
#define SYS_THREAD_CREATE_JOINABLE SYS_PPU_THREAD_CREATE_JOINABLE

#define sysThreadCreate sys_ppu_thread_create 
#define sysThreadJoin sys_ppu_thread_join 
#define sysThreadExit sys_ppu_thread_exit 

#define sysProcessExit sys_process_exit 
#define sysProcessExitSpawn2 sys_game_process_exitspawn 

#endif

/*============================================================
	MEMORY PROTOTYPES
============================================================ */

#ifndef __PSL1GHT__
#define sysMemContainerCreate sys_memory_container_create 
#define sysMemContainerDestroy sys_memory_container_destroy 
#endif

/*============================================================
	RSX PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;sysutil/video.h&gt;
#define CELL_GCM_FALSE GCM_FALSE
#define CELL_GCM_TRUE GCM_TRUE

#define CELL_GCM_ONE GCM_ONE
#define CELL_GCM_ZERO GCM_ZERO
#define CELL_GCM_ALWAYS GCM_ALWAYS

#define CELL_GCM_LOCATION_LOCAL GCM_LOCATION_RSX
#define CELL_GCM_LOCATION_MAIN GCM_LOCATION_CELL

#define CELL_GCM_MAX_RT_DIMENSION (4096)

#define CELL_GCM_TEXTURE_LINEAR_NEAREST GCM_TEXTURE_LINEAR_MIPMAP_NEAREST
#define CELL_GCM_TEXTURE_LINEAR_LINEAR GCM_TEXTURE_LINEAR_MIPMAP_LINEAR
#define CELL_GCM_TEXTURE_NEAREST_LINEAR GCM_TEXTURE_NEAREST_MIPMAP_LINEAR
#define CELL_GCM_TEXTURE_NEAREST_NEAREST GCM_TEXTURE_NEAREST_MIPMAP_NEAREST
#define CELL_GCM_TEXTURE_NEAREST GCM_TEXTURE_NEAREST
#define CELL_GCM_TEXTURE_LINEAR GCM_TEXTURE_LINEAR

#define CELL_GCM_TEXTURE_A8R8G8B8 GCM_TEXTURE_FORMAT_A8R8G8B8
#define CELL_GCM_TEXTURE_R5G6B5 GCM_TEXTURE_FORMAT_R5G6B5
#define CELL_GCM_TEXTURE_A1R5G5B5 GCM_TEXTURE_FORMAT_A1R5G5B5

#define CELL_GCM_TEXTURE_CLAMP_TO_EDGE GCM_TEXTURE_CLAMP_TO_EDGE

#define CELL_GCM_TEXTURE_MAX_ANISO_1 GCM_TEXTURE_MAX_ANISO_1
#define CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX GCM_TEXTURE_CONVOLUTION_QUINCUNX
#define CELL_GCM_TEXTURE_ZFUNC_NEVER GCM_TEXTURE_ZFUNC_NEVER

#define CELL_GCM_DISPLAY_HSYNC GCM_FLIP_HSYNC
#define CELL_GCM_DISPLAY_VSYNC GCM_FLIP_VSYNC

#define CELL_GCM_CLEAR_R GCM_CLEAR_R
#define CELL_GCM_CLEAR_G GCM_CLEAR_G
#define CELL_GCM_CLEAR_B GCM_CLEAR_B
#define CELL_GCM_CLEAR_A GCM_CLEAR_A

#define CELL_GCM_FUNC_ADD GCM_FUNC_ADD

#define CELL_GCM_SMOOTH	(0x1D01)
#define CELL_GCM_DEBUG_LEVEL2 2

#define CELL_GCM_COMPMODE_DISABLED 0

#define CELL_GCM_TRANSFER_LOCAL_TO_LOCAL 0

#define CELL_GCM_TEXTURE_REMAP_ORDER_XYXY (0)
#define CELL_GCM_TEXTURE_REMAP_ORDER_XXXY (1)

#define CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL (0)

#define CELL_GCM_TEXTURE_REMAP_FROM_A (0)
#define CELL_GCM_TEXTURE_REMAP_FROM_R (1)
#define CELL_GCM_TEXTURE_REMAP_FROM_G (2)
#define CELL_GCM_TEXTURE_REMAP_FROM_B (3)

#define CELL_GCM_TEXTURE_REMAP_ZERO (0)
#define CELL_GCM_TEXTURE_REMAP_ONE (1)
#define CELL_GCM_TEXTURE_REMAP_REMAP (2)

#define CELL_GCM_MAX_TEXIMAGE_COUNT (16)

#define CELL_GCM_TEXTURE_WRAP (1)

#define CELL_GCM_TEXTURE_NR (0x00)
#define CELL_GCM_TEXTURE_LN (0x20)

#define CELL_GCM_TEXTURE_B8 (0x81)

#define CELL_RESC_720x480 RESC_720x480
#define CELL_RESC_720x576 RESC_720x576
#define CELL_RESC_1280x720 RESC_1280x720
#define CELL_RESC_1920x1080 RESC_1920x1080

#define CELL_RESC_FULLSCREEN RESC_FULLSCREEN
#define CELL_RESC_PANSCAN RESC_PANSCAN
#define CELL_RESC_LETTERBOX RESC_LETTERBOX
#define CELL_RESC_CONSTANT_VRAM RESC_CONSTANT_VRAM
#define CELL_RESC_MINIMUM_GPU_LOAD RESC_MINIMUM_GPU_LOAD

#define CELL_RESC_PAL_50 RESC_PAL_50
#define CELL_RESC_PAL_60_DROP RESC_PAL_60_DROP
#define CELL_RESC_PAL_60_INTERPOLATE RESC_PAL_60_INTERPOLATE
#define CELL_RESC_PAL_60_INTERPOLATE_30_DROP RESC_PAL_60_INTERPOLATE_30_DROP
#define CELL_RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE

#define CELL_RESC_INTERLACE_FILTER RESC_INTERLACE_FILTER
#define CELL_RESC_NORMAL_BILINEAR RESC_NORMAL_BILINEAR

#define CELL_RESC_ELEMENT_HALF RESC_ELEMENT_HALF

#define CELL_VIDEO_OUT_ASPECT_AUTO VIDEO_ASPECT_AUTO
#define CELL_VIDEO_OUT_ASPECT_4_3 VIDEO_ASPECT_4_3
#define CELL_VIDEO_OUT_ASPECT_16_9 VIDEO_ASPECT_16_9

#define CELL_VIDEO_OUT_RESOLUTION_480 VIDEO_RESOLUTION_480
#define CELL_VIDEO_OUT_RESOLUTION_576 VIDEO_RESOLUTION_576
#define CELL_VIDEO_OUT_RESOLUTION_720 VIDEO_RESOLUTION_720
#define CELL_VIDEO_OUT_RESOLUTION_1080 VIDEO_RESOLUTION_1080
#define CELL_VIDEO_OUT_RESOLUTION_960x1080 VIDEO_RESOLUTION_960x1080
#define CELL_VIDEO_OUT_RESOLUTION_1280x1080 VIDEO_RESOLUTION_1280x1080
#define CELL_VIDEO_OUT_RESOLUTION_1440x1080 VIDEO_RESOLUTION_1440x1080
#define CELL_VIDEO_OUT_RESOLUTION_1600x1080 VIDEO_RESOLUTION_1600x1080

#define CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE VIDEO_SCANMODE_PROGRESSIVE

#define CELL_VIDEO_OUT_PRIMARY VIDEO_PRIMARY

#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8 VIDEO_BUFFER_FORMAT_XRGB
#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT VIDEO_BUFFER_FORMAT_FLOAT

#define CellGcmSurface gcmSurface
#define CellGcmTexture gcmTexture
#define CellGcmContextData _gcmCtxData
#define CellGcmConfig gcmConfiguration
#define CellVideoOutConfiguration videoConfiguration
#define CellVideoOutResolution videoResolution
#define CellVideoOutState videoState

#define CellRescInitConfig rescInitConfig
#define CellRescSrc rescSrc
#define CellRescBufferMode rescBufferMode

#define resolutionId resolution
#define memoryFrequency memoryFreq
#define coreFrequency coreFreq

#define cellGcmFinish rsxFinish

#define cellGcmGetFlipStatus gcmGetFlipStatus
#define cellGcmResetFlipStatus gcmResetFlipStatus
#define cellGcmSetWaitFlip gcmSetWaitFlip
#define cellGcmSetDebugOutputLevel gcmSetDebugOutputLevel
#define cellGcmSetDisplayBuffer gcmSetDisplayBuffer
#define cellGcmSetGraphicsHandler gcmSetGraphicsHandler
#define cellGcmSetFlipHandler gcmSetFlipHandler
#define cellGcmSetVBlankHandler gcmSetVBlankHandler
#define cellGcmGetConfiguration gcmGetConfiguration
#define cellGcmSetJumpCommand rsxSetJumpCommand
#define cellGcmFlush rsxFlushBuffer
#define cellGcmSetFlipMode gcmSetFlipMode
#define cellGcmSetFlip gcmSetFlip
#define cellGcmGetLabelAddress gcmGetLabelAddress
#define cellGcmUnbindTile gcmUnbindTile
#define cellGcmBindTile gcmBindTile
#define cellGcmSetTileInfo gcmSetTileInfo
#define cellGcmAddressToOffset gcmAddressToOffset

#define cellRescCreateInterlaceTable rescCreateInterlaceTable
#define cellRescSetDisplayMode rescSetDisplayMode
#define cellRescGetNumColorBuffers rescGetNumColorBuffers
#define cellRescGetBufferSize rescGetBufferSize
#define cellRescSetBufferAddress rescSetBufferAddress
#define cellRescGetFlipStatus rescGetFlipStatus
#define cellRescResetFlipStatus rescResetFlipStatus
#define cellRescSetConvertAndFlip rescSetConvertAndFlip
#define cellRescSetVBlankHandler rescSetVBlankHandler
#define cellRescSetFlipHandler rescSetFlipHandler
#define cellRescAdjustAspectRatio rescAdjustAspectRatio
#define cellRescSetWaitFlip rescSetWaitFlip
#define cellRescSetSrc rescSetSrc
#define cellRescInit rescInit
#define cellRescExit rescExit

#define cellVideoOutConfigure videoConfigure
#define cellVideoOutGetState videoGetState
#define cellVideoOutGetResolution videoGetResolution
#define cellVideoOutGetResolutionAvailability videoGetResolutionAvailability

#define cellGcmSetViewportInline rsxSetViewport
#define cellGcmSetReferenceCommandInline rsxSetReferenceCommand
#define cellGcmSetBlendEquationInline rsxSetBlendEquation
#define cellGcmSetWriteBackEndLabelInline rsxSetWriteBackendLabel
#define cellGcmSetWaitLabelInline rsxSetWaitLabel
#define cellGcmSetDepthTestEnableInline rsxSetDepthTestEnable
#define cellGcmSetScissorInline rsxSetScissor
#define cellGcmSetBlendEnableInline rsxSetBlendEnable
#define cellGcmSetClearColorInline rsxSetClearColor
#define cellGcmSetBlendFuncInline rsxSetBlendFunc
#define cellGcmSetBlendColorInline rsxSetBlendColor
#define cellGcmSetTextureFilterInline rsxTextureFilter
#define cellGcmSetTextureControlInline rsxTextureControl
#define cellGcmSetCullFaceEnableInline rsxSetCullFaceEnable
#define cellGcmSetShadeModeInline rsxSetShadeModel
#define cellGcmSetTransferImage rsxSetTransferImage
#define cellGcmSetBlendColor rsxSetBlendColor
#define cellGcmSetBlendEquation rsxSetBlendEquation
#define cellGcmSetBlendFunc rsxSetBlendFunc
#define cellGcmSetClearColor rsxSetClearColor
#define cellGcmSetScissor rsxSetScissor
#define celGcmSetInvalidateVertexCache(fifo) rsxInvalidateTextureCache(fifo, GCM_INVALIDATE_VERTEX_TEXTURE)
#else
#define cellGcmSetTransferImage cellGcmSetTransferImageInline
#define celGcmSetInvalidateVertexCache cellGcmSetInvalidateVertexCacheInline
#define rsxInit cellGcmInit
#define rsxInvalidateTextureCache(a, b) cellGcmSetInvalidateVertexCache(a)
#define rsxTextureControl cellGcmSetTextureControlInline
#define rsxSetBlendEnable cellGcmSetBlendEnableInline 
#endif

/*============================================================
	NETWORK PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;net/netctl.h&gt;

#define cellNetCtlInit netCtlInit
#define cellNetCtlGetState netCtlGetState
#define cellNetCtlTerm netCtlTerm

#define CELL_NET_CTL_STATE_IPObtained NET_CTL_STATE_IPObtained
#else
#define netCtlInit cellNetCtlInit
#define netCtlGetState cellNetCtlGetState
#define netCtlTerm cellNetCtlTerm
#define NET_CTL_STATE_IPObtained CELL_NET_CTL_STATE_IPObtained
#endif

/*============================================================
	NET PROTOTYPES
============================================================ */

#if defined(HAVE_NETWORKING)
#ifdef __PSL1GHT__
#include &lt;net/net.h&gt;

#define socketselect select
#define socketclose close

#define sys_net_initialize_network netInitialize
#define sys_net_finalize_network netFinalizeNetwork
#else
#include &lt;netex/net.h&gt;
#include &lt;np.h&gt;
#include &lt;np/drm.h&gt;

#define netInitialize sys_net_initialize_network
#define netFinalizeNetwork sys_net_finalize_network
#endif
#endif

/*============================================================
	SYSUTIL PROTOTYPES
============================================================ */

#ifdef __PSL1GHT__
#include &lt;sysutil/game.h&gt;
#define CellGameContentSize sysGameContentSize
#define cellGameContentPermit sysGameContentPermit
#define cellGameBootCheck sysGameBootCheck

#define CELL_GAME_ATTRIBUTE_APP_HOME   (UINT64_C(1) &lt;&lt;1) /* boot from / app_home/PS3_GAME */
#define CELL_GAME_DIRNAME_SIZE			32

#define CELL_GAME_GAMETYPE_SYS		0
#define CELL_GAME_GAMETYPE_DISC		1
#define CELL_GAME_GAMETYPE_HDD		2
#define CELL_GAME_GAMETYPE_GAMEDATA	3
#define CELL_GAME_GAMETYPE_HOME		4

#endif

#if defined(HAVE_SYSUTILS)
#ifdef __PSL1GHT__
#include &lt;sysutil/sysutil.h&gt;

#define CELL_SYSUTIL_REQUEST_EXITGAME SYSUTIL_EXIT_GAME

#define cellSysutilRegisterCallback sysUtilRegisterCallback
#define cellSysutilCheckCallback sysUtilCheckCallback
#else
#include &lt;sysutil/sysutil_screenshot.h&gt;
#include &lt;sysutil/sysutil_common.h&gt;
#include &lt;sysutil/sysutil_gamecontent.h&gt;
#endif
#endif

#if(CELL_SDK_VERSION &gt; 0x340000)
#include &lt;sysutil/sysutil_bgmplayback.h&gt;
#endif

/*============================================================
	SYSMODULE PROTOTYPES
============================================================ */

#if defined(HAVE_SYSMODULES)
#ifdef __PSL1GHT__
#include &lt;sysmodule/sysmodule.h&gt;

#define CELL_SYSMODULE_IO SYSMODULE_IO
#define CELL_SYSMODULE_FS SYSMODULE_FS
#define CELL_SYSMODULE_NET SYSMODULE_NET
#define CELL_SYSMODULE_SYSUTIL_NP SYSMODULE_SYSUTIL_NP
#define CELL_SYSMODULE_JPGDEC SYSMODULE_JPGDEC
#define CELL_SYSMODULE_PNGDEC SYSMODULE_PNGDEC
#define CELL_SYSMODULE_FONT SYSMODULE_FONT
#define CELL_SYSMODULE_FREETYPE SYSMODULE_FREETYPE
#define CELL_SYSMODULE_FONTFT SYSMODULE_FONTFT

#define cellSysmoduleLoadModule sysModuleLoad
#define cellSysmoduleUnloadModule sysModuleUnload

#else
#include &lt;cell/sysmodule.h&gt;

#define sysModuleLoad cellSysmoduleLoadModule
#define sysModuleUnload cellSysmoduleUnloadModule
#define SYSMODULE_NET CELL_SYSMODULE_NET
#endif
#endif

/*============================================================
	FS PROTOTYPES
============================================================ */
#define FS_SUCCEEDED 0
#define FS_TYPE_DIR 1
#ifdef __PSL1GHT__
#include &lt;lv2/sysfs.h&gt;
#ifndef O_RDONLY
#define O_RDONLY SYS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY SYS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT SYS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC SYS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR SYS_O_RDWR
#endif
#else
#include &lt;cell/cell_fs.h&gt;
#ifndef O_RDONLY
#define O_RDONLY CELL_FS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY CELL_FS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT CELL_FS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC CELL_FS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR CELL_FS_O_RDWR
#endif
#ifndef sysFsStat
#define sysFsStat cellFsStat
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsOpendir
#define sysFsOpendir cellFsOpendir
#endif
#ifndef sysFsReaddir
#define sysFsReaddir cellFsReaddir
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsClosedir
#define sysFsClosedir cellFsClosedir
#endif
#endif

#endif</pre>
<h2>./include/libretro-common/include/defines/ps4_defines.h</h2>
<pre>#ifndef _PS4_DEFINES_H
#define _PS4_DEFINES_H

#define PS4_MAX_ORBISPADS 16
#define PS4_MAX_PAD_PORT_TYPES 3

#define	ORBISPAD_L3		        0x00000002
#define	ORBISPAD_R3		        0x00000004
#define	ORBISPAD_OPTIONS	    0x00000008
#define	ORBISPAD_UP		        0x00000010
#define	ORBISPAD_RIGHT		    0x00000020
#define	ORBISPAD_DOWN		      0x00000040
#define	ORBISPAD_LEFT		      0x00000080
#define	ORBISPAD_L2		        0x00000100
#define	ORBISPAD_R2		        0x00000200
#define	ORBISPAD_L1		        0x00000400
#define	ORBISPAD_R1		        0x00000800
#define	ORBISPAD_TRIANGLE	    0x00001000
#define	ORBISPAD_CIRCLE		    0x00002000
#define	ORBISPAD_CROSS		    0x00004000
#define	ORBISPAD_SQUARE		    0x00008000
#define	ORBISPAD_TOUCH_PAD	  0x00100000
#define	ORBISPAD_INTERCEPTED	0x80000000

#define SceUID uint32_t
#define SceKernelStat OrbisKernelStat
#define SCE_KERNEL_PRIO_FIFO_DEFAULT 700
#define SCE_AUDIO_OUT_PORT_TYPE_MAIN   0
#define SCE_AUDIO_OUT_MODE_STEREO      1
#define SCE_MOUSE_BUTTON_PRIMARY 0x00000001
#define SCE_MOUSE_BUTTON_SECONDARY 0x00000002
#define SCE_MOUSE_BUTTON_OPTIONAL 0x00000004
#define SCE_MOUSE_BUTTON_INTERCEPTED 0x80000000
#define SCE_MOUSE_OPEN_PARAM_MERGED	0x01
#define SCE_MOUSE_PORT_TYPE_STANDARD 0
#define SCE_DBG_KEYBOARD_PORT_TYPE_STANDARD	0
#define SCE_USER_SERVICE_MAX_LOGIN_USERS 16
#define SCE_USER_SERVICE_USER_ID_INVALID 0xFFFFFFFF
#define SCE_ORBISPAD_ERROR_ALREADY_OPENED 0x80920004
#define SCE_PAD_PORT_TYPE_STANDARD 0
#define SCE_PAD_PORT_TYPE_SPECIAL	2
#define SCE_PAD_PORT_TYPE_REMOTE_CONTROL 16
#define SCE_KERNEL_PROT_CPU_RW 0x02
#define SCE_KERNEL_MAP_FIXED 0x10

#endif</pre>
<h2>./include/libretro-common/include/defines/psp_defines.h</h2>
<pre>/* Copyright (C) 2010-2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (psp_defines.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _PSP_DEFINES_H
#define _PSP_DEFINES_H

/*============================================================
	ERROR PROTOTYPES
============================================================ */

#ifndef SCE_OK
#define SCE_OK 0
#endif

/*============================================================
	DISPLAY PROTOTYPES
============================================================ */

#if defined(SN_TARGET_PSP2) || defined(VITA)

#ifdef VITA
int sceClibPrintf ( const char * format, ... );
#define printf sceClibPrintf
#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
#else
#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
#endif

#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, sync)

#define PSP_FB_WIDTH        960
#define PSP_FB_HEIGHT       544
#define PSP_PITCH_PIXELS 1024

/* Memory left to the system for threads and other internal stuffs */
#ifdef SCE_LIBC_SIZE
#define RAM_THRESHOLD 0x2000000 + SCE_LIBC_SIZE
#else
#define RAM_THRESHOLD 0x2000000
#endif

#elif defined(PSP)
#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync)

#define SCE_DISPLAY_UPDATETIMING_NEXTVSYNC 1

#define PSP_FB_WIDTH        512
#define PSP_FB_HEIGHT       512
#define PSP_PITCH_PIXELS 512

#endif

/*============================================================
	INPUT PROTOTYPES
============================================================ */

#if defined(SN_TARGET_PSP2) || defined(VITA)

#define STATE_BUTTON(state) ((state).buttons)
#define STATE_ANALOGLX(state) ((state).lx)
#define STATE_ANALOGLY(state) ((state).ly)
#define STATE_ANALOGRX(state) ((state).rx)
#define STATE_ANALOGRY(state) ((state).ry)

#if defined(VITA)
#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_ANALOG)

#define PSP_CTRL_LEFT SCE_CTRL_LEFT
#define PSP_CTRL_DOWN SCE_CTRL_DOWN
#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT
#define PSP_CTRL_UP SCE_CTRL_UP
#define PSP_CTRL_START SCE_CTRL_START
#define PSP_CTRL_SELECT SCE_CTRL_SELECT
#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE
#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE
#define PSP_CTRL_CROSS SCE_CTRL_CROSS
#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE
#define PSP_CTRL_L SCE_CTRL_L1
#define PSP_CTRL_R SCE_CTRL_R1
#define PSP_CTRL_L2 SCE_CTRL_LTRIGGER
#define PSP_CTRL_R2 SCE_CTRL_RTRIGGER
#define PSP_CTRL_L3 SCE_CTRL_L3
#define PSP_CTRL_R3 SCE_CTRL_R3
#define STATE_ANALOGL2(state) ((state).lt)
#define STATE_ANALOGR2(state) ((state).rt)
#else
#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_DIGITALANALOG)

#define PSP_CTRL_LEFT SCE_CTRL_LEFT
#define PSP_CTRL_DOWN SCE_CTRL_DOWN
#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT
#define PSP_CTRL_UP SCE_CTRL_UP
#define PSP_CTRL_START SCE_CTRL_START
#define PSP_CTRL_SELECT SCE_CTRL_SELECT
#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE
#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE
#define PSP_CTRL_CROSS SCE_CTRL_CROSS
#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE
#define PSP_CTRL_L SCE_CTRL_L
#define PSP_CTRL_R SCE_CTRL_R
#endif

#if defined(VITA)
#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingModeExt(mode)
#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositiveExt2(port, pad_data, bufs)
#else
#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)
#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(port, pad_data, bufs)
#endif

#elif defined(PSP)

#define PSP_CTRL_L PSP_CTRL_LTRIGGER
#define PSP_CTRL_R PSP_CTRL_RTRIGGER

#define STATE_BUTTON(state) ((state).Buttons)
#define STATE_ANALOGLX(state) ((state).Lx)
#define STATE_ANALOGLY(state) ((state).Ly)
#define STATE_ANALOGRX(state) ((state).Rx)
#define STATE_ANALOGRY(state) ((state).Ry)

#define DEFAULT_SAMPLING_MODE (PSP_CTRL_MODE_ANALOG)

#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)
#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(pad_data, bufs)
#endif

#endif</pre>
<h2>./include/libretro-common/include/dynamic/dylib.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dylib.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __DYLIB_H
#define __DYLIB_H

#include &lt;boolean.h&gt;

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include &lt;retro_common_api.h&gt;

#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
#define NEED_DYNAMIC
#else
#undef NEED_DYNAMIC
#endif

RETRO_BEGIN_DECLS

/**
 * Opaque handle to a dynamic library.
 * @see dylib_load
 */
typedef void *dylib_t;

/**
 * Opaque handle to a function exposed by a dynamic library.
 *
 * Should be cast to a known function pointer type before being used.
 * @see dylib_proc
 */
typedef void (*function_t)(void);

#ifdef NEED_DYNAMIC
/**
 * Loads a dynamic library in a platform-independent manner.
 *
 * @param path Path to the library to load.
 * May be either a complete path or a filename without an extension.
 * If not a complete path, the operating system will search for a library by this name;
 * details will depend on the platform.
 * @note The returned library must be freed with \c dylib_close
 * before the core or frontend exits.
 *
 * @return Handle to the loaded library, or \c NULL on failure.
 * Upon failure, \c dylib_error may be used
 * to retrieve a string describing the error.
 * @see dylib_close
 * @see dylib_error
 * @see dylib_proc
 **/
dylib_t dylib_load(const char *path);

/**
 * Frees the resources associated with a dynamic library.
 *
 * Any function pointers obtained from the library may become invalid,
 * depending on whether the operating system manages reference counts to dynamic libraries.
 *
 * If there was an error closing the library,
 * it will be reported by \c dylib_error.
 *
 * @param lib Handle to the library to close.
 * Behavior is undefined if \c NULL.
 **/
void dylib_close(dylib_t lib);

/**
 * Returns a string describing the most recent error that occurred
 * within the other \c dylib functions.
 *
 * @return Pointer to the most recent error string,
 * \c or NULL if there was no error.
 * @warning The returned string is only valid
 * until the next call to a \c dylib function.
 * Additionally, the string is managed by the library
 * and should not be modified or freed by the caller.
 */
char *dylib_error(void);

/**
 * Returns a pointer to a function exposed by a dynamic library.
 *
 * @param lib The library to get a function pointer from.
 * @param proc The name of the function to get a pointer to.
 * @return Pointer to the requested function,
 * or \c NULL if there was an error.
 * This must be cast to the correct function pointer type before being used.
 * @warning The returned pointer is only valid for the lifetime of \c lib.
 * Once \c lib is closed, all function pointers returned from it will be invalidated;
 * using them is undefined behavior.
 */
function_t dylib_proc(dylib_t lib, const char *proc);
#endif

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/encodings/base64.h</h2>
<pre>#ifndef _LIBRETRO_ENCODINGS_BASE64_H
#define _LIBRETRO_ENCODINGS_BASE64_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/**
 * Encodes binary data into a \c NULL-terminated base64 string.
 *
 * @param binaryData The data to encode.
 * Behavior is undefined if \c NULL.
 * @param len The length of the data to encode.
 * @param flen Pointer to the length of the returned string.
 * @return Pointer to the base64-encoded string, or \c NULL on failure.
 * The returned string is owned by the caller and must be released with \c free().
 * @see unbase64
 */
char* base64(const void* binaryData, int len, int *flen);

/**
 * Decodes a base64-encoded string into binary data.
 *
 * @param ascii The base64 string to decode, in ASCII format.
 * @param len Length of the string to decode.
 * @param flen Pointer to the length of the returned data.
 * @return The decoded binary data, or \c NULL on failure.
 * The returned buffer is owned by the caller and must be released with \c free().
 * @see base64
 */
unsigned char* unbase64(const char* ascii, int len, int *flen);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/encodings/crc32.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (crc32.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_ENCODINGS_CRC32_H
#define _LIBRETRO_ENCODINGS_CRC32_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/**
 * Computes a buffer's CRC32 checksum.
 *
 * @param crc The initial CRC32 value.
 * @param buf The buffer to calculate the CRC32 checksum of.
 * @param len The length of the data in \c buf.
 * @return The CRC32 checksum of the given buffer.
 */
uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/encodings/utf.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (utf.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_ENCODINGS_UTF_H
#define _LIBRETRO_ENCODINGS_UTF_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;boolean.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

enum CodePage
{
   CODEPAGE_LOCAL = 0, /* CP_ACP */
   CODEPAGE_UTF8  = 65001 /* CP_UTF8 */
};

/**
 * utf8_conv_utf32:
 *
 * Simple implementation. Assumes the sequence is
 * properly synchronized and terminated.
 **/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
      const char *in, size_t in_size);

/**
 * utf16_conv_utf8:
 *
 * Leaf function.
 **/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
      const uint16_t *in, size_t in_size);

/**
 * utf8len:
 *
 * Leaf function.
 **/
size_t utf8len(const char *string);

/**
 * utf8cpy:
 *
 * Acts mostly like strlcpy.
 *
 * Copies the given number of UTF-8 characters,
 * but at most @d_len bytes.
 *
 * Always NULL terminates. Does not copy half a character.
 * @s is assumed valid UTF-8.
 * Use only if @chars is considerably less than @d_len. 
 *
 * Hidden non-leaf function cost:
 * - Calls memcpy
 *
 * @return Number of bytes. 
 **/
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);

/**
 * utf8skip:
 *
 * Leaf function
 **/
const char *utf8skip(const char *str, size_t chars);

/** 
 * utf8_walk:
 *
 * Does not validate the input.
 *
 * Leaf function.
 *
 * @return Returns garbage if it's not UTF-8.
 **/
uint32_t utf8_walk(const char **string);

/**
 * utf16_to_char_string:
 **/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);

/**
 * utf8_to_local_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *utf8_to_local_string_alloc(const char *str);

/**
 * local_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *local_to_utf8_string_alloc(const char *str);

/**
 * utf8_to_utf16_string_alloc:
 * 
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
wchar_t *utf8_to_utf16_string_alloc(const char *str);

/**
 * utf16_to_utf8_string_alloc:
 *
 * @return Returned pointer MUST be freed by the caller if non-NULL.
 **/
char *utf16_to_utf8_string_alloc(const wchar_t *str);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/encodings/win32.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (utf.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_ENCODINGS_WIN32_H
#define _LIBRETRO_ENCODINGS_WIN32_H

#ifndef _XBOX
#ifdef _WIN32
/*#define UNICODE
#include &lt;tchar.h&gt;
#include &lt;wchar.h&gt;*/

#ifdef __cplusplus
extern "C" {
#endif

#include &lt;encodings/utf.h&gt;

#ifdef __cplusplus
}
#endif

#endif
#endif

#ifdef UNICODE
#define CHAR_TO_WCHAR_ALLOC(s, ws) \
   size_t ws##_size = (NULL != s &amp;&amp; s[0] ? strlen(s) : 0) + 1; \
   wchar_t *ws = (wchar_t*)calloc(ws##_size, 2); \
   if (NULL != s &amp;&amp; s[0]) \
      MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws##_size / sizeof(wchar_t));

#define WCHAR_TO_CHAR_ALLOC(ws, s) \
   size_t s##_size = ((NULL != ws &amp;&amp; ws[0] ? wcslen((const wchar_t*)ws) : 0) / 2) + 1; \
   char *s = (char*)calloc(s##_size, 1); \
   if (NULL != ws &amp;&amp; ws[0]) \
      utf16_to_char_string((const uint16_t*)ws, s, s##_size);

#else
#define CHAR_TO_WCHAR_ALLOC(s, ws) char *ws = (NULL != s &amp;&amp; s[0] ? strdup(s) : NULL);
#define WCHAR_TO_CHAR_ALLOC(ws, s) char *s = (NULL != ws &amp;&amp; ws[0] ? strdup(ws) : NULL);
#endif

#endif</pre>
<h2>./include/libretro-common/include/fastcpy.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fastcpy.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* in the future ASM and new c++ features can be added to speed up copying */
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;
#include &lt;retro_inline.h&gt;

static INLINE void* memcpy16(void* dst, void* src, size_t len)
{
   return memcpy(dst, src, len * 2);
}

static INLINE void* memcpy32(void* dst, void* src, size_t len)
{
   return memcpy(dst, src, len * 4);
}

static INLINE void* memcpy64(void* dst, void* src, size_t len)
{
   return memcpy(dst, src, len * 8);
}

#ifdef USECPPSTDFILL
#include &lt;algorithm&gt;

static INLINE void* memset16(void* dst,uint16_t val, size_t len)
{
   uint16_t *typedptr = (uint16_t*)dst;
   std::fill(typedptr, typedptr + len, val);
   return dst;
}

static INLINE void* memset32(void* dst, uint32_t val, size_t len)
{
   uint32_t *typedptr = (uint32_t*)dst;
   std::fill(typedptr, typedptr + len, val);
   return dst;
}

static INLINE void* memset64(void* dst, uint64_t val, size_t len)
{
   uint64_t *typedptr = (uint64_t*)dst;
   std::fill(typedptr, typedptr + len, val);
   return dst;
}
#else
static INLINE void *memset16(void* dst, uint16_t val, size_t len)
{
   size_t i;
   uint16_t *typedptr = (uint16_t*)dst;
   for (i = 0; i &lt; len; i++)
      typedptr[i] = val;
   return dst;
}

static INLINE void *memset32(void* dst, uint32_t val, size_t len)
{
   size_t i;
   uint32_t *typedptr = (uint32_t*)dst;
   for (i = 0; i &lt; len; i++)
      typedptr[i] = val;
   return dst;
}

static INLINE void *memset64(void* dst, uint64_t val, size_t len)
{
   size_t i;
   uint64_t *typedptr = (uint64_t*)dst;
   for (i = 0; i &lt; len;i++)
      typedptr[i] = val;
   return dst;
}
#endif</pre>
<h2>./include/libretro-common/include/features/features_cpu.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (features_cpu.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_CPU_INFO_H
#define _LIBRETRO_SDK_CPU_INFO_H

#include &lt;retro_common_api.h&gt;

#include &lt;stdint.h&gt;

#include &lt;libretro.h&gt;

RETRO_BEGIN_DECLS

/**
 * Gets the time in ticks since some unspecified epoch.
 * The notion of a "tick" varies per platform.
 *
 * The epoch may change between devices or across reboots.
 *
 * Suitable for use as a default implementation of \c retro_perf_callback::get_perf_counter,
 * (or as a fallback by the core),
 * although a frontend may provide its own implementation.
 *
 * @return The current time, in ticks.
 * @see retro_perf_callback::get_perf_counter
 */
retro_perf_tick_t cpu_features_get_perf_counter(void);

/**
 * Gets the time in microseconds since some unspecified epoch.
 *
 * The epoch may change between devices or across reboots.
 *
 * Suitable for use as a default implementation of \c retro_perf_callback::get_time_usec,
 * (or as a fallback by the core),
 * although a frontend may provide its own implementation.
 *
 * @return The current time, in microseconds.
 * @see retro_perf_callback::get_time_usec
 */
retro_time_t cpu_features_get_time_usec(void);

/**
 * Returns the available features (mostly SIMD extensions)
 * supported by this CPU.
 *
 * Suitable for use as a default implementation of \c retro_perf_callback::get_time_usec,
 * (or as a fallback by the core),
 * although a frontend may provide its own implementation.
 *
 * @return Bitmask of all CPU features available.
 * @see RETRO_SIMD
 * @see retro_perf_callback::get_cpu_features
 */
uint64_t cpu_features_get(void);

/**
 * @return The number of CPU cores available,
 * or 1 if the number of cores could not be determined.
 */
unsigned cpu_features_get_core_amount(void);

/**
 * Returns the name of the CPU model.
 *
 * @param[out] name Pointer to a buffer to store the name.
 * Will be \c NULL-terminated.
 * If \c NULL, this value will not be modified.
 * @param len The amount of space available in \c name.
 */
void cpu_features_get_model_name(char *name, int len);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/file/archive_file.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (archive_file.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_ARCHIVE_FILE_H__
#define LIBRETRO_SDK_ARCHIVE_FILE_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;boolean.h&gt;

#ifdef _WIN32
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt;
#endif

#include &lt;retro_miscellaneous.h&gt;

#include &lt;retro_common_api.h&gt;

#if defined(RARCH_INTERNAL) &amp;&amp; defined(HAVE_CONFIG_H)
#include "../../../config.h" /* for HAVE_MMAP */
#endif

RETRO_BEGIN_DECLS

enum file_archive_transfer_type
{
   ARCHIVE_TRANSFER_NONE = 0,
   ARCHIVE_TRANSFER_INIT,
   ARCHIVE_TRANSFER_ITERATE,
   ARCHIVE_TRANSFER_DEINIT,
   ARCHIVE_TRANSFER_DEINIT_ERROR
};

typedef struct file_archive_handle
{
   uint8_t  *data;
   uint32_t real_checksum;
} file_archive_file_handle_t;

typedef struct file_archive_transfer
{
   int64_t archive_size;
   void *context;
   struct RFILE *archive_file;
   const struct file_archive_file_backend *backend;
#ifdef HAVE_MMAP
   uint8_t *archive_mmap_data;
   int archive_mmap_fd;
#endif
   unsigned step_total;
   unsigned step_current;
   enum file_archive_transfer_type type;
} file_archive_transfer_t;

typedef struct
{
   file_archive_transfer_t archive;             /* int64_t alignment */
   char *source_file;
   char *subdir;
   char *target_dir;
   char *target_file;
   char *valid_ext;
   char *callback_error;
   struct archive_extract_userdata *userdata;
} decompress_state_t;

struct archive_extract_userdata
{
   /* These are set or read by the archive processing */
   char *first_extracted_file_path;
   const char *extraction_directory;
   struct string_list *ext;
   struct string_list *list;
   file_archive_transfer_t *transfer;
   /* Not used by the processing, free to use outside or in iterate callback */
   decompress_state_t *dec;
   void* cb_data;
   uint32_t crc;
   char archive_path[PATH_MAX_LENGTH];
   char current_file_path[PATH_MAX_LENGTH];
   bool found_file;
   bool list_only;
};

/* Returns true when parsing should continue. False to stop. */
typedef int (*file_archive_file_cb)(const char *name, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata);

struct file_archive_file_backend
{
   int (*archive_parse_file_init)(
      file_archive_transfer_t *state,
      const char *file);
   int (*archive_parse_file_iterate_step)(
      void *context,
      const char *valid_exts,
      struct archive_extract_userdata *userdata,
      file_archive_file_cb file_cb);
   void (*archive_parse_file_free)(
      void *context);

   bool     (*stream_decompress_data_to_file_init)(
      void *context, file_archive_file_handle_t *handle,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size);
   int      (*stream_decompress_data_to_file_iterate)(
      void *context,
      file_archive_file_handle_t *handle);

   uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t);
   int64_t (*compressed_file_read)(const char *path, const char *needle, void **buf,
         const char *optional_outfile);
   const char *ident;
};

int file_archive_parse_file_iterate(
      file_archive_transfer_t *state,
      bool *returnerr,
      const char *file,
      const char *valid_exts,
      file_archive_file_cb file_cb,
      struct archive_extract_userdata *userdata);

void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state);

int file_archive_parse_file_progress(file_archive_transfer_t *state);

/**
 * file_archive_extract_file:
 * @archive_path                : filename path to ZIP archive.
 * @valid_exts                  : valid extensions for a file.
 * @extraction_directory        : the directory to extract the temporary
 *                                file to.
 *
 * Extract file from archive. If no file inside the archive is
 * specified, the first file found will be used.
 *
 * Returns : true (1) on success, otherwise false (0).
 **/
bool file_archive_extract_file(const char *archive_path,
      const char *valid_exts, const char *extraction_dir,
      char *out_path, size_t len);

/* Warning: 'list' must zero initialised before
 * calling this function, otherwise memory leaks/
 * undefined behaviour will occur */
bool file_archive_get_file_list_noalloc(struct string_list *list,
      const char *path,
      const char *valid_exts);

/**
 * file_archive_get_file_list:
 * @path                        : filename path of archive
 * @valid_exts                  : Valid extensions of archive to be parsed.
 *                                If NULL, allow all.
 *
 * Returns: string listing of files from archive on success, otherwise NULL.
 **/
struct string_list* file_archive_get_file_list(const char *path, const char *valid_exts);

bool file_archive_perform_mode(const char *name, const char *valid_exts,
      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
      uint32_t crc32, struct archive_extract_userdata *userdata);

int file_archive_compressed_read(
      const char* path, void **buf,
      const char* optional_filename, int64_t *length);

const struct file_archive_file_backend* file_archive_get_zlib_file_backend(void);
const struct file_archive_file_backend* file_archive_get_7z_file_backend(void);

const struct file_archive_file_backend* file_archive_get_file_backend(const char *path);

/**
 * file_archive_get_file_crc32:
 * @path                         : filename path of archive
 *
 * Returns: CRC32 of the specified file in the archive, otherwise 0.
 * If no path within the archive is specified, the first
 * file found inside is used.
 **/
uint32_t file_archive_get_file_crc32(const char *path);

extern const struct file_archive_file_backend zlib_backend;
extern const struct file_archive_file_backend sevenzip_backend;

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/file/config_file.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_CONFIG_FILE_H
#define __LIBRETRO_SDK_CONFIG_FILE_H

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;boolean.h&gt;

#define CONFIG_GET_BOOL_BASE(conf, base, var, key) do { \
   bool tmp = false; \
   if (config_get_bool(conf, key, &amp;tmp)) \
      base-&gt;var = tmp; \
} while(0)

#define CONFIG_GET_INT_BASE(conf, base, var, key) do { \
   int tmp = 0; \
   if (config_get_int(conf, key, &amp;tmp)) \
      base-&gt;var = tmp; \
} while(0)

#define CONFIG_GET_FLOAT_BASE(conf, base, var, key) do { \
   float tmp = 0.0f; \
   if (config_get_float(conf, key, &amp;tmp)) \
      base-&gt;var = tmp; \
} while(0)

enum config_file_flags
{
   CONF_FILE_FLG_MODIFIED                 = (1 &lt;&lt; 0),
   CONF_FILE_FLG_GUARANTEED_NO_DUPLICATES = (1 &lt;&lt; 1)
};

struct config_file
{
   char *path;
   struct config_entry_list **entries_map;
   struct config_entry_list *entries;
   struct config_entry_list *tail;
   struct config_entry_list *last;
   struct config_include_list *includes;
   struct path_linked_list *references;
   unsigned include_depth;
   uint8_t flags;
};

typedef struct config_file config_file_t;

struct config_file_cb
{
   void (*config_file_new_entry_cb)(char*, char*);
};

typedef struct config_file_cb config_file_cb_t ;

/* Config file format
 * - # are treated as comments. Rest of the line is ignored.
 * - Format is: key = value. There can be as many spaces as you like in-between.
 * - Value can be wrapped inside "" for multiword strings. (foo = "hai u")
 * - #include includes a config file in-place.
 *
 * Path is relative to where config file was loaded unless an absolute path is chosen.
 * Key/value pairs from an #include are read-only, and cannot be modified.
 */

/**
 * config_file_new:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new(const char *path);

config_file_t *config_file_new_alloc(void);

/**
 * config_file_initialize:
 *
 * Leaf function.
 **/
void config_file_initialize(struct config_file *conf);

/**
 * config_file_new_with_callback:
 *
 * Loads a config file.
 * If @path is NULL, will create an empty config file.
 * Includes cb callbacks  to run custom code during config file processing.
 *
 * @return Returns NULL if file doesn't exist.
 **/
config_file_t *config_file_new_with_callback(
      const char *path, config_file_cb_t *cb);

/**
 * config_file_new_from_string:
 *
 * Load a config file from a string.
 *
 * NOTE: This will modify @from_string.
 * Pass a copy of source string if original
 * contents must be preserved
 **/
config_file_t *config_file_new_from_string(char *from_string,
      const char *path);

config_file_t *config_file_new_from_path_to_string(const char *path);

/**
 * config_file_free:
 *
 * Frees config file.
 **/
void config_file_free(config_file_t *conf);

size_t config_file_add_reference(config_file_t *conf, char *path);

bool config_file_deinitialize(config_file_t *conf);

/**
 * config_append_file:
 *
 * Loads a new config, and appends its data to @conf.
 * The key-value pairs of the new config file takes priority over the old.
 **/
bool config_append_file(config_file_t *conf, const char *path);

/* All extract functions return true when value is valid and exists.
 * Returns false otherwise. */

struct config_entry_list
{
   char *key;
   char *value;
   struct config_entry_list *next;
   /* If we got this from an #include,
    * do not allow overwrite. */
   bool readonly;
};

struct config_file_entry
{
   const char *key;
   const char *value;
   /* Used intentionally. Opaque here. */
   const struct config_entry_list *next;
};

struct config_entry_list *config_get_entry(
      const config_file_t *conf, const char *key);

/**
 * config_get_entry_list_head:
 *
 * Leaf function.
 **/
bool config_get_entry_list_head(config_file_t *conf,
      struct config_file_entry *entry);

/**
 * config_get_entry_list_next:
 *
 * Leaf function.
 **/
bool config_get_entry_list_next(struct config_file_entry *entry);

/**
 * config_get_double:
 *
 * Extracts a double from config file.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 * - Calls strtod
 *
 * @return True if double found, otherwise false.
 **/
bool config_get_double(config_file_t *conf, const char *entry, double *in);

/**
 * config_get_float:
 *
 * Extracts a float from config file.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 * - Calls strtod
 *
 * @return true if found, otherwise false.
 **/
bool config_get_float(config_file_t *conf, const char *entry, float *in);

/* Extracts an int from config file. */
bool config_get_int(config_file_t *conf, const char *entry, int *in);

/* Extracts an uint from config file. */
bool config_get_uint(config_file_t *conf, const char *entry, unsigned *in);

/* Extracts an size_t from config file. */
bool config_get_size_t(config_file_t *conf, const char *key, size_t *in);

#if defined(__STDC_VERSION__) &amp;&amp; __STDC_VERSION__&gt;=199901L
/* Extracts an uint64 from config file. */
bool config_get_uint64(config_file_t *conf, const char *entry, uint64_t *in);
#endif

/* Extracts an unsigned int from config file treating input as hex. */
bool config_get_hex(config_file_t *conf, const char *entry, unsigned *in);

/**
 * config_get_char:
 *
 * Extracts a single char from config file.
 * If value consists of several chars, this is an error.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 *
 * @return true if found, otherwise false.
 **/
bool config_get_char(config_file_t *conf, const char *entry, char *in);

/**
 * config_get_string:
 *
 * Extracts an allocated string in *in. This must be free()-d if
 * this function succeeds.
 *
 * Hidden non-leaf function cost:
 * - Calls config_get_entry()
 * - Calls strdup
 *
 * @return true if found, otherwise false.
 **/
bool config_get_string(config_file_t *conf, const char *entry, char **in);

/* Extracts a string to a preallocated buffer. Avoid memory allocation. */
bool config_get_array(config_file_t *conf, const char *entry, char *s, size_t len);

/**
  * config_get_config_path:
  *
  * Extracts a string to a preallocated buffer.
  * Avoid memory allocation.
  *
  * Hidden non-leaf function cost:
  * - Calls strlcpy
  **/
size_t config_get_config_path(config_file_t *conf, char *s, size_t len);

/* Extracts a string to a preallocated buffer. Avoid memory allocation.
 * Recognized magic like ~/. Similar to config_get_array() otherwise. */
bool config_get_path(config_file_t *conf, const char *entry, char *s, size_t len);

/**
 * config_get_bool:
 *
 * Extracts a boolean from config.
 * Valid boolean true are "true" and "1". Valid false are "false" and "0".
 * Other values will be treated as an error.
 *
 * Hidden non-leaf function cost:
 * - Calls string_is_equal() x times
 *
 * @return true if preconditions are true, otherwise false.
 **/
bool config_get_bool(config_file_t *conf, const char *entry, bool *in);

/* Setters. Similar to the getters.
 * Will not write to entry if the entry was obtained from an #include. */
size_t config_set_double(config_file_t *conf, const char *entry, double value);
size_t config_set_float(config_file_t *conf, const char *entry, float value);
size_t config_set_int(config_file_t *conf, const char *entry, int val);
size_t config_set_hex(config_file_t *conf, const char *entry, unsigned val);
size_t config_set_uint64(config_file_t *conf, const char *entry, uint64_t val);
size_t config_set_char(config_file_t *conf, const char *entry, char val);
size_t config_set_uint(config_file_t *conf, const char *key, unsigned int val);

void config_set_path(config_file_t *conf, const char *entry, const char *val);
void config_set_string(config_file_t *conf, const char *entry, const char *val);
void config_unset(config_file_t *conf, const char *key);

/**
 * config_file_write:
 *
 * Write the current config to a file.
 **/
bool config_file_write(config_file_t *conf, const char *path, bool val);

/**
 * config_file_dump:
 *
 * Dump the current config to an already opened file.
 * Does not close the file.
 **/
void config_file_dump(config_file_t *conf, FILE *file, bool val);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/file/config_file_userdata.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_userdata.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H
#define _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H

#include &lt;string.h&gt;

#include &lt;file/config_file.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

struct config_file_userdata
{
   config_file_t *conf;
   const char *prefix[2];
};

int config_userdata_get_float(void *userdata, const char *key_str,
      float *value, float default_value);

int config_userdata_get_int(void *userdata, const char *key_str,
      int *value, int default_value);

int config_userdata_get_hex(void *userdata, const char *key_str,
      unsigned *value, unsigned default_value);

int config_userdata_get_float_array(void *userdata, const char *key_str,
      float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values);

int config_userdata_get_int_array(void *userdata, const char *key_str,
      int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values);

int config_userdata_get_string(void *userdata, const char *key_str,
      char **output, const char *default_output);

void config_userdata_free(void *ptr);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/file/file_path.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_path.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FILE_PATH_H
#define __LIBRETRO_SDK_FILE_PATH_H

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;sys/types.h&gt;

#include &lt;libretro.h&gt;
#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

#define PATH_REQUIRED_VFS_VERSION 3

void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);

/* Order in this enum is equivalent to negative sort order in filelist
 *  (i.e. DIRECTORY is on top of PLAIN_FILE) */
enum
{
   RARCH_FILETYPE_UNSET,
   RARCH_PLAIN_FILE,
   RARCH_COMPRESSED_FILE_IN_ARCHIVE,
   RARCH_COMPRESSED_ARCHIVE,
   RARCH_DIRECTORY,
   RARCH_FILE_UNSUPPORTED
};

struct path_linked_list
{
   char *path;
   struct path_linked_list *next;
};

/**
 * Create a new linked list with one item in it
 * The path on this item will be set to NULL
**/
struct path_linked_list* path_linked_list_new(void);

/* Free the entire linked list */
void path_linked_list_free(struct path_linked_list *in_path_linked_list);

/**
 * Add a node to the linked list with this path
 * If the first node's path if it's not yet set,
 * set this instead
**/
void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);

/**
 * path_is_compressed_file:
 * @path               : path
 *
 * Checks if path is a compressed file.
 *
 * Returns: true (1) if path is a compressed file, otherwise false (0).
 **/
bool path_is_compressed_file(const char *path);

/**
 * path_contains_compressed_file:
 * @path               : path
 *
 * Checks if path contains a compressed file.
 *
 * Currently we only check for hash symbol (#) inside the pathname.
 * If path is ever expanded to a general URI, we should check for that here.
 *
 * Example:  Somewhere in the path there might be a compressed file
 * E.g.: /path/to/file.7z#mygame.img
 *
 * Returns: true (1) if path contains compressed file, otherwise false (0).
 **/
#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)

/**
 * path_get_archive_delim:
 * @path               : path
 *
 * Find delimiter of an archive file. Only the first '#'
 * after a compression extension is considered.
 *
 * @return pointer to the delimiter in the path if it contains
 * a path inside a compressed file, otherwise NULL.
 **/
const char *path_get_archive_delim(const char *path);

/**
 * path_get_extension:
 * @path               : path
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * Hidden non-leaf function cost:
 * - calls string_is_empty()
 * - calls strrchr
 *
 * @return extension part from the path.
 **/
const char *path_get_extension(const char *path);

/**
 * path_get_extension_mutable:
 * @path               : path
 *
 * Specialized version of path_get_extension(). Return
 * value is mutable.
 *
 * Gets extension of file. Only '.'s
 * after the last slash are considered.
 *
 * @return extension part from the path.
 **/
char *path_get_extension_mutable(const char *path);

/**
 * path_remove_extension:
 * @path               : path
 *
 * Mutates path by removing its extension. Removes all
 * text after and including the last '.'.
 * Only '.'s after the last slash are considered.
 *
 * Hidden non-leaf function cost:
 * - calls strrchr
 *
 * @return
 * 1) If path has an extension, returns path with the
 *    extension removed.
 * 2) If there is no extension, returns NULL.
 * 3) If path is empty or NULL, returns NULL
 */
char *path_remove_extension(char *path);

/**
 * path_basename:
 * @path               : path
 *
 * Get basename from @path.
 *
 * Hidden non-leaf function cost:
 * - Calls path_get_archive_delim()
 *
 * @return basename from path.
 **/
const char *path_basename(const char *path);

/**
 * path_basename_nocompression:
 * @path               : path
 *
 * Specialized version of path_basename().
 * Get basename from @path.
 *
 * @return basename from path.
 **/
const char *path_basename_nocompression(const char *path);

/**
 * path_basedir:
 * @path               : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 **/
size_t path_basedir(char *path);

/**
 * path_parent_dir:
 * @s                  : path
 * @len                : size of buffer
 *
 * Extracts parent directory by mutating path.
 * Assumes that path is a directory. Keeps trailing '/'.
 * If the path was already at the root directory, returns empty string
 **/
size_t path_parent_dir(char *s, size_t len);

/**
 * path_resolve_realpath:
 * @s                  : input and output buffer for path
 * @size               : size of buffer
 * @resolve_symlinks   : whether to resolve symlinks or not
 *
 * Resolves use of ".", "..", multiple slashes etc in absolute paths.
 *
 * Relative paths are rebased on the current working dir.
 *
 * @return @s if successful, NULL otherwise.
 * Note: Not implemented on consoles
 * Note: Symlinks are only resolved on Unix-likes
 * Note: The current working dir might not be what you expect,
 *       e.g. on Android it is "/"
 *       Use of fill_pathname_resolve_relative() should be preferred
 **/
char *path_resolve_realpath(char *s, size_t len, bool resolve_symlinks);

/**
 * path_relative_to:
 * @s                  : buffer to write the relative path to
 * @path               : path to be expressed relatively
 * @base               : relative to this
 * @len                : size of output buffer
 *
 * Turns @path into a path relative to @base and writes it to @s.
 *
 * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
 * Both @path and @base are assumed to be absolute paths without "." or "..".
 *
 * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
 *
 * @return Length of the string copied into @s
 **/
size_t path_relative_to(char *s, const char *path, const char *base,
      size_t len);

/**
 * path_is_absolute:
 * @path               : path
 *
 * Checks if @path is an absolute path or a relative path.
 *
 * @return true if path is absolute, false if path is relative.
 **/
bool path_is_absolute(const char *path);

/**
 * fill_pathname:
 * @s                  : output path
 * @in_path            : input  path
 * @replace            : what to replace
 * @len                : buffer size of output path
 *
 * FIXME: Verify
 *
 * Replaces filename extension with 'replace' and outputs result to s.
 * The extension here is considered to be the string from the last '.'
 * to the end.
 *
 * Only '.'s after the last slash are considered as extensions.
 * If no '.' is present, in_path and replace will simply be concatenated.
 * 'len' is buffer size of 's'.
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =&gt;
 * s = "/foo/bar/baz/boo.asm"
 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =&gt;
 * s = "/foo/bar/baz/boo"
 *
 * Hidden non-leaf function cost:
 * - calls strlcpy 2x
 * - calls strrchr
 * - calls strlcat
 *
 * @return Length of the string copied into @s
 */
size_t fill_pathname(char *s, const char *in_path,
      const char *replace, size_t len);

/**
 * fill_dated_filename:
 * @s                  : output filename
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by 'RetroArch', and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
 *
 * Hidden non-leaf function cost:
 * - Calls rtime_localtime()
 * - Calls strftime
 * - Calls strlcat
 *
 **/
size_t fill_dated_filename(char *s, const char *ext, size_t len);

/**
 * fill_str_dated_filename:
 * @s                  : output filename
 * @in_str             : input string
 * @ext                : extension of output filename
 * @len                : buffer size of output filename
 *
 * Creates a 'dated' filename prefixed by the string @in_str, and
 * concatenates extension (@ext) to it.
 *
 * E.g.:
 * s = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
 *
 * Hidden non-leaf function cost:
 * - Calls time
 * - Calls rtime_localtime()
 * - Calls strlcpy 2x
 * - Calls string_is_empty()
 * - Calls strftime
 * - Calls strlcat
 *
 * @return Length of the string copied into @s
 **/
size_t fill_str_dated_filename(char *s, const char *in_str, const char *ext, size_t len);

/**
 * find_last_slash:
 * @str                : path
 *
 * Find last slash in path. Tries to find
 * a backslash on Windows too which takes precedence
 * over regular slash.

 * Hidden non-leaf function cost:
 * - calls strrchr
 *
 * @return pointer to last slash/backslash found in @str.
 **/
char *find_last_slash(const char *str);

/**
 * fill_pathname_dir:
 * @s                  : input directory path
 * @in_basename        : input basename to be appended to @s
 * @replace            : replacement to be appended to @in_basename
 * @len                : size of buffer
 *
 * Appends basename of 'in_basename', to 's', along with 'replace'.
 * Basename of in_basename is the string after the last '/' or '\\',
 * i.e the filename without directories.
 *
 * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
 * 'len' is buffer size of 's'.
 *
 * E.g..: s = "/tmp/some_dir", in_basename = "/some_content/foo.c",
 * replace = ".asm" =&gt; s = "/tmp/some_dir/foo.c.asm"
 *
 * Hidden non-leaf function cost:
 * - Calls fill_pathname_slash()
 * - Calls path_basename()
 * - Calls strlcpy 2x
 **/
size_t fill_pathname_dir(char *s, const char *in_basename,
      const char *replace, size_t len);

/**
 * fill_pathname_base:
 * @s                  : output path
 * @in_path            : input path
 * @len                : size of output path
 *
 * Copies basename of @in_path into @s.
 *
 * Hidden non-leaf function cost:
 * - Calls path_basename()
 * - Calls strlcpy
 *
 * @return length of the string copied into @s
 **/
size_t fill_pathname_base(char *s, const char *in_path, size_t len);

/**
 * fill_pathname_basedir:
 * @s                  : output directory
 * @in_path            : input path
 * @len                : size of output directory
 *
 * Copies base directory of @in_path into @s.
 * If in_path is a path without any slashes (relative current directory),
 * @s will get path "./".
 *
 * Hidden non-leaf function cost:
 * - Calls strlcpy
 * - Calls path_basedir()
 **/
size_t fill_pathname_basedir(char *s, const char *in_path, size_t len);

/**
 * fill_pathname_parent_dir_name:
 * @s                  : output string
 * @in_dir             : input directory
 * @len                : size of @s
 *
 * Copies only the parent directory name of @in_dir into @s.
 * The two buffers must not overlap. Removes trailing '/'.
 *
 * Hidden non-leaf function cost:
 * - Calls strdup
 * - Can call strlcpy
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_parent_dir_name(char *s,
      const char *in_dir, size_t len);

/**
 * fill_pathname_parent_dir:
 * @s                  : output directory
 * @in_dir             : input directory
 * @len                : size of output directory
 *
 * Copies parent directory of @in_dir into @s.
 * Assumes @in_dir is a directory. Keeps trailing '/'.
 * If the path was already at the root directory, @s will be an empty string.
 *
 * Hidden non-leaf function cost:
 * - Can call strlcpy if (@s!= @in_dir)
 * - Calls strlen if (@s == @in_dir)
 * - Calls path_parent_dir()
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_parent_dir(char *s,
      const char *in_dir, size_t len);

/**
 * fill_pathname_resolve_relative:
 * @s                  : output path
 * @in_refpath         : input reference path
 * @in_path            : input path
 * @len                : size of @s
 *
 * Joins basedir of @in_refpath together with @in_path.
 * If @in_path is an absolute path, s = in_path.
 * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
 * s = "/foo/bar/foobar.cg".
 **/
void fill_pathname_resolve_relative(char *s, const char *in_refpath,
      const char *in_path, size_t len);

/**
 * fill_pathname_join:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get two consecutive slashes
 * between directory and path.
 *
 * Hidden non-leaf function cost:
 * - calls strlcpy at least once
 * - calls fill_pathname_slash()
 *
 * Deprecated. Use fill_pathname_join_special() instead
 * if you can ensure @dir != @s
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join(char *s, const char *dir,
      const char *path, size_t len);

/**
 * fill_pathname_join_special:
 * @s                  : output path
 * @dir                : directory. Cannot be identical to @s
 * @path               : path
 * @len                : size of output path
 *
 *
 * Specialized version of fill_pathname_join.
 * Unlike fill_pathname_join(),
 * @dir and @s CANNOT be identical.
 *
 * Joins a directory (@dir) and path (@path) together.
 * Makes sure not to get two consecutive slashes
 * between directory and path.
 *
 * Hidden non-leaf function cost:
 * - calls strlcpy 2x
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_join_special(char *s,
      const char *dir, const char *path, size_t len);

size_t fill_pathname_join_special_ext(char *s,
      const char *dir,  const char *path,
      const char *last, const char *ext,
      size_t len);

/**
 * fill_pathname_join_delim:
 * @s                  : output path
 * @dir                : directory
 * @path               : path
 * @delim              : delimiter
 * @len                : size of output path
 *
 * Joins a directory (@dir) and path (@path) together
 * using the given delimiter (@delim).
 *
 * Hidden non-leaf function cost:
 * - can call strlen
 * - can call strlcpy
 * - can call strlcat
 **/
size_t fill_pathname_join_delim(char *s, const char *dir,
      const char *path, const char delim, size_t len);

size_t fill_pathname_expand_special(char *s,
      const char *in_path, size_t len);

size_t fill_pathname_abbreviate_special(char *s,
      const char *in_path, size_t len);

/**
 * fill_pathname_abbreviated_or_relative:
 *
 * Fills the supplied path with either the abbreviated path or
 * the relative path, which ever one has less depth / number of slashes
 *
 * If lengths of abbreviated and relative paths are the same,
 * the relative path will be used
 * @in_path can be an absolute, relative or abbreviated path
 *
 * @return Length of the string copied into @s
 **/
size_t fill_pathname_abbreviated_or_relative(char *s,
		const char *in_refpath, const char *in_path, size_t len);

/**
 * sanitize_path_part:
 *
 * @path_part          : directory or filename
 * @len                : length of path_part
 *
 * Takes single part of a path eg. single filename
 * or directory, and removes any special chars that are
 * unavailable.
 *
 * @returns new string that has been sanitized
 **/
const char *sanitize_path_part(const char *path_part, size_t len);

/**
 * pathname_conform_slashes_to_os:
 *
 * @path               : path
 *
 * Leaf function.
 *
 * Changes the slashes to the correct kind for the os
 * So forward slash on linux and backslash on Windows
 **/
void pathname_conform_slashes_to_os(char *s);

/**
 * pathname_make_slashes_portable:
 * @path               : path
 *
 * Leaf function.
 *
 * Change all slashes to forward so they are more
 * portable between Windows and Linux
 **/
void pathname_make_slashes_portable(char *s);

/**
 * path_basedir:
 * @path               : path
 *
 * Extracts base directory by mutating path.
 * Keeps trailing '/'.
 **/
void path_basedir_wrapper(char *s);

/**
 * path_char_is_slash:
 * @c                  : character
 *
 * Checks if character (@c) is a slash.
 *
 * @return true if character is a slash, otherwise false.
 **/
#ifdef _WIN32
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else
#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
#endif

/**
 * path_default_slash and path_default_slash_c:
 *
 * Gets the default slash separator.
 *
 * @return default slash separator.
 **/
#ifdef _WIN32
#define PATH_DEFAULT_SLASH() "\\"
#define PATH_DEFAULT_SLASH_C() '\\'
#else
#define PATH_DEFAULT_SLASH() "/"
#define PATH_DEFAULT_SLASH_C() '/'
#endif

/**
 * fill_pathname_slash:
 * @s                  : path
 * @len                : size of path
 *
 * Assumes path is a directory. Appends a slash
 * if not already there.

 * Hidden non-leaf function cost:
 * - can call strlcat once if it returns false
 * - calls strlen
 **/
size_t fill_pathname_slash(char *s, size_t len);

#if !defined(RARCH_CONSOLE) &amp;&amp; defined(RARCH_INTERNAL)
size_t fill_pathname_application_path(char *s, size_t len);
size_t fill_pathname_application_dir(char *s, size_t len);
size_t fill_pathname_home_dir(char *s, size_t len);
#endif

/**
 * path_mkdir:
 * @dir                : directory
 *
 * Create directory on filesystem.
 *
 * Recursive function.
 *
 * Hidden non-leaf function cost:
 * - Calls strdup
 * - Calls path_parent_dir()
 * - Calls strcmp
 * - Calls path_is_directory()
 * - Calls path_mkdir()
 *
 * @return true if directory could be created, otherwise false.
 **/
bool path_mkdir(const char *dir);

/**
 * path_is_directory:
 * @path               : path
 *
 * Checks if path is a directory.
 *
 * @return true if path is a directory, otherwise false.
 */
bool path_is_directory(const char *path);

/* Time format strings with AM-PM designation require special
 * handling due to platform dependence
 * @return Length of the string written to @s
 */
size_t strftime_am_pm(char *s, size_t len, const char* format,
      const void* timeptr);

bool path_is_character_special(const char *path);

int path_stat(const char *path);

bool path_is_valid(const char *path);

int32_t path_get_size(const char *path);

bool is_path_accessible_using_standard_io(const char *path);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/file/nbio.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nbio.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_NBIO_H
#define __LIBRETRO_SDK_NBIO_H

#include &lt;stddef.h&gt;
#include &lt;boolean.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#ifndef NBIO_READ
#define NBIO_READ   0
#endif

#ifndef NBIO_WRITE
#define NBIO_WRITE  1
#endif

#ifndef NBIO_UPDATE
#define NBIO_UPDATE 2
#endif

/* these two are blocking; nbio_iterate always returns true, but that operation (or something earlier) may take arbitrarily long */
#ifndef BIO_READ
#define BIO_READ    3
#endif

#ifndef BIO_WRITE
#define BIO_WRITE   4
#endif

typedef struct nbio_intf
{
   void *(*open)(const char * filename, unsigned mode);

   void (*begin_read)(void *data);

   void (*begin_write)(void *data);

   bool (*iterate)(void *data);

   void (*resize)(void *data, size_t len);

   void *(*get_ptr)(void *data, size_t* len);

   void (*cancel)(void *data);

   void (*free)(void *data);

   /* Human readable string. */
   const char *ident;
} nbio_intf_t;

/*
 * Creates an nbio structure for performing the
 * given operation on the given file.
 */
void *nbio_open(const char * filename, unsigned mode);

/*
 * Starts reading the given file. When done, it will be available in nbio_get_ptr.
 * Can not be done if the structure was created with {N,}BIO_WRITE.
 */
void nbio_begin_read(void *data);

/*
 * Starts writing to the given file. Before this, you should've copied the data to nbio_get_ptr.
 * Can not be done if the structure was created with {N,}BIO_READ.
 */
void nbio_begin_write(void *data);

/*
 * Performs part of the requested operation, or checks how it's going.
 * When it returns true, it's done.
 */
bool nbio_iterate(void *data);

/*
 * Resizes the file up to the given size; cannot shrink.
 * Can not be done if the structure was created with {N,}BIO_READ.
 */
void nbio_resize(void *data, size_t len);

/*
 * Returns a pointer to the file data. Writable only if structure was not created with {N,}BIO_READ.
 * If any operation is in progress, the pointer will be NULL, but len will still be correct.
 */
void* nbio_get_ptr(void *data, size_t* len);

/*
 * Stops any pending operation, allowing the object to be freed.
 */
void nbio_cancel(void *data);

/*
 * Deletes the nbio structure and its associated pointer.
 */
void nbio_free(void *data);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/filters.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (filters.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILTERS_H
#define _LIBRETRO_SDK_FILTERS_H

/* for MSVC; should be benign under any circumstances */
#define _USE_MATH_DEFINES

#include &lt;stdlib.h&gt;
#include &lt;math.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;retro_math.h&gt;

/**
 * sinc:
 *
 * Pure function.
 **/
static INLINE double sinc(double val)
{
   if (fabs(val) &lt; 0.00001)
      return 1.0;
   return sin(val) / val;
}

/**
 * paeth:
 *
 * Pure function.
 * Paeth prediction filter.
 **/
static INLINE int paeth(int a, int b, int c)
{
   int p  = a + b - c;
   int pa = abs(p - a);
   int pb = abs(p - b);
   int pc = abs(p - c);

   if (pa &lt;= pb &amp;&amp; pa &lt;= pc)
      return a;
   else if (pb &lt;= pc)
      return b;
   return c;
}

/**
 * besseli0:
 *
 * Pure function.
 *
 * Modified Bessel function of first order.
 * Check Wiki for mathematical definition ...
 **/
static INLINE double besseli0(double x)
{
   int i;
   double sum            = 0.0;
   double factorial      = 1.0;
   double factorial_mult = 0.0;
   double x_pow          = 1.0;
   double two_div_pow    = 1.0;
   double x_sqr          = x * x;

   /* Approximate. This is an infinite sum.
    * Luckily, it converges rather fast. */
   for (i = 0; i &lt; 18; i++)
   {
      sum            += x_pow * two_div_pow / (factorial * factorial);
      factorial_mult += 1.0;
      x_pow          *= x_sqr;
      two_div_pow    *= 0.25;
      factorial      *= factorial_mult;
   }

   return sum;
}

static INLINE double kaiser_window_function(double index, double beta)
{
   return besseli0(beta * sqrtf(1 - index * index));
}

#endif</pre>
<h2>./include/libretro-common/include/formats/cdfs.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (cdfs.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RARCH_CDFS_H
#define __RARCH_CDFS_H

#include &lt;streams/interface_stream.h&gt;

RETRO_BEGIN_DECLS

/* these functions provide an interface for locating and reading files within a data track
 * of a CD (following the ISO-9660 directory structure definition)
 */

typedef struct cdfs_track_t
{
   intfstream_t* stream;
   unsigned int stream_sector_size;
   unsigned int stream_sector_header_size;
   unsigned int first_sector_offset;
   unsigned int first_sector_index;
} cdfs_track_t;

typedef struct cdfs_file_t
{
   struct cdfs_track_t* track;
   int first_sector;
   int current_sector;
   int sector_buffer_valid;
   unsigned int current_sector_offset;
   unsigned int size;
   unsigned int pos;
   uint8_t sector_buffer[2048];
} cdfs_file_t;

/* opens the specified file within the CD or virtual CD.
 * if path is NULL, will open the raw CD (useful for 
 * reading CD without having to worry about sector sizes,
 * headers, or checksum data)
 */
int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* stream, const char* path);

void cdfs_close_file(cdfs_file_t* file);

int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len);

int64_t cdfs_get_size(cdfs_file_t* file);

int64_t cdfs_tell(cdfs_file_t* file);

int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence);

void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector);

uint32_t cdfs_get_num_sectors(cdfs_file_t* file);

uint32_t cdfs_get_first_sector(cdfs_file_t* file);

/* opens the specified track in a CD or virtual CD file - the resulting stream should be passed to
 * cdfs_open_file to get access to a file within the CD.
 *
 * supported files:
 *   real CD - path will be in the form "cdrom://drive1.cue" or "cdrom://d:/drive.cue"
 *   bin/cue - path will point to the cue file
 *   chd     - path will point to the chd file
 *
 * for bin/cue files, the following storage modes are supported:
 *   MODE2/2352
 *   MODE1/2352
 *   MODE1/2048 - untested
 *   MODE2/2336 - untested
 */
cdfs_track_t* cdfs_open_track(const char* path, unsigned int track_index);

/* opens the first data track in a CD or virtual CD file. see cdfs_open_track for supported file formats
 */
cdfs_track_t* cdfs_open_data_track(const char* path);

/* opens a raw track file for a CD or virtual CD.
 *
 * supported files:
 *   real CD - path will be in the form "cdrom://drive1-track01.bin" or "cdrom://d:/drive-track01.bin"
 *             NOTE: cue file for CD must be opened first to populate vfs_cdrom_toc.
 *   bin     - path will point to the bin file
 *   iso     - path will point to the iso file
 */
cdfs_track_t* cdfs_open_raw_track(const char* path);

/* closes the CD or virtual CD track and frees the associated memory */
void cdfs_close_track(cdfs_track_t* track);

RETRO_END_DECLS

#endif /* __RARCH_CDFS_H */</pre>
<h2>./include/libretro-common/include/formats/image.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (image.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RARCH_IMAGE_CONTEXT_H
#define __RARCH_IMAGE_CONTEXT_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

enum image_process_code
{
   IMAGE_PROCESS_ERROR     = -2,
   IMAGE_PROCESS_ERROR_END = -1,
   IMAGE_PROCESS_NEXT      =  0,
   IMAGE_PROCESS_END       =  1
};

struct texture_image
{
   uint32_t *pixels;
   unsigned width;
   unsigned height;
   bool supports_rgba;
};

enum image_type_enum
{
   IMAGE_TYPE_NONE = 0,
   IMAGE_TYPE_PNG,
   IMAGE_TYPE_JPEG,
   IMAGE_TYPE_BMP,
   IMAGE_TYPE_TGA
};

enum image_type_enum image_texture_get_type(const char *path);

bool image_texture_set_color_shifts(unsigned *r_shift, unsigned *g_shift,
      unsigned *b_shift, unsigned *a_shift,
      struct texture_image *out_img);

bool image_texture_color_convert(unsigned r_shift,
      unsigned g_shift, unsigned b_shift, unsigned a_shift,
      struct texture_image *out_img);

bool image_texture_load_buffer(struct texture_image *img,
   enum image_type_enum type, void *s, size_t len);

bool image_texture_load(struct texture_image *img, const char *path);
void image_texture_free(struct texture_image *img);

/* Image transfer */

void image_transfer_free(void *data, enum image_type_enum type);

void *image_transfer_new(enum image_type_enum type);

bool image_transfer_start(void *data, enum image_type_enum type);

void image_transfer_set_buffer_ptr(
      void *data,
      enum image_type_enum type,
      void *ptr,
      size_t len);

int image_transfer_process(
      void *data,
      enum image_type_enum type,
      uint32_t **buf,
      size_t len,
      unsigned *width,
      unsigned *height);

bool image_transfer_iterate(void *data, enum image_type_enum type);

bool image_transfer_is_valid(void *data, enum image_type_enum type);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/logiqx_dat.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (logiqx_dat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__
#define __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__

#include &lt;retro_common_api.h&gt;
#include &lt;retro_miscellaneous.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

/* Trivial handler for DAT files in Logiqx XML format
 * (http://www.logiqx.com/). Provides bare minimum
 * functionality - predominantly concerned with obtaining
 * description text for specific arcade ROM images.
 *
 * Note: Also supports the following alternative DAT
 * formats, since they are functionally identical to
 * Logiqx XML (but with different element names):
 * &gt; MAME List XML
 * &gt; MAME 'Software List' */

/* Prevent direct access to logiqx_dat_t members */
typedef struct logiqx_dat logiqx_dat_t;

/* Holds all metadata for a single game entry
 * in the DAT file (minimal at present - may be
 * expanded with individual internal ROM data
 * if required) */
typedef struct
{
   char name[NAME_MAX_LENGTH];
   char description[NAME_MAX_LENGTH];
   char year[8];
   char manufacturer[128];
   bool is_bios;
   bool is_runnable;
} logiqx_dat_game_info_t;

/* Validation */

/* Performs rudimentary validation of the specified
 * Logiqx XML DAT file path (not rigorous - just
 * enough to prevent obvious errors).
 * Also provides access to file size (DAT files can
 * be very large, so it is useful to have this information
 * on hand - i.e. so we can check that the system has
 * enough free memory to load the file). */
bool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size);

/* File initialisation/de-initialisation */

/* Loads specified Logiqx XML DAT file from disk.
 * Returned logiqx_dat_t object must be free'd using
 * logiqx_dat_free().
 * Returns NULL if file is invalid or a read error
 * occurs. */
logiqx_dat_t *logiqx_dat_init(const char *path);

/* Frees specified DAT file */
void logiqx_dat_free(logiqx_dat_t *dat_file);

/* Game information access */

/* Sets/resets internal node pointer to the first
 * entry in the DAT file */
void logiqx_dat_set_first(logiqx_dat_t *dat_file);

/* Fetches game information for the current entry
 * in the DAT file and increments the internal node
 * pointer.
 * Returns false if the end of the DAT file has been
 * reached (in which case 'game_info' will be invalid) */
bool logiqx_dat_get_next(
      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info);

/* Fetches information for the specified game.
 * Returns false if game does not exist, or arguments
 * are invalid. */
bool logiqx_dat_search(
      logiqx_dat_t *dat_file, const char *game_name,
      logiqx_dat_game_info_t *game_info);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/m3u_file.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (m3u_file.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_M3U_FILE_H__
#define __LIBRETRO_SDK_FORMAT_M3U_FILE_H__

#include &lt;retro_common_api.h&gt;

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

/* Trivial handler for M3U playlist files */

/* M3U file extension */
#define M3U_FILE_EXT "m3u"

/* Prevent direct access to m3u_file_t members */
typedef struct content_m3u_file m3u_file_t;

/* Holds all metadata for a single M3U file entry */
typedef struct
{
   char *path;
   char *full_path;
   char *label;
} m3u_file_entry_t;

/* Defines entry label formatting when
 * writing M3U files to disk */
enum m3u_file_label_type
{
   M3U_FILE_LABEL_NONE = 0,
   M3U_FILE_LABEL_NONSTD,
   M3U_FILE_LABEL_EXTSTD,
   M3U_FILE_LABEL_RETRO
};

/* File Initialisation / De-Initialisation */

/* Creates and initialises an M3U file
 * - If 'path' refers to an existing file,
 *   contents is parsed
 * - If path does not exist, an empty M3U file
 *   is created
 * - Returned m3u_file_t object must be free'd using
 *   m3u_file_free()
 * - Returns NULL in the event of an error */
m3u_file_t *m3u_file_init(const char *path);

/* Frees specified M3U file */
void m3u_file_free(m3u_file_t *m3u_file);

/* Getters */

/* Returns M3U file path */
char *m3u_file_get_path(m3u_file_t *m3u_file);

/* Returns number of entries in M3U file */
size_t m3u_file_get_size(m3u_file_t *m3u_file);

/* Fetches specified M3U file entry
 * - Returns false if 'idx' is invalid, or internal
 *   entry is NULL */
bool m3u_file_get_entry(
      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry);

/* Setters */

/* Adds specified entry to the M3U file
 * - Returns false if path is invalid, or
 *   memory could not be allocated for the
 *   entry */
bool m3u_file_add_entry(
      m3u_file_t *m3u_file, const char *path, const char *label);

/* Removes all entries in M3U file */
void m3u_file_clear(m3u_file_t *m3u_file);

/* Saving */

/* Saves M3U file to disk
 * - Setting 'label_type' to M3U_FILE_LABEL_NONE
 *   just outputs entry paths - this the most
 *   common format supported by most cores
 * - Returns false in the event of an error */
bool m3u_file_save(
      m3u_file_t *m3u_file, enum m3u_file_label_type label_type);

/* Utilities */

/* Sorts M3U file entries in alphabetical order */
void m3u_file_qsort(m3u_file_t *m3u_file);

/* Returns true if specified path corresponds
 * to an M3U file (simple convenience function) */
bool m3u_file_is_m3u(const char *path);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rbmp.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rbmp.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RBMP_H__
#define __LIBRETRO_SDK_FORMAT_RBMP_H__

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

enum rbmp_source_type
{
   RBMP_SOURCE_TYPE_DONT_CARE,
   RBMP_SOURCE_TYPE_BGR24,
   RBMP_SOURCE_TYPE_XRGB888,
   RBMP_SOURCE_TYPE_RGB565,
   RBMP_SOURCE_TYPE_ARGB8888
};

typedef struct rbmp rbmp_t;

bool rbmp_save_image(
      const char *filename,
      const void *frame,
      unsigned width,
      unsigned height,
      unsigned pitch,
      enum rbmp_source_type type);

int rbmp_process_image(rbmp_t *rbmp, void **buf,
      size_t size, unsigned *width, unsigned *height);

void form_bmp_header(uint8_t *header,
      unsigned width, unsigned height,
      bool is32bpp);

bool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data);

void rbmp_free(rbmp_t *rbmp);

rbmp_t *rbmp_alloc(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rjpeg.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjpeg.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RJPEG_H__
#define __LIBRETRO_SDK_FORMAT_RJPEG_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

typedef struct rjpeg rjpeg_t;

int rjpeg_process_image(rjpeg_t *rjpeg, void **buf,
      size_t size, unsigned *width, unsigned *height);

bool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data);

void rjpeg_free(rjpeg_t *rjpeg);

rjpeg_t *rjpeg_alloc(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rjson.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjson.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RJSON_H__
#define __LIBRETRO_SDK_FORMAT_RJSON_H__

#include &lt;retro_common_api.h&gt;
#include &lt;boolean.h&gt; /* bool */
#include &lt;stddef.h&gt; /* size_t */

RETRO_BEGIN_DECLS

/* List of possible element types returned by rjson_next */
enum rjson_type
{
   RJSON_DONE,
   RJSON_OBJECT, RJSON_ARRAY, RJSON_OBJECT_END, RJSON_ARRAY_END,
   RJSON_STRING, RJSON_NUMBER, RJSON_TRUE, RJSON_FALSE, RJSON_NULL,
   RJSON_ERROR
};

/* Options that can be passed to rjson_set_options */
enum rjson_option
{
   /* Allow UTF-8 byte order marks */
   RJSON_OPTION_ALLOW_UTF8BOM                      = (1&lt;&lt;0),
   /* Allow JavaScript style comments in the stream */
   RJSON_OPTION_ALLOW_COMMENTS                     = (1&lt;&lt;1),
   /* Allow unescaped control characters in strings (bytes 0x00 - 0x1F) */
   RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS = (1&lt;&lt;2),
   /* Ignore invalid Unicode escapes and don't validate UTF-8 codes */
   RJSON_OPTION_IGNORE_INVALID_ENCODING            = (1&lt;&lt;3),
   /* Replace invalid Unicode escapes and UTF-8 codes with a '?' character */
   RJSON_OPTION_REPLACE_INVALID_ENCODING           = (1&lt;&lt;4),
   /* Ignore carriage return (\r escape sequence) in strings */
   RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN      = (1&lt;&lt;5),
   /* Allow data after the end of the top JSON object/array/value */
   RJSON_OPTION_ALLOW_TRAILING_DATA                = (1&lt;&lt;6)
};

/* Custom data input callback
 * Should return &gt; 0 and &lt;= len on success, 0 on file end and &lt; 0 on error. */
typedef int (*rjson_io_t)(void* buf, int len, void *user_data);
typedef struct rjson rjson_t;
struct intfstream_internal;
struct RFILE;

/* Create a new parser instance from various sources */
rjson_t *rjson_open_stream(struct intfstream_internal *stream);
rjson_t *rjson_open_rfile(struct RFILE *rfile);
rjson_t *rjson_open_buffer(const void *buffer, size_t len);
rjson_t *rjson_open_string(const char *string, size_t len);
rjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size);

/* Free the parser instance created with rjson_open_* */
void rjson_free(rjson_t *json);

/* Set one or more enum rjson_option, will override previously set options.
 * Use bitwise OR to concatenate multiple options.
 * By default none of the options are set. */
void rjson_set_options(rjson_t *json, char rjson_option_flags);

/* Sets the maximum context depth, recursion inside arrays and objects.
 * By default this is set to 50. */
void rjson_set_max_depth(rjson_t *json, unsigned int max_depth);

/* Parse to the next JSON element and return the type of it.
 * Will return RJSON_DONE when successfully reaching the end or
 * RJSON_ERROR when an error was encountered. */
enum rjson_type rjson_next(rjson_t *json);

/* Get the current string, null-terminated unescaped UTF-8 encoded.
 * Can only be used when the current element is RJSON_STRING or RJSON_NUMBER.
 * The returned pointer is only valid until the parsing continues. */
const char *rjson_get_string(rjson_t *json, size_t *length);

/* Returns the current number (or string) converted to double or int */
double rjson_get_double(rjson_t *json);
int    rjson_get_int(rjson_t *json);

/* Returns a string describing the error once rjson_next/rjson_parse
 * has returned an unrecoverable RJSON_ERROR (otherwise returns ""). */
const char *rjson_get_error(rjson_t *json);

/* Can be used to set a custom error description on an invalid JSON structure.
 * Maximum length of 79 characters and once set the parsing can't continue. */
void rjson_set_error(rjson_t *json, const char* error);

/* Functions to get the current position in the source stream as well as */
/* a bit of source json around the current position for additional detail
 * when parsing has failed with RJSON_ERROR.
 * Intended to be used with printf style formatting like:
 * printf("Invalid JSON at line %d, column %d - %s - Source: ...%.*s...\n",
 *       (int)rjson_get_source_line(json), (int)rjson_get_source_column(json),
 *       rjson_get_error(json), rjson_get_source_context_len(json),
 *       rjson_get_source_context_buf(json)); */
size_t      rjson_get_source_line(rjson_t *json);
size_t      rjson_get_source_column(rjson_t *json);
int         rjson_get_source_context_len(rjson_t *json);
const char* rjson_get_source_context_buf(rjson_t *json);

/* Confirm the parsing context stack, for example calling
   rjson_check_context(json, 2, RJSON_OBJECT, RJSON_ARRAY)
   returns true when inside "{ [ ..." but not for "[ .." or "{ [ { ..." */
bool rjson_check_context(rjson_t *json, unsigned int depth, ...);

/* Returns the current level of nested objects/arrays */
unsigned int rjson_get_context_depth(rjson_t *json);

/* Return the current parsing context, that is, RJSON_OBJECT if we are inside
 * an object, RJSON_ARRAY if we are inside an array, and RJSON_DONE or
 * RJSON_ERROR if we are not yet/anymore in either. */
enum rjson_type rjson_get_context_type(rjson_t *json);

/* While inside an object or an array, this return the number of parsing
 * events that have already been observed at this level with rjson_next.
 * In particular, inside an object, an odd number would indicate that the just
 * observed RJSON_STRING event is a member name. */
size_t rjson_get_context_count(rjson_t *json);

/* Parse an entire JSON stream with a list of element specific handlers.
 * Each of the handlers can be passed a function or NULL to ignore it.
 * If a handler returns false, the parsing will abort and the returned
 * rjson_type will indicate on which element type parsing was aborted.
 * Otherwise the return value will be RJSON_DONE or RJSON_ERROR. */
enum rjson_type rjson_parse(rjson_t *json, void* context,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context));

/* A simpler interface to parse a JSON in memory. This will avoid any memory
 * allocations unless the document contains strings longer than 512 characters.
 * In the error handler, error will be "" if any of the other handlers aborted. */
bool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,
      bool (*object_member_handler)(void *context, const char *str, size_t len),
      bool (*string_handler       )(void *context, const char *str, size_t len),
      bool (*number_handler       )(void *context, const char *str, size_t len),
      bool (*start_object_handler )(void *context),
      bool (*end_object_handler   )(void *context),
      bool (*start_array_handler  )(void *context),
      bool (*end_array_handler    )(void *context),
      bool (*boolean_handler      )(void *context, bool value),
      bool (*null_handler         )(void *context),
      void (*error_handler        )(void *context, int line, int col, const char* error));

/* ------------------------------------------------------------------------- */

/* Options that can be passed to rjsonwriter_set_options */
enum rjsonwriter_option
{
   /* Don't write spaces, tabs or newlines to the output (except in strings) */
   RJSONWRITER_OPTION_SKIP_WHITESPACE = (1&lt;&lt;0)
};

/* Custom data output callback
 * Should return len on success and &lt; len on a write error. */
typedef int (*rjsonwriter_io_t)(const void* buf, int len, void *user_data);
typedef struct rjsonwriter rjsonwriter_t;

/* Create a new writer instance to various targets */
rjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream);
rjsonwriter_t *rjsonwriter_open_rfile(struct RFILE *rfile);
rjsonwriter_t *rjsonwriter_open_memory(void);
rjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data);

/* When opened with rjsonwriter_open_memory, will return the generated JSON.
 * Result is always null-terminated. Passed len can be NULL if not needed,
 * otherwise returned len will be string length without null-terminator.
 * Returns NULL if writing ran out of memory or not opened from memory.
 * Returned buffer is only valid until writer is modified or freed. */
char* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len);

/* When opened with rjsonwriter_open_memory, will return current length */
int rjsonwriter_count_memory_buffer(rjsonwriter_t *writer);

/* When opened with rjsonwriter_open_memory, will clear the buffer.
   The buffer will be partially erased if keep_len is &gt; 0.
   No memory is freed or re-allocated with this function. */
void rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len);

/* Free rjsonwriter handle and return result of final rjsonwriter_flush call */
bool rjsonwriter_free(rjsonwriter_t *writer);

/* Set one or more enum rjsonwriter_option, will override previously set options.
 * Use bitwise OR to concatenate multiple options.
 * By default none of the options are set. */
void rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags);

/* Flush any buffered output data to the output stream.
 * Returns true if the data was successfully written. Once writing fails once,
 * no more data will be written and flush will always returns false */
bool rjsonwriter_flush(rjsonwriter_t *writer);

/* Returns a string describing an error or "" if there was none.
 * The only error possible is "output error" after the io function failed.
 * If rjsonwriter_rawf were used manually, "out of memory" is also possible. */
const char *rjsonwriter_get_error(rjsonwriter_t *writer);

/* Used by the inline functions below to append raw data */
void rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len);
void rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...);

/* Add a UTF-8 encoded string
 * Special and control characters are automatically escaped.
 * If NULL is passed an empty string will be written (not JSON null). */
void rjsonwriter_add_string(rjsonwriter_t *writer, const char *value);
void rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len);

void rjsonwriter_add_double(rjsonwriter_t *writer, double value);

void rjsonwriter_add_spaces(rjsonwriter_t *writer, int count);

void rjsonwriter_add_tabs(rjsonwriter_t *writer, int count);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rjson_helpers.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rjson.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__
#define __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__

#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt; /* INLINE */
#include &lt;boolean.h&gt; /* bool */
#include &lt;stddef.h&gt; /* size_t */

RETRO_BEGIN_DECLS

/* Functions to add JSON token characters */
static INLINE void rjsonwriter_add_start_object(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "{", 1); }

static INLINE void rjsonwriter_add_end_object(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "}", 1); }

static INLINE void rjsonwriter_add_start_array(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "[", 1); }

static INLINE void rjsonwriter_add_end_array(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "]", 1); }

static INLINE void rjsonwriter_add_colon(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, ":", 1); }

static INLINE void rjsonwriter_add_comma(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, ",", 1); }

/* Functions to add whitespace characters */
/* These do nothing with the option RJSONWRITER_OPTION_SKIP_WHITESPACE */
static INLINE void rjsonwriter_add_newline(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "\n", 1); }

static INLINE void rjsonwriter_add_space(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, " ", 1); }

static INLINE void rjsonwriter_add_tab(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "\t", 1); }

static INLINE void rjsonwriter_add_unsigned(rjsonwriter_t *writer, unsigned value)
      { rjsonwriter_rawf(writer, "%u", value); }

/* Add a signed or unsigned integer or a double number */
static INLINE void rjsonwriter_add_int(rjsonwriter_t *writer, int value)
      { rjsonwriter_rawf(writer, "%d", value); }

static INLINE void rjsonwriter_add_bool(rjsonwriter_t *writer, bool value)
      { rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5)); }

static INLINE void rjsonwriter_add_null(rjsonwriter_t *writer)
      { rjsonwriter_raw(writer, "null", 4); }

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rpng.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RPNG_H__
#define __LIBRETRO_SDK_FORMAT_RPNG_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

typedef struct rpng rpng_t;

rpng_t *rpng_init(const char *path);

bool rpng_is_valid(rpng_t *rpng);

bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len);

rpng_t *rpng_alloc(void);

void rpng_free(rpng_t *rpng);

bool rpng_iterate_image(rpng_t *rpng);

int rpng_process_image(rpng_t *rpng,
      void **data, size_t size, unsigned *width, unsigned *height);

bool rpng_start(rpng_t *rpng);

bool rpng_save_image_argb(const char *path, const uint32_t *data,
      unsigned width, unsigned height, unsigned pitch);
bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
      unsigned width, unsigned height, unsigned pitch);

uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
      unsigned width, unsigned height, signed pitch, uint64_t *bytes);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rtga.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtga.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RTGA_H__
#define __LIBRETRO_SDK_FORMAT_RTGA_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

typedef struct rtga rtga_t;

int rtga_process_image(rtga_t *rtga, void **buf,
      size_t size, unsigned *width, unsigned *height);

bool rtga_set_buf_ptr(rtga_t *rtga, void *data);

void rtga_free(rtga_t *rtga);

rtga_t *rtga_alloc(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rwav.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rwav.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FORMAT_RWAV_H__
#define __LIBRETRO_SDK_FORMAT_RWAV_H__

#include &lt;retro_common_api.h&gt;
#include &lt;stdint.h&gt;

RETRO_BEGIN_DECLS

typedef struct
{
   /* bits per sample */
   unsigned int bitspersample;

   /* number of channels */
   unsigned int numchannels;

   /* sample rate */
   unsigned int samplerate;

   /* number of *samples* */
   size_t numsamples;

   /* number of *bytes* in the pointer below, i.e. numsamples * numchannels * bitspersample/8 */
   size_t subchunk2size;

   /* PCM data */
   const void* samples;
} rwav_t;

enum rwav_state
{
   RWAV_ITERATE_ERROR    = -1,
   RWAV_ITERATE_MORE     = 0,
   RWAV_ITERATE_DONE     = 1,
   RWAV_ITERATE_BUF_SIZE = 4096
};

typedef struct rwav_iterator rwav_iterator_t;

/**
 * Initializes the iterator to fill the out structure with data parsed from buf.
 */
void rwav_init(rwav_iterator_t *iter, rwav_t *out, const void* buf, size_t len);

/**
 * Parses a piece of the data. Continue calling as long as it returns RWAV_ITERATE_MORE.
 * Stop calling otherwise, and check for errors. If RWAV_ITERATE_DONE is returned,
 * the rwav_t structure passed to rwav_init is ready to be used. The iterator does not
 * have to be freed.
 */
enum rwav_state rwav_iterate(rwav_iterator_t *iter);

/**
 * Loads the entire data in one go.
 */
enum rwav_state rwav_load(rwav_t *out, const void *buf, size_t len);

/**
 * Frees parsed wave data.
 */
void rwav_free(rwav_t *rwav);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/formats/rxml.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_FORMAT_RXML_H__
#define __LIBRETRO_SDK_FORMAT_RXML_H__

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/* Total NIH. Very trivial "XML" implementation for use in RetroArch.
 * Error checking is minimal. Invalid documents may lead to very
 * buggy behavior, but memory corruption should never happen.
 *
 * Only parts of standard that RetroArch cares about is supported.
 * Nothing more, nothing less. "Clever" XML documents will
 * probably break the implementation.
 *
 * Do *NOT* try to use this for anything else. You have been warned.
 */

typedef struct rxml_document rxml_document_t;

struct rxml_attrib_node
{
   char *attrib;
   char *value;
   struct rxml_attrib_node *next;
};

typedef struct rxml_node
{
   char *name;
   char *data;
   struct rxml_attrib_node *attrib;

   struct rxml_node *children;
   struct rxml_node *next;
} rxml_node_t;

rxml_document_t *rxml_load_document(const char *path);
rxml_document_t *rxml_load_document_string(const char *str);
void rxml_free_document(rxml_document_t *doc);

struct rxml_node *rxml_root_node(rxml_document_t *doc);

const char *rxml_node_attrib(struct rxml_node *node, const char *attrib);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/gl_capabilities.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gl_capabilities.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _GL_CAPABILITIES_H
#define _GL_CAPABILITIES_H

#include &lt;boolean.h&gt;
#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

enum gl_capability_enum
{
   GL_CAPS_NONE = 0,
   GL_CAPS_EGLIMAGE,
   GL_CAPS_SYNC,
   GL_CAPS_MIPMAP,
   GL_CAPS_VAO,
   GL_CAPS_FBO,
   GL_CAPS_ARGB8,
   GL_CAPS_DEBUG,
   GL_CAPS_PACKED_DEPTH_STENCIL,
   GL_CAPS_ES2_COMPAT,
   GL_CAPS_UNPACK_ROW_LENGTH,
   GL_CAPS_FULL_NPOT_SUPPORT,
   GL_CAPS_SRGB_FBO,
   GL_CAPS_SRGB_FBO_ES3,
   GL_CAPS_FP_FBO,
   GL_CAPS_BGRA8888,
   GL_CAPS_GLES3_SUPPORTED,
   GL_CAPS_TEX_STORAGE,
   GL_CAPS_TEX_STORAGE_EXT
};

bool gl_query_core_context_in_use(void);

void gl_query_core_context_set(bool set);

void gl_query_core_context_unset(void);

bool gl_query_extension(const char *ext);

bool gl_check_error(char **error_string);

bool gl_check_capability(enum gl_capability_enum enum_idx);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/math/matrix_3x3.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (matrix_3x3.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__
#define __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__

#include &lt;boolean.h&gt;
#include &lt;math.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;

RETRO_BEGIN_DECLS

typedef struct math_matrix_3x3
{
   float data[9];
} math_matrix_3x3;

#define MAT_ELEM_3X3(mat, r, c) ((mat).data[3 * (r) + (c)])

#define matrix_3x3_init(mat, n11, n12, n13, n21, n22, n23, n31, n32, n33) \
   MAT_ELEM_3X3(mat, 0, 0) = n11; \
   MAT_ELEM_3X3(mat, 0, 1) = n12; \
   MAT_ELEM_3X3(mat, 0, 2) = n13; \
   MAT_ELEM_3X3(mat, 1, 0) = n21; \
   MAT_ELEM_3X3(mat, 1, 1) = n22; \
   MAT_ELEM_3X3(mat, 1, 2) = n23; \
   MAT_ELEM_3X3(mat, 2, 0) = n31; \
   MAT_ELEM_3X3(mat, 2, 1) = n32; \
   MAT_ELEM_3X3(mat, 2, 2) = n33

#define matrix_3x3_identity(mat) \
   MAT_ELEM_3X3(mat, 0, 0) = 1.0f; \
   MAT_ELEM_3X3(mat, 0, 1) = 0; \
   MAT_ELEM_3X3(mat, 0, 2) = 0; \
   MAT_ELEM_3X3(mat, 1, 0) = 0; \
   MAT_ELEM_3X3(mat, 1, 1) = 1.0f; \
   MAT_ELEM_3X3(mat, 1, 2) = 0; \
   MAT_ELEM_3X3(mat, 2, 0) = 0; \
   MAT_ELEM_3X3(mat, 2, 1) = 0; \
   MAT_ELEM_3X3(mat, 2, 2) = 1.0f

#define matrix_3x3_divide_scalar(mat, s) \
   MAT_ELEM_3X3(mat, 0, 0) /= s; \
   MAT_ELEM_3X3(mat, 0, 1) /= s; \
   MAT_ELEM_3X3(mat, 0, 2) /= s; \
   MAT_ELEM_3X3(mat, 1, 0) /= s; \
   MAT_ELEM_3X3(mat, 1, 1) /= s; \
   MAT_ELEM_3X3(mat, 1, 2) /= s; \
   MAT_ELEM_3X3(mat, 2, 0) /= s; \
   MAT_ELEM_3X3(mat, 2, 1) /= s; \
   MAT_ELEM_3X3(mat, 2, 2) /= s

#define matrix_3x3_transpose(mat, in) \
   MAT_ELEM_3X3(mat, 0, 0) = MAT_ELEM_3X3(in, 0, 0); \
   MAT_ELEM_3X3(mat, 1, 0) = MAT_ELEM_3X3(in, 0, 1); \
   MAT_ELEM_3X3(mat, 2, 0) = MAT_ELEM_3X3(in, 0, 2); \
   MAT_ELEM_3X3(mat, 0, 1) = MAT_ELEM_3X3(in, 1, 0); \
   MAT_ELEM_3X3(mat, 1, 1) = MAT_ELEM_3X3(in, 1, 1); \
   MAT_ELEM_3X3(mat, 2, 1) = MAT_ELEM_3X3(in, 1, 2); \
   MAT_ELEM_3X3(mat, 0, 2) = MAT_ELEM_3X3(in, 2, 0); \
   MAT_ELEM_3X3(mat, 1, 2) = MAT_ELEM_3X3(in, 2, 1); \
   MAT_ELEM_3X3(mat, 2, 2) = MAT_ELEM_3X3(in, 2, 2)

#define matrix_3x3_multiply(out, a, b) \
   MAT_ELEM_3X3(out, 0, 0) =  \
      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 0) + \
      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 0) + \
      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 0); \
   MAT_ELEM_3X3(out, 0, 1) = \
      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 1) + \
      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 1) + \
      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 1); \
   MAT_ELEM_3X3(out, 0, 2) = \
      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 2) + \
      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 2) + \
      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 2); \
   MAT_ELEM_3X3(out, 1, 0) = \
      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 0) + \
      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 0) + \
      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 0); \
   MAT_ELEM_3X3(out, 1, 1) =  \
      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 1) + \
      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 1) + \
      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 1); \
   MAT_ELEM_3X3(out, 1, 2) = \
      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 2) + \
      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 2) + \
      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 2); \
   MAT_ELEM_3X3(out, 2, 0) =  \
      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 0) + \
      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 0) + \
      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 0); \
   MAT_ELEM_3X3(out, 2, 1) = \
      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 1) + \
      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 1) + \
      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 1); \
   MAT_ELEM_3X3(out, 2, 2) =  \
      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 2) + \
      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 2) + \
      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 2)

#define matrix_3x3_determinant(mat) (MAT_ELEM_3X3(mat, 0, 0) * (MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 1)) - MAT_ELEM_3X3(mat, 0, 1) * (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 0)) + MAT_ELEM_3X3(mat, 0, 2) * (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 0)))

#define matrix_3x3_adjoint(mat) \
   MAT_ELEM_3X3(mat, 0, 0) =  (MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 1)); \
   MAT_ELEM_3X3(mat, 0, 1) = -(MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 2, 1)); \
   MAT_ELEM_3X3(mat, 0, 2) =  (MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 1, 1) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 1, 1)); \
   MAT_ELEM_3X3(mat, 1, 0) = -(MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 1, 1) =  (MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 1, 2) = -(MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 1, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 1, 0)); \
   MAT_ELEM_3X3(mat, 2, 0) =  (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 2, 1) = -(MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 2, 0)); \
   MAT_ELEM_3X3(mat, 2, 2) =  (MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 1, 1) - MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 1, 0))

#define FLOATS_ARE_EQUAL(x, y)  (fabs(x - y) &lt;= 0.00001f * ((x) &gt; (y) ? (y) : (x)))
#define FLOAT_IS_ZERO(x)        (FLOATS_ARE_EQUAL((x) + 1, 1))

static INLINE bool matrix_3x3_invert(math_matrix_3x3 *mat)
{
   float det = matrix_3x3_determinant(*mat);

   if (FLOAT_IS_ZERO(det))
      return false;

   matrix_3x3_adjoint(*mat);
   matrix_3x3_divide_scalar(*mat, det);

   return true;
}

static INLINE bool matrix_3x3_square_to_quad(
      const float dx0, const float dy0,
      const float dx1, const float dy1,
      const float dx3, const float dy3,
      const float dx2, const float dy2,
      math_matrix_3x3 *mat)
{
   float a, b, d, e;
   float ax  = dx0 - dx1 + dx2 - dx3;
   float ay  = dy0 - dy1 + dy2 - dy3;
   float c   = dx0;
   float f   = dy0;
   float g   = 0;
   float h   = 0;

   if (FLOAT_IS_ZERO(ax) &amp;&amp; FLOAT_IS_ZERO(ay))
   {
      /* affine case */
      a = dx1 - dx0;
      b = dx2 - dx1;
      d = dy1 - dy0;
      e = dy2 - dy1;
   }
   else
   {
      float ax1 = dx1 - dx2;
      float ax2 = dx3 - dx2;
      float ay1 = dy1 - dy2;
      float ay2 = dy3 - dy2;

      /* determinants */
      float gtop    =  ax  * ay2 - ax2 * ay;
      float htop    =  ax1 * ay  - ax  * ay1;
      float bottom  =  ax1 * ay2 - ax2 * ay1;

      if (!bottom)
         return false;

      g = gtop / bottom;
      h = htop / bottom;

      a = dx1 - dx0 + g * dx1;
      b = dx3 - dx0 + h * dx3;
      d = dy1 - dy0 + g * dy1;
      e = dy3 - dy0 + h * dy3;
   }

   matrix_3x3_init(*mat,
         a, d, g,
         b, e, h,
         c, f, 1.f);

   return true;
}

static INLINE bool matrix_3x3_quad_to_square(
      const float sx0, const float sy0,
      const float sx1, const float sy1,
      const float sx2, const float sy2,
      const float sx3, const float sy3,
      math_matrix_3x3 *mat)
{
   return matrix_3x3_square_to_quad(sx0, sy0, sx1, sy1,
         sx2, sy2, sx3, sy3,
         mat) ? matrix_3x3_invert(mat) : false;
}

static INLINE bool matrix_3x3_quad_to_quad(
      const float dx0, const float dy0,
      const float dx1, const float dy1,
      const float dx2, const float dy2,
      const float dx3, const float dy3,
      const float sx0, const float sy0,
      const float sx1, const float sy1,
      const float sx2, const float sy2,
      const float sx3, const float sy3,
      math_matrix_3x3 *mat)
{
   math_matrix_3x3 square_to_quad;

   if (matrix_3x3_square_to_quad(dx0, dy0, dx1, dy1,
            dx2, dy2, dx3, dy3,
            &amp;square_to_quad))
   {
      math_matrix_3x3 quad_to_square;
      if (matrix_3x3_quad_to_square(sx0, sy0, sx1, sy1,
               sx2, sy2, sx3, sy3,
               &amp;quad_to_square))
      {
         matrix_3x3_multiply(*mat, quad_to_square, square_to_quad);

         return true;
      }
   }

   return false;
}

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/math/matrix_4x4.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (matrix_4x4.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__
#define __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__

#include &lt;retro_common_api.h&gt;

#include &lt;math.h&gt;
#include &lt;gfx/math/vector_3.h&gt;

/* Column-major matrix (OpenGL-style).
 * Reimplements functionality from FF OpenGL pipeline to be able
 * to work on GLES 2.0 and modern GL variants.
 */

#define MAT_ELEM_4X4(mat, row, column) ((mat).data[4 * (column) + (row)])

RETRO_BEGIN_DECLS

typedef struct math_matrix_4x4
{
   float data[16];
} math_matrix_4x4;

#define matrix_4x4_copy(dst, src) \
   MAT_ELEM_4X4(dst, 0, 0) = MAT_ELEM_4X4(src, 0, 0); \
   MAT_ELEM_4X4(dst, 0, 1) = MAT_ELEM_4X4(src, 0, 1); \
   MAT_ELEM_4X4(dst, 0, 2) = MAT_ELEM_4X4(src, 0, 2); \
   MAT_ELEM_4X4(dst, 0, 3) = MAT_ELEM_4X4(src, 0, 3); \
   MAT_ELEM_4X4(dst, 1, 0) = MAT_ELEM_4X4(src, 1, 0); \
   MAT_ELEM_4X4(dst, 1, 1) = MAT_ELEM_4X4(src, 1, 1); \
   MAT_ELEM_4X4(dst, 1, 2) = MAT_ELEM_4X4(src, 1, 2); \
   MAT_ELEM_4X4(dst, 1, 3) = MAT_ELEM_4X4(src, 1, 3); \
   MAT_ELEM_4X4(dst, 2, 0) = MAT_ELEM_4X4(src, 2, 0); \
   MAT_ELEM_4X4(dst, 2, 1) = MAT_ELEM_4X4(src, 2, 1); \
   MAT_ELEM_4X4(dst, 2, 2) = MAT_ELEM_4X4(src, 2, 2); \
   MAT_ELEM_4X4(dst, 2, 3) = MAT_ELEM_4X4(src, 2, 3); \
   MAT_ELEM_4X4(dst, 3, 0) = MAT_ELEM_4X4(src, 3, 0); \
   MAT_ELEM_4X4(dst, 3, 1) = MAT_ELEM_4X4(src, 3, 1); \
   MAT_ELEM_4X4(dst, 3, 2) = MAT_ELEM_4X4(src, 3, 2); \
   MAT_ELEM_4X4(dst, 3, 3) = MAT_ELEM_4X4(src, 3, 3)

/*
 * Sets mat to an identity matrix
 */
#define matrix_4x4_identity(mat) \
   MAT_ELEM_4X4(mat, 0, 0)    = 1.0f; \
   MAT_ELEM_4X4(mat, 0, 1)    = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2)    = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3)    = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0)    = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1)    = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 2)    = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3)    = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0)    = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1)    = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2)    = 1.0f; \
   MAT_ELEM_4X4(mat, 2, 3)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2)    = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3)    = 1.0f

/*
 * Sets out to the transposed matrix of in
 */

#define matrix_4x4_transpose(out, in) \
   MAT_ELEM_4X4(out, 0, 0) = MAT_ELEM_4X4(in, 0, 0); \
   MAT_ELEM_4X4(out, 1, 0) = MAT_ELEM_4X4(in, 0, 1); \
   MAT_ELEM_4X4(out, 2, 0) = MAT_ELEM_4X4(in, 0, 2); \
   MAT_ELEM_4X4(out, 3, 0) = MAT_ELEM_4X4(in, 0, 3); \
   MAT_ELEM_4X4(out, 0, 1) = MAT_ELEM_4X4(in, 1, 0); \
   MAT_ELEM_4X4(out, 1, 1) = MAT_ELEM_4X4(in, 1, 1); \
   MAT_ELEM_4X4(out, 2, 1) = MAT_ELEM_4X4(in, 1, 2); \
   MAT_ELEM_4X4(out, 3, 1) = MAT_ELEM_4X4(in, 1, 3); \
   MAT_ELEM_4X4(out, 0, 2) = MAT_ELEM_4X4(in, 2, 0); \
   MAT_ELEM_4X4(out, 1, 2) = MAT_ELEM_4X4(in, 2, 1); \
   MAT_ELEM_4X4(out, 2, 2) = MAT_ELEM_4X4(in, 2, 2); \
   MAT_ELEM_4X4(out, 3, 2) = MAT_ELEM_4X4(in, 2, 3); \
   MAT_ELEM_4X4(out, 0, 3) = MAT_ELEM_4X4(in, 3, 0); \
   MAT_ELEM_4X4(out, 1, 3) = MAT_ELEM_4X4(in, 3, 1); \
   MAT_ELEM_4X4(out, 2, 3) = MAT_ELEM_4X4(in, 3, 2); \
   MAT_ELEM_4X4(out, 3, 3) = MAT_ELEM_4X4(in, 3, 3)

/*
 * Builds an X-axis rotation matrix
 */
#define matrix_4x4_rotate_x(mat, radians) \
{ \
   float cosine            = cosf(radians); \
   float sine              = sinf(radians); \
   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = cosine; \
   MAT_ELEM_4X4(mat, 1, 2) = -sine; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = sine; \
   MAT_ELEM_4X4(mat, 2, 2) = cosine; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
}

/*
 * Builds a rotation matrix using the
 * rotation around the Y-axis.
 */

#define matrix_4x4_rotate_y(mat, radians) \
{ \
   float cosine            = cosf(radians); \
   float sine              = sinf(radians); \
   MAT_ELEM_4X4(mat, 0, 0) = cosine; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = -sine; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = sine; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = cosine; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
}

/*
 * Builds a rotation matrix using the
 * rotation around the Z-axis.
 */
#define matrix_4x4_rotate_z(mat, radians) \
{ \
   float cosine            = cosf(radians); \
   float sine              = sinf(radians); \
   MAT_ELEM_4X4(mat, 0, 0) = cosine; \
   MAT_ELEM_4X4(mat, 0, 1) = -sine; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = sine; \
   MAT_ELEM_4X4(mat, 1, 1) = cosine; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
}

/*
 * Creates an orthographic projection matrix.
 */
#define matrix_4x4_ortho(mat, left, right, bottom, top, znear, zfar) \
{ \
   float rl                = (right) - (left); \
   float tb                = (top)   - (bottom); \
   float fn                = (zfar)  - (znear); \
   MAT_ELEM_4X4(mat, 0, 0) =  2.0f / rl; \
   MAT_ELEM_4X4(mat, 0, 1) =  0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) =  0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = -((left) + (right))  / rl; \
   MAT_ELEM_4X4(mat, 1, 0) =  0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) =  2.0f / tb; \
   MAT_ELEM_4X4(mat, 1, 2) =  0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = -((top)  + (bottom)) / tb; \
   MAT_ELEM_4X4(mat, 2, 0) =  0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) =  0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = -2.0f / fn; \
   MAT_ELEM_4X4(mat, 2, 3) = -((zfar) + (znear))  / fn; \
   MAT_ELEM_4X4(mat, 3, 0) =  0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) =  0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) =  0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) =  1.0f; \
}

#define matrix_4x4_lookat(out, eye, center, up) \
{ \
   vec3_t zaxis;   /* the "forward" vector */ \
   vec3_t xaxis;   /* the "right"   vector */ \
   vec3_t yaxis;   /* the "up"      vector */ \
   vec3_copy(zaxis, center); \
   vec3_subtract(zaxis, eye); \
   vec3_normalize(zaxis); \
   vec3_cross(xaxis, zaxis, up); \
   vec3_normalize(xaxis); \
   vec3_cross(yaxis, xaxis, zaxis); \
   MAT_ELEM_4X4(out, 0, 0) = xaxis[0]; \
   MAT_ELEM_4X4(out, 0, 1) = yaxis[0]; \
   MAT_ELEM_4X4(out, 0, 2) = -zaxis[0]; \
   MAT_ELEM_4X4(out, 0, 3) = 0.0; \
   MAT_ELEM_4X4(out, 1, 0) = xaxis[1]; \
   MAT_ELEM_4X4(out, 1, 1) = yaxis[1]; \
   MAT_ELEM_4X4(out, 1, 2) = -zaxis[1]; \
   MAT_ELEM_4X4(out, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(out, 2, 0) = xaxis[2]; \
   MAT_ELEM_4X4(out, 2, 1) = yaxis[2]; \
   MAT_ELEM_4X4(out, 2, 2) = -zaxis[2]; \
   MAT_ELEM_4X4(out, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(out, 3, 0) = -(xaxis[0] * eye[0] + xaxis[1] * eye[1] + xaxis[2] * eye[2]); \
   MAT_ELEM_4X4(out, 3, 1) = -(yaxis[0] * eye[0] + yaxis[1] * eye[1] + yaxis[2] * eye[2]); \
   MAT_ELEM_4X4(out, 3, 2) = (zaxis[0] * eye[0] + zaxis[1] * eye[1] + zaxis[2] * eye[2]); \
   MAT_ELEM_4X4(out, 3, 3) = 1.f; \
}

/*
 * Multiplies a with b, stores the result in out
 */

#define matrix_4x4_multiply(out, a, b) \
   MAT_ELEM_4X4(out, 0, 0) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 0, 1) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 0, 2) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 0, 3) =  \
      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 3); \
   MAT_ELEM_4X4(out, 1, 0) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 1, 1) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 1, 2) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 1, 3) =  \
      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 3); \
   MAT_ELEM_4X4(out, 2, 0) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 2, 1) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 2, 2) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 2, 3) =  \
      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 3); \
   MAT_ELEM_4X4(out, 3, 0) =  \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 0) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 0) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 0) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 0); \
   MAT_ELEM_4X4(out, 3, 1) =  \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 1) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 1) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 1) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 1); \
   MAT_ELEM_4X4(out, 3, 2) = \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 2) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 2) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 2) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 2); \
   MAT_ELEM_4X4(out, 3, 3) =  \
      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 3) + \
      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 3) + \
      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 3) + \
      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 3)

#define matrix_4x4_scale(mat, x, y, z) \
   MAT_ELEM_4X4(mat, 0, 0) = x; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = y; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = z; \
   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f

/*
 * Builds a translation matrix. All other elements in
 * the matrix will be set to zero except for the
 * diagonal which is set to 1.0
 */

#define matrix_4x4_translate(mat, x, y, z) \
   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = x; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 2) = 1.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = y; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \
   MAT_ELEM_4X4(mat, 2, 3) = z; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 3) = 1.0f

/*
 * Creates a perspective projection matrix.
 */

#define  matrix_4x4_projection(mat, y_fov, aspect, znear, zfar) \
{ \
   float const a           = 1.f / tan((y_fov) / 2.f); \
   float delta_z           = (zfar) - (znear); \
   MAT_ELEM_4X4(mat, 0, 0) = a / (aspect); \
   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 1) = a; \
   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 2, 2) = -(((zfar) + (znear)) / delta_z); \
   MAT_ELEM_4X4(mat, 2, 3) = -1.f; \
   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
   MAT_ELEM_4X4(mat, 3, 2) = -((2.f * (zfar) * (znear)) / delta_z); \
   MAT_ELEM_4X4(mat, 3, 3) = 0.0f; \
}

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/math/vector_2.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_2.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__
#define __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__

#include &lt;stdint.h&gt;
#include &lt;math.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;

RETRO_BEGIN_DECLS

typedef float vec2_t[2];

#define vec2_dot(a, b)   ((a[0] * b[0]) + (a[1] * b[1]))

#define vec2_cross(a, b) ((a[0]*b[1]) - (a[1]*b[0]))

#define vec2_add(dst, src) \
   dst[0] += src[0]; \
   dst[1] += src[1]

#define vec2_subtract(dst, src) \
   dst[0] -= src[0]; \
   dst[1] -= src[1]

#define vec2_copy(dst, src) \
   dst[0] = src[0]; \
   dst[1] = src[1]

static INLINE float overflow(void)
{
   unsigned i;
   volatile float f = 1e10;

   for (i = 0; i &lt; 10; ++i)
      f *= f;
   return f;
}

static INLINE int16_t tofloat16(float f)
{
	union uif32
   {
      float f;
      uint32_t i;
   };

   int i, s, e, m;
   union uif32 Entry;
   Entry.f = f;
   i       = (int)Entry.i;
   s       =  (i &gt;&gt; 16) &amp; 0x00008000;
   e       = ((i &gt;&gt; 23) &amp; 0x000000ff) - (127 - 15);
   m       =   i        &amp; 0x007fffff;

   if (e &lt;= 0)
   {
      if (e &lt; -10)
         return (int16_t)(s);

      m = (m | 0x00800000) &gt;&gt; (1 - e);

      if (m &amp; 0x00001000)
         m += 0x00002000;

      return (int16_t)(s | (m &gt;&gt; 13));
   }

   if (e == 0xff - (127 - 15))
   {
      if (m == 0)
         return (int16_t)(s | 0x7c00);

      m &gt;&gt;= 13;

      return (int16_t)(s | 0x7c00 | m | (m == 0));
   }

   if (m &amp;  0x00001000)
   {
      m += 0x00002000;

      if (m &amp; 0x00800000)
      {
         m =  0;
         e += 1;
      }
   }

   if (e &gt; 30)
   {
      overflow();

      return (int16_t)(s | 0x7c00);
   }

   return (int16_t)(s | (e &lt;&lt; 10) | (m &gt;&gt; 13));
}

static INLINE unsigned int vec2_packHalf2x16(float vec0, float vec1)
{
   union
   {
      int16_t in[2];
      unsigned int out;
   } u;

   u.in[0] = tofloat16(vec0);
   u.in[1] = tofloat16(vec1);

   return u.out;
}

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/math/vector_3.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_3.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__
#define __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__

#include &lt;stdint.h&gt;
#include &lt;math.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

typedef float vec3_t[3];

#define vec3_dot(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])

#define vec3_cross(dst, a, b)  \
   dst[0] = a[1]*b[2] - a[2]*b[1]; \
   dst[1] = a[2]*b[0] - a[0]*b[2]; \
   dst[2] = a[0]*b[1] - a[1]*b[0]

#define vec3_length(a) sqrtf(vec3_dot(a,a))

#define vec3_add(dst, src) \
   dst[0] += src[0]; \
   dst[1] += src[1]; \
   dst[2] += src[2]

#define vec3_subtract(dst, src) \
   dst[0] -= src[0]; \
   dst[1] -= src[1]; \
   dst[2] -= src[2]

#define vec3_scale(dst, scale) \
   dst[0] *= scale; \
   dst[1] *= scale; \
   dst[2] *= scale

#define vec3_copy(dst, src) \
   dst[0] = src[0]; \
   dst[1] = src[1]; \
   dst[2] = src[2]

#define vec3_normalize(dst) vec3_scale(dst,1.0f / vec3_length(dst))

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/math/vector_4.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_4.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__
#define __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__

#include &lt;stdint.h&gt;
#include &lt;math.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

typedef float vec4_t[4];

#define vec4_add(dst, src) \
   dst[0] += src[0]; \
   dst[1] += src[1]; \
   dst[2] += src[2]; \
   dst[3] += src[3]

#define vec4_subtract(dst, src) \
   dst[0] -= src[0]; \
   dst[1] -= src[1]; \
   dst[2] -= src[2]; \
   dst[3] -= src[3]

#define vec4_scale(dst, scale) \
   dst[0] *= scale; \
   dst[1] *= scale; \
   dst[2] *= scale; \
   dst[3] *= scale

#define vec4_copy(dst, src) \
   dst[0] = src[0]; \
   dst[1] = src[1]; \
   dst[2] = src[2]; \
   dst[3] = src[3]

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/scaler/filter.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (filter.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_FILTER_H__
#define __LIBRETRO_SDK_SCALER_FILTER_H__

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#include &lt;boolean.h&gt;
#include &lt;gfx/scaler/scaler.h&gt;

bool scaler_gen_filter(struct scaler_ctx *ctx);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/scaler/pixconv.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (pixconv.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_PIXCONV_H__
#define __LIBRETRO_SDK_SCALER_PIXCONV_H__

#include &lt;clamping.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

void conv_0rgb1555_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_0rgb1555_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_0rgb1555(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_abgr8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgba4444_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgba4444_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_bgr24_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_bgr24_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_0rgb1555(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_rgba4444(void *output_, const void *input_,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_rgb565(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_abgr8888_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_argb8888_abgr8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_0rgb1555_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_rgb565_bgr24(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_yuyv_argb8888(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

void conv_copy(void *output, const void *input,
      int width, int height,
      int out_stride, int in_stride);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/scaler/scaler.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_H__
#define __LIBRETRO_SDK_SCALER_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;boolean.h&gt;
#include &lt;clamping.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

enum scaler_pix_fmt
{
   SCALER_FMT_ARGB8888 = 0,
   SCALER_FMT_ABGR8888,
   SCALER_FMT_0RGB1555,
   SCALER_FMT_RGB565,
   SCALER_FMT_BGR24,
   SCALER_FMT_YUYV,
   SCALER_FMT_RGBA4444
};

enum scaler_type
{
   SCALER_TYPE_UNKNOWN = 0,
   SCALER_TYPE_POINT,
   SCALER_TYPE_BILINEAR,
   SCALER_TYPE_SINC
};

struct scaler_filter
{
   int16_t *filter;
   int     *filter_pos;
   int      filter_len;
   int      filter_stride;
};

struct scaler_ctx
{
   void (*scaler_horiz)(const struct scaler_ctx*,
         const void*, int);
   void (*scaler_vert)(const struct scaler_ctx*,
         void*, int);
   void (*scaler_special)(const struct scaler_ctx*,
         void*, const void*, int, int, int, int, int, int);

   void (*in_pixconv)(void*, const void*, int, int, int, int);
   void (*out_pixconv)(void*, const void*, int, int, int, int);
   void (*direct_pixconv)(void*, const void*, int, int, int, int);
   struct scaler_filter horiz, vert;   /* ptr alignment */

   struct
   {
      uint32_t *frame;
      int stride;
   } input;

   struct
   {
      uint64_t *frame;
      int width;
      int height;
      int stride;
   } scaled;

   struct
   {
      uint32_t *frame;
      int stride;
   } output;

   int in_width;
   int in_height;
   int in_stride;

   int out_width;
   int out_height;
   int out_stride;

   enum scaler_pix_fmt in_fmt;
   enum scaler_pix_fmt out_fmt;
   enum scaler_type scaler_type;

   bool unscaled;
};

bool scaler_ctx_gen_filter(struct scaler_ctx *ctx);

void scaler_ctx_gen_reset(struct scaler_ctx *ctx);

/**
 * scaler_ctx_scale:
 * @ctx          : pointer to scaler context object.
 * @output       : pointer to output image.
 * @input        : pointer to input image.
 *
 * Scales an input image to an output image.
 **/
void scaler_ctx_scale(struct scaler_ctx *ctx,
      void *output, const void *input);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/scaler/scaler_int.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (scaler_int.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_SCALER_INT_H__
#define __LIBRETRO_SDK_SCALER_INT_H__

#include &lt;gfx/scaler/scaler.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

void scaler_argb8888_vert(const struct scaler_ctx *ctx,
      void *output, int stride);

void scaler_argb8888_horiz(const struct scaler_ctx *ctx,
      const void *input, int stride);

void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
      void *output, const void *input,
      int out_width, int out_height,
      int in_width, int in_height,
      int out_stride, int in_stride);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/gfx/video_frame.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (video_frame.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_VIDEO_FRAME_H
#define _LIBRETRO_SDK_VIDEO_FRAME_H

#include &lt;stdint.h&gt;
#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;

#include &lt;gfx/scaler/scaler.h&gt;

#include &lt;libretro.h&gt;

RETRO_BEGIN_DECLS

#define scaler_ctx_scale_direct(ctx, output, input) \
{ \
   if (ctx &amp;&amp; ctx-&gt;unscaled &amp;&amp; ctx-&gt;direct_pixconv) \
      /* Just perform straight pixel conversion. */ \
      ctx-&gt;direct_pixconv(output, input, \
            ctx-&gt;out_width,  ctx-&gt;out_height, \
            ctx-&gt;out_stride, ctx-&gt;in_stride); \
   else \
      scaler_ctx_scale(ctx, output, input); \
}

static INLINE void video_frame_convert_rgb16_to_rgb32(
      struct scaler_ctx *scaler,
      void *output,
      const void *input,
      int width, int height,
      int in_pitch)
{
   if (width != scaler-&gt;in_width || height != scaler-&gt;in_height)
   {
      scaler-&gt;in_width    = width;
      scaler-&gt;in_height   = height;
      scaler-&gt;out_width   = width;
      scaler-&gt;out_height  = height;
      scaler-&gt;in_fmt      = SCALER_FMT_RGB565;
      scaler-&gt;out_fmt     = SCALER_FMT_ARGB8888;
      scaler-&gt;scaler_type = SCALER_TYPE_POINT;
      scaler_ctx_gen_filter(scaler);
   }

   scaler-&gt;in_stride  = in_pitch;
   scaler-&gt;out_stride = width * sizeof(uint32_t);

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_scale(
      struct scaler_ctx *scaler,
      void *output,
      const void *input,
      enum scaler_pix_fmt format,
      unsigned scaler_width,
      unsigned scaler_height,
      unsigned scaler_pitch,
      unsigned width,
      unsigned height,
      unsigned pitch)
{
   if (
            width  != (unsigned)scaler-&gt;in_width
         || height != (unsigned)scaler-&gt;in_height
         || format != scaler-&gt;in_fmt
         || pitch  != (unsigned)scaler-&gt;in_stride
      )
   {
      scaler-&gt;in_fmt    = format;
      scaler-&gt;in_width  = width;
      scaler-&gt;in_height = height;
      scaler-&gt;in_stride = pitch;

      scaler-&gt;out_width  = scaler_width;
      scaler-&gt;out_height = scaler_height;
      scaler-&gt;out_stride = scaler_pitch;

      scaler_ctx_gen_filter(scaler);
   }

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_record_scale(
      struct scaler_ctx *scaler,
      void *output,
      const void *input,
      unsigned scaler_width,
      unsigned scaler_height,
      unsigned scaler_pitch,
      unsigned width,
      unsigned height,
      unsigned pitch,
      bool bilinear)
{
   if (
            width  != (unsigned)scaler-&gt;in_width
         || height != (unsigned)scaler-&gt;in_height
      )
   {
      scaler-&gt;in_width    = width;
      scaler-&gt;in_height   = height;
      scaler-&gt;in_stride   = pitch;

      scaler-&gt;scaler_type = bilinear ?
         SCALER_TYPE_BILINEAR : SCALER_TYPE_POINT;

      scaler-&gt;out_width  = scaler_width;
      scaler-&gt;out_height = scaler_height;
      scaler-&gt;out_stride = scaler_pitch;

      scaler_ctx_gen_filter(scaler);
   }

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_convert_argb8888_to_abgr8888(
      struct scaler_ctx *scaler,
      void *output, const void *input,
      int width, int height, int in_pitch)
{
   if (width != scaler-&gt;in_width || height != scaler-&gt;in_height)
   {
      scaler-&gt;in_width    = width;
      scaler-&gt;in_height   = height;
      scaler-&gt;out_width   = width;
      scaler-&gt;out_height  = height;
      scaler-&gt;in_fmt      = SCALER_FMT_ARGB8888;
      scaler-&gt;out_fmt     = SCALER_FMT_ABGR8888;
      scaler-&gt;scaler_type = SCALER_TYPE_POINT;
      scaler_ctx_gen_filter(scaler);
   }

   scaler-&gt;in_stride  = in_pitch;
   scaler-&gt;out_stride = width * sizeof(uint32_t);

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_convert_to_bgr24(
      struct scaler_ctx *scaler,
      void *output, const void *input,
      int width, int height, int in_pitch)
{
   scaler-&gt;in_width    = width;
   scaler-&gt;in_height   = height;
   scaler-&gt;out_width   = width;
   scaler-&gt;out_height  = height;
   scaler-&gt;out_fmt     = SCALER_FMT_BGR24;
   scaler-&gt;scaler_type = SCALER_TYPE_POINT;

   scaler_ctx_gen_filter(scaler);

   scaler-&gt;in_stride   = in_pitch;
   scaler-&gt;out_stride  = width * 3;

   scaler_ctx_scale_direct(scaler, output, input);
}

static INLINE void video_frame_convert_rgba_to_bgr(
      const void *src_data,
      void *dst_data,
      unsigned width)
{
   unsigned x;
   uint8_t      *dst  = (uint8_t*)dst_data;
   const uint8_t *src = (const uint8_t*)src_data;

   for (x = 0; x &lt; width; x++, dst += 3, src += 4)
   {
      dst[0] = src[2];
      dst[1] = src[1];
      dst[2] = src[0];
   }
}

static INLINE void video_pixel_frame_scale(
      struct scaler_ctx *scaler,
      void *output, const void *data,
      unsigned width, unsigned height,
      size_t pitch)
{
   scaler-&gt;in_width      = width;
   scaler-&gt;in_height     = height;
   scaler-&gt;out_width     = width;
   scaler-&gt;out_height    = height;
   scaler-&gt;in_stride     = (int)pitch;
   scaler-&gt;out_stride    = width * sizeof(uint16_t);
   scaler_ctx_scale_direct(scaler, output, data);
}

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/glsm/glsm.h</h2>
<pre>/* Copyright (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsm.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_GLSM_H
#define LIBRETRO_SDK_GLSM_H

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;
#include &lt;libretro.h&gt;
#include &lt;glsym/rglgen_headers.h&gt;

RETRO_BEGIN_DECLS

#ifdef HAVE_OPENGLES2
typedef double GLdouble;
typedef double GLclampd;
#endif

#if defined(HAVE_OPENGLES2)
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
#elif (defined(__MACH__) &amp;&amp; (defined(__ppc__) || defined(__ppc64__)))
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER_EXT
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT
#elif defined(HAVE_PSGL)
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER_OES
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_SCE
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_OES
#else
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
#endif

#if defined(HAVE_PSGL)
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
#elif (defined(__MACH__) &amp;&amp; (defined(__ppc__) || defined(__ppc64__)))
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
#else
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0
#endif

#ifndef GL_FOG
#define GL_FOG 0x0B60
#endif

#ifndef GL_ALPHA_TEST
#define GL_ALPHA_TEST 0x0BC0
#endif

#ifndef GL_CLIP_DISTANCE0
#define GL_CLIP_DISTANCE0 0x3000
#endif

#define MAX_ATTRIB 8

enum
{
   SGL_DEPTH_TEST             = 0,
   SGL_BLEND,
   SGL_POLYGON_OFFSET_FILL,
   SGL_FOG,
   SGL_CULL_FACE,
   SGL_ALPHA_TEST,
   SGL_SCISSOR_TEST,
   SGL_STENCIL_TEST,
#if !defined(HAVE_OPENGLES)
   SGL_DEPTH_CLAMP,
   SGL_CLIP_DISTANCE0,
#endif
   SGL_DITHER,
   SGL_SAMPLE_ALPHA_TO_COVERAGE,
   SGL_SAMPLE_COVERAGE,
#ifndef HAVE_OPENGLES
   SGL_COLOR_LOGIC_OP,
#endif
   SGL_CAP_MAX
};

enum glsm_state_ctl
{
   GLSM_CTL_NONE = 0,
   GLSM_CTL_STATE_SETUP,
   GLSM_CTL_STATE_BIND,
   GLSM_CTL_STATE_UNBIND,
   GLSM_CTL_STATE_CONTEXT_RESET,
   GLSM_CTL_STATE_CONTEXT_DESTROY,
   GLSM_CTL_STATE_CONTEXT_INIT,
   GLSM_CTL_IS_IMM_VBO,
   GLSM_CTL_SET_IMM_VBO,
   GLSM_CTL_UNSET_IMM_VBO,
   GLSM_CTL_IMM_VBO_DISABLE,
   GLSM_CTL_IMM_VBO_DRAW,
   GLSM_CTL_PROC_ADDRESS_GET
};

typedef bool (*glsm_imm_vbo_draw)(void *);
typedef bool (*glsm_imm_vbo_disable)(void *);
typedef bool (*glsm_framebuffer_lock)(void *);

typedef struct glsm_ctx_proc_address
{
   retro_get_proc_address_t addr;
} glsm_ctx_proc_address_t;

typedef struct glsm_ctx_params
{
   glsm_framebuffer_lock    framebuffer_lock;
   glsm_imm_vbo_draw        imm_vbo_draw;
   glsm_imm_vbo_disable     imm_vbo_disable;
   retro_hw_context_reset_t context_reset;
   retro_hw_context_reset_t context_destroy;
   retro_environment_t environ_cb;
   bool stencil;
   unsigned major;
   unsigned minor;
   enum retro_hw_context_type context_type;
} glsm_ctx_params_t;

GLuint glsm_get_current_framebuffer(void);

bool glsm_ctl(enum glsm_state_ctl state, void *data);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/glsm/glsmsym.h</h2>
<pre>/* Copyright (C) 2010-2018 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsmsym.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_GLSM_SYM_H
#define LIBRETRO_SDK_GLSM_SYM_H

#include &lt;glsm/glsm.h&gt;

#ifdef HAVE_GLSYM_PRIVATE
#include "glsym_private.h"
#endif

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/* deprecated old FF-style GL symbols */
#define glTexCoord2f                rglTexCoord2f

/* more forward-compatible GL subset symbols */
#define glDrawRangeElementsBaseVertex rglDrawRangeElementsBaseVertex
#define glProvokingVertex           rglProvokingVertex
#define glGetInteger64v             rglGetInteger64v
#define glGenSamplers               rglGenSamplers
#define glBindSampler               rglBindSampler
#define glSamplerParameteri         rglSamplerParameteri
#define glGetBufferSubData          rglGetBufferSubData
#define glUniform2iv                rglUniform2iv
#define glUniform2uiv               rglUniform2uiv
#define glTextureView               rglTextureView
#define glGetQueryObjectuiv         rglGetQueryObjectuiv
#define glGenQueries                rglGenQueries
#define glDeleteQueries             rglDeleteQueries
#define glBeginQuery                rglBeginQuery
#define glEndQuery                  rglEndQuery
#define glBlitFramebuffer           rglBlitFramebuffer
#define glVertexAttrib4f            rglVertexAttrib4f
#define glVertexAttrib4fv           rglVertexAttrib4fv
#define glDrawArrays                rglDrawArrays
#define glDrawElements              rglDrawElements
#define glCompressedTexImage2D      rglCompressedTexImage2D
#define glBindTexture               rglBindTexture
#define glActiveTexture             rglActiveTexture
#define glFramebufferTexture        rglFramebufferTexture
#define glFramebufferTexture2D      rglFramebufferTexture2D
#define glFramebufferRenderbuffer   rglFramebufferRenderbuffer
#define glDeleteFramebuffers        rglDeleteFramebuffers
#define glDeleteTextures            rglDeleteTextures
#define glDeleteBuffers             rglDeleteBuffers
#define glRenderbufferStorage       rglRenderbufferStorage
#define glBindRenderbuffer          rglBindRenderbuffer
#define glDeleteRenderbuffers       rglDeleteRenderbuffers
#define glGenRenderbuffers          rglGenRenderbuffers
#define glGenFramebuffers           rglGenFramebuffers
#define glGenTextures               rglGenTextures
#define glBindFramebuffer           rglBindFramebuffer
#define glGenerateMipmap            rglGenerateMipmap
#define glCheckFramebufferStatus    rglCheckFramebufferStatus
#define glBindFragDataLocation      rglBindFragDataLocation
#define glBindAttribLocation        rglBindAttribLocation
#define glLinkProgram               rglLinkProgram
#define glGetProgramiv              rglGetProgramiv
#define glGetShaderiv               rglGetShaderiv
#define glAttachShader              rglAttachShader
#define glDetachShader              rglDetachShader
#define glShaderSource              rglShaderSource
#define glCompileShader             rglCompileShader
#define glCreateProgram             rglCreateProgram
#define glGetShaderInfoLog          rglGetShaderInfoLog
#define glGetProgramInfoLog         rglGetProgramInfoLog
#define glIsProgram                 rglIsProgram
#define glEnableVertexAttribArray   rglEnableVertexAttribArray
#define glDisableVertexAttribArray  rglDisableVertexAttribArray
#define glVertexAttribPointer       rglVertexAttribPointer
#define glVertexAttribIPointer      rglVertexAttribIPointer
#define glVertexAttribLPointer      rglVertexAttribLPointer
#define glGetUniformLocation        rglGetUniformLocation
#define glGenBuffers                rglGenBuffers
#define glDisable(T)                rglDisable(S##T)
#define glEnable(T)                 rglEnable(S##T)
#define glIsEnabled(T)              rglIsEnabled(S##T)
#define glUseProgram                rglUseProgram
#define glDepthMask                 rglDepthMask
#define glStencilMask               rglStencilMask
#define glBufferData                rglBufferData
#define glBufferSubData             rglBufferSubData
#define glBindBuffer                rglBindBuffer
#define glCreateShader              rglCreateShader
#define glDeleteShader              rglDeleteShader
#define glDeleteProgram             rglDeleteProgram
#define glUniform1f                 rglUniform1f
#define glUniform1i                 rglUniform1i
#define glUniform2f                 rglUniform2f
#define glUniform2i                 rglUniform2i
#define glUniform2fv                rglUniform2fv
#define glUniform3f                 rglUniform3f
#define glUniform3fv                rglUniform3fv
#define glUniform4i                 rglUniform4i
#define glUniform4f                 rglUniform4f
#define glUniform4fv                rglUniform4fv
#define glUniform1ui                rglUniform1ui
#define glUniform2ui                rglUniform2ui
#define glUniform3ui                rglUniform3ui
#define glUniform4ui                rglUniform4ui
#define glGetActiveUniform          rglGetActiveUniform
#define glBlendFunc                 rglBlendFunc
#define glBlendFuncSeparate         rglBlendFuncSeparate
#define glDepthFunc                 rglDepthFunc
#define glColorMask                 rglColorMask
#define glClearColor                rglClearColor
#define glViewport                  rglViewport
#define glScissor                   rglScissor
#define glStencilFunc               rglStencilFunc
#define glCullFace                  rglCullFace
#define glStencilOp                 rglStencilOp
#define glFrontFace                 rglFrontFace
#define glDepthRange                rglDepthRange
#define glClearDepth                rglClearDepth
#define glPolygonOffset             rglPolygonOffset
#define glPixelStorei               rglPixelStorei
#define glReadBuffer                rglReadBuffer
#define glUniformMatrix4fv          rglUniformMatrix4fv
#define glGetAttribLocation         rglGetAttribLocation
#define glTexStorage2D              rglTexStorage2D
#define glDrawBuffers               rglDrawBuffers
#define glGenVertexArrays           rglGenVertexArrays
#define glBindVertexArray           rglBindVertexArray
#define glBlendEquation             rglBlendEquation
#define glBlendColor                rglBlendColor
#define glBlendEquationSeparate     rglBlendEquationSeparate
#define glCopyImageSubData          rglCopyImageSubData
#define glMapBuffer                 rglMapBuffer
#define glUnmapBuffer               rglUnmapBuffer
#define glMapBufferRange            rglMapBufferRange
#define glUniformBlockBinding       rglUniformBlockBinding
#define glGetUniformBlockIndex      rglGetUniformBlockIndex
#define glGetActiveUniformBlockiv   rglGetActiveUniformBlockiv
#define glBindBufferBase            rglBindBufferBase
#define glGetUniformIndices         rglGetUniformIndices
#define glGetActiveUniformsiv       rglGetActiveUniformsiv
#define glGetError                  rglGetError
#define glClear                     rglClear
#define glPolygonMode               rglPolygonMode
#define glLineWidth                 rglLineWidth
#define glTexImage3D                rglTexImage3D
#define glTexImage2DMultisample     rglTexImage2DMultisample
#define glTexStorage2DMultisample   rglTexStorage2DMultisample
#define glMemoryBarrier             rglMemoryBarrier
#define glBindImageTexture          rglBindImageTexture
#define glProgramBinary             rglProgramBinary
#define glGetProgramBinary          rglGetProgramBinary
#define glProgramParameteri         rglProgramParameteri
#define glTexSubImage2D             rglTexSubImage2D
#define glDeleteVertexArrays        rglDeleteVertexArrays
#define glRenderbufferStorageMultisample rglRenderbufferStorageMultisample
#define glUniform1iv                rglUniform1iv
#define glUniform1fv                rglUniform1fv
#define glValidateProgram           rglValidateProgram
#define glGetStringi                rglGetStringi
#define glTexBuffer                 rglTexBuffer
#define glClearBufferfv             rglClearBufferfv
#define glClearBufferfi             rglClearBufferfi
#define glWaitSync                  rglWaitSync
#define glFenceSync                 rglFenceSync
#define glDeleteSync                rglDeleteSync
#define glBufferStorage             rglBufferStorage
#define glFlushMappedBufferRange    rglFlushMappedBufferRange
#define glClientWaitSync            rglClientWaitSync
#define glDrawElementsBaseVertex    rglDrawElementsBaseVertex

const GLubyte* rglGetStringi(GLenum name, GLuint index);
void rglTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer);
void rglClearBufferfv( 	GLenum buffer,
  	GLint drawBuffer,
  	const GLfloat * value);
void rglClearBufferfi( 	GLenum buffer,
  	GLint drawBuffer,
  	GLfloat depth,
  	GLint stencil);
void rglValidateProgram(GLuint program);
void rglRenderbufferStorageMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height);
void rglUniform1iv(GLint location,  GLsizei count,  const GLint *value);
void rglUniform1fv(GLint location,  GLsizei count,  const GLfloat *value);
void rglProgramParameteri( 	GLuint program,
  	GLenum pname,
  	GLint value);
void rglGetProgramBinary( 	GLuint program,
  	GLsizei bufsize,
  	GLsizei *length,
  	GLenum *binaryFormat,
  	void *binary);
void rglProgramBinary(GLuint program,
  	GLenum binaryFormat,
  	const void *binary,
  	GLsizei length);
void rglBindImageTexture( 	GLuint unit,
  	GLuint texture,
  	GLint level,
  	GLboolean layered,
  	GLint layer,
  	GLenum access,
  	GLenum format);
void rglTexStorage2DMultisample(GLenum target, GLsizei samples,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLboolean fixedsamplelocations);
void rglGetActiveUniformsiv( 	GLuint program,
  	GLsizei uniformCount,
  	const GLuint *uniformIndices,
  	GLenum pname,
  	GLint *params);
void rglGetUniformIndices( 	GLuint program,
  	GLsizei uniformCount,
  	const GLchar **uniformNames,
  	GLuint *uniformIndices);
void rglBindBufferBase( 	GLenum target,
  	GLuint index,
  	GLuint buffer);
void rglGetActiveUniformBlockiv( 	GLuint program,
  	GLuint uniformBlockIndex,
  	GLenum pname,
  	GLint *params);
GLuint rglGetUniformBlockIndex( 	GLuint program,
  	const GLchar *uniformBlockName);
void * rglMapBuffer(	GLenum target, GLenum access);
void *rglMapBufferRange( 	GLenum target,
  	GLintptr offset,
  	GLsizeiptr length,
  	GLbitfield access);
GLboolean rglUnmapBuffer( 	GLenum target);
void rglBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void rglBlendEquation(GLenum mode);
void rglGenVertexArrays(GLsizei n, GLuint *arrays);
void rglReadBuffer(GLenum mode);
void rglPixelStorei(GLenum pname, GLint param);
void rglTexCoord2f(GLfloat s, GLfloat t);
void rglDrawElements(GLenum mode, GLsizei count, GLenum type,
                           const GLvoid * indices);
void rglTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
      GLsizei width, GLsizei height);
void rglCompressedTexImage2D(GLenum target, GLint level,
      GLenum internalformat, GLsizei width, GLsizei height,
      GLint border, GLsizei imageSize, const GLvoid *data);
void glBindTexture(GLenum target, GLuint texture);
void glActiveTexture(GLenum texture);
void rglFramebufferTexture(GLenum target, GLenum attachment,
  	GLuint texture, GLint level);
void rglFramebufferTexture2D(GLenum target, GLenum attachment,
      GLenum textarget, GLuint texture, GLint level);
void rglFramebufferRenderbuffer(GLenum target, GLenum attachment,
      GLenum renderbuffertarget, GLuint renderbuffer);
void rglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
void rglRenderbufferStorage(GLenum target, GLenum internalFormat,
      GLsizei width, GLsizei height);
void rglDeleteTextures(GLsizei n, const GLuint *textures);
void rglBindRenderbuffer(GLenum target, GLuint renderbuffer);
void rglDeleteRenderbuffers(GLsizei n, GLuint *renderbuffers);
void rglGenRenderbuffers(GLsizei n, GLuint *renderbuffers);
void rglGenFramebuffers(GLsizei n, GLuint *ids);
void rglGenTextures(GLsizei n, GLuint *textures);
void rglBindFramebuffer(GLenum target, GLuint framebuffer);
void rglGenerateMipmap(GLenum target);
GLenum rglCheckFramebufferStatus(GLenum target);
void rglBindFragDataLocation(GLuint program, GLuint colorNumber,
                                   const char * name);
void rglBindAttribLocation(GLuint program, GLuint index, const GLchar *name);
void rglLinkProgram(GLuint program);
void rglGetProgramiv(GLuint shader, GLenum pname, GLint *params);
void rglGetShaderiv(GLuint shader, GLenum pname, GLint *params);
void rglAttachShader(GLuint program, GLuint shader);
void rglShaderSource(GLuint shader, GLsizei count,
      const GLchar **string, const GLint *length);
void rglCompileShader(GLuint shader);
GLuint rglCreateProgram(void);
void rglGetShaderInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog);
void rglGetProgramInfoLog(GLuint shader, GLsizei maxLength,
      GLsizei *length, GLchar *infoLog);
GLboolean rglIsProgram(GLuint program);
void rglEnableVertexAttribArray(GLuint index);
void rglDisableVertexAttribArray(GLuint index);
void rglVertexAttribPointer(GLuint name, GLint size,
      GLenum type, GLboolean normalized, GLsizei stride,
      const GLvoid* pointer);
GLint rglGetUniformLocation(GLuint program, const GLchar *name);
void rglGenBuffers(GLsizei n, GLuint *buffers);
void rglDisable(GLenum cap);
void rglEnable(GLenum cap);
void rglUseProgram(GLuint program);
void rglDepthMask(GLboolean flag);
void rglStencilMask(GLenum mask);
void rglBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
void rglBufferSubData(GLenum target, GLintptr offset,
      GLsizeiptr size, const GLvoid *data);
void rglBindBuffer(GLenum target, GLuint buffer);
GLuint rglCreateShader(GLenum shader);
void rglDeleteShader(GLuint shader);
void rglUniform1f(GLint location, GLfloat v0);
void rglUniform1i(GLint location, GLint v0);
void rglUniform2f(GLint location, GLfloat v0, GLfloat v1);
void rglUniform2i(GLint location, GLint v0, GLint v1);
void rglUniform2fv(GLint location, GLsizei count, const GLfloat *value);
void rglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void rglUniform3fv(GLint location, GLsizei count, const GLfloat *value);
void rglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
void rglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
void rglUniform4fv(GLint location, GLsizei count, const GLfloat *value);
void rglBlendFunc(GLenum sfactor, GLenum dfactor);
void rglBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha,
      GLenum dstAlpha);
void rglDepthFunc(GLenum func);
void rglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
void rglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void rglViewport(GLint x, GLint y, GLsizei width, GLsizei height);
void rglScissor(GLint x, GLint y, GLsizei width, GLsizei height);
GLboolean rglIsEnabled(GLenum cap);
void rglStencilFunc(GLenum func, GLint ref, GLuint mask);
void rglCullFace(GLenum mode);
void rglStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
void rglFrontFace(GLenum mode);
void rglDepthRange(GLclampd zNear, GLclampd zFar);
void rglClearDepth(GLdouble depth);
void rglPolygonOffset(GLfloat factor, GLfloat units);
void rglDrawArrays(GLenum mode, GLint first, GLsizei count);
void rglVertexAttrib4f(GLuint name, GLfloat x, GLfloat y,
      GLfloat z, GLfloat w);
void rglVertexAttrib4fv(GLuint name, GLfloat* v);
void rglDeleteProgram(GLuint program);
void rglDeleteBuffers(GLsizei n, const GLuint *buffers);
void rglUniform2uiv(	GLint location,
 	GLsizei count,
 	const GLuint *value);
void rglTextureView(	GLuint texture,
 	GLenum target,
 	GLuint origtexture,
 	GLenum internalformat,
 	GLuint minlevel,
 	GLuint numlevels,
 	GLuint minlayer,
 	GLuint numlayers);
void rglGenQueries(	GLsizei n,
 	GLuint * ids);
void rglDeleteQueries(	GLsizei n,
 	const GLuint * ids);
void rglBeginQuery(	GLenum target,
 	GLuint id);
void rglEndQuery(	GLenum target);
void rglGetQueryObjectuiv(	GLuint id,
 	GLenum pname,
 	GLuint * params);
void rglBlitFramebuffer(
      GLint srcX0, GLint srcY0,
      GLint srcX1, GLint srcY1,
      GLint dstX0, GLint dstY0,
      GLint dstX1, GLint dstY1,
      GLbitfield mask, GLenum filter);
void rglDetachShader(GLuint program, GLuint shader);
void rglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
      const GLfloat *value);
GLint rglGetAttribLocation(GLuint program, const GLchar *name);
void rglDrawBuffers(GLsizei n, const GLenum *bufs);
void rglBindVertexArray(GLuint array);

void rglGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
      GLsizei *length, GLint *size, GLenum *type, GLchar *name);
void rglUniform1ui(GLint location, GLuint v);
void rglUniform2ui(GLint location, GLuint v0, GLuint v1);
void rglUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);
void rglUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
void rglBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
void rglCopyImageSubData( 	GLuint srcName,
  	GLenum srcTarget,
  	GLint srcLevel,
  	GLint srcX,
  	GLint srcY,
  	GLint srcZ,
  	GLuint dstName,
  	GLenum dstTarget,
  	GLint dstLevel,
  	GLint dstX,
  	GLint dstY,
  	GLint dstZ,
  	GLsizei srcWidth,
  	GLsizei srcHeight,
  	GLsizei srcDepth);
void rglVertexAttribIPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer);
void rglVertexAttribLPointer(
      GLuint index,
      GLint size,
      GLenum type,
      GLsizei stride,
      const GLvoid * pointer);
void rglUniformBlockBinding( 	GLuint program,
  	GLuint uniformBlockIndex,
  	GLuint uniformBlockBinding);
GLenum rglGetError(void);
void rglClear(GLbitfield mask);
void rglPolygonMode(GLenum face, GLenum mode);
void rglLineWidth(GLfloat width);
void rglTexImage3D(	GLenum target,
 	GLint level,
 	GLint internalFormat,
 	GLsizei width,
 	GLsizei height,
 	GLsizei depth,
 	GLint border,
 	GLenum format,
 	GLenum type,
 	const GLvoid * data);
void rglTexImage2DMultisample( 	GLenum target,
  	GLsizei samples,
  	GLenum internalformat,
  	GLsizei width,
  	GLsizei height,
  	GLboolean fixedsamplelocations);
void rglMemoryBarrier( 	GLbitfield barriers);
void rglTexSubImage2D( 	GLenum target,
  	GLint level,
  	GLint xoffset,
  	GLint yoffset,
  	GLsizei width,
  	GLsizei height,
  	GLenum format,
  	GLenum type,
  	const GLvoid * pixels);
void rglDeleteVertexArrays(GLsizei n, const GLuint *arrays);
void *rglFenceSync(GLenum condition, GLbitfield flags);
void rglDeleteSync(void *sync);
void rglWaitSync(void *sync, GLbitfield flags, uint64_t timeout);
void rglBufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GLbitfield flags);
void rglFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
GLenum rglClientWaitSync(void *sync, GLbitfield flags, uint64_t timeout);
void rglDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
			       GLvoid *indices, GLint basevertex);
void rglGetBufferSubData(	GLenum target,
 	GLintptr offset,
 	GLsizeiptr size,
 	GLvoid * data);
void rglSamplerParameteri(	GLuint sampler,
 	GLenum pname,
 	GLint param);
void rglBindSampler(	GLuint unit,
 	GLuint sampler);
void rglGenSamplers(	GLsizei n,
 	GLuint *samplers);
void rglGetInteger64v(	GLenum pname,
 	int64_t * data);
void rglUniform2iv(	GLint location,
 	GLsizei count,
 	const GLint *value);
void rglProvokingVertex(	GLenum provokeMode);
void rglDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/glsym/glsym_es2.h</h2>
<pre>#ifndef RGLGEN_DECL_H__
#define RGLGEN_DECL_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef GL_APIENTRY
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#endif
#ifndef GL_OES_EGL_image
typedef void *GLeglImageOES;
#endif
#if !defined(GL_OES_fixed_point) &amp;&amp; !defined(HAVE_OPENGLES2)
typedef GLint GLfixed;
#endif

typedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);
typedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
typedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAOESPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
typedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
typedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);
typedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
typedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
typedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
typedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
typedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
typedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
typedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
typedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);
typedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);
typedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);
typedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);

#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR
#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR
#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR
#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR
#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR
#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR
#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR
#define glObjectLabelKHR __rglgen_glObjectLabelKHR
#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR
#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR
#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR
#define glGetPointervKHR __rglgen_glGetPointervKHR
#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR
#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR
#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR
#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR
#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR
#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES
#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES
#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES
#define glEnableiOES __rglgen_glEnableiOES
#define glDisableiOES __rglgen_glDisableiOES
#define glBlendEquationiOES __rglgen_glBlendEquationiOES
#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES
#define glBlendFunciOES __rglgen_glBlendFunciOES
#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES
#define glColorMaskiOES __rglgen_glColorMaskiOES
#define glIsEnablediOES __rglgen_glIsEnablediOES
#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES
#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES
#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES
#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES
#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES
#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES
#define glProgramBinaryOES __rglgen_glProgramBinaryOES
#define glMapBufferOES __rglgen_glMapBufferOES
#define glUnmapBufferOES __rglgen_glUnmapBufferOES
#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES
#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES
#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES
#define glPatchParameteriOES __rglgen_glPatchParameteriOES
#define glTexImage3DOES __rglgen_glTexImage3DOES
#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES
#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES
#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES
#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES
#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES
#define glTexParameterIivOES __rglgen_glTexParameterIivOES
#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES
#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES
#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES
#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES
#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES
#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES
#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES
#define glTexBufferOES __rglgen_glTexBufferOES
#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES
#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES
#define glTextureViewOES __rglgen_glTextureViewOES
#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES
#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES
#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES
#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES
#define glViewportArrayvOES __rglgen_glViewportArrayvOES
#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES
#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES
#define glScissorArrayvOES __rglgen_glScissorArrayvOES
#define glScissorIndexedOES __rglgen_glScissorIndexedOES
#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES
#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES
#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES
#define glGetFloati_vOES __rglgen_glGetFloati_vOES
#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT
#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT
#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT
#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT
#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT
#define glBufferStorageEXT __rglgen_glBufferStorageEXT
#define glClearTexImageEXT __rglgen_glClearTexImageEXT
#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT
#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT
#define glLabelObjectEXT __rglgen_glLabelObjectEXT
#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT
#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT
#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT
#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT
#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT
#define glGenQueriesEXT __rglgen_glGenQueriesEXT
#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT
#define glIsQueryEXT __rglgen_glIsQueryEXT
#define glBeginQueryEXT __rglgen_glBeginQueryEXT
#define glEndQueryEXT __rglgen_glEndQueryEXT
#define glQueryCounterEXT __rglgen_glQueryCounterEXT
#define glGetQueryivEXT __rglgen_glGetQueryivEXT
#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT
#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT
#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT
#define glEnableiEXT __rglgen_glEnableiEXT
#define glDisableiEXT __rglgen_glDisableiEXT
#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT
#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT
#define glBlendFunciEXT __rglgen_glBlendFunciEXT
#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT
#define glColorMaskiEXT __rglgen_glColorMaskiEXT
#define glIsEnablediEXT __rglgen_glIsEnablediEXT
#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT
#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT
#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT
#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT
#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT
#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT
#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT
#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT
#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT
#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT
#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT
#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT
#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT
#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT
#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT
#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT
#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT
#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT
#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT
#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT
#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT
#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT
#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT
#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT
#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT
#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT
#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT
#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT
#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT
#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT
#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT
#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT
#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT
#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT
#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT
#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT
#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT
#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT
#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT
#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT
#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT
#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT
#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT
#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT
#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT
#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT
#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT
#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT
#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT
#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT
#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT
#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT
#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT
#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT
#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT
#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT
#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT
#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT
#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT
#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT
#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT
#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT
#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT
#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT
#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT
#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT
#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT
#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT
#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT
#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT
#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT
#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT
#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT
#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT
#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT
#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT
#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT
#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT
#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT
#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT
#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT
#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT
#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT
#define glTexBufferEXT __rglgen_glTexBufferEXT
#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT
#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT
#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT
#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT
#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT
#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT
#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT
#define glTextureViewEXT __rglgen_glTextureViewEXT
#define glesEXT __rglgen_glesEXT
#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR
#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR

extern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
extern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
extern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
extern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
extern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
extern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
extern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
extern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
extern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
extern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
extern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
extern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
extern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
extern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
extern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
extern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
extern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
extern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
extern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
extern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
extern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
extern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
extern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
extern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
extern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
extern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
extern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
extern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
extern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
extern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
extern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
extern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
extern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
extern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
extern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
extern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
extern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
extern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
extern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
extern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
extern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
extern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
extern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
extern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
extern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
extern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
extern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
extern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
extern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
extern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
extern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
extern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
extern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
extern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
extern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
extern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
extern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
extern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
extern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
extern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
extern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
extern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
extern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
extern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
extern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
extern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
extern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
extern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
extern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
extern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
extern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
extern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
extern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
extern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
extern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
extern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
extern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
extern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
extern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
extern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
extern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
extern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
extern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
extern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
extern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
extern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
extern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
extern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
extern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
extern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
extern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
extern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
extern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
extern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
extern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
extern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
extern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
extern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
extern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
extern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
extern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
extern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
extern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
extern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
extern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
extern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
extern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
extern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
extern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
extern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
extern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
extern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
extern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
extern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
extern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
extern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
extern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
extern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
extern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
extern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
extern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
extern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
extern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
extern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
extern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
extern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
extern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
extern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
extern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
extern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
extern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
extern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
extern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
extern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
extern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
extern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
extern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
extern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
extern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
extern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
extern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
extern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
extern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
extern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
extern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
extern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
extern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
extern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
extern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;

struct rglgen_sym_map { const char *sym; void *ptr; };
extern const struct rglgen_sym_map rglgen_symbol_map[];
#ifdef __cplusplus
}
#endif
#endif</pre>
<h2>./include/libretro-common/include/glsym/glsym_es3.h</h2>
<pre>#ifndef RGLGEN_DECL_H__
#define RGLGEN_DECL_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef GL_APIENTRY
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#endif
#ifndef GL_OES_EGL_image
typedef void *GLeglImageOES;
#endif
#if !defined(GL_OES_fixed_point) &amp;&amp; !defined(HAVE_OPENGLES2)
typedef GLint GLfixed;
#endif
#if defined(OSX) &amp;&amp; !defined(MAC_OS_X_VERSION_10_7)
typedef long long int GLint64;
typedef unsigned long long int GLuint64;
typedef unsigned long long int GLuint64EXT;
typedef struct __GLsync *GLsync;
#endif
#ifndef GL_APIENTRYP
#define GL_APIENTRYP GL_APIENTRY*
#endif
typedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);
typedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
typedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAOESPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
typedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
typedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
typedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);
typedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);
typedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
typedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
typedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
typedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);
typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
typedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);
typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
typedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
typedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
typedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
typedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
typedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
typedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
typedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
typedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);
typedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);
typedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);
typedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);

#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR
#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR
#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR
#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR
#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR
#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR
#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR
#define glObjectLabelKHR __rglgen_glObjectLabelKHR
#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR
#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR
#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR
#define glGetPointervKHR __rglgen_glGetPointervKHR
#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR
#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR
#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR
#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR
#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR
#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES
#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES
#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES
#define glEnableiOES __rglgen_glEnableiOES
#define glDisableiOES __rglgen_glDisableiOES
#define glBlendEquationiOES __rglgen_glBlendEquationiOES
#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES
#define glBlendFunciOES __rglgen_glBlendFunciOES
#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES
#define glColorMaskiOES __rglgen_glColorMaskiOES
#define glIsEnablediOES __rglgen_glIsEnablediOES
#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES
#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES
#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES
#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES
#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES
#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES
#define glProgramBinaryOES __rglgen_glProgramBinaryOES
#define glMapBufferOES __rglgen_glMapBufferOES
#define glUnmapBufferOES __rglgen_glUnmapBufferOES
#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES
#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES
#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES
#define glPatchParameteriOES __rglgen_glPatchParameteriOES
#define glTexImage3DOES __rglgen_glTexImage3DOES
#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES
#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES
#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES
#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES
#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES
#define glTexParameterIivOES __rglgen_glTexParameterIivOES
#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES
#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES
#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES
#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES
#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES
#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES
#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES
#define glTexBufferOES __rglgen_glTexBufferOES
#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES
#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES
#define glTextureViewOES __rglgen_glTextureViewOES
#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES
#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES
#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES
#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES
#define glViewportArrayvOES __rglgen_glViewportArrayvOES
#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES
#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES
#define glScissorArrayvOES __rglgen_glScissorArrayvOES
#define glScissorIndexedOES __rglgen_glScissorIndexedOES
#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES
#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES
#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES
#define glGetFloati_vOES __rglgen_glGetFloati_vOES
#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT
#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT
#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT
#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT
#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT
#define glBufferStorageEXT __rglgen_glBufferStorageEXT
#define glClearTexImageEXT __rglgen_glClearTexImageEXT
#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT
#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT
#define glLabelObjectEXT __rglgen_glLabelObjectEXT
#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT
#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT
#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT
#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT
#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT
#define glGenQueriesEXT __rglgen_glGenQueriesEXT
#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT
#define glIsQueryEXT __rglgen_glIsQueryEXT
#define glBeginQueryEXT __rglgen_glBeginQueryEXT
#define glEndQueryEXT __rglgen_glEndQueryEXT
#define glQueryCounterEXT __rglgen_glQueryCounterEXT
#define glGetQueryivEXT __rglgen_glGetQueryivEXT
#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT
#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT
#define glGetQueryObjecti64vEXT __rglgen_glGetQueryObjecti64vEXT
#define glGetQueryObjectui64vEXT __rglgen_glGetQueryObjectui64vEXT
#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT
#define glEnableiEXT __rglgen_glEnableiEXT
#define glDisableiEXT __rglgen_glDisableiEXT
#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT
#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT
#define glBlendFunciEXT __rglgen_glBlendFunciEXT
#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT
#define glColorMaskiEXT __rglgen_glColorMaskiEXT
#define glIsEnablediEXT __rglgen_glIsEnablediEXT
#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT
#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT
#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT
#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT
#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT
#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT
#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT
#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT
#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT
#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT
#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT
#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT
#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT
#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT
#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT
#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT
#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT
#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT
#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT
#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT
#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT
#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT
#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT
#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT
#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT
#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT
#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT
#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT
#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT
#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT
#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT
#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT
#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT
#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT
#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT
#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT
#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT
#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT
#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT
#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT
#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT
#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT
#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT
#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT
#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT
#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT
#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT
#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT
#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT
#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT
#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT
#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT
#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT
#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT
#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT
#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT
#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT
#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT
#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT
#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT
#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT
#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT
#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT
#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT
#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT
#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT
#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT
#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT
#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT
#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT
#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT
#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT
#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT
#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT
#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT
#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT
#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT
#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT
#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT
#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT
#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT
#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT
#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT
#define glTexBufferEXT __rglgen_glTexBufferEXT
#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT
#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT
#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT
#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT
#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT
#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT
#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT
#define glTextureViewEXT __rglgen_glTextureViewEXT
#define glesEXT __rglgen_glesEXT
#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR
#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR

extern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
extern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
extern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
extern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
extern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
extern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
extern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
extern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
extern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
extern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
extern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
extern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
extern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
extern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
extern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
extern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
extern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
extern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
extern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
extern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
extern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
extern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
extern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
extern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
extern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
extern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
extern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
extern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
extern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
extern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
extern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
extern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
extern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
extern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
extern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
extern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
extern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
extern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
extern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
extern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
extern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
extern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
extern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
extern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
extern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
extern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
extern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
extern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
extern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
extern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
extern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
extern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
extern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
extern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
extern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
extern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
extern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
extern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
extern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
extern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
extern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
extern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
extern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
extern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
extern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
extern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
extern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
extern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
extern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
extern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
extern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
extern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
extern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
extern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
extern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
extern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
extern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
extern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
extern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
extern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
extern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
extern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
extern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
extern RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;
extern RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;
extern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
extern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
extern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
extern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
extern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
extern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
extern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
extern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
extern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
extern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
extern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
extern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
extern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
extern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
extern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
extern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
extern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
extern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
extern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
extern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
extern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
extern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
extern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
extern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
extern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
extern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
extern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
extern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
extern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
extern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
extern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
extern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
extern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
extern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
extern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
extern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
extern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
extern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
extern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
extern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
extern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
extern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
extern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
extern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
extern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
extern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
extern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
extern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
extern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
extern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
extern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
extern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
extern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
extern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
extern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
extern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
extern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
extern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
extern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
extern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
extern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
extern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
extern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
extern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
extern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
extern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
extern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
extern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
extern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
extern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
extern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
extern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
extern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
extern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
extern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
extern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;

struct rglgen_sym_map { const char *sym; void *ptr; };
extern const struct rglgen_sym_map rglgen_symbol_map[];
#ifdef __cplusplus
}
#endif
#endif</pre>
<h2>./include/libretro-common/include/glsym/glsym_gl.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_DECL_H__
#define RGLGEN_DECL_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef GL_APIENTRY
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
#endif
#ifndef GL_OES_EGL_image
typedef void *GLeglImageOES;
#endif
#if !defined(GL_OES_fixed_point) &amp;&amp; !defined(HAVE_OPENGLES2)
typedef GLint GLfixed;
#endif
#if defined(__MACH__) &amp;&amp; !defined(OS_TARGET_IPHONE) &amp;&amp; !defined(MAC_OS_X_VERSION_10_7)
typedef long long int GLint64;
typedef unsigned long long int GLuint64;
typedef unsigned long long int GLuint64EXT;
typedef struct __GLsync *GLsync;
#endif
typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLFOGCOORDFPROC) (GLfloat coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDFVPROC) (const GLfloat *coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDDPROC) (GLdouble coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDDVPROC) (const GLdouble *coord);
typedef void (APIENTRYP RGLSYMGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IVPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IPROC) (GLint x, GLint y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) (GLenum mode);
typedef void (APIENTRYP RGLSYMGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
typedef void (APIENTRYP RGLSYMGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (APIENTRYP RGLSYMGLISQUERYPROC) (GLuint id);
typedef void (APIENTRYP RGLSYMGLBEGINQUERYPROC) (GLenum target, GLuint id);
typedef void (APIENTRYP RGLSYMGLENDQUERYPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP RGLSYMGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef GLboolean (APIENTRYP RGLSYMGLISBUFFERPROC) (GLuint buffer);
typedef void (APIENTRYP RGLSYMGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
typedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
typedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data);
typedef void *(APIENTRYP RGLSYMGLMAPBUFFERPROC) (GLenum target, GLenum access);
typedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP RGLSYMGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
typedef void (APIENTRYP RGLSYMGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
typedef void (APIENTRYP RGLSYMGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask);
typedef void (APIENTRYP RGLSYMGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
typedef void (APIENTRYP RGLSYMGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint (APIENTRYP RGLSYMGLCREATEPROGRAMPROC) (void);
typedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP RGLSYMGLDETACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
typedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP RGLSYMGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
typedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPROC) (GLuint program);
typedef GLboolean (APIENTRYP RGLSYMGLISSHADERPROC) (GLuint shader);
typedef void (APIENTRYP RGLSYMGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
typedef void (APIENTRYP RGLSYMGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FPROC) (GLint location, GLfloat v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
typedef void (APIENTRYP RGLSYMGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
typedef void (APIENTRYP RGLSYMGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
typedef void (APIENTRYP RGLSYMGLENABLEIPROC) (GLenum target, GLuint index);
typedef void (APIENTRYP RGLSYMGLDISABLEIPROC) (GLenum target, GLuint index);
typedef GLboolean (APIENTRYP RGLSYMGLISENABLEDIPROC) (GLenum target, GLuint index);
typedef void (APIENTRYP RGLSYMGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);
typedef void (APIENTRYP RGLSYMGLENDTRANSFORMFEEDBACKPROC) (void);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
typedef void (APIENTRYP RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
typedef void (APIENTRYP RGLSYMGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);
typedef void (APIENTRYP RGLSYMGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);
typedef void (APIENTRYP RGLSYMGLENDCONDITIONALRENDERPROC) (void);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params);
typedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name);
typedef GLint (APIENTRYP RGLSYMGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLUNIFORM1UIPROC) (GLint location, GLuint v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
typedef const GLubyte *(APIENTRYP RGLSYMGLGETSTRINGIPROC) (GLenum name, GLuint index);
typedef GLboolean (APIENTRYP RGLSYMGLISRENDERBUFFERPROC) (GLuint renderbuffer);
typedef void (APIENTRYP RGLSYMGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);
typedef void (APIENTRYP RGLSYMGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers);
typedef void (APIENTRYP RGLSYMGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);
typedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef GLboolean (APIENTRYP RGLSYMGLISFRAMEBUFFERPROC) (GLuint framebuffer);
typedef void (APIENTRYP RGLSYMGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
typedef void (APIENTRYP RGLSYMGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers);
typedef void (APIENTRYP RGLSYMGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);
typedef GLenum (APIENTRYP RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
typedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGENERATEMIPMAPPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
typedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
typedef void *(APIENTRYP RGLSYMGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
typedef void (APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
typedef void (APIENTRYP RGLSYMGLBINDVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRYP RGLSYMGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
typedef void (APIENTRYP RGLSYMGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
typedef GLboolean (APIENTRYP RGLSYMGLISVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLPRIMITIVERESTARTINDEXPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
typedef GLuint (APIENTRYP RGLSYMGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
typedef void (APIENTRYP RGLSYMGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
typedef void (APIENTRYP RGLSYMGLPROVOKINGVERTEXPROC) (GLenum mode);
typedef GLsync (APIENTRYP RGLSYMGLFENCESYNCPROC) (GLenum condition, GLbitfield flags);
typedef GLboolean (APIENTRYP RGLSYMGLISSYNCPROC) (GLsync sync);
typedef void (APIENTRYP RGLSYMGLDELETESYNCPROC) (GLsync sync);
typedef GLenum (APIENTRYP RGLSYMGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
typedef void (APIENTRYP RGLSYMGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
typedef void (APIENTRYP RGLSYMGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data);
typedef void (APIENTRYP RGLSYMGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
typedef void (APIENTRYP RGLSYMGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val);
typedef void (APIENTRYP RGLSYMGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask);
typedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
typedef GLint (APIENTRYP RGLSYMGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
typedef void (APIENTRYP RGLSYMGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers);
typedef GLboolean (APIENTRYP RGLSYMGLISSAMPLERPROC) (GLuint sampler);
typedef void (APIENTRYP RGLSYMGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLQUERYCOUNTERPROC) (GLuint id, GLenum target);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXP2UIPROC) (GLenum type, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXP3UIPROC) (GLenum type, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLVERTEXP4UIPROC) (GLenum type, GLuint value);
typedef void (APIENTRYP RGLSYMGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLNORMALP3UIPROC) (GLenum type, GLuint coords);
typedef void (APIENTRYP RGLSYMGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords);
typedef void (APIENTRYP RGLSYMGLCOLORP3UIPROC) (GLenum type, GLuint color);
typedef void (APIENTRYP RGLSYMGLCOLORP3UIVPROC) (GLenum type, const GLuint *color);
typedef void (APIENTRYP RGLSYMGLCOLORP4UIPROC) (GLenum type, GLuint color);
typedef void (APIENTRYP RGLSYMGLCOLORP4UIVPROC) (GLenum type, const GLuint *color);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color);
typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color);
typedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGPROC) (GLfloat value);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);
typedef void (APIENTRYP RGLSYMGLUNIFORM1DPROC) (GLint location, GLdouble x);
typedef void (APIENTRYP RGLSYMGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params);
typedef GLint (APIENTRYP RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name);
typedef GLuint (APIENTRYP RGLSYMGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
typedef void (APIENTRYP RGLSYMGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values);
typedef void (APIENTRYP RGLSYMGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
typedef void (APIENTRYP RGLSYMGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values);
typedef void (APIENTRYP RGLSYMGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id);
typedef void (APIENTRYP RGLSYMGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids);
typedef void (APIENTRYP RGLSYMGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);
typedef GLboolean (APIENTRYP RGLSYMGLISTRANSFORMFEEDBACKPROC) (GLuint id);
typedef void (APIENTRYP RGLSYMGLPAUSETRANSFORMFEEDBACKPROC) (void);
typedef void (APIENTRYP RGLSYMGLRESUMETRANSFORMFEEDBACKPROC) (void);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream);
typedef void (APIENTRYP RGLSYMGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id);
typedef void (APIENTRYP RGLSYMGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index);
typedef void (APIENTRYP RGLSYMGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLRELEASESHADERCOMPILERPROC) (void);
typedef void (APIENTRYP RGLSYMGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
typedef void (APIENTRYP RGLSYMGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f);
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHFPROC) (GLfloat d);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
typedef void (APIENTRYP RGLSYMGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
typedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
typedef void (APIENTRYP RGLSYMGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
typedef void (APIENTRYP RGLSYMGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);
typedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings);
typedef void (APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);
typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines);
typedef void (APIENTRYP RGLSYMGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);
typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPIPELINEPROC) (GLuint pipeline);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
typedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v);
typedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f);
typedef void (APIENTRYP RGLSYMGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (APIENTRYP RGLSYMGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
typedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
typedef void (APIENTRYP RGLSYMGLMEMORYBARRIERPROC) (GLbitfield barriers);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect);
typedef void (APIENTRYP RGLSYMGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
typedef void (APIENTRYP RGLSYMGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
typedef void (APIENTRYP RGLSYMGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
typedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERDATAPROC) (GLuint buffer);
typedef void (APIENTRYP RGLSYMGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
typedef void (APIENTRYP RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params);
typedef GLuint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
typedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
typedef void (APIENTRYP RGLSYMGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
typedef void (APIENTRYP RGLSYMGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
typedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
typedef void (APIENTRYP RGLSYMGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKPROC) (RGLGENGLDEBUGPROC callback, const void *userParam);
typedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (APIENTRYP RGLSYMGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
typedef void (APIENTRYP RGLSYMGLPOPDEBUGGROUPPROC) (void);
typedef void (APIENTRYP RGLSYMGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
typedef void (APIENTRYP RGLSYMGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (APIENTRYP RGLSYMGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
typedef void (APIENTRYP RGLSYMGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
typedef void (APIENTRYP RGLSYMGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
typedef void (APIENTRYP RGLSYMGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
typedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP RGLSYMGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);
typedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
typedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTUREHANDLEARBPROC) (GLuint texture);
typedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler);
typedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
typedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle);
typedef GLuint64 (APIENTRYP RGLSYMGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
typedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access);
typedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle);
typedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value);
typedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value);
typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
typedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
typedef GLboolean (APIENTRYP RGLSYMGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
#ifdef __APPLE__
	struct _cl_context;
	struct _cl_event;
#endif
typedef GLsync (APIENTRYP RGLSYMGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);
typedef void (APIENTRYP RGLSYMGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKARBPROC) (RGLGENGLDEBUGPROCARB callback, const void *userParam);
typedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
typedef void (APIENTRYP RGLSYMGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode);
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst);
typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (APIENTRYP RGLSYMGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);
typedef void (APIENTRYP RGLSYMGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
typedef void (APIENTRYP RGLSYMGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);
typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMARBPROC) (GLuint program);
typedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
typedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
typedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
typedef void (APIENTRYP RGLSYMGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
typedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor);
typedef void (APIENTRYP RGLSYMGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
typedef void (APIENTRYP RGLSYMGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert);
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
typedef void (APIENTRYP RGLSYMGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean (APIENTRYP RGLSYMGLISQUERYARBPROC) (GLuint id);
typedef void (APIENTRYP RGLSYMGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
typedef void (APIENTRYP RGLSYMGLENDQUERYARBPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
typedef GLenum (APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC) (void);
typedef void (APIENTRYP RGLSYMGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);
typedef void (APIENTRYP RGLSYMGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (APIENTRYP RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
typedef void (APIENTRYP RGLSYMGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
typedef void (APIENTRYP RGLSYMGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
typedef void (APIENTRYP RGLSYMGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values);
typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values);
typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values);
typedef void (APIENTRYP RGLSYMGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern);
typedef void (APIENTRYP RGLSYMGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
typedef void (APIENTRYP RGLSYMGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
typedef void (APIENTRYP RGLSYMGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
typedef void (APIENTRYP RGLSYMGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
typedef void (APIENTRYP RGLSYMGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
typedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGARBPROC) (GLfloat value);
typedef void (APIENTRYP RGLSYMGLDELETEOBJECTARBPROC) (GLhandleARB obj);
typedef GLhandleARB (APIENTRYP RGLSYMGLGETHANDLEARBPROC) (GLenum pname);
typedef void (APIENTRYP RGLSYMGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
typedef GLhandleARB (APIENTRYP RGLSYMGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
typedef void (APIENTRYP RGLSYMGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);
typedef void (APIENTRYP RGLSYMGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
typedef GLhandleARB (APIENTRYP RGLSYMGLCREATEPROGRAMOBJECTARBPROC) (void);
typedef void (APIENTRYP RGLSYMGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
typedef void (APIENTRYP RGLSYMGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
typedef void (APIENTRYP RGLSYMGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IARBPROC) (GLint location, GLint v0);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
typedef void (APIENTRYP RGLSYMGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
typedef void (APIENTRYP RGLSYMGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
typedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
typedef void (APIENTRYP RGLSYMGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);
typedef void (APIENTRYP RGLSYMGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);
typedef GLboolean (APIENTRYP RGLSYMGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
typedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);
typedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);
typedef void (APIENTRYP RGLSYMGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
typedef void (APIENTRYP RGLSYMGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
typedef void (APIENTRYP RGLSYMGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLVERTEXBLENDARBPROC) (GLint count);
typedef void (APIENTRYP RGLSYMGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP RGLSYMGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP RGLSYMGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
typedef GLboolean (APIENTRYP RGLSYMGLISBUFFERARBPROC) (GLuint buffer);
typedef void (APIENTRYP RGLSYMGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
typedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
typedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
typedef void *(APIENTRYP RGLSYMGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
typedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERARBPROC) (GLenum target);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
typedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer);
typedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
typedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVARBPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVARBPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVARBPROC) (const GLint *v);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVARBPROC) (const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1BOESPROC) (GLbyte s);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX2BOESPROC) (GLbyte x);
typedef void (APIENTRYP RGLSYMGLVERTEX2BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX3BOESPROC) (GLbyte x, GLbyte y);
typedef void (APIENTRYP RGLSYMGLVERTEX3BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z);
typedef void (APIENTRYP RGLSYMGLVERTEX4BVOESPROC) (const GLbyte *coords);
typedef void (APIENTRYP RGLSYMGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);
typedef void (APIENTRYP RGLSYMGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHXOESPROC) (GLfixed depth);
typedef void (APIENTRYP RGLSYMGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
typedef void (APIENTRYP RGLSYMGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);
typedef void (APIENTRYP RGLSYMGLFOGXOESPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);
typedef void (APIENTRYP RGLSYMGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);
typedef void (APIENTRYP RGLSYMGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);
typedef void (APIENTRYP RGLSYMGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLLINEWIDTHXOESPROC) (GLfixed width);
typedef void (APIENTRYP RGLSYMGLLOADMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);
typedef void (APIENTRYP RGLSYMGLMULTMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
typedef void (APIENTRYP RGLSYMGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
typedef void (APIENTRYP RGLSYMGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLPOINTSIZEXOESPROC) (GLfixed size);
typedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
typedef void (APIENTRYP RGLSYMGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert);
typedef void (APIENTRYP RGLSYMGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLACCUMXOESPROC) (GLenum op, GLfixed value);
typedef void (APIENTRYP RGLSYMGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);
typedef void (APIENTRYP RGLSYMGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
typedef void (APIENTRYP RGLSYMGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue);
typedef void (APIENTRYP RGLSYMGLCOLOR3XVOESPROC) (const GLfixed *components);
typedef void (APIENTRYP RGLSYMGLCOLOR4XVOESPROC) (const GLfixed *components);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLEVALCOORD1XOESPROC) (GLfixed u);
typedef void (APIENTRYP RGLSYMGLEVALCOORD1XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v);
typedef void (APIENTRYP RGLSYMGLEVALCOORD2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v);
typedef void (APIENTRYP RGLSYMGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values);
typedef void (APIENTRYP RGLSYMGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params);
typedef void (APIENTRYP RGLSYMGLINDEXXOESPROC) (GLfixed component);
typedef void (APIENTRYP RGLSYMGLINDEXXVOESPROC) (const GLfixed *component);
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);
typedef void (APIENTRYP RGLSYMGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);
typedef void (APIENTRYP RGLSYMGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2);
typedef void (APIENTRYP RGLSYMGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLNORMAL3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLPASSTHROUGHXOESPROC) (GLfixed token);
typedef void (APIENTRYP RGLSYMGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values);
typedef void (APIENTRYP RGLSYMGLPIXELSTOREXPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor);
typedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities);
typedef void (APIENTRYP RGLSYMGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y);
typedef void (APIENTRYP RGLSYMGLRASTERPOS2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLRASTERPOS3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w);
typedef void (APIENTRYP RGLSYMGLRASTERPOS4XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);
typedef void (APIENTRYP RGLSYMGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1XOESPROC) (GLfixed s);
typedef void (APIENTRYP RGLSYMGLTEXCOORD1XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t);
typedef void (APIENTRYP RGLSYMGLTEXCOORD2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r);
typedef void (APIENTRYP RGLSYMGLTEXCOORD3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q);
typedef void (APIENTRYP RGLSYMGLTEXCOORD4XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
typedef void (APIENTRYP RGLSYMGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
typedef void (APIENTRYP RGLSYMGLVERTEX2XOESPROC) (GLfixed x);
typedef void (APIENTRYP RGLSYMGLVERTEX2XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX3XOESPROC) (GLfixed x, GLfixed y);
typedef void (APIENTRYP RGLSYMGLVERTEX3XVOESPROC) (const GLfixed *coords);
typedef void (APIENTRYP RGLSYMGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
typedef void (APIENTRYP RGLSYMGLVERTEX4XVOESPROC) (const GLfixed *coords);
typedef GLbitfield (APIENTRYP RGLSYMGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHFOESPROC) (GLclampf depth);
typedef void (APIENTRYP RGLSYMGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
typedef void (APIENTRYP RGLSYMGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);
typedef void (APIENTRYP RGLSYMGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);

#define glDrawRangeElements __rglgen_glDrawRangeElements
#define glTexImage3D __rglgen_glTexImage3D
#define glTexSubImage3D __rglgen_glTexSubImage3D
#define glCopyTexSubImage3D __rglgen_glCopyTexSubImage3D
#define glActiveTexture __rglgen_glActiveTexture
#define glSampleCoverage __rglgen_glSampleCoverage
#define glCompressedTexImage3D __rglgen_glCompressedTexImage3D
#define glCompressedTexImage2D __rglgen_glCompressedTexImage2D
#define glCompressedTexImage1D __rglgen_glCompressedTexImage1D
#define glCompressedTexSubImage3D __rglgen_glCompressedTexSubImage3D
#define glCompressedTexSubImage2D __rglgen_glCompressedTexSubImage2D
#define glCompressedTexSubImage1D __rglgen_glCompressedTexSubImage1D
#define glGetCompressedTexImage __rglgen_glGetCompressedTexImage
#define glClientActiveTexture __rglgen_glClientActiveTexture
#define glMultiTexCoord1d __rglgen_glMultiTexCoord1d
#define glMultiTexCoord1dv __rglgen_glMultiTexCoord1dv
#define glMultiTexCoord1f __rglgen_glMultiTexCoord1f
#define glMultiTexCoord1fv __rglgen_glMultiTexCoord1fv
#define glMultiTexCoord1i __rglgen_glMultiTexCoord1i
#define glMultiTexCoord1iv __rglgen_glMultiTexCoord1iv
#define glMultiTexCoord1s __rglgen_glMultiTexCoord1s
#define glMultiTexCoord1sv __rglgen_glMultiTexCoord1sv
#define glMultiTexCoord2d __rglgen_glMultiTexCoord2d
#define glMultiTexCoord2dv __rglgen_glMultiTexCoord2dv
#define glMultiTexCoord2f __rglgen_glMultiTexCoord2f
#define glMultiTexCoord2fv __rglgen_glMultiTexCoord2fv
#define glMultiTexCoord2i __rglgen_glMultiTexCoord2i
#define glMultiTexCoord2iv __rglgen_glMultiTexCoord2iv
#define glMultiTexCoord2s __rglgen_glMultiTexCoord2s
#define glMultiTexCoord2sv __rglgen_glMultiTexCoord2sv
#define glMultiTexCoord3d __rglgen_glMultiTexCoord3d
#define glMultiTexCoord3dv __rglgen_glMultiTexCoord3dv
#define glMultiTexCoord3f __rglgen_glMultiTexCoord3f
#define glMultiTexCoord3fv __rglgen_glMultiTexCoord3fv
#define glMultiTexCoord3i __rglgen_glMultiTexCoord3i
#define glMultiTexCoord3iv __rglgen_glMultiTexCoord3iv
#define glMultiTexCoord3s __rglgen_glMultiTexCoord3s
#define glMultiTexCoord3sv __rglgen_glMultiTexCoord3sv
#define glMultiTexCoord4d __rglgen_glMultiTexCoord4d
#define glMultiTexCoord4dv __rglgen_glMultiTexCoord4dv
#define glMultiTexCoord4f __rglgen_glMultiTexCoord4f
#define glMultiTexCoord4fv __rglgen_glMultiTexCoord4fv
#define glMultiTexCoord4i __rglgen_glMultiTexCoord4i
#define glMultiTexCoord4iv __rglgen_glMultiTexCoord4iv
#define glMultiTexCoord4s __rglgen_glMultiTexCoord4s
#define glMultiTexCoord4sv __rglgen_glMultiTexCoord4sv
#define glLoadTransposeMatrixf __rglgen_glLoadTransposeMatrixf
#define glLoadTransposeMatrixd __rglgen_glLoadTransposeMatrixd
#define glMultTransposeMatrixf __rglgen_glMultTransposeMatrixf
#define glMultTransposeMatrixd __rglgen_glMultTransposeMatrixd
#define glBlendFuncSeparate __rglgen_glBlendFuncSeparate
#define glMultiDrawArrays __rglgen_glMultiDrawArrays
#define glMultiDrawElements __rglgen_glMultiDrawElements
#define glPointParameterf __rglgen_glPointParameterf
#define glPointParameterfv __rglgen_glPointParameterfv
#define glPointParameteri __rglgen_glPointParameteri
#define glPointParameteriv __rglgen_glPointParameteriv
#define glFogCoordf __rglgen_glFogCoordf
#define glFogCoordfv __rglgen_glFogCoordfv
#define glFogCoordd __rglgen_glFogCoordd
#define glFogCoorddv __rglgen_glFogCoorddv
#define glFogCoordPointer __rglgen_glFogCoordPointer
#define glSecondaryColor3b __rglgen_glSecondaryColor3b
#define glSecondaryColor3bv __rglgen_glSecondaryColor3bv
#define glSecondaryColor3d __rglgen_glSecondaryColor3d
#define glSecondaryColor3dv __rglgen_glSecondaryColor3dv
#define glSecondaryColor3f __rglgen_glSecondaryColor3f
#define glSecondaryColor3fv __rglgen_glSecondaryColor3fv
#define glSecondaryColor3i __rglgen_glSecondaryColor3i
#define glSecondaryColor3iv __rglgen_glSecondaryColor3iv
#define glSecondaryColor3s __rglgen_glSecondaryColor3s
#define glSecondaryColor3sv __rglgen_glSecondaryColor3sv
#define glSecondaryColor3ub __rglgen_glSecondaryColor3ub
#define glSecondaryColor3ubv __rglgen_glSecondaryColor3ubv
#define glSecondaryColor3ui __rglgen_glSecondaryColor3ui
#define glSecondaryColor3uiv __rglgen_glSecondaryColor3uiv
#define glSecondaryColor3us __rglgen_glSecondaryColor3us
#define glSecondaryColor3usv __rglgen_glSecondaryColor3usv
#define glSecondaryColorPointer __rglgen_glSecondaryColorPointer
#define glWindowPos2d __rglgen_glWindowPos2d
#define glWindowPos2dv __rglgen_glWindowPos2dv
#define glWindowPos2f __rglgen_glWindowPos2f
#define glWindowPos2fv __rglgen_glWindowPos2fv
#define glWindowPos2i __rglgen_glWindowPos2i
#define glWindowPos2iv __rglgen_glWindowPos2iv
#define glWindowPos2s __rglgen_glWindowPos2s
#define glWindowPos2sv __rglgen_glWindowPos2sv
#define glWindowPos3d __rglgen_glWindowPos3d
#define glWindowPos3dv __rglgen_glWindowPos3dv
#define glWindowPos3f __rglgen_glWindowPos3f
#define glWindowPos3fv __rglgen_glWindowPos3fv
#define glWindowPos3i __rglgen_glWindowPos3i
#define glWindowPos3iv __rglgen_glWindowPos3iv
#define glWindowPos3s __rglgen_glWindowPos3s
#define glWindowPos3sv __rglgen_glWindowPos3sv
#define glBlendColor __rglgen_glBlendColor
#define glBlendEquation __rglgen_glBlendEquation
#define glGenQueries __rglgen_glGenQueries
#define glDeleteQueries __rglgen_glDeleteQueries
#define glIsQuery __rglgen_glIsQuery
#define glBeginQuery __rglgen_glBeginQuery
#define glEndQuery __rglgen_glEndQuery
#define glGetQueryiv __rglgen_glGetQueryiv
#define glGetQueryObjectiv __rglgen_glGetQueryObjectiv
#define glGetQueryObjectuiv __rglgen_glGetQueryObjectuiv
#define glBindBuffer __rglgen_glBindBuffer
#define glDeleteBuffers __rglgen_glDeleteBuffers
#define glGenBuffers __rglgen_glGenBuffers
#define glIsBuffer __rglgen_glIsBuffer
#define glBufferData __rglgen_glBufferData
#define glBufferSubData __rglgen_glBufferSubData
#define glGetBufferSubData __rglgen_glGetBufferSubData
#define glMapBuffer __rglgen_glMapBuffer
#define glUnmapBuffer __rglgen_glUnmapBuffer
#define glGetBufferParameteriv __rglgen_glGetBufferParameteriv
#define glGetBufferPointerv __rglgen_glGetBufferPointerv
#define glBlendEquationSeparate __rglgen_glBlendEquationSeparate
#define glDrawBuffers __rglgen_glDrawBuffers
#define glStencilOpSeparate __rglgen_glStencilOpSeparate
#define glStencilFuncSeparate __rglgen_glStencilFuncSeparate
#define glStencilMaskSeparate __rglgen_glStencilMaskSeparate
#define glAttachShader __rglgen_glAttachShader
#define glBindAttribLocation __rglgen_glBindAttribLocation
#define glCompileShader __rglgen_glCompileShader
#define glCreateProgram __rglgen_glCreateProgram
#define glCreateShader __rglgen_glCreateShader
#define glDeleteProgram __rglgen_glDeleteProgram
#define glDeleteShader __rglgen_glDeleteShader
#define glDetachShader __rglgen_glDetachShader
#define glDisableVertexAttribArray __rglgen_glDisableVertexAttribArray
#define glEnableVertexAttribArray __rglgen_glEnableVertexAttribArray
#define glGetActiveAttrib __rglgen_glGetActiveAttrib
#define glGetActiveUniform __rglgen_glGetActiveUniform
#define glGetAttachedShaders __rglgen_glGetAttachedShaders
#define glGetAttribLocation __rglgen_glGetAttribLocation
#define glGetProgramiv __rglgen_glGetProgramiv
#define glGetProgramInfoLog __rglgen_glGetProgramInfoLog
#define glGetShaderiv __rglgen_glGetShaderiv
#define glGetShaderInfoLog __rglgen_glGetShaderInfoLog
#define glGetShaderSource __rglgen_glGetShaderSource
#define glGetUniformLocation __rglgen_glGetUniformLocation
#define glGetUniformfv __rglgen_glGetUniformfv
#define glGetUniformiv __rglgen_glGetUniformiv
#define glGetVertexAttribdv __rglgen_glGetVertexAttribdv
#define glGetVertexAttribfv __rglgen_glGetVertexAttribfv
#define glGetVertexAttribiv __rglgen_glGetVertexAttribiv
#define glGetVertexAttribPointerv __rglgen_glGetVertexAttribPointerv
#define glIsProgram __rglgen_glIsProgram
#define glIsShader __rglgen_glIsShader
#define glLinkProgram __rglgen_glLinkProgram
#define glShaderSource __rglgen_glShaderSource
#define glUseProgram __rglgen_glUseProgram
#define glUniform1f __rglgen_glUniform1f
#define glUniform2f __rglgen_glUniform2f
#define glUniform3f __rglgen_glUniform3f
#define glUniform4f __rglgen_glUniform4f
#define glUniform1i __rglgen_glUniform1i
#define glUniform2i __rglgen_glUniform2i
#define glUniform3i __rglgen_glUniform3i
#define glUniform4i __rglgen_glUniform4i
#define glUniform1fv __rglgen_glUniform1fv
#define glUniform2fv __rglgen_glUniform2fv
#define glUniform3fv __rglgen_glUniform3fv
#define glUniform4fv __rglgen_glUniform4fv
#define glUniform1iv __rglgen_glUniform1iv
#define glUniform2iv __rglgen_glUniform2iv
#define glUniform3iv __rglgen_glUniform3iv
#define glUniform4iv __rglgen_glUniform4iv
#define glUniformMatrix2fv __rglgen_glUniformMatrix2fv
#define glUniformMatrix3fv __rglgen_glUniformMatrix3fv
#define glUniformMatrix4fv __rglgen_glUniformMatrix4fv
#define glValidateProgram __rglgen_glValidateProgram
#define glVertexAttrib1d __rglgen_glVertexAttrib1d
#define glVertexAttrib1dv __rglgen_glVertexAttrib1dv
#define glVertexAttrib1f __rglgen_glVertexAttrib1f
#define glVertexAttrib1fv __rglgen_glVertexAttrib1fv
#define glVertexAttrib1s __rglgen_glVertexAttrib1s
#define glVertexAttrib1sv __rglgen_glVertexAttrib1sv
#define glVertexAttrib2d __rglgen_glVertexAttrib2d
#define glVertexAttrib2dv __rglgen_glVertexAttrib2dv
#define glVertexAttrib2f __rglgen_glVertexAttrib2f
#define glVertexAttrib2fv __rglgen_glVertexAttrib2fv
#define glVertexAttrib2s __rglgen_glVertexAttrib2s
#define glVertexAttrib2sv __rglgen_glVertexAttrib2sv
#define glVertexAttrib3d __rglgen_glVertexAttrib3d
#define glVertexAttrib3dv __rglgen_glVertexAttrib3dv
#define glVertexAttrib3f __rglgen_glVertexAttrib3f
#define glVertexAttrib3fv __rglgen_glVertexAttrib3fv
#define glVertexAttrib3s __rglgen_glVertexAttrib3s
#define glVertexAttrib3sv __rglgen_glVertexAttrib3sv
#define glVertexAttrib4Nbv __rglgen_glVertexAttrib4Nbv
#define glVertexAttrib4Niv __rglgen_glVertexAttrib4Niv
#define glVertexAttrib4Nsv __rglgen_glVertexAttrib4Nsv
#define glVertexAttrib4Nub __rglgen_glVertexAttrib4Nub
#define glVertexAttrib4Nubv __rglgen_glVertexAttrib4Nubv
#define glVertexAttrib4Nuiv __rglgen_glVertexAttrib4Nuiv
#define glVertexAttrib4Nusv __rglgen_glVertexAttrib4Nusv
#define glVertexAttrib4bv __rglgen_glVertexAttrib4bv
#define glVertexAttrib4d __rglgen_glVertexAttrib4d
#define glVertexAttrib4dv __rglgen_glVertexAttrib4dv
#define glVertexAttrib4f __rglgen_glVertexAttrib4f
#define glVertexAttrib4fv __rglgen_glVertexAttrib4fv
#define glVertexAttrib4iv __rglgen_glVertexAttrib4iv
#define glVertexAttrib4s __rglgen_glVertexAttrib4s
#define glVertexAttrib4sv __rglgen_glVertexAttrib4sv
#define glVertexAttrib4ubv __rglgen_glVertexAttrib4ubv
#define glVertexAttrib4uiv __rglgen_glVertexAttrib4uiv
#define glVertexAttrib4usv __rglgen_glVertexAttrib4usv
#define glVertexAttribPointer __rglgen_glVertexAttribPointer
#define glUniformMatrix2x3fv __rglgen_glUniformMatrix2x3fv
#define glUniformMatrix3x2fv __rglgen_glUniformMatrix3x2fv
#define glUniformMatrix2x4fv __rglgen_glUniformMatrix2x4fv
#define glUniformMatrix4x2fv __rglgen_glUniformMatrix4x2fv
#define glUniformMatrix3x4fv __rglgen_glUniformMatrix3x4fv
#define glUniformMatrix4x3fv __rglgen_glUniformMatrix4x3fv
#define glColorMaski __rglgen_glColorMaski
#define glGetBooleani_v __rglgen_glGetBooleani_v
#define glGetIntegeri_v __rglgen_glGetIntegeri_v
#define glEnablei __rglgen_glEnablei
#define glDisablei __rglgen_glDisablei
#define glIsEnabledi __rglgen_glIsEnabledi
#define glBeginTransformFeedback __rglgen_glBeginTransformFeedback
#define glEndTransformFeedback __rglgen_glEndTransformFeedback
#define glBindBufferRange __rglgen_glBindBufferRange
#define glBindBufferBase __rglgen_glBindBufferBase
#define glTransformFeedbackVaryings __rglgen_glTransformFeedbackVaryings
#define glGetTransformFeedbackVarying __rglgen_glGetTransformFeedbackVarying
#define glClampColor __rglgen_glClampColor
#define glBeginConditionalRender __rglgen_glBeginConditionalRender
#define glEndConditionalRender __rglgen_glEndConditionalRender
#define glVertexAttribIPointer __rglgen_glVertexAttribIPointer
#define glGetVertexAttribIiv __rglgen_glGetVertexAttribIiv
#define glGetVertexAttribIuiv __rglgen_glGetVertexAttribIuiv
#define glVertexAttribI1i __rglgen_glVertexAttribI1i
#define glVertexAttribI2i __rglgen_glVertexAttribI2i
#define glVertexAttribI3i __rglgen_glVertexAttribI3i
#define glVertexAttribI4i __rglgen_glVertexAttribI4i
#define glVertexAttribI1ui __rglgen_glVertexAttribI1ui
#define glVertexAttribI2ui __rglgen_glVertexAttribI2ui
#define glVertexAttribI3ui __rglgen_glVertexAttribI3ui
#define glVertexAttribI4ui __rglgen_glVertexAttribI4ui
#define glVertexAttribI1iv __rglgen_glVertexAttribI1iv
#define glVertexAttribI2iv __rglgen_glVertexAttribI2iv
#define glVertexAttribI3iv __rglgen_glVertexAttribI3iv
#define glVertexAttribI4iv __rglgen_glVertexAttribI4iv
#define glVertexAttribI1uiv __rglgen_glVertexAttribI1uiv
#define glVertexAttribI2uiv __rglgen_glVertexAttribI2uiv
#define glVertexAttribI3uiv __rglgen_glVertexAttribI3uiv
#define glVertexAttribI4uiv __rglgen_glVertexAttribI4uiv
#define glVertexAttribI4bv __rglgen_glVertexAttribI4bv
#define glVertexAttribI4sv __rglgen_glVertexAttribI4sv
#define glVertexAttribI4ubv __rglgen_glVertexAttribI4ubv
#define glVertexAttribI4usv __rglgen_glVertexAttribI4usv
#define glGetUniformuiv __rglgen_glGetUniformuiv
#define glBindFragDataLocation __rglgen_glBindFragDataLocation
#define glGetFragDataLocation __rglgen_glGetFragDataLocation
#define glUniform1ui __rglgen_glUniform1ui
#define glUniform2ui __rglgen_glUniform2ui
#define glUniform3ui __rglgen_glUniform3ui
#define glUniform4ui __rglgen_glUniform4ui
#define glUniform1uiv __rglgen_glUniform1uiv
#define glUniform2uiv __rglgen_glUniform2uiv
#define glUniform3uiv __rglgen_glUniform3uiv
#define glUniform4uiv __rglgen_glUniform4uiv
#define glTexParameterIiv __rglgen_glTexParameterIiv
#define glTexParameterIuiv __rglgen_glTexParameterIuiv
#define glGetTexParameterIiv __rglgen_glGetTexParameterIiv
#define glGetTexParameterIuiv __rglgen_glGetTexParameterIuiv
#define glClearBufferiv __rglgen_glClearBufferiv
#define glClearBufferuiv __rglgen_glClearBufferuiv
#define glClearBufferfv __rglgen_glClearBufferfv
#define glClearBufferfi __rglgen_glClearBufferfi
#define glGetStringi __rglgen_glGetStringi
#define glIsRenderbuffer __rglgen_glIsRenderbuffer
#define glBindRenderbuffer __rglgen_glBindRenderbuffer
#define glDeleteRenderbuffers __rglgen_glDeleteRenderbuffers
#define glGenRenderbuffers __rglgen_glGenRenderbuffers
#define glRenderbufferStorage __rglgen_glRenderbufferStorage
#define glGetRenderbufferParameteriv __rglgen_glGetRenderbufferParameteriv
#define glIsFramebuffer __rglgen_glIsFramebuffer
#define glBindFramebuffer __rglgen_glBindFramebuffer
#define glDeleteFramebuffers __rglgen_glDeleteFramebuffers
#define glGenFramebuffers __rglgen_glGenFramebuffers
#define glCheckFramebufferStatus __rglgen_glCheckFramebufferStatus
#define glFramebufferTexture1D __rglgen_glFramebufferTexture1D
#define glFramebufferTexture2D __rglgen_glFramebufferTexture2D
#define glFramebufferTexture3D __rglgen_glFramebufferTexture3D
#define glFramebufferRenderbuffer __rglgen_glFramebufferRenderbuffer
#define glGetFramebufferAttachmentParameteriv __rglgen_glGetFramebufferAttachmentParameteriv
#define glGenerateMipmap __rglgen_glGenerateMipmap
#define glBlitFramebuffer __rglgen_glBlitFramebuffer
#define glRenderbufferStorageMultisample __rglgen_glRenderbufferStorageMultisample
#define glFramebufferTextureLayer __rglgen_glFramebufferTextureLayer
#define glMapBufferRange __rglgen_glMapBufferRange
#define glFlushMappedBufferRange __rglgen_glFlushMappedBufferRange
#define glBindVertexArray __rglgen_glBindVertexArray
#define glDeleteVertexArrays __rglgen_glDeleteVertexArrays
#define glGenVertexArrays __rglgen_glGenVertexArrays
#define glIsVertexArray __rglgen_glIsVertexArray
#define glDrawArraysInstanced __rglgen_glDrawArraysInstanced
#define glDrawElementsInstanced __rglgen_glDrawElementsInstanced
#define glTexBuffer __rglgen_glTexBuffer
#define glPrimitiveRestartIndex __rglgen_glPrimitiveRestartIndex
#define glCopyBufferSubData __rglgen_glCopyBufferSubData
#define glGetUniformIndices __rglgen_glGetUniformIndices
#define glGetActiveUniformsiv __rglgen_glGetActiveUniformsiv
#define glGetActiveUniformName __rglgen_glGetActiveUniformName
#define glGetUniformBlockIndex __rglgen_glGetUniformBlockIndex
#define glGetActiveUniformBlockiv __rglgen_glGetActiveUniformBlockiv
#define glGetActiveUniformBlockName __rglgen_glGetActiveUniformBlockName
#define glUniformBlockBinding __rglgen_glUniformBlockBinding
#define glDrawElementsBaseVertex __rglgen_glDrawElementsBaseVertex
#define glDrawRangeElementsBaseVertex __rglgen_glDrawRangeElementsBaseVertex
#define glDrawElementsInstancedBaseVertex __rglgen_glDrawElementsInstancedBaseVertex
#define glMultiDrawElementsBaseVertex __rglgen_glMultiDrawElementsBaseVertex
#define glProvokingVertex __rglgen_glProvokingVertex
#define glFenceSync __rglgen_glFenceSync
#define glIsSync __rglgen_glIsSync
#define glDeleteSync __rglgen_glDeleteSync
#define glClientWaitSync __rglgen_glClientWaitSync
#define glWaitSync __rglgen_glWaitSync
#define glGetInteger64v __rglgen_glGetInteger64v
#define glGetSynciv __rglgen_glGetSynciv
#define glGetInteger64i_v __rglgen_glGetInteger64i_v
#define glGetBufferParameteri64v __rglgen_glGetBufferParameteri64v
#define glFramebufferTexture __rglgen_glFramebufferTexture
#define glTexImage2DMultisample __rglgen_glTexImage2DMultisample
#define glTexImage3DMultisample __rglgen_glTexImage3DMultisample
#define glGetMultisamplefv __rglgen_glGetMultisamplefv
#define glSampleMaski __rglgen_glSampleMaski
#define glBindFragDataLocationIndexed __rglgen_glBindFragDataLocationIndexed
#define glGetFragDataIndex __rglgen_glGetFragDataIndex
#define glGenSamplers __rglgen_glGenSamplers
#define glDeleteSamplers __rglgen_glDeleteSamplers
#define glIsSampler __rglgen_glIsSampler
#define glBindSampler __rglgen_glBindSampler
#define glSamplerParameteri __rglgen_glSamplerParameteri
#define glSamplerParameteriv __rglgen_glSamplerParameteriv
#define glSamplerParameterf __rglgen_glSamplerParameterf
#define glSamplerParameterfv __rglgen_glSamplerParameterfv
#define glSamplerParameterIiv __rglgen_glSamplerParameterIiv
#define glSamplerParameterIuiv __rglgen_glSamplerParameterIuiv
#define glGetSamplerParameteriv __rglgen_glGetSamplerParameteriv
#define glGetSamplerParameterIiv __rglgen_glGetSamplerParameterIiv
#define glGetSamplerParameterfv __rglgen_glGetSamplerParameterfv
#define glGetSamplerParameterIuiv __rglgen_glGetSamplerParameterIuiv
#define glQueryCounter __rglgen_glQueryCounter
#define glGetQueryObjecti64v __rglgen_glGetQueryObjecti64v
#define glGetQueryObjectui64v __rglgen_glGetQueryObjectui64v
#define glVertexAttribDivisor __rglgen_glVertexAttribDivisor
#define glVertexAttribP1ui __rglgen_glVertexAttribP1ui
#define glVertexAttribP1uiv __rglgen_glVertexAttribP1uiv
#define glVertexAttribP2ui __rglgen_glVertexAttribP2ui
#define glVertexAttribP2uiv __rglgen_glVertexAttribP2uiv
#define glVertexAttribP3ui __rglgen_glVertexAttribP3ui
#define glVertexAttribP3uiv __rglgen_glVertexAttribP3uiv
#define glVertexAttribP4ui __rglgen_glVertexAttribP4ui
#define glVertexAttribP4uiv __rglgen_glVertexAttribP4uiv
#define glVertexP2ui __rglgen_glVertexP2ui
#define glVertexP2uiv __rglgen_glVertexP2uiv
#define glVertexP3ui __rglgen_glVertexP3ui
#define glVertexP3uiv __rglgen_glVertexP3uiv
#define glVertexP4ui __rglgen_glVertexP4ui
#define glVertexP4uiv __rglgen_glVertexP4uiv
#define glTexCoordP1ui __rglgen_glTexCoordP1ui
#define glTexCoordP1uiv __rglgen_glTexCoordP1uiv
#define glTexCoordP2ui __rglgen_glTexCoordP2ui
#define glTexCoordP2uiv __rglgen_glTexCoordP2uiv
#define glTexCoordP3ui __rglgen_glTexCoordP3ui
#define glTexCoordP3uiv __rglgen_glTexCoordP3uiv
#define glTexCoordP4ui __rglgen_glTexCoordP4ui
#define glTexCoordP4uiv __rglgen_glTexCoordP4uiv
#define glMultiTexCoordP1ui __rglgen_glMultiTexCoordP1ui
#define glMultiTexCoordP1uiv __rglgen_glMultiTexCoordP1uiv
#define glMultiTexCoordP2ui __rglgen_glMultiTexCoordP2ui
#define glMultiTexCoordP2uiv __rglgen_glMultiTexCoordP2uiv
#define glMultiTexCoordP3ui __rglgen_glMultiTexCoordP3ui
#define glMultiTexCoordP3uiv __rglgen_glMultiTexCoordP3uiv
#define glMultiTexCoordP4ui __rglgen_glMultiTexCoordP4ui
#define glMultiTexCoordP4uiv __rglgen_glMultiTexCoordP4uiv
#define glNormalP3ui __rglgen_glNormalP3ui
#define glNormalP3uiv __rglgen_glNormalP3uiv
#define glColorP3ui __rglgen_glColorP3ui
#define glColorP3uiv __rglgen_glColorP3uiv
#define glColorP4ui __rglgen_glColorP4ui
#define glColorP4uiv __rglgen_glColorP4uiv
#define glSecondaryColorP3ui __rglgen_glSecondaryColorP3ui
#define glSecondaryColorP3uiv __rglgen_glSecondaryColorP3uiv
#define glMinSampleShading __rglgen_glMinSampleShading
#define glBlendEquationi __rglgen_glBlendEquationi
#define glBlendEquationSeparatei __rglgen_glBlendEquationSeparatei
#define glBlendFunci __rglgen_glBlendFunci
#define glBlendFuncSeparatei __rglgen_glBlendFuncSeparatei
#define glDrawArraysIndirect __rglgen_glDrawArraysIndirect
#define glDrawElementsIndirect __rglgen_glDrawElementsIndirect
#define glUniform1d __rglgen_glUniform1d
#define glUniform2d __rglgen_glUniform2d
#define glUniform3d __rglgen_glUniform3d
#define glUniform4d __rglgen_glUniform4d
#define glUniform1dv __rglgen_glUniform1dv
#define glUniform2dv __rglgen_glUniform2dv
#define glUniform3dv __rglgen_glUniform3dv
#define glUniform4dv __rglgen_glUniform4dv
#define glUniformMatrix2dv __rglgen_glUniformMatrix2dv
#define glUniformMatrix3dv __rglgen_glUniformMatrix3dv
#define glUniformMatrix4dv __rglgen_glUniformMatrix4dv
#define glUniformMatrix2x3dv __rglgen_glUniformMatrix2x3dv
#define glUniformMatrix2x4dv __rglgen_glUniformMatrix2x4dv
#define glUniformMatrix3x2dv __rglgen_glUniformMatrix3x2dv
#define glUniformMatrix3x4dv __rglgen_glUniformMatrix3x4dv
#define glUniformMatrix4x2dv __rglgen_glUniformMatrix4x2dv
#define glUniformMatrix4x3dv __rglgen_glUniformMatrix4x3dv
#define glGetUniformdv __rglgen_glGetUniformdv
#define glGetSubroutineUniformLocation __rglgen_glGetSubroutineUniformLocation
#define glGetSubroutineIndex __rglgen_glGetSubroutineIndex
#define glGetActiveSubroutineUniformiv __rglgen_glGetActiveSubroutineUniformiv
#define glGetActiveSubroutineUniformName __rglgen_glGetActiveSubroutineUniformName
#define glGetActiveSubroutineName __rglgen_glGetActiveSubroutineName
#define glUniformSubroutinesuiv __rglgen_glUniformSubroutinesuiv
#define glGetUniformSubroutineuiv __rglgen_glGetUniformSubroutineuiv
#define glGetProgramStageiv __rglgen_glGetProgramStageiv
#define glPatchParameteri __rglgen_glPatchParameteri
#define glPatchParameterfv __rglgen_glPatchParameterfv
#define glBindTransformFeedback __rglgen_glBindTransformFeedback
#define glDeleteTransformFeedbacks __rglgen_glDeleteTransformFeedbacks
#define glGenTransformFeedbacks __rglgen_glGenTransformFeedbacks
#define glIsTransformFeedback __rglgen_glIsTransformFeedback
#define glPauseTransformFeedback __rglgen_glPauseTransformFeedback
#define glResumeTransformFeedback __rglgen_glResumeTransformFeedback
#define glDrawTransformFeedback __rglgen_glDrawTransformFeedback
#define glDrawTransformFeedbackStream __rglgen_glDrawTransformFeedbackStream
#define glBeginQueryIndexed __rglgen_glBeginQueryIndexed
#define glEndQueryIndexed __rglgen_glEndQueryIndexed
#define glGetQueryIndexediv __rglgen_glGetQueryIndexediv
#define glReleaseShaderCompiler __rglgen_glReleaseShaderCompiler
#define glShaderBinary __rglgen_glShaderBinary
#define glGetShaderPrecisionFormat __rglgen_glGetShaderPrecisionFormat
#define glDepthRangef __rglgen_glDepthRangef
#define glClearDepthf __rglgen_glClearDepthf
#define glGetProgramBinary __rglgen_glGetProgramBinary
#define glProgramBinary __rglgen_glProgramBinary
#define glProgramParameteri __rglgen_glProgramParameteri
#define glUseProgramStages __rglgen_glUseProgramStages
#define glActiveShaderProgram __rglgen_glActiveShaderProgram
#define glCreateShaderProgramv __rglgen_glCreateShaderProgramv
#define glBindProgramPipeline __rglgen_glBindProgramPipeline
#define glDeleteProgramPipelines __rglgen_glDeleteProgramPipelines
#define glGenProgramPipelines __rglgen_glGenProgramPipelines
#define glIsProgramPipeline __rglgen_glIsProgramPipeline
#define glGetProgramPipelineiv __rglgen_glGetProgramPipelineiv
#define glProgramUniform1i __rglgen_glProgramUniform1i
#define glProgramUniform1iv __rglgen_glProgramUniform1iv
#define glProgramUniform1f __rglgen_glProgramUniform1f
#define glProgramUniform1fv __rglgen_glProgramUniform1fv
#define glProgramUniform1d __rglgen_glProgramUniform1d
#define glProgramUniform1dv __rglgen_glProgramUniform1dv
#define glProgramUniform1ui __rglgen_glProgramUniform1ui
#define glProgramUniform1uiv __rglgen_glProgramUniform1uiv
#define glProgramUniform2i __rglgen_glProgramUniform2i
#define glProgramUniform2iv __rglgen_glProgramUniform2iv
#define glProgramUniform2f __rglgen_glProgramUniform2f
#define glProgramUniform2fv __rglgen_glProgramUniform2fv
#define glProgramUniform2d __rglgen_glProgramUniform2d
#define glProgramUniform2dv __rglgen_glProgramUniform2dv
#define glProgramUniform2ui __rglgen_glProgramUniform2ui
#define glProgramUniform2uiv __rglgen_glProgramUniform2uiv
#define glProgramUniform3i __rglgen_glProgramUniform3i
#define glProgramUniform3iv __rglgen_glProgramUniform3iv
#define glProgramUniform3f __rglgen_glProgramUniform3f
#define glProgramUniform3fv __rglgen_glProgramUniform3fv
#define glProgramUniform3d __rglgen_glProgramUniform3d
#define glProgramUniform3dv __rglgen_glProgramUniform3dv
#define glProgramUniform3ui __rglgen_glProgramUniform3ui
#define glProgramUniform3uiv __rglgen_glProgramUniform3uiv
#define glProgramUniform4i __rglgen_glProgramUniform4i
#define glProgramUniform4iv __rglgen_glProgramUniform4iv
#define glProgramUniform4f __rglgen_glProgramUniform4f
#define glProgramUniform4fv __rglgen_glProgramUniform4fv
#define glProgramUniform4d __rglgen_glProgramUniform4d
#define glProgramUniform4dv __rglgen_glProgramUniform4dv
#define glProgramUniform4ui __rglgen_glProgramUniform4ui
#define glProgramUniform4uiv __rglgen_glProgramUniform4uiv
#define glProgramUniformMatrix2fv __rglgen_glProgramUniformMatrix2fv
#define glProgramUniformMatrix3fv __rglgen_glProgramUniformMatrix3fv
#define glProgramUniformMatrix4fv __rglgen_glProgramUniformMatrix4fv
#define glProgramUniformMatrix2dv __rglgen_glProgramUniformMatrix2dv
#define glProgramUniformMatrix3dv __rglgen_glProgramUniformMatrix3dv
#define glProgramUniformMatrix4dv __rglgen_glProgramUniformMatrix4dv
#define glProgramUniformMatrix2x3fv __rglgen_glProgramUniformMatrix2x3fv
#define glProgramUniformMatrix3x2fv __rglgen_glProgramUniformMatrix3x2fv
#define glProgramUniformMatrix2x4fv __rglgen_glProgramUniformMatrix2x4fv
#define glProgramUniformMatrix4x2fv __rglgen_glProgramUniformMatrix4x2fv
#define glProgramUniformMatrix3x4fv __rglgen_glProgramUniformMatrix3x4fv
#define glProgramUniformMatrix4x3fv __rglgen_glProgramUniformMatrix4x3fv
#define glProgramUniformMatrix2x3dv __rglgen_glProgramUniformMatrix2x3dv
#define glProgramUniformMatrix3x2dv __rglgen_glProgramUniformMatrix3x2dv
#define glProgramUniformMatrix2x4dv __rglgen_glProgramUniformMatrix2x4dv
#define glProgramUniformMatrix4x2dv __rglgen_glProgramUniformMatrix4x2dv
#define glProgramUniformMatrix3x4dv __rglgen_glProgramUniformMatrix3x4dv
#define glProgramUniformMatrix4x3dv __rglgen_glProgramUniformMatrix4x3dv
#define glValidateProgramPipeline __rglgen_glValidateProgramPipeline
#define glGetProgramPipelineInfoLog __rglgen_glGetProgramPipelineInfoLog
#define glVertexAttribL1d __rglgen_glVertexAttribL1d
#define glVertexAttribL2d __rglgen_glVertexAttribL2d
#define glVertexAttribL3d __rglgen_glVertexAttribL3d
#define glVertexAttribL4d __rglgen_glVertexAttribL4d
#define glVertexAttribL1dv __rglgen_glVertexAttribL1dv
#define glVertexAttribL2dv __rglgen_glVertexAttribL2dv
#define glVertexAttribL3dv __rglgen_glVertexAttribL3dv
#define glVertexAttribL4dv __rglgen_glVertexAttribL4dv
#define glVertexAttribLPointer __rglgen_glVertexAttribLPointer
#define glGetVertexAttribLdv __rglgen_glGetVertexAttribLdv
#define glViewportArrayv __rglgen_glViewportArrayv
#define glViewportIndexedf __rglgen_glViewportIndexedf
#define glViewportIndexedfv __rglgen_glViewportIndexedfv
#define glScissorArrayv __rglgen_glScissorArrayv
#define glScissorIndexed __rglgen_glScissorIndexed
#define glScissorIndexedv __rglgen_glScissorIndexedv
#define glDepthRangeArrayv __rglgen_glDepthRangeArrayv
#define glDepthRangeIndexed __rglgen_glDepthRangeIndexed
#define glGetFloati_v __rglgen_glGetFloati_v
#define glGetDoublei_v __rglgen_glGetDoublei_v
#define glDrawArraysInstancedBaseInstance __rglgen_glDrawArraysInstancedBaseInstance
#define glDrawElementsInstancedBaseInstance __rglgen_glDrawElementsInstancedBaseInstance
#define glDrawElementsInstancedBaseVertexBaseInstance __rglgen_glDrawElementsInstancedBaseVertexBaseInstance
#define glGetInternalformativ __rglgen_glGetInternalformativ
#define glGetActiveAtomicCounterBufferiv __rglgen_glGetActiveAtomicCounterBufferiv
#define glBindImageTexture __rglgen_glBindImageTexture
#define glMemoryBarrier __rglgen_glMemoryBarrier
#define glTexStorage1D __rglgen_glTexStorage1D
#define glTexStorage2D __rglgen_glTexStorage2D
#define glTexStorage3D __rglgen_glTexStorage3D
#define glDrawTransformFeedbackInstanced __rglgen_glDrawTransformFeedbackInstanced
#define glDrawTransformFeedbackStreamInstanced __rglgen_glDrawTransformFeedbackStreamInstanced
#define glClearBufferData __rglgen_glClearBufferData
#define glClearBufferSubData __rglgen_glClearBufferSubData
#define glDispatchCompute __rglgen_glDispatchCompute
#define glDispatchComputeIndirect __rglgen_glDispatchComputeIndirect
#define glCopyImageSubData __rglgen_glCopyImageSubData
#define glFramebufferParameteri __rglgen_glFramebufferParameteri
#define glGetFramebufferParameteriv __rglgen_glGetFramebufferParameteriv
#define glGetInternalformati64v __rglgen_glGetInternalformati64v
#define glInvalidateTexSubImage __rglgen_glInvalidateTexSubImage
#define glInvalidateTexImage __rglgen_glInvalidateTexImage
#define glInvalidateBufferSubData __rglgen_glInvalidateBufferSubData
#define glInvalidateBufferData __rglgen_glInvalidateBufferData
#define glInvalidateFramebuffer __rglgen_glInvalidateFramebuffer
#define glInvalidateSubFramebuffer __rglgen_glInvalidateSubFramebuffer
#define glMultiDrawArraysIndirect __rglgen_glMultiDrawArraysIndirect
#define glMultiDrawElementsIndirect __rglgen_glMultiDrawElementsIndirect
#define glGetProgramInterfaceiv __rglgen_glGetProgramInterfaceiv
#define glGetProgramResourceIndex __rglgen_glGetProgramResourceIndex
#define glGetProgramResourceName __rglgen_glGetProgramResourceName
#define glGetProgramResourceiv __rglgen_glGetProgramResourceiv
#define glGetProgramResourceLocation __rglgen_glGetProgramResourceLocation
#define glGetProgramResourceLocationIndex __rglgen_glGetProgramResourceLocationIndex
#define glShaderStorageBlockBinding __rglgen_glShaderStorageBlockBinding
#define glTexBufferRange __rglgen_glTexBufferRange
#define glTexStorage2DMultisample __rglgen_glTexStorage2DMultisample
#define glTexStorage3DMultisample __rglgen_glTexStorage3DMultisample
#define glTextureView __rglgen_glTextureView
#define glBindVertexBuffer __rglgen_glBindVertexBuffer
#define glVertexAttribFormat __rglgen_glVertexAttribFormat
#define glVertexAttribIFormat __rglgen_glVertexAttribIFormat
#define glVertexAttribLFormat __rglgen_glVertexAttribLFormat
#define glVertexAttribBinding __rglgen_glVertexAttribBinding
#define glVertexBindingDivisor __rglgen_glVertexBindingDivisor
#define glDebugMessageControl __rglgen_glDebugMessageControl
#define glDebugMessageInsert __rglgen_glDebugMessageInsert
#define glDebugMessageCallback __rglgen_glDebugMessageCallback
#define glGetDebugMessageLog __rglgen_glGetDebugMessageLog
#define glPushDebugGroup __rglgen_glPushDebugGroup
#define glPopDebugGroup __rglgen_glPopDebugGroup
#define glObjectLabel __rglgen_glObjectLabel
#define glGetObjectLabel __rglgen_glGetObjectLabel
#define glObjectPtrLabel __rglgen_glObjectPtrLabel
#define glGetObjectPtrLabel __rglgen_glGetObjectPtrLabel
#define glBufferStorage __rglgen_glBufferStorage
#define glClearTexImage __rglgen_glClearTexImage
#define glClearTexSubImage __rglgen_glClearTexSubImage
#define glBindBuffersBase __rglgen_glBindBuffersBase
#define glBindBuffersRange __rglgen_glBindBuffersRange
#define glBindTextures __rglgen_glBindTextures
#define glBindSamplers __rglgen_glBindSamplers
#define glBindImageTextures __rglgen_glBindImageTextures
#define glBindVertexBuffers __rglgen_glBindVertexBuffers
#define glGetTextureHandleARB __rglgen_glGetTextureHandleARB
#define glGetTextureSamplerHandleARB __rglgen_glGetTextureSamplerHandleARB
#define glMakeTextureHandleResidentARB __rglgen_glMakeTextureHandleResidentARB
#define glMakeTextureHandleNonResidentARB __rglgen_glMakeTextureHandleNonResidentARB
#define glGetImageHandleARB __rglgen_glGetImageHandleARB
#define glMakeImageHandleResidentARB __rglgen_glMakeImageHandleResidentARB
#define glMakeImageHandleNonResidentARB __rglgen_glMakeImageHandleNonResidentARB
#define glUniformHandleui64ARB __rglgen_glUniformHandleui64ARB
#define glUniformHandleui64vARB __rglgen_glUniformHandleui64vARB
#define glProgramUniformHandleui64ARB __rglgen_glProgramUniformHandleui64ARB
#define glProgramUniformHandleui64vARB __rglgen_glProgramUniformHandleui64vARB
#define glIsTextureHandleResidentARB __rglgen_glIsTextureHandleResidentARB
#define glIsImageHandleResidentARB __rglgen_glIsImageHandleResidentARB
#define glVertexAttribL1ui64ARB __rglgen_glVertexAttribL1ui64ARB
#define glVertexAttribL1ui64vARB __rglgen_glVertexAttribL1ui64vARB
#define glGetVertexAttribLui64vARB __rglgen_glGetVertexAttribLui64vARB
#define glCreateSyncFromCLeventARB __rglgen_glCreateSyncFromCLeventARB
#define glClampColorARB __rglgen_glClampColorARB
#define glDispatchComputeGroupSizeARB __rglgen_glDispatchComputeGroupSizeARB
#define glDebugMessageControlARB __rglgen_glDebugMessageControlARB
#define glDebugMessageInsertARB __rglgen_glDebugMessageInsertARB
#define glDebugMessageCallbackARB __rglgen_glDebugMessageCallbackARB
#define glGetDebugMessageLogARB __rglgen_glGetDebugMessageLogARB
#define glDrawBuffersARB __rglgen_glDrawBuffersARB
#define glBlendEquationiARB __rglgen_glBlendEquationiARB
#define glBlendEquationSeparateiARB __rglgen_glBlendEquationSeparateiARB
#define glBlendFunciARB __rglgen_glBlendFunciARB
#define glBlendFuncSeparateiARB __rglgen_glBlendFuncSeparateiARB
#define glDrawArraysInstancedARB __rglgen_glDrawArraysInstancedARB
#define glDrawElementsInstancedARB __rglgen_glDrawElementsInstancedARB
#define glProgramStringARB __rglgen_glProgramStringARB
#define glBindProgramARB __rglgen_glBindProgramARB
#define glDeleteProgramsARB __rglgen_glDeleteProgramsARB
#define glGenProgramsARB __rglgen_glGenProgramsARB
#define glProgramEnvParameter4dARB __rglgen_glProgramEnvParameter4dARB
#define glProgramEnvParameter4dvARB __rglgen_glProgramEnvParameter4dvARB
#define glProgramEnvParameter4fARB __rglgen_glProgramEnvParameter4fARB
#define glProgramEnvParameter4fvARB __rglgen_glProgramEnvParameter4fvARB
#define glProgramLocalParameter4dARB __rglgen_glProgramLocalParameter4dARB
#define glProgramLocalParameter4dvARB __rglgen_glProgramLocalParameter4dvARB
#define glProgramLocalParameter4fARB __rglgen_glProgramLocalParameter4fARB
#define glProgramLocalParameter4fvARB __rglgen_glProgramLocalParameter4fvARB
#define glGetProgramEnvParameterdvARB __rglgen_glGetProgramEnvParameterdvARB
#define glGetProgramEnvParameterfvARB __rglgen_glGetProgramEnvParameterfvARB
#define glGetProgramLocalParameterdvARB __rglgen_glGetProgramLocalParameterdvARB
#define glGetProgramLocalParameterfvARB __rglgen_glGetProgramLocalParameterfvARB
#define glGetProgramivARB __rglgen_glGetProgramivARB
#define glGetProgramStringARB __rglgen_glGetProgramStringARB
#define glIsProgramARB __rglgen_glIsProgramARB
#define glProgramParameteriARB __rglgen_glProgramParameteriARB
#define glFramebufferTextureARB __rglgen_glFramebufferTextureARB
#define glFramebufferTextureLayerARB __rglgen_glFramebufferTextureLayerARB
#define glFramebufferTextureFaceARB __rglgen_glFramebufferTextureFaceARB
#define glColorTable __rglgen_glColorTable
#define glColorTableParameterfv __rglgen_glColorTableParameterfv
#define glColorTableParameteriv __rglgen_glColorTableParameteriv
#define glCopyColorTable __rglgen_glCopyColorTable
#define glGetColorTable __rglgen_glGetColorTable
#define glGetColorTableParameterfv __rglgen_glGetColorTableParameterfv
#define glGetColorTableParameteriv __rglgen_glGetColorTableParameteriv
#define glColorSubTable __rglgen_glColorSubTable
#define glCopyColorSubTable __rglgen_glCopyColorSubTable
#define glConvolutionFilter1D __rglgen_glConvolutionFilter1D
#define glConvolutionFilter2D __rglgen_glConvolutionFilter2D
#define glConvolutionParameterf __rglgen_glConvolutionParameterf
#define glConvolutionParameterfv __rglgen_glConvolutionParameterfv
#define glConvolutionParameteri __rglgen_glConvolutionParameteri
#define glConvolutionParameteriv __rglgen_glConvolutionParameteriv
#define glCopyConvolutionFilter1D __rglgen_glCopyConvolutionFilter1D
#define glCopyConvolutionFilter2D __rglgen_glCopyConvolutionFilter2D
#define glGetConvolutionFilter __rglgen_glGetConvolutionFilter
#define glGetConvolutionParameterfv __rglgen_glGetConvolutionParameterfv
#define glGetConvolutionParameteriv __rglgen_glGetConvolutionParameteriv
#define glGetSeparableFilter __rglgen_glGetSeparableFilter
#define glSeparableFilter2D __rglgen_glSeparableFilter2D
#define glGetHistogram __rglgen_glGetHistogram
#define glGetHistogramParameterfv __rglgen_glGetHistogramParameterfv
#define glGetHistogramParameteriv __rglgen_glGetHistogramParameteriv
#define glGetMinmax __rglgen_glGetMinmax
#define glGetMinmaxParameterfv __rglgen_glGetMinmaxParameterfv
#define glGetMinmaxParameteriv __rglgen_glGetMinmaxParameteriv
#define glHistogram __rglgen_glHistogram
#define glMinmax __rglgen_glMinmax
#define glResetHistogram __rglgen_glResetHistogram
#define glResetMinmax __rglgen_glResetMinmax
#define glMultiDrawArraysIndirectCountARB __rglgen_glMultiDrawArraysIndirectCountARB
#define glMultiDrawElementsIndirectCountARB __rglgen_glMultiDrawElementsIndirectCountARB
#define glVertexAttribDivisorARB __rglgen_glVertexAttribDivisorARB
#define glCurrentPaletteMatrixARB __rglgen_glCurrentPaletteMatrixARB
#define glMatrixIndexubvARB __rglgen_glMatrixIndexubvARB
#define glMatrixIndexusvARB __rglgen_glMatrixIndexusvARB
#define glMatrixIndexuivARB __rglgen_glMatrixIndexuivARB
#define glMatrixIndexPointerARB __rglgen_glMatrixIndexPointerARB
#define glSampleCoverageARB __rglgen_glSampleCoverageARB
#define glActiveTextureARB __rglgen_glActiveTextureARB
#define glClientActiveTextureARB __rglgen_glClientActiveTextureARB
#define glMultiTexCoord1dARB __rglgen_glMultiTexCoord1dARB
#define glMultiTexCoord1dvARB __rglgen_glMultiTexCoord1dvARB
#define glMultiTexCoord1fARB __rglgen_glMultiTexCoord1fARB
#define glMultiTexCoord1fvARB __rglgen_glMultiTexCoord1fvARB
#define glMultiTexCoord1iARB __rglgen_glMultiTexCoord1iARB
#define glMultiTexCoord1ivARB __rglgen_glMultiTexCoord1ivARB
#define glMultiTexCoord1sARB __rglgen_glMultiTexCoord1sARB
#define glMultiTexCoord1svARB __rglgen_glMultiTexCoord1svARB
#define glMultiTexCoord2dARB __rglgen_glMultiTexCoord2dARB
#define glMultiTexCoord2dvARB __rglgen_glMultiTexCoord2dvARB
#define glMultiTexCoord2fARB __rglgen_glMultiTexCoord2fARB
#define glMultiTexCoord2fvARB __rglgen_glMultiTexCoord2fvARB
#define glMultiTexCoord2iARB __rglgen_glMultiTexCoord2iARB
#define glMultiTexCoord2ivARB __rglgen_glMultiTexCoord2ivARB
#define glMultiTexCoord2sARB __rglgen_glMultiTexCoord2sARB
#define glMultiTexCoord2svARB __rglgen_glMultiTexCoord2svARB
#define glMultiTexCoord3dARB __rglgen_glMultiTexCoord3dARB
#define glMultiTexCoord3dvARB __rglgen_glMultiTexCoord3dvARB
#define glMultiTexCoord3fARB __rglgen_glMultiTexCoord3fARB
#define glMultiTexCoord3fvARB __rglgen_glMultiTexCoord3fvARB
#define glMultiTexCoord3iARB __rglgen_glMultiTexCoord3iARB
#define glMultiTexCoord3ivARB __rglgen_glMultiTexCoord3ivARB
#define glMultiTexCoord3sARB __rglgen_glMultiTexCoord3sARB
#define glMultiTexCoord3svARB __rglgen_glMultiTexCoord3svARB
#define glMultiTexCoord4dARB __rglgen_glMultiTexCoord4dARB
#define glMultiTexCoord4dvARB __rglgen_glMultiTexCoord4dvARB
#define glMultiTexCoord4fARB __rglgen_glMultiTexCoord4fARB
#define glMultiTexCoord4fvARB __rglgen_glMultiTexCoord4fvARB
#define glMultiTexCoord4iARB __rglgen_glMultiTexCoord4iARB
#define glMultiTexCoord4ivARB __rglgen_glMultiTexCoord4ivARB
#define glMultiTexCoord4sARB __rglgen_glMultiTexCoord4sARB
#define glMultiTexCoord4svARB __rglgen_glMultiTexCoord4svARB
#define glGenQueriesARB __rglgen_glGenQueriesARB
#define glDeleteQueriesARB __rglgen_glDeleteQueriesARB
#define glIsQueryARB __rglgen_glIsQueryARB
#define glBeginQueryARB __rglgen_glBeginQueryARB
#define glEndQueryARB __rglgen_glEndQueryARB
#define glGetQueryivARB __rglgen_glGetQueryivARB
#define glGetQueryObjectivARB __rglgen_glGetQueryObjectivARB
#define glGetQueryObjectuivARB __rglgen_glGetQueryObjectuivARB
#define glPointParameterfARB __rglgen_glPointParameterfARB
#define glPointParameterfvARB __rglgen_glPointParameterfvARB
#define glGetGraphicsResetStatusARB __rglgen_glGetGraphicsResetStatusARB
#define glGetnTexImageARB __rglgen_glGetnTexImageARB
#define glReadnPixelsARB __rglgen_glReadnPixelsARB
#define glGetnCompressedTexImageARB __rglgen_glGetnCompressedTexImageARB
#define glGetnUniformfvARB __rglgen_glGetnUniformfvARB
#define glGetnUniformivARB __rglgen_glGetnUniformivARB
#define glGetnUniformuivARB __rglgen_glGetnUniformuivARB
#define glGetnUniformdvARB __rglgen_glGetnUniformdvARB
#define glGetnMapdvARB __rglgen_glGetnMapdvARB
#define glGetnMapfvARB __rglgen_glGetnMapfvARB
#define glGetnMapivARB __rglgen_glGetnMapivARB
#define glGetnPixelMapfvARB __rglgen_glGetnPixelMapfvARB
#define glGetnPixelMapuivARB __rglgen_glGetnPixelMapuivARB
#define glGetnPixelMapusvARB __rglgen_glGetnPixelMapusvARB
#define glGetnPolygonStippleARB __rglgen_glGetnPolygonStippleARB
#define glGetnColorTableARB __rglgen_glGetnColorTableARB
#define glGetnConvolutionFilterARB __rglgen_glGetnConvolutionFilterARB
#define glGetnSeparableFilterARB __rglgen_glGetnSeparableFilterARB
#define glGetnHistogramARB __rglgen_glGetnHistogramARB
#define glGetnMinmaxARB __rglgen_glGetnMinmaxARB
#define glMinSampleShadingARB __rglgen_glMinSampleShadingARB
#define glDeleteObjectARB __rglgen_glDeleteObjectARB
#define glGetHandleARB __rglgen_glGetHandleARB
#define glDetachObjectARB __rglgen_glDetachObjectARB
#define glCreateShaderObjectARB __rglgen_glCreateShaderObjectARB
#define glShaderSourceARB __rglgen_glShaderSourceARB
#define glCompileShaderARB __rglgen_glCompileShaderARB
#define glCreateProgramObjectARB __rglgen_glCreateProgramObjectARB
#define glAttachObjectARB __rglgen_glAttachObjectARB
#define glLinkProgramARB __rglgen_glLinkProgramARB
#define glUseProgramObjectARB __rglgen_glUseProgramObjectARB
#define glValidateProgramARB __rglgen_glValidateProgramARB
#define glUniform1fARB __rglgen_glUniform1fARB
#define glUniform2fARB __rglgen_glUniform2fARB
#define glUniform3fARB __rglgen_glUniform3fARB
#define glUniform4fARB __rglgen_glUniform4fARB
#define glUniform1iARB __rglgen_glUniform1iARB
#define glUniform2iARB __rglgen_glUniform2iARB
#define glUniform3iARB __rglgen_glUniform3iARB
#define glUniform4iARB __rglgen_glUniform4iARB
#define glUniform1fvARB __rglgen_glUniform1fvARB
#define glUniform2fvARB __rglgen_glUniform2fvARB
#define glUniform3fvARB __rglgen_glUniform3fvARB
#define glUniform4fvARB __rglgen_glUniform4fvARB
#define glUniform1ivARB __rglgen_glUniform1ivARB
#define glUniform2ivARB __rglgen_glUniform2ivARB
#define glUniform3ivARB __rglgen_glUniform3ivARB
#define glUniform4ivARB __rglgen_glUniform4ivARB
#define glUniformMatrix2fvARB __rglgen_glUniformMatrix2fvARB
#define glUniformMatrix3fvARB __rglgen_glUniformMatrix3fvARB
#define glUniformMatrix4fvARB __rglgen_glUniformMatrix4fvARB
#define glGetObjectParameterfvARB __rglgen_glGetObjectParameterfvARB
#define glGetObjectParameterivARB __rglgen_glGetObjectParameterivARB
#define glGetInfoLogARB __rglgen_glGetInfoLogARB
#define glGetAttachedObjectsARB __rglgen_glGetAttachedObjectsARB
#define glGetUniformLocationARB __rglgen_glGetUniformLocationARB
#define glGetActiveUniformARB __rglgen_glGetActiveUniformARB
#define glGetUniformfvARB __rglgen_glGetUniformfvARB
#define glGetUniformivARB __rglgen_glGetUniformivARB
#define glGetShaderSourceARB __rglgen_glGetShaderSourceARB
#define glNamedStringARB __rglgen_glNamedStringARB
#define glDeleteNamedStringARB __rglgen_glDeleteNamedStringARB
#define glCompileShaderIncludeARB __rglgen_glCompileShaderIncludeARB
#define glIsNamedStringARB __rglgen_glIsNamedStringARB
#define glGetNamedStringARB __rglgen_glGetNamedStringARB
#define glGetNamedStringivARB __rglgen_glGetNamedStringivARB
#define glTexPageCommitmentARB __rglgen_glTexPageCommitmentARB
#define glTexBufferARB __rglgen_glTexBufferARB
#define glCompressedTexImage3DARB __rglgen_glCompressedTexImage3DARB
#define glCompressedTexImage2DARB __rglgen_glCompressedTexImage2DARB
#define glCompressedTexImage1DARB __rglgen_glCompressedTexImage1DARB
#define glCompressedTexSubImage3DARB __rglgen_glCompressedTexSubImage3DARB
#define glCompressedTexSubImage2DARB __rglgen_glCompressedTexSubImage2DARB
#define glCompressedTexSubImage1DARB __rglgen_glCompressedTexSubImage1DARB
#define glGetCompressedTexImageARB __rglgen_glGetCompressedTexImageARB
#define glLoadTransposeMatrixfARB __rglgen_glLoadTransposeMatrixfARB
#define glLoadTransposeMatrixdARB __rglgen_glLoadTransposeMatrixdARB
#define glMultTransposeMatrixfARB __rglgen_glMultTransposeMatrixfARB
#define glMultTransposeMatrixdARB __rglgen_glMultTransposeMatrixdARB
#define glWeightbvARB __rglgen_glWeightbvARB
#define glWeightsvARB __rglgen_glWeightsvARB
#define glWeightivARB __rglgen_glWeightivARB
#define glWeightfvARB __rglgen_glWeightfvARB
#define glWeightdvARB __rglgen_glWeightdvARB
#define glWeightubvARB __rglgen_glWeightubvARB
#define glWeightusvARB __rglgen_glWeightusvARB
#define glWeightuivARB __rglgen_glWeightuivARB
#define glWeightPointerARB __rglgen_glWeightPointerARB
#define glVertexBlendARB __rglgen_glVertexBlendARB
#define glBindBufferARB __rglgen_glBindBufferARB
#define glDeleteBuffersARB __rglgen_glDeleteBuffersARB
#define glGenBuffersARB __rglgen_glGenBuffersARB
#define glIsBufferARB __rglgen_glIsBufferARB
#define glBufferDataARB __rglgen_glBufferDataARB
#define glBufferSubDataARB __rglgen_glBufferSubDataARB
#define glGetBufferSubDataARB __rglgen_glGetBufferSubDataARB
#define glMapBufferARB __rglgen_glMapBufferARB
#define glUnmapBufferARB __rglgen_glUnmapBufferARB
#define glGetBufferParameterivARB __rglgen_glGetBufferParameterivARB
#define glGetBufferPointervARB __rglgen_glGetBufferPointervARB
#define glVertexAttrib1dARB __rglgen_glVertexAttrib1dARB
#define glVertexAttrib1dvARB __rglgen_glVertexAttrib1dvARB
#define glVertexAttrib1fARB __rglgen_glVertexAttrib1fARB
#define glVertexAttrib1fvARB __rglgen_glVertexAttrib1fvARB
#define glVertexAttrib1sARB __rglgen_glVertexAttrib1sARB
#define glVertexAttrib1svARB __rglgen_glVertexAttrib1svARB
#define glVertexAttrib2dARB __rglgen_glVertexAttrib2dARB
#define glVertexAttrib2dvARB __rglgen_glVertexAttrib2dvARB
#define glVertexAttrib2fARB __rglgen_glVertexAttrib2fARB
#define glVertexAttrib2fvARB __rglgen_glVertexAttrib2fvARB
#define glVertexAttrib2sARB __rglgen_glVertexAttrib2sARB
#define glVertexAttrib2svARB __rglgen_glVertexAttrib2svARB
#define glVertexAttrib3dARB __rglgen_glVertexAttrib3dARB
#define glVertexAttrib3dvARB __rglgen_glVertexAttrib3dvARB
#define glVertexAttrib3fARB __rglgen_glVertexAttrib3fARB
#define glVertexAttrib3fvARB __rglgen_glVertexAttrib3fvARB
#define glVertexAttrib3sARB __rglgen_glVertexAttrib3sARB
#define glVertexAttrib3svARB __rglgen_glVertexAttrib3svARB
#define glVertexAttrib4NbvARB __rglgen_glVertexAttrib4NbvARB
#define glVertexAttrib4NivARB __rglgen_glVertexAttrib4NivARB
#define glVertexAttrib4NsvARB __rglgen_glVertexAttrib4NsvARB
#define glVertexAttrib4NubARB __rglgen_glVertexAttrib4NubARB
#define glVertexAttrib4NubvARB __rglgen_glVertexAttrib4NubvARB
#define glVertexAttrib4NuivARB __rglgen_glVertexAttrib4NuivARB
#define glVertexAttrib4NusvARB __rglgen_glVertexAttrib4NusvARB
#define glVertexAttrib4bvARB __rglgen_glVertexAttrib4bvARB
#define glVertexAttrib4dARB __rglgen_glVertexAttrib4dARB
#define glVertexAttrib4dvARB __rglgen_glVertexAttrib4dvARB
#define glVertexAttrib4fARB __rglgen_glVertexAttrib4fARB
#define glVertexAttrib4fvARB __rglgen_glVertexAttrib4fvARB
#define glVertexAttrib4ivARB __rglgen_glVertexAttrib4ivARB
#define glVertexAttrib4sARB __rglgen_glVertexAttrib4sARB
#define glVertexAttrib4svARB __rglgen_glVertexAttrib4svARB
#define glVertexAttrib4ubvARB __rglgen_glVertexAttrib4ubvARB
#define glVertexAttrib4uivARB __rglgen_glVertexAttrib4uivARB
#define glVertexAttrib4usvARB __rglgen_glVertexAttrib4usvARB
#define glVertexAttribPointerARB __rglgen_glVertexAttribPointerARB
#define glEnableVertexAttribArrayARB __rglgen_glEnableVertexAttribArrayARB
#define glDisableVertexAttribArrayARB __rglgen_glDisableVertexAttribArrayARB
#define glGetVertexAttribdvARB __rglgen_glGetVertexAttribdvARB
#define glGetVertexAttribfvARB __rglgen_glGetVertexAttribfvARB
#define glGetVertexAttribivARB __rglgen_glGetVertexAttribivARB
#define glGetVertexAttribPointervARB __rglgen_glGetVertexAttribPointervARB
#define glBindAttribLocationARB __rglgen_glBindAttribLocationARB
#define glGetActiveAttribARB __rglgen_glGetActiveAttribARB
#define glGetAttribLocationARB __rglgen_glGetAttribLocationARB
#define glWindowPos2dARB __rglgen_glWindowPos2dARB
#define glWindowPos2dvARB __rglgen_glWindowPos2dvARB
#define glWindowPos2fARB __rglgen_glWindowPos2fARB
#define glWindowPos2fvARB __rglgen_glWindowPos2fvARB
#define glWindowPos2iARB __rglgen_glWindowPos2iARB
#define glWindowPos2ivARB __rglgen_glWindowPos2ivARB
#define glWindowPos2sARB __rglgen_glWindowPos2sARB
#define glWindowPos2svARB __rglgen_glWindowPos2svARB
#define glWindowPos3dARB __rglgen_glWindowPos3dARB
#define glWindowPos3dvARB __rglgen_glWindowPos3dvARB
#define glWindowPos3fARB __rglgen_glWindowPos3fARB
#define glWindowPos3fvARB __rglgen_glWindowPos3fvARB
#define glWindowPos3iARB __rglgen_glWindowPos3iARB
#define glWindowPos3ivARB __rglgen_glWindowPos3ivARB
#define glWindowPos3sARB __rglgen_glWindowPos3sARB
#define glWindowPos3svARB __rglgen_glWindowPos3svARB
#define glMultiTexCoord1bOES __rglgen_glMultiTexCoord1bOES
#define glMultiTexCoord1bvOES __rglgen_glMultiTexCoord1bvOES
#define glMultiTexCoord2bOES __rglgen_glMultiTexCoord2bOES
#define glMultiTexCoord2bvOES __rglgen_glMultiTexCoord2bvOES
#define glMultiTexCoord3bOES __rglgen_glMultiTexCoord3bOES
#define glMultiTexCoord3bvOES __rglgen_glMultiTexCoord3bvOES
#define glMultiTexCoord4bOES __rglgen_glMultiTexCoord4bOES
#define glMultiTexCoord4bvOES __rglgen_glMultiTexCoord4bvOES
#define glTexCoord1bOES __rglgen_glTexCoord1bOES
#define glTexCoord1bvOES __rglgen_glTexCoord1bvOES
#define glTexCoord2bOES __rglgen_glTexCoord2bOES
#define glTexCoord2bvOES __rglgen_glTexCoord2bvOES
#define glTexCoord3bOES __rglgen_glTexCoord3bOES
#define glTexCoord3bvOES __rglgen_glTexCoord3bvOES
#define glTexCoord4bOES __rglgen_glTexCoord4bOES
#define glTexCoord4bvOES __rglgen_glTexCoord4bvOES
#define glVertex2bOES __rglgen_glVertex2bOES
#define glVertex2bvOES __rglgen_glVertex2bvOES
#define glVertex3bOES __rglgen_glVertex3bOES
#define glVertex3bvOES __rglgen_glVertex3bvOES
#define glVertex4bOES __rglgen_glVertex4bOES
#define glVertex4bvOES __rglgen_glVertex4bvOES
#define glAlphaFuncxOES __rglgen_glAlphaFuncxOES
#define glClearColorxOES __rglgen_glClearColorxOES
#define glClearDepthxOES __rglgen_glClearDepthxOES
#define glClipPlanexOES __rglgen_glClipPlanexOES
#define glColor4xOES __rglgen_glColor4xOES
#define glDepthRangexOES __rglgen_glDepthRangexOES
#define glFogxOES __rglgen_glFogxOES
#define glFogxvOES __rglgen_glFogxvOES
#define glFrustumxOES __rglgen_glFrustumxOES
#define glGetClipPlanexOES __rglgen_glGetClipPlanexOES
#define glGetFixedvOES __rglgen_glGetFixedvOES
#define glGetTexEnvxvOES __rglgen_glGetTexEnvxvOES
#define glGetTexParameterxvOES __rglgen_glGetTexParameterxvOES
#define glLightModelxOES __rglgen_glLightModelxOES
#define glLightModelxvOES __rglgen_glLightModelxvOES
#define glLightxOES __rglgen_glLightxOES
#define glLightxvOES __rglgen_glLightxvOES
#define glLineWidthxOES __rglgen_glLineWidthxOES
#define glLoadMatrixxOES __rglgen_glLoadMatrixxOES
#define glMaterialxOES __rglgen_glMaterialxOES
#define glMaterialxvOES __rglgen_glMaterialxvOES
#define glMultMatrixxOES __rglgen_glMultMatrixxOES
#define glMultiTexCoord4xOES __rglgen_glMultiTexCoord4xOES
#define glNormal3xOES __rglgen_glNormal3xOES
#define glOrthoxOES __rglgen_glOrthoxOES
#define glPointParameterxvOES __rglgen_glPointParameterxvOES
#define glPointSizexOES __rglgen_glPointSizexOES
#define glPolygonOffsetxOES __rglgen_glPolygonOffsetxOES
#define glRotatexOES __rglgen_glRotatexOES
#define glSampleCoverageOES __rglgen_glSampleCoverageOES
#define glScalexOES __rglgen_glScalexOES
#define glTexEnvxOES __rglgen_glTexEnvxOES
#define glTexEnvxvOES __rglgen_glTexEnvxvOES
#define glTexParameterxOES __rglgen_glTexParameterxOES
#define glTexParameterxvOES __rglgen_glTexParameterxvOES
#define glTranslatexOES __rglgen_glTranslatexOES
#define glAccumxOES __rglgen_glAccumxOES
#define glBitmapxOES __rglgen_glBitmapxOES
#define glBlendColorxOES __rglgen_glBlendColorxOES
#define glClearAccumxOES __rglgen_glClearAccumxOES
#define glColor3xOES __rglgen_glColor3xOES
#define glColor3xvOES __rglgen_glColor3xvOES
#define glColor4xvOES __rglgen_glColor4xvOES
#define glConvolutionParameterxOES __rglgen_glConvolutionParameterxOES
#define glConvolutionParameterxvOES __rglgen_glConvolutionParameterxvOES
#define glEvalCoord1xOES __rglgen_glEvalCoord1xOES
#define glEvalCoord1xvOES __rglgen_glEvalCoord1xvOES
#define glEvalCoord2xOES __rglgen_glEvalCoord2xOES
#define glEvalCoord2xvOES __rglgen_glEvalCoord2xvOES
#define glFeedbackBufferxOES __rglgen_glFeedbackBufferxOES
#define glGetConvolutionParameterxvOES __rglgen_glGetConvolutionParameterxvOES
#define glGetHistogramParameterxvOES __rglgen_glGetHistogramParameterxvOES
#define glGetLightxOES __rglgen_glGetLightxOES
#define glGetMapxvOES __rglgen_glGetMapxvOES
#define glGetMaterialxOES __rglgen_glGetMaterialxOES
#define glGetPixelMapxv __rglgen_glGetPixelMapxv
#define glGetTexGenxvOES __rglgen_glGetTexGenxvOES
#define glGetTexLevelParameterxvOES __rglgen_glGetTexLevelParameterxvOES
#define glIndexxOES __rglgen_glIndexxOES
#define glIndexxvOES __rglgen_glIndexxvOES
#define glLoadTransposeMatrixxOES __rglgen_glLoadTransposeMatrixxOES
#define glMap1xOES __rglgen_glMap1xOES
#define glMap2xOES __rglgen_glMap2xOES
#define glMapGrid1xOES __rglgen_glMapGrid1xOES
#define glMapGrid2xOES __rglgen_glMapGrid2xOES
#define glMultTransposeMatrixxOES __rglgen_glMultTransposeMatrixxOES
#define glMultiTexCoord1xOES __rglgen_glMultiTexCoord1xOES
#define glMultiTexCoord1xvOES __rglgen_glMultiTexCoord1xvOES
#define glMultiTexCoord2xOES __rglgen_glMultiTexCoord2xOES
#define glMultiTexCoord2xvOES __rglgen_glMultiTexCoord2xvOES
#define glMultiTexCoord3xOES __rglgen_glMultiTexCoord3xOES
#define glMultiTexCoord3xvOES __rglgen_glMultiTexCoord3xvOES
#define glMultiTexCoord4xvOES __rglgen_glMultiTexCoord4xvOES
#define glNormal3xvOES __rglgen_glNormal3xvOES
#define glPassThroughxOES __rglgen_glPassThroughxOES
#define glPixelMapx __rglgen_glPixelMapx
#define glPixelStorex __rglgen_glPixelStorex
#define glPixelTransferxOES __rglgen_glPixelTransferxOES
#define glPixelZoomxOES __rglgen_glPixelZoomxOES
#define glPrioritizeTexturesxOES __rglgen_glPrioritizeTexturesxOES
#define glRasterPos2xOES __rglgen_glRasterPos2xOES
#define glRasterPos2xvOES __rglgen_glRasterPos2xvOES
#define glRasterPos3xOES __rglgen_glRasterPos3xOES
#define glRasterPos3xvOES __rglgen_glRasterPos3xvOES
#define glRasterPos4xOES __rglgen_glRasterPos4xOES
#define glRasterPos4xvOES __rglgen_glRasterPos4xvOES
#define glRectxOES __rglgen_glRectxOES
#define glRectxvOES __rglgen_glRectxvOES
#define glTexCoord1xOES __rglgen_glTexCoord1xOES
#define glTexCoord1xvOES __rglgen_glTexCoord1xvOES
#define glTexCoord2xOES __rglgen_glTexCoord2xOES
#define glTexCoord2xvOES __rglgen_glTexCoord2xvOES
#define glTexCoord3xOES __rglgen_glTexCoord3xOES
#define glTexCoord3xvOES __rglgen_glTexCoord3xvOES
#define glTexCoord4xOES __rglgen_glTexCoord4xOES
#define glTexCoord4xvOES __rglgen_glTexCoord4xvOES
#define glTexGenxOES __rglgen_glTexGenxOES
#define glTexGenxvOES __rglgen_glTexGenxvOES
#define glVertex2xOES __rglgen_glVertex2xOES
#define glVertex2xvOES __rglgen_glVertex2xvOES
#define glVertex3xOES __rglgen_glVertex3xOES
#define glVertex3xvOES __rglgen_glVertex3xvOES
#define glVertex4xOES __rglgen_glVertex4xOES
#define glVertex4xvOES __rglgen_glVertex4xvOES
#define glQueryMatrixxOES __rglgen_glQueryMatrixxOES
#define glClearDepthfOES __rglgen_glClearDepthfOES
#define glClipPlanefOES __rglgen_glClipPlanefOES
#define glDepthRangefOES __rglgen_glDepthRangefOES
#define glFrustumfOES __rglgen_glFrustumfOES
#define glGetClipPlanefOES __rglgen_glGetClipPlanefOES
#define glOrthofOES __rglgen_glOrthofOES
#define glImageTransformParameteriHP __rglgen_glImageTransformParameteriHP
#define glImageTransformParameterfHP __rglgen_glImageTransformParameterfHP
#define glImageTransformParameterivHP __rglgen_glImageTransformParameterivHP
#define glImageTransformParameterfvHP __rglgen_glImageTransformParameterfvHP
#define glGetImageTransformParameterivHP __rglgen_glGetImageTransformParameterivHP
#define glGetImageTransformParameterfvHP __rglgen_glGetImageTransformParameterfvHP

extern RGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;
extern RGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;
extern RGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;
extern RGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;
extern RGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;
extern RGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;
extern RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;
extern RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;
extern RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;
extern RGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;
extern RGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;
extern RGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;
extern RGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;
extern RGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;
extern RGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;
extern RGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;
extern RGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;
extern RGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;
extern RGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;
extern RGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;
extern RGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;
extern RGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;
extern RGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;
extern RGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;
extern RGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;
extern RGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;
extern RGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;
extern RGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;
extern RGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;
extern RGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;
extern RGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;
extern RGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;
extern RGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;
extern RGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;
extern RGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;
extern RGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;
extern RGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;
extern RGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;
extern RGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;
extern RGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;
extern RGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;
extern RGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;
extern RGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;
extern RGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;
extern RGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;
extern RGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;
extern RGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;
extern RGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;
extern RGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;
extern RGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;
extern RGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;
extern RGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;
extern RGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;
extern RGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;
extern RGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;
extern RGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;
extern RGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;
extern RGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;
extern RGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;
extern RGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;
extern RGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;
extern RGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;
extern RGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;
extern RGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;
extern RGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;
extern RGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;
extern RGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;
extern RGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;
extern RGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;
extern RGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;
extern RGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;
extern RGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;
extern RGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;
extern RGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;
extern RGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;
extern RGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;
extern RGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;
extern RGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;
extern RGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;
extern RGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;
extern RGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;
extern RGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;
extern RGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;
extern RGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;
extern RGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;
extern RGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;
extern RGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;
extern RGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;
extern RGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;
extern RGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;
extern RGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;
extern RGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;
extern RGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;
extern RGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;
extern RGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;
extern RGLSYMGLISQUERYPROC __rglgen_glIsQuery;
extern RGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;
extern RGLSYMGLENDQUERYPROC __rglgen_glEndQuery;
extern RGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;
extern RGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;
extern RGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;
extern RGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;
extern RGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;
extern RGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;
extern RGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;
extern RGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;
extern RGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;
extern RGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;
extern RGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;
extern RGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;
extern RGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;
extern RGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;
extern RGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;
extern RGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;
extern RGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;
extern RGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;
extern RGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;
extern RGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;
extern RGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;
extern RGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;
extern RGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;
extern RGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;
extern RGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;
extern RGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;
extern RGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;
extern RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;
extern RGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;
extern RGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;
extern RGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;
extern RGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;
extern RGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;
extern RGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;
extern RGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;
extern RGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;
extern RGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;
extern RGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;
extern RGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;
extern RGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;
extern RGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;
extern RGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;
extern RGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;
extern RGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;
extern RGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;
extern RGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;
extern RGLSYMGLISSHADERPROC __rglgen_glIsShader;
extern RGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;
extern RGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;
extern RGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;
extern RGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;
extern RGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;
extern RGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;
extern RGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;
extern RGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;
extern RGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;
extern RGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;
extern RGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;
extern RGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;
extern RGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;
extern RGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;
extern RGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;
extern RGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;
extern RGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;
extern RGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;
extern RGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;
extern RGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;
extern RGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;
extern RGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;
extern RGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;
extern RGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;
extern RGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;
extern RGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;
extern RGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;
extern RGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;
extern RGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;
extern RGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;
extern RGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;
extern RGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;
extern RGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;
extern RGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;
extern RGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;
extern RGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;
extern RGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;
extern RGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;
extern RGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;
extern RGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;
extern RGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;
extern RGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;
extern RGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;
extern RGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;
extern RGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;
extern RGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;
extern RGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;
extern RGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;
extern RGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;
extern RGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;
extern RGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;
extern RGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;
extern RGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;
extern RGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;
extern RGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;
extern RGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;
extern RGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;
extern RGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;
extern RGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;
extern RGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;
extern RGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;
extern RGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;
extern RGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;
extern RGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;
extern RGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;
extern RGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;
extern RGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;
extern RGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;
extern RGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;
extern RGLSYMGLENABLEIPROC __rglgen_glEnablei;
extern RGLSYMGLDISABLEIPROC __rglgen_glDisablei;
extern RGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;
extern RGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;
extern RGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;
extern RGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;
extern RGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;
extern RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;
extern RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;
extern RGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;
extern RGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;
extern RGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;
extern RGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;
extern RGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;
extern RGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;
extern RGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;
extern RGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;
extern RGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;
extern RGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;
extern RGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;
extern RGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;
extern RGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;
extern RGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;
extern RGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;
extern RGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;
extern RGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;
extern RGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;
extern RGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;
extern RGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;
extern RGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;
extern RGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;
extern RGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;
extern RGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;
extern RGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;
extern RGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;
extern RGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;
extern RGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;
extern RGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;
extern RGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;
extern RGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;
extern RGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;
extern RGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;
extern RGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;
extern RGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;
extern RGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;
extern RGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;
extern RGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;
extern RGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;
extern RGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;
extern RGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;
extern RGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;
extern RGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;
extern RGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;
extern RGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;
extern RGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;
extern RGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;
extern RGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;
extern RGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;
extern RGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;
extern RGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;
extern RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;
extern RGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;
extern RGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;
extern RGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;
extern RGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;
extern RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;
extern RGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;
extern RGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;
extern RGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;
extern RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;
extern RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;
extern RGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;
extern RGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;
extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;
extern RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;
extern RGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;
extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;
extern RGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;
extern RGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;
extern RGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;
extern RGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;
extern RGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;
extern RGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;
extern RGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;
extern RGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;
extern RGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;
extern RGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;
extern RGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;
extern RGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;
extern RGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;
extern RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;
extern RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;
extern RGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;
extern RGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;
extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;
extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;
extern RGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;
extern RGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;
extern RGLSYMGLISSYNCPROC __rglgen_glIsSync;
extern RGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;
extern RGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;
extern RGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;
extern RGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;
extern RGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;
extern RGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;
extern RGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;
extern RGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;
extern RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;
extern RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;
extern RGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;
extern RGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;
extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;
extern RGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;
extern RGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;
extern RGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;
extern RGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;
extern RGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;
extern RGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;
extern RGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;
extern RGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;
extern RGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;
extern RGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;
extern RGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;
extern RGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;
extern RGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;
extern RGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;
extern RGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;
extern RGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;
extern RGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;
extern RGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;
extern RGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;
extern RGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;
extern RGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;
extern RGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;
extern RGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;
extern RGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;
extern RGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;
extern RGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;
extern RGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;
extern RGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;
extern RGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;
extern RGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;
extern RGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;
extern RGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;
extern RGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;
extern RGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;
extern RGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;
extern RGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;
extern RGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;
extern RGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;
extern RGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;
extern RGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;
extern RGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;
extern RGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;
extern RGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;
extern RGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;
extern RGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;
extern RGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;
extern RGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;
extern RGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;
extern RGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;
extern RGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;
extern RGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;
extern RGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;
extern RGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;
extern RGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;
extern RGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;
extern RGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;
extern RGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;
extern RGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;
extern RGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;
extern RGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;
extern RGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;
extern RGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;
extern RGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;
extern RGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;
extern RGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;
extern RGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;
extern RGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;
extern RGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;
extern RGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;
extern RGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;
extern RGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;
extern RGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;
extern RGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;
extern RGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;
extern RGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;
extern RGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;
extern RGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;
extern RGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;
extern RGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;
extern RGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;
extern RGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;
extern RGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;
extern RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;
extern RGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;
extern RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;
extern RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;
extern RGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;
extern RGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;
extern RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;
extern RGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;
extern RGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;
extern RGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;
extern RGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;
extern RGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;
extern RGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;
extern RGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;
extern RGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;
extern RGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;
extern RGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;
extern RGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;
extern RGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;
extern RGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;
extern RGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;
extern RGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;
extern RGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;
extern RGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;
extern RGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;
extern RGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;
extern RGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;
extern RGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;
extern RGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;
extern RGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;
extern RGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;
extern RGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;
extern RGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;
extern RGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;
extern RGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;
extern RGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;
extern RGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;
extern RGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;
extern RGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;
extern RGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;
extern RGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;
extern RGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;
extern RGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;
extern RGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;
extern RGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;
extern RGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;
extern RGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;
extern RGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;
extern RGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;
extern RGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;
extern RGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;
extern RGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;
extern RGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;
extern RGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;
extern RGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;
extern RGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;
extern RGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;
extern RGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;
extern RGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;
extern RGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;
extern RGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;
extern RGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;
extern RGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;
extern RGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;
extern RGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;
extern RGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;
extern RGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;
extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;
extern RGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;
extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;
extern RGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;
extern RGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;
extern RGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;
extern RGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;
extern RGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;
extern RGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;
extern RGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;
extern RGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;
extern RGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;
extern RGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;
extern RGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;
extern RGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;
extern RGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;
extern RGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;
extern RGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;
extern RGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;
extern RGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;
extern RGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;
extern RGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;
extern RGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;
extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;
extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;
extern RGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;
extern RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;
extern RGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;
extern RGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;
extern RGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;
extern RGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;
extern RGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;
extern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;
extern RGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;
extern RGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;
extern RGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;
extern RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;
extern RGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;
extern RGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;
extern RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;
extern RGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;
extern RGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;
extern RGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;
extern RGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;
extern RGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;
extern RGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;
extern RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;
extern RGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;
extern RGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;
extern RGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;
extern RGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;
extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;
extern RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;
extern RGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;
extern RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;
extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;
extern RGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;
extern RGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;
extern RGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;
extern RGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;
extern RGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;
extern RGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;
extern RGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;
extern RGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;
extern RGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;
extern RGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;
extern RGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;
extern RGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;
extern RGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;
extern RGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;
extern RGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;
extern RGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;
extern RGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;
extern RGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;
extern RGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;
extern RGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;
extern RGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;
extern RGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;
extern RGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;
extern RGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;
extern RGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;
extern RGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;
extern RGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;
extern RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;
extern RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;
extern RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;
extern RGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;
extern RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;
extern RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;
extern RGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;
extern RGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;
extern RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;
extern RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;
extern RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;
extern RGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;
extern RGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;
extern RGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;
extern RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;
extern RGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;
extern RGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;
extern RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;
extern RGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;
extern RGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;
extern RGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;
extern RGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;
extern RGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;
extern RGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;
extern RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;
extern RGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;
extern RGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;
extern RGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;
extern RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;
extern RGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;
extern RGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;
extern RGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;
extern RGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;
extern RGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;
extern RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;
extern RGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;
extern RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;
extern RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;
extern RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;
extern RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;
extern RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;
extern RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;
extern RGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;
extern RGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;
extern RGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;
extern RGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;
extern RGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;
extern RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;
extern RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;
extern RGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;
extern RGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;
extern RGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;
extern RGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;
extern RGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;
extern RGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;
extern RGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;
extern RGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;
extern RGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;
extern RGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;
extern RGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;
extern RGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;
extern RGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;
extern RGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;
extern RGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;
extern RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;
extern RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;
extern RGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;
extern RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;
extern RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;
extern RGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;
extern RGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;
extern RGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;
extern RGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;
extern RGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;
extern RGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;
extern RGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;
extern RGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;
extern RGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;
extern RGLSYMGLMINMAXPROC __rglgen_glMinmax;
extern RGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;
extern RGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;
extern RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;
extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;
extern RGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;
extern RGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;
extern RGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;
extern RGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;
extern RGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;
extern RGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;
extern RGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;
extern RGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;
extern RGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;
extern RGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;
extern RGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;
extern RGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;
extern RGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;
extern RGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;
extern RGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;
extern RGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;
extern RGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;
extern RGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;
extern RGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;
extern RGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;
extern RGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;
extern RGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;
extern RGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;
extern RGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;
extern RGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;
extern RGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;
extern RGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;
extern RGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;
extern RGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;
extern RGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;
extern RGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;
extern RGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;
extern RGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;
extern RGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;
extern RGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;
extern RGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;
extern RGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;
extern RGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;
extern RGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;
extern RGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;
extern RGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;
extern RGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;
extern RGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;
extern RGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;
extern RGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;
extern RGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;
extern RGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;
extern RGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;
extern RGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;
extern RGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;
extern RGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;
extern RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;
extern RGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;
extern RGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;
extern RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;
extern RGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;
extern RGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;
extern RGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;
extern RGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;
extern RGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;
extern RGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;
extern RGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;
extern RGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;
extern RGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;
extern RGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;
extern RGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;
extern RGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;
extern RGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;
extern RGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;
extern RGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;
extern RGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;
extern RGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;
extern RGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;
extern RGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;
extern RGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;
extern RGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;
extern RGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;
extern RGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;
extern RGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;
extern RGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;
extern RGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;
extern RGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;
extern RGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;
extern RGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;
extern RGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;
extern RGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;
extern RGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;
extern RGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;
extern RGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;
extern RGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;
extern RGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;
extern RGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;
extern RGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;
extern RGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;
extern RGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;
extern RGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;
extern RGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;
extern RGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;
extern RGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;
extern RGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;
extern RGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;
extern RGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;
extern RGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;
extern RGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;
extern RGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;
extern RGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;
extern RGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;
extern RGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;
extern RGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;
extern RGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;
extern RGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;
extern RGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;
extern RGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;
extern RGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;
extern RGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;
extern RGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;
extern RGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;
extern RGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;
extern RGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;
extern RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;
extern RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;
extern RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;
extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;
extern RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;
extern RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;
extern RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;
extern RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;
extern RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;
extern RGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;
extern RGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;
extern RGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;
extern RGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;
extern RGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;
extern RGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;
extern RGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;
extern RGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;
extern RGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;
extern RGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;
extern RGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;
extern RGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;
extern RGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;
extern RGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;
extern RGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;
extern RGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;
extern RGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;
extern RGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;
extern RGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;
extern RGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;
extern RGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;
extern RGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;
extern RGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;
extern RGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;
extern RGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;
extern RGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;
extern RGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;
extern RGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;
extern RGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;
extern RGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;
extern RGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;
extern RGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;
extern RGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;
extern RGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;
extern RGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;
extern RGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;
extern RGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;
extern RGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;
extern RGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;
extern RGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;
extern RGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;
extern RGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;
extern RGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;
extern RGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;
extern RGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;
extern RGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;
extern RGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;
extern RGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;
extern RGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;
extern RGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;
extern RGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;
extern RGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;
extern RGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;
extern RGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;
extern RGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;
extern RGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;
extern RGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;
extern RGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;
extern RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;
extern RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;
extern RGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;
extern RGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;
extern RGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;
extern RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;
extern RGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;
extern RGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;
extern RGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;
extern RGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;
extern RGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;
extern RGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;
extern RGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;
extern RGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;
extern RGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;
extern RGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;
extern RGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;
extern RGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;
extern RGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;
extern RGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;
extern RGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;
extern RGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;
extern RGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;
extern RGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;
extern RGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;
extern RGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;
extern RGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;
extern RGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;
extern RGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;
extern RGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;
extern RGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;
extern RGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;
extern RGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;
extern RGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;
extern RGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;
extern RGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;
extern RGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;
extern RGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;
extern RGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;
extern RGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;
extern RGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;
extern RGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;
extern RGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;
extern RGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;
extern RGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;
extern RGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;
extern RGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;
extern RGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;
extern RGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;
extern RGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;
extern RGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;
extern RGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;
extern RGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;
extern RGLSYMGLFOGXOESPROC __rglgen_glFogxOES;
extern RGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;
extern RGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;
extern RGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;
extern RGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;
extern RGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;
extern RGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;
extern RGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;
extern RGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;
extern RGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;
extern RGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;
extern RGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;
extern RGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;
extern RGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;
extern RGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;
extern RGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;
extern RGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;
extern RGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;
extern RGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;
extern RGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;
extern RGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;
extern RGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;
extern RGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;
extern RGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;
extern RGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;
extern RGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;
extern RGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;
extern RGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;
extern RGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;
extern RGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;
extern RGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;
extern RGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;
extern RGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;
extern RGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;
extern RGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;
extern RGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;
extern RGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;
extern RGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;
extern RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;
extern RGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;
extern RGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;
extern RGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;
extern RGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;
extern RGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;
extern RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;
extern RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;
extern RGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;
extern RGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;
extern RGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;
extern RGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;
extern RGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;
extern RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;
extern RGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;
extern RGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;
extern RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;
extern RGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;
extern RGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;
extern RGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;
extern RGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;
extern RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;
extern RGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;
extern RGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;
extern RGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;
extern RGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;
extern RGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;
extern RGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;
extern RGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;
extern RGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;
extern RGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;
extern RGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;
extern RGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;
extern RGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;
extern RGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;
extern RGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;
extern RGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;
extern RGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;
extern RGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;
extern RGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;
extern RGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;
extern RGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;
extern RGLSYMGLRECTXOESPROC __rglgen_glRectxOES;
extern RGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;
extern RGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;
extern RGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;
extern RGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;
extern RGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;
extern RGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;
extern RGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;
extern RGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;
extern RGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;
extern RGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;
extern RGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;
extern RGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;
extern RGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;
extern RGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;
extern RGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;
extern RGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;
extern RGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;
extern RGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;
extern RGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;
extern RGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;
extern RGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;
extern RGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;
extern RGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;
extern RGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;
extern RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;
extern RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;
extern RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;
extern RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;
extern RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;
extern RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;

struct rglgen_sym_map { const char *sym; void *ptr; };
extern const struct rglgen_sym_map rglgen_symbol_map[];
#ifdef __cplusplus
}
#endif
#endif</pre>
<h2>./include/libretro-common/include/glsym/glsym.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GLSYM_H__
#define __LIBRETRO_SDK_GLSYM_H__

#include "rglgen.h"

#ifndef HAVE_PSGL
#if defined(HAVE_OPENGLES2)
#include "glsym_es2.h"
#elif defined(HAVE_OPENGLES3)
#include "glsym_es3.h"
#else
#ifdef HAVE_LIBNX
#include "switch/nx_glsym.h"
#endif
#include "glsym_gl.h"
#endif
#endif

#ifdef HAVE_GLSYM_PRIVATE
#include "glsym_private.h"
#endif

#endif</pre>
<h2>./include/libretro-common/include/glsym/rglgen.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_H__
#define RGLGEN_H__

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include &lt;retro_common_api.h&gt;

#include "rglgen_headers.h"

RETRO_BEGIN_DECLS

struct rglgen_sym_map;

typedef void (*rglgen_func_t)(void);
typedef rglgen_func_t (*rglgen_proc_address_t)(const char*);
void rglgen_resolve_symbols(rglgen_proc_address_t proc);
void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
      const struct rglgen_sym_map *map);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/glsym/rglgen_headers.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_HEADERS_H__
#define RGLGEN_HEADERS_H__

#ifdef HAVE_EGL
#include &lt;EGL/egl.h&gt;
#include &lt;EGL/eglext.h&gt;
#endif

#include "rglgen_private_headers.h"

#ifndef GL_MAP_WRITE_BIT
#define GL_MAP_WRITE_BIT 0x0002
#endif

#ifndef GL_MAP_INVALIDATE_BUFFER_BIT
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#endif

#ifndef GL_RED_INTEGER
#define GL_RED_INTEGER 0x8D94
#endif

#ifndef GL_BGRA_EXT
#define GL_BGRA_EXT GL_BGRA
#endif

#ifndef GL_LUMINANCE_ALPHA
#define GL_LUMINANCE_ALPHA 0x190A
#endif

#endif</pre>
<h2>./include/libretro-common/include/glsym/rglgen_private_headers.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (glsym).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RGLGEN_PRIVATE_HEADERS_H__
#define RGLGEN_PRIVATE_HEADERS_H__

#if defined(IOS)

#if defined(HAVE_OPENGLES3)
#include &lt;OpenGLES/ES3/gl.h&gt;
#include &lt;OpenGLES/ES3/glext.h&gt;
#else
#include &lt;OpenGLES/ES2/gl.h&gt;
#include &lt;OpenGLES/ES2/glext.h&gt;
#endif

#elif defined(__APPLE__)
#include &lt;compat/apple_compat.h&gt;
#if MAC_OS_X_VERSION_10_7
#include &lt;OpenGL/gl3.h&gt;
#include &lt;OpenGL/gl3ext.h&gt;
#else
#include &lt;OpenGL/gl.h&gt;
#include &lt;OpenGL/glext.h&gt;
#endif
#elif defined(HAVE_PSGL)
#include &lt;PSGL/psgl.h&gt;
#include &lt;GLES/glext.h&gt;
#elif defined(HAVE_OPENGL_MODERN)
#include &lt;GL3/gl3.h&gt;
#include &lt;GL3/gl3ext.h&gt;
#elif defined(HAVE_OPENGLES3)
#include &lt;GLES3/gl3.h&gt;
#define __gl2_h_
#include &lt;GLES2/gl2ext.h&gt;
#elif defined(HAVE_OPENGLES2)
#include &lt;GLES2/gl2.h&gt;
#include &lt;GLES2/gl2ext.h&gt;
#elif defined(HAVE_OPENGLES1)
#include &lt;GLES/gl.h&gt;
#include &lt;GLES/glext.h&gt;
#else
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include &lt;windows.h&gt;
#endif
#ifndef HAVE_LIBNX
#include &lt;GL/gl.h&gt;
#include &lt;GL/glext.h&gt;
#else
/* We need to avoid including &lt;GL/gl.h&gt; on this platform */
#include "switch/nx_gl.h"
#include &lt;GL/glext.h&gt;
#endif /* SWITCH */
#endif

#endif
</pre>
<h2>./include/libretro-common/include/glsym/switch/nx_gl.h</h2>
<pre>/* Copyright (C) 2018-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro SDK code part (nx_gl.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __NX_GL_H__
#define __NX_GL_H__

#ifdef __cplusplus
extern "C" {
#endif

#ifndef APIENTRY
#define APIENTRY
#endif

#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif

/* GL.h types */
typedef unsigned int	GLenum;
typedef unsigned char	GLboolean;
typedef unsigned int	GLbitfield;
typedef void		GLvoid;
typedef signed char	GLbyte;		/* 1-byte signed */
typedef short		GLshort;	/* 2-byte signed */
typedef int		GLint;		/* 4-byte signed */
typedef unsigned char	GLubyte;	/* 1-byte unsigned */
typedef unsigned short	GLushort;	/* 2-byte unsigned */
typedef unsigned int	GLuint;		/* 4-byte unsigned */
typedef int		GLsizei;	/* 4-byte signed */
typedef float		GLfloat;	/* single precision float */
typedef float		GLclampf;	/* single precision float in [0,1] */
typedef double		GLdouble;	/* double precision float */
typedef double		GLclampd;	/* double precision float in [0,1] */

/* GL.h defines */
#define GL_ARB_imaging   1
#define GL_FALSE                                0
#define GL_TRUE                                 1
#define GL_BYTE                                 0x1400
#define GL_UNSIGNED_BYTE                        0x1401
#define GL_SHORT                                0x1402
#define GL_UNSIGNED_SHORT                       0x1403
#define GL_INT                                  0x1404
#define GL_UNSIGNED_INT                         0x1405
#define GL_FLOAT                                0x1406
#define GL_2_BYTES                              0x1407
#define GL_3_BYTES                              0x1408
#define GL_4_BYTES                              0x1409
#define GL_DOUBLE                               0x140A
#define GL_POINTS                               0x0000
#define GL_LINES                                0x0001
#define GL_LINE_LOOP                            0x0002
#define GL_LINE_STRIP                           0x0003
#define GL_TRIANGLES                            0x0004
#define GL_TRIANGLE_STRIP                       0x0005
#define GL_TRIANGLE_FAN                         0x0006
#define GL_QUADS                                0x0007
#define GL_QUAD_STRIP                           0x0008
#define GL_POLYGON                              0x0009
#define GL_VERTEX_ARRAY                         0x8074
#define GL_NORMAL_ARRAY                         0x8075
#define GL_COLOR_ARRAY                          0x8076
#define GL_INDEX_ARRAY                          0x8077
#define GL_TEXTURE_COORD_ARRAY                  0x8078
#define GL_EDGE_FLAG_ARRAY                      0x8079
#define GL_VERTEX_ARRAY_SIZE                    0x807A
#define GL_VERTEX_ARRAY_TYPE                    0x807B
#define GL_VERTEX_ARRAY_STRIDE                  0x807C
#define GL_NORMAL_ARRAY_TYPE                    0x807E
#define GL_NORMAL_ARRAY_STRIDE                  0x807F
#define GL_COLOR_ARRAY_SIZE                     0x8081
#define GL_COLOR_ARRAY_TYPE                     0x8082
#define GL_COLOR_ARRAY_STRIDE                   0x8083
#define GL_INDEX_ARRAY_TYPE                     0x8085
#define GL_INDEX_ARRAY_STRIDE                   0x8086
#define GL_TEXTURE_COORD_ARRAY_SIZE             0x8088
#define GL_TEXTURE_COORD_ARRAY_TYPE             0x8089
#define GL_TEXTURE_COORD_ARRAY_STRIDE           0x808A
#define GL_EDGE_FLAG_ARRAY_STRIDE               0x808C
#define GL_VERTEX_ARRAY_POINTER                 0x808E
#define GL_NORMAL_ARRAY_POINTER                 0x808F
#define GL_COLOR_ARRAY_POINTER                  0x8090
#define GL_INDEX_ARRAY_POINTER                  0x8091
#define GL_TEXTURE_COORD_ARRAY_POINTER          0x8092
#define GL_EDGE_FLAG_ARRAY_POINTER              0x8093
#define GL_V2F                                  0x2A20
#define GL_V3F                                  0x2A21
#define GL_C4UB_V2F                             0x2A22
#define GL_C4UB_V3F                             0x2A23
#define GL_C3F_V3F                              0x2A24
#define GL_N3F_V3F                              0x2A25
#define GL_C4F_N3F_V3F                          0x2A26
#define GL_T2F_V3F                              0x2A27
#define GL_T4F_V4F                              0x2A28
#define GL_T2F_C4UB_V3F                         0x2A29
#define GL_T2F_C3F_V3F                          0x2A2A
#define GL_T2F_N3F_V3F                          0x2A2B
#define GL_T2F_C4F_N3F_V3F                      0x2A2C
#define GL_T4F_C4F_N3F_V4F                      0x2A2D
#define GL_MATRIX_MODE                          0x0BA0
#define GL_MODELVIEW                            0x1700
#define GL_PROJECTION                           0x1701
#define GL_TEXTURE                              0x1702
#define GL_POINT_SMOOTH                         0x0B10
#define GL_POINT_SIZE                           0x0B11
#define GL_POINT_SIZE_GRANULARITY               0x0B13
#define GL_POINT_SIZE_RANGE                     0x0B12
#define GL_LINE_SMOOTH                          0x0B20
#define GL_LINE_STIPPLE                         0x0B24
#define GL_LINE_STIPPLE_PATTERN                 0x0B25
#define GL_LINE_STIPPLE_REPEAT                  0x0B26
#define GL_LINE_WIDTH                           0x0B21
#define GL_LINE_WIDTH_GRANULARITY               0x0B23
#define GL_LINE_WIDTH_RANGE                     0x0B22
#define GL_POINT                                0x1B00
#define GL_LINE                                 0x1B01
#define GL_FILL                                 0x1B02
#define GL_CW                                   0x0900
#define GL_CCW                                  0x0901
#define GL_FRONT                                0x0404
#define GL_BACK                                 0x0405
#define GL_POLYGON_MODE                         0x0B40
#define GL_POLYGON_SMOOTH                       0x0B41
#define GL_POLYGON_STIPPLE                      0x0B42
#define GL_EDGE_FLAG                            0x0B43
#define GL_CULL_FACE                            0x0B44
#define GL_CULL_FACE_MODE                       0x0B45
#define GL_FRONT_FACE                           0x0B46
#define GL_POLYGON_OFFSET_FACTOR                0x8038
#define GL_POLYGON_OFFSET_UNITS                 0x2A00
#define GL_POLYGON_OFFSET_POINT                 0x2A01
#define GL_POLYGON_OFFSET_LINE                  0x2A02
#define GL_POLYGON_OFFSET_FILL                  0x8037
#define GL_COMPILE                              0x1300
#define GL_COMPILE_AND_EXECUTE                  0x1301
#define GL_LIST_BASE                            0x0B32
#define GL_LIST_INDEX                           0x0B33
#define GL_LIST_MODE                            0x0B30
#define GL_NEVER                                0x0200
#define GL_LESS                                 0x0201
#define GL_EQUAL                                0x0202
#define GL_LEQUAL                               0x0203
#define GL_GREATER                              0x0204
#define GL_NOTEQUAL                             0x0205
#define GL_GEQUAL                               0x0206
#define GL_ALWAYS                               0x0207
#define GL_DEPTH_TEST                           0x0B71
#define GL_DEPTH_BITS                           0x0D56
#define GL_DEPTH_CLEAR_VALUE                    0x0B73
#define GL_DEPTH_FUNC                           0x0B74
#define GL_DEPTH_RANGE                          0x0B70
#define GL_DEPTH_WRITEMASK                      0x0B72
#define GL_DEPTH_COMPONENT                      0x1902
#define GL_LIGHTING                             0x0B50
#define GL_LIGHT0                               0x4000
#define GL_LIGHT1                               0x4001
#define GL_LIGHT2                               0x4002
#define GL_LIGHT3                               0x4003
#define GL_LIGHT4                               0x4004
#define GL_LIGHT5                               0x4005
#define GL_LIGHT6                               0x4006
#define GL_LIGHT7                               0x4007
#define GL_SPOT_EXPONENT                        0x1205
#define GL_SPOT_CUTOFF                          0x1206
#define GL_CONSTANT_ATTENUATION                 0x1207
#define GL_LINEAR_ATTENUATION                   0x1208
#define GL_QUADRATIC_ATTENUATION                0x1209
#define GL_AMBIENT                              0x1200
#define GL_DIFFUSE                              0x1201
#define GL_SPECULAR                             0x1202
#define GL_SHININESS                            0x1601
#define GL_EMISSION                             0x1600
#define GL_POSITION                             0x1203
#define GL_SPOT_DIRECTION                       0x1204
#define GL_AMBIENT_AND_DIFFUSE                  0x1602
#define GL_COLOR_INDEXES                        0x1603
#define GL_LIGHT_MODEL_TWO_SIDE                 0x0B52
#define GL_LIGHT_MODEL_LOCAL_VIEWER             0x0B51
#define GL_LIGHT_MODEL_AMBIENT                  0x0B53
#define GL_FRONT_AND_BACK                       0x0408
#define GL_SHADE_MODEL                          0x0B54
#define GL_FLAT                                 0x1D00
#define GL_SMOOTH                               0x1D01
#define GL_COLOR_MATERIAL                       0x0B57
#define GL_COLOR_MATERIAL_FACE                  0x0B55
#define GL_COLOR_MATERIAL_PARAMETER             0x0B56
#define GL_NORMALIZE                            0x0BA1
#define GL_CLIP_PLANE0                          0x3000
#define GL_CLIP_PLANE1                          0x3001
#define GL_CLIP_PLANE2                          0x3002
#define GL_CLIP_PLANE3                          0x3003
#define GL_CLIP_PLANE4                          0x3004
#define GL_CLIP_PLANE5                          0x3005
#define GL_ACCUM_RED_BITS                       0x0D58
#define GL_ACCUM_GREEN_BITS                     0x0D59
#define GL_ACCUM_BLUE_BITS                      0x0D5A
#define GL_ACCUM_ALPHA_BITS                     0x0D5B
#define GL_ACCUM_CLEAR_VALUE                    0x0B80
#define GL_ACCUM                                0x0100
#define GL_ADD                                  0x0104
#define GL_LOAD                                 0x0101
#define GL_MULT                                 0x0103
#define GL_RETURN                               0x0102
#define GL_ALPHA_TEST                           0x0BC0
#define GL_ALPHA_TEST_REF                       0x0BC2
#define GL_ALPHA_TEST_FUNC                      0x0BC1
#define GL_BLEND                                0x0BE2
#define GL_BLEND_SRC                            0x0BE1
#define GL_BLEND_DST                            0x0BE0
#define GL_ZERO                                 0
#define GL_ONE                                  1
#define GL_SRC_COLOR                            0x0300
#define GL_ONE_MINUS_SRC_COLOR                  0x0301
#define GL_SRC_ALPHA                            0x0302
#define GL_ONE_MINUS_SRC_ALPHA                  0x0303
#define GL_DST_ALPHA                            0x0304
#define GL_ONE_MINUS_DST_ALPHA                  0x0305
#define GL_DST_COLOR                            0x0306
#define GL_ONE_MINUS_DST_COLOR                  0x0307
#define GL_SRC_ALPHA_SATURATE                   0x0308
#define GL_FEEDBACK                             0x1C01
#define GL_RENDER                               0x1C00
#define GL_SELECT                               0x1C02
#define GL_2D                                   0x0600
#define GL_3D                                   0x0601
#define GL_3D_COLOR                             0x0602
#define GL_3D_COLOR_TEXTURE                     0x0603
#define GL_4D_COLOR_TEXTURE                     0x0604
#define GL_POINT_TOKEN                          0x0701
#define GL_LINE_TOKEN                           0x0702
#define GL_LINE_RESET_TOKEN                     0x0707
#define GL_POLYGON_TOKEN                        0x0703
#define GL_BITMAP_TOKEN                         0x0704
#define GL_DRAW_PIXEL_TOKEN                     0x0705
#define GL_COPY_PIXEL_TOKEN                     0x0706
#define GL_PASS_THROUGH_TOKEN                   0x0700
#define GL_FEEDBACK_BUFFER_POINTER              0x0DF0
#define GL_FEEDBACK_BUFFER_SIZE                 0x0DF1
#define GL_FEEDBACK_BUFFER_TYPE                 0x0DF2
#define GL_SELECTION_BUFFER_POINTER             0x0DF3
#define GL_SELECTION_BUFFER_SIZE                0x0DF4
#define GL_FOG                                  0x0B60
#define GL_FOG_MODE                             0x0B65
#define GL_FOG_DENSITY                          0x0B62
#define GL_FOG_COLOR                            0x0B66
#define GL_FOG_INDEX                            0x0B61
#define GL_FOG_START                            0x0B63
#define GL_FOG_END                              0x0B64
#define GL_LINEAR                               0x2601
#define GL_EXP                                  0x0800
#define GL_EXP2                                 0x0801
#define GL_LOGIC_OP                             0x0BF1
#define GL_INDEX_LOGIC_OP                       0x0BF1
#define GL_COLOR_LOGIC_OP                       0x0BF2
#define GL_LOGIC_OP_MODE                        0x0BF0
#define GL_CLEAR                                0x1500
#define GL_SET                                  0x150F
#define GL_COPY                                 0x1503
#define GL_COPY_INVERTED                        0x150C
#define GL_NOOP                                 0x1505
#define GL_INVERT                               0x150A
#define GL_AND                                  0x1501
#define GL_NAND                                 0x150E
#define GL_OR                                   0x1507
#define GL_NOR                                  0x1508
#define GL_XOR                                  0x1506
#define GL_EQUIV                                0x1509
#define GL_AND_REVERSE                          0x1502
#define GL_AND_INVERTED                         0x1504
#define GL_OR_REVERSE                           0x150B
#define GL_OR_INVERTED                          0x150D
#define GL_STENCIL_BITS                         0x0D57
#define GL_STENCIL_TEST                         0x0B90
#define GL_STENCIL_CLEAR_VALUE                  0x0B91
#define GL_STENCIL_FUNC                         0x0B92
#define GL_STENCIL_VALUE_MASK                   0x0B93
#define GL_STENCIL_FAIL                         0x0B94
#define GL_STENCIL_PASS_DEPTH_FAIL              0x0B95
#define GL_STENCIL_PASS_DEPTH_PASS              0x0B96
#define GL_STENCIL_REF                          0x0B97
#define GL_STENCIL_WRITEMASK                    0x0B98
#define GL_STENCIL_INDEX                        0x1901
#define GL_KEEP                                 0x1E00
#define GL_REPLACE                              0x1E01
#define GL_INCR                                 0x1E02
#define GL_DECR                                 0x1E03
#define GL_NONE                                 0
#define GL_LEFT                                 0x0406
#define GL_RIGHT                                0x0407
#define GL_FRONT_LEFT                           0x0400
#define GL_FRONT_RIGHT                          0x0401
#define GL_BACK_LEFT                            0x0402
#define GL_BACK_RIGHT                           0x0403
#define GL_AUX0                                 0x0409
#define GL_AUX1                                 0x040A
#define GL_AUX2                                 0x040B
#define GL_AUX3                                 0x040C
#define GL_COLOR_INDEX                          0x1900
#define GL_RED                                  0x1903
#define GL_GREEN                                0x1904
#define GL_BLUE                                 0x1905
#define GL_ALPHA                                0x1906
#define GL_LUMINANCE                            0x1909
#define GL_LUMINANCE_ALPHA                      0x190A
#define GL_ALPHA_BITS                           0x0D55
#define GL_RED_BITS                             0x0D52
#define GL_GREEN_BITS                           0x0D53
#define GL_BLUE_BITS                            0x0D54
#define GL_INDEX_BITS                           0x0D51
#define GL_SUBPIXEL_BITS                        0x0D50
#define GL_AUX_BUFFERS                          0x0C00
#define GL_READ_BUFFER                          0x0C02
#define GL_DRAW_BUFFER                          0x0C01
#define GL_DOUBLEBUFFER                         0x0C32
#define GL_STEREO                               0x0C33
#define GL_BITMAP                               0x1A00
#define GL_COLOR                                0x1800
#define GL_DEPTH                                0x1801
#define GL_STENCIL                              0x1802
#define GL_DITHER                               0x0BD0
#define GL_RGB                                  0x1907
#define GL_RGBA                                 0x1908
#define GL_MAX_LIST_NESTING                     0x0B31
#define GL_MAX_EVAL_ORDER                       0x0D30
#define GL_MAX_LIGHTS                           0x0D31
#define GL_MAX_CLIP_PLANES                      0x0D32
#define GL_MAX_TEXTURE_SIZE                     0x0D33
#define GL_MAX_PIXEL_MAP_TABLE                  0x0D34
#define GL_MAX_ATTRIB_STACK_DEPTH               0x0D35
#define GL_MAX_MODELVIEW_STACK_DEPTH            0x0D36
#define GL_MAX_NAME_STACK_DEPTH                 0x0D37
#define GL_MAX_PROJECTION_STACK_DEPTH           0x0D38
#define GL_MAX_TEXTURE_STACK_DEPTH              0x0D39
#define GL_MAX_VIEWPORT_DIMS                    0x0D3A
#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH        0x0D3B
#define GL_ATTRIB_STACK_DEPTH                   0x0BB0
#define GL_CLIENT_ATTRIB_STACK_DEPTH            0x0BB1
#define GL_COLOR_CLEAR_VALUE                    0x0C22
#define GL_COLOR_WRITEMASK                      0x0C23
#define GL_CURRENT_INDEX                        0x0B01
#define GL_CURRENT_COLOR                        0x0B00
#define GL_CURRENT_NORMAL                       0x0B02
#define GL_CURRENT_RASTER_COLOR                 0x0B04
#define GL_CURRENT_RASTER_DISTANCE              0x0B09
#define GL_CURRENT_RASTER_INDEX                 0x0B05
#define GL_CURRENT_RASTER_POSITION              0x0B07
#define GL_CURRENT_RASTER_TEXTURE_COORDS        0x0B06
#define GL_CURRENT_RASTER_POSITION_VALID        0x0B08
#define GL_CURRENT_TEXTURE_COORDS               0x0B03
#define GL_INDEX_CLEAR_VALUE                    0x0C20
#define GL_INDEX_MODE                           0x0C30
#define GL_INDEX_WRITEMASK                      0x0C21
#define GL_MODELVIEW_MATRIX                     0x0BA6
#define GL_MODELVIEW_STACK_DEPTH                0x0BA3
#define GL_NAME_STACK_DEPTH                     0x0D70
#define GL_PROJECTION_MATRIX                    0x0BA7
#define GL_PROJECTION_STACK_DEPTH               0x0BA4
#define GL_RENDER_MODE                          0x0C40
#define GL_RGBA_MODE                            0x0C31
#define GL_TEXTURE_MATRIX                       0x0BA8
#define GL_TEXTURE_STACK_DEPTH                  0x0BA5
#define GL_VIEWPORT                             0x0BA2
#define GL_AUTO_NORMAL                          0x0D80
#define GL_MAP1_COLOR_4                         0x0D90
#define GL_MAP1_INDEX                           0x0D91
#define GL_MAP1_NORMAL                          0x0D92
#define GL_MAP1_TEXTURE_COORD_1                 0x0D93
#define GL_MAP1_TEXTURE_COORD_2                 0x0D94
#define GL_MAP1_TEXTURE_COORD_3                 0x0D95
#define GL_MAP1_TEXTURE_COORD_4                 0x0D96
#define GL_MAP1_VERTEX_3                        0x0D97
#define GL_MAP1_VERTEX_4                        0x0D98
#define GL_MAP2_COLOR_4                         0x0DB0
#define GL_MAP2_INDEX                           0x0DB1
#define GL_MAP2_NORMAL                          0x0DB2
#define GL_MAP2_TEXTURE_COORD_1                 0x0DB3
#define GL_MAP2_TEXTURE_COORD_2                 0x0DB4
#define GL_MAP2_TEXTURE_COORD_3                 0x0DB5
#define GL_MAP2_TEXTURE_COORD_4                 0x0DB6
#define GL_MAP2_VERTEX_3                        0x0DB7
#define GL_MAP2_VERTEX_4                        0x0DB8
#define GL_MAP1_GRID_DOMAIN                     0x0DD0
#define GL_MAP1_GRID_SEGMENTS                   0x0DD1
#define GL_MAP2_GRID_DOMAIN                     0x0DD2
#define GL_MAP2_GRID_SEGMENTS                   0x0DD3
#define GL_COEFF                                0x0A00
#define GL_ORDER                                0x0A01
#define GL_DOMAIN                               0x0A02
#define GL_PERSPECTIVE_CORRECTION_HINT          0x0C50
#define GL_POINT_SMOOTH_HINT                    0x0C51
#define GL_LINE_SMOOTH_HINT                     0x0C52
#define GL_POLYGON_SMOOTH_HINT                  0x0C53
#define GL_FOG_HINT                             0x0C54
#define GL_DONT_CARE                            0x1100
#define GL_FASTEST                              0x1101
#define GL_NICEST                               0x1102
#define GL_SCISSOR_BOX                          0x0C10
#define GL_SCISSOR_TEST                         0x0C11
#define GL_MAP_COLOR                            0x0D10
#define GL_MAP_STENCIL                          0x0D11
#define GL_INDEX_SHIFT                          0x0D12
#define GL_INDEX_OFFSET                         0x0D13
#define GL_RED_SCALE                            0x0D14
#define GL_RED_BIAS                             0x0D15
#define GL_GREEN_SCALE                          0x0D18
#define GL_GREEN_BIAS                           0x0D19
#define GL_BLUE_SCALE                           0x0D1A
#define GL_BLUE_BIAS                            0x0D1B
#define GL_ALPHA_SCALE                          0x0D1C
#define GL_ALPHA_BIAS                           0x0D1D
#define GL_DEPTH_SCALE                          0x0D1E
#define GL_DEPTH_BIAS                           0x0D1F
#define GL_PIXEL_MAP_S_TO_S_SIZE                0x0CB1
#define GL_PIXEL_MAP_I_TO_I_SIZE                0x0CB0
#define GL_PIXEL_MAP_I_TO_R_SIZE                0x0CB2
#define GL_PIXEL_MAP_I_TO_G_SIZE                0x0CB3
#define GL_PIXEL_MAP_I_TO_B_SIZE                0x0CB4
#define GL_PIXEL_MAP_I_TO_A_SIZE                0x0CB5
#define GL_PIXEL_MAP_R_TO_R_SIZE                0x0CB6
#define GL_PIXEL_MAP_G_TO_G_SIZE                0x0CB7
#define GL_PIXEL_MAP_B_TO_B_SIZE                0x0CB8
#define GL_PIXEL_MAP_A_TO_A_SIZE                0x0CB9
#define GL_PIXEL_MAP_S_TO_S                     0x0C71
#define GL_PIXEL_MAP_I_TO_I                     0x0C70
#define GL_PIXEL_MAP_I_TO_R                     0x0C72
#define GL_PIXEL_MAP_I_TO_G                     0x0C73
#define GL_PIXEL_MAP_I_TO_B                     0x0C74
#define GL_PIXEL_MAP_I_TO_A                     0x0C75
#define GL_PIXEL_MAP_R_TO_R                     0x0C76
#define GL_PIXEL_MAP_G_TO_G                     0x0C77
#define GL_PIXEL_MAP_B_TO_B                     0x0C78
#define GL_PIXEL_MAP_A_TO_A                     0x0C79
#define GL_PACK_ALIGNMENT                       0x0D05
#define GL_PACK_LSB_FIRST                       0x0D01
#define GL_PACK_ROW_LENGTH                      0x0D02
#define GL_PACK_SKIP_PIXELS                     0x0D04
#define GL_PACK_SKIP_ROWS                       0x0D03
#define GL_PACK_SWAP_BYTES                      0x0D00
#define GL_UNPACK_ALIGNMENT                     0x0CF5
#define GL_UNPACK_LSB_FIRST                     0x0CF1
#define GL_UNPACK_ROW_LENGTH                    0x0CF2
#define GL_UNPACK_SKIP_PIXELS                   0x0CF4
#define GL_UNPACK_SKIP_ROWS                     0x0CF3
#define GL_UNPACK_SWAP_BYTES                    0x0CF0
#define GL_ZOOM_X                               0x0D16
#define GL_ZOOM_Y                               0x0D17
#define GL_TEXTURE_ENV                          0x2300
#define GL_TEXTURE_ENV_MODE                     0x2200
#define GL_TEXTURE_1D                           0x0DE0
#define GL_TEXTURE_2D                           0x0DE1
#define GL_TEXTURE_WRAP_S                       0x2802
#define GL_TEXTURE_WRAP_T                       0x2803
#define GL_TEXTURE_MAG_FILTER                   0x2800
#define GL_TEXTURE_MIN_FILTER                   0x2801
#define GL_TEXTURE_ENV_COLOR                    0x2201
#define GL_TEXTURE_GEN_S                        0x0C60
#define GL_TEXTURE_GEN_T                        0x0C61
#define GL_TEXTURE_GEN_R                        0x0C62
#define GL_TEXTURE_GEN_Q                        0x0C63
#define GL_TEXTURE_GEN_MODE                     0x2500
#define GL_TEXTURE_BORDER_COLOR                 0x1004
#define GL_TEXTURE_WIDTH                        0x1000
#define GL_TEXTURE_HEIGHT                       0x1001
#define GL_TEXTURE_BORDER                       0x1005
#define GL_TEXTURE_COMPONENTS                   0x1003
#define GL_TEXTURE_RED_SIZE                     0x805C
#define GL_TEXTURE_GREEN_SIZE                   0x805D
#define GL_TEXTURE_BLUE_SIZE                    0x805E
#define GL_TEXTURE_ALPHA_SIZE                   0x805F
#define GL_TEXTURE_LUMINANCE_SIZE               0x8060
#define GL_TEXTURE_INTENSITY_SIZE               0x8061
#define GL_NEAREST_MIPMAP_NEAREST               0x2700
#define GL_NEAREST_MIPMAP_LINEAR                0x2702
#define GL_LINEAR_MIPMAP_NEAREST                0x2701
#define GL_LINEAR_MIPMAP_LINEAR                 0x2703
#define GL_OBJECT_LINEAR                        0x2401
#define GL_OBJECT_PLANE                         0x2501
#define GL_EYE_LINEAR                           0x2400
#define GL_EYE_PLANE                            0x2502
#define GL_SPHERE_MAP                           0x2402
#define GL_DECAL                                0x2101
#define GL_MODULATE                             0x2100
#define GL_NEAREST                              0x2600
#define GL_REPEAT                               0x2901
#define GL_CLAMP                                0x2900
#define GL_S                                    0x2000
#define GL_T                                    0x2001
#define GL_R                                    0x2002
#define GL_Q                                    0x2003
#define GL_VENDOR                               0x1F00
#define GL_RENDERER                             0x1F01
#define GL_VERSION                              0x1F02
#define GL_EXTENSIONS                           0x1F03
#define GL_NO_ERROR                             0
#define GL_INVALID_ENUM                         0x0500
#define GL_INVALID_VALUE                        0x0501
#define GL_INVALID_OPERATION                    0x0502
#define GL_STACK_OVERFLOW                       0x0503
#define GL_STACK_UNDERFLOW                      0x0504
#define GL_OUT_OF_MEMORY                        0x0505
#define GL_CURRENT_BIT                          0x00000001
#define GL_POINT_BIT                            0x00000002
#define GL_LINE_BIT                             0x00000004
#define GL_POLYGON_BIT                          0x00000008
#define GL_POLYGON_STIPPLE_BIT                  0x00000010
#define GL_PIXEL_MODE_BIT                       0x00000020
#define GL_LIGHTING_BIT                         0x00000040
#define GL_FOG_BIT                              0x00000080
#define GL_DEPTH_BUFFER_BIT                     0x00000100
#define GL_ACCUM_BUFFER_BIT                     0x00000200
#define GL_STENCIL_BUFFER_BIT                   0x00000400
#define GL_VIEWPORT_BIT                         0x00000800
#define GL_TRANSFORM_BIT                        0x00001000
#define GL_ENABLE_BIT                           0x00002000
#define GL_COLOR_BUFFER_BIT                     0x00004000
#define GL_HINT_BIT                             0x00008000
#define GL_EVAL_BIT                             0x00010000
#define GL_LIST_BIT                             0x00020000
#define GL_TEXTURE_BIT                          0x00040000
#define GL_SCISSOR_BIT                          0x00080000
#define GL_ALL_ATTRIB_BITS                      0xFFFFFFFF
#define GL_PROXY_TEXTURE_1D                     0x8063
#define GL_PROXY_TEXTURE_2D                     0x8064
#define GL_TEXTURE_PRIORITY                     0x8066
#define GL_TEXTURE_RESIDENT                     0x8067
#define GL_TEXTURE_BINDING_1D                   0x8068
#define GL_TEXTURE_BINDING_2D                   0x8069
#define GL_TEXTURE_INTERNAL_FORMAT              0x1003
#define GL_ALPHA4                               0x803B
#define GL_ALPHA8                               0x803C
#define GL_ALPHA12                              0x803D
#define GL_ALPHA16                              0x803E
#define GL_LUMINANCE4                           0x803F
#define GL_LUMINANCE8                           0x8040
#define GL_LUMINANCE12                          0x8041
#define GL_LUMINANCE16                          0x8042
#define GL_LUMINANCE4_ALPHA4                    0x8043
#define GL_LUMINANCE6_ALPHA2                    0x8044
#define GL_LUMINANCE8_ALPHA8                    0x8045
#define GL_LUMINANCE12_ALPHA4                   0x8046
#define GL_LUMINANCE12_ALPHA12                  0x8047
#define GL_LUMINANCE16_ALPHA16                  0x8048
#define GL_INTENSITY                            0x8049
#define GL_INTENSITY4                           0x804A
#define GL_INTENSITY8                           0x804B
#define GL_INTENSITY12                          0x804C
#define GL_INTENSITY16                          0x804D
#define GL_R3_G3_B2                             0x2A10
#define GL_RGB4                                 0x804F
#define GL_RGB5                                 0x8050
#define GL_RGB8                                 0x8051
#define GL_RGB10                                0x8052
#define GL_RGB12                                0x8053
#define GL_RGB16                                0x8054
#define GL_RGBA2                                0x8055
#define GL_RGBA4                                0x8056
#define GL_RGB5_A1                              0x8057
#define GL_RGBA8                                0x8058
#define GL_RGB10_A2                             0x8059
#define GL_RGBA12                               0x805A
#define GL_RGBA16                               0x805B
#define GL_CLIENT_PIXEL_STORE_BIT               0x00000001
#define GL_CLIENT_VERTEX_ARRAY_BIT              0x00000002
#define GL_ALL_CLIENT_ATTRIB_BITS               0xFFFFFFFF
#define GL_CLIENT_ALL_ATTRIB_BITS               0xFFFFFFFF
#define GL_RESCALE_NORMAL                       0x803A
#define GL_CLAMP_TO_EDGE                        0x812F
#define GL_MAX_ELEMENTS_VERTICES                0x80E8
#define GL_MAX_ELEMENTS_INDICES                 0x80E9
#define GL_BGR                                  0x80E0
#define GL_BGRA                                 0x80E1
#define GL_UNSIGNED_BYTE_3_3_2                  0x8032
#define GL_UNSIGNED_BYTE_2_3_3_REV              0x8362
#define GL_UNSIGNED_SHORT_5_6_5                 0x8363
#define GL_UNSIGNED_SHORT_5_6_5_REV             0x8364
#define GL_UNSIGNED_SHORT_4_4_4_4               0x8033
#define GL_UNSIGNED_SHORT_4_4_4_4_REV           0x8365
#define GL_UNSIGNED_SHORT_5_5_5_1               0x8034
#define GL_UNSIGNED_SHORT_1_5_5_5_REV           0x8366
#define GL_UNSIGNED_INT_8_8_8_8                 0x8035
#define GL_UNSIGNED_INT_8_8_8_8_REV             0x8367
#define GL_UNSIGNED_INT_10_10_10_2              0x8036
#define GL_UNSIGNED_INT_2_10_10_10_REV          0x8368
#define GL_LIGHT_MODEL_COLOR_CONTROL            0x81F8
#define GL_SINGLE_COLOR                         0x81F9
#define GL_SEPARATE_SPECULAR_COLOR              0x81FA
#define GL_TEXTURE_MIN_LOD                      0x813A
#define GL_TEXTURE_MAX_LOD                      0x813B
#define GL_TEXTURE_BASE_LEVEL                   0x813C
#define GL_TEXTURE_MAX_LEVEL                    0x813D
#define GL_SMOOTH_POINT_SIZE_RANGE              0x0B12
#define GL_SMOOTH_POINT_SIZE_GRANULARITY        0x0B13
#define GL_SMOOTH_LINE_WIDTH_RANGE              0x0B22
#define GL_SMOOTH_LINE_WIDTH_GRANULARITY        0x0B23
#define GL_ALIASED_POINT_SIZE_RANGE             0x846D
#define GL_ALIASED_LINE_WIDTH_RANGE             0x846E
#define GL_PACK_SKIP_IMAGES                     0x806B
#define GL_PACK_IMAGE_HEIGHT                    0x806C
#define GL_UNPACK_SKIP_IMAGES                   0x806D
#define GL_UNPACK_IMAGE_HEIGHT                  0x806E
#define GL_TEXTURE_3D                           0x806F
#define GL_PROXY_TEXTURE_3D                     0x8070
#define GL_TEXTURE_DEPTH                        0x8071
#define GL_TEXTURE_WRAP_R                       0x8072
#define GL_MAX_3D_TEXTURE_SIZE                  0x8073
#define GL_TEXTURE_BINDING_3D                   0x806A
#define GL_CONSTANT_COLOR                       0x8001
#define GL_ONE_MINUS_CONSTANT_COLOR             0x8002
#define GL_CONSTANT_ALPHA                       0x8003
#define GL_ONE_MINUS_CONSTANT_ALPHA             0x8004
#define GL_COLOR_TABLE                          0x80D0
#define GL_POST_CONVOLUTION_COLOR_TABLE         0x80D1
#define GL_POST_COLOR_MATRIX_COLOR_TABLE        0x80D2
#define GL_PROXY_COLOR_TABLE                    0x80D3
#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE   0x80D4
#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE  0x80D5
#define GL_COLOR_TABLE_SCALE                    0x80D6
#define GL_COLOR_TABLE_BIAS                     0x80D7
#define GL_COLOR_TABLE_FORMAT                   0x80D8
#define GL_COLOR_TABLE_WIDTH                    0x80D9
#define GL_COLOR_TABLE_RED_SIZE                 0x80DA
#define GL_COLOR_TABLE_GREEN_SIZE               0x80DB
#define GL_COLOR_TABLE_BLUE_SIZE                0x80DC
#define GL_COLOR_TABLE_ALPHA_SIZE               0x80DD
#define GL_COLOR_TABLE_LUMINANCE_SIZE           0x80DE
#define GL_COLOR_TABLE_INTENSITY_SIZE           0x80DF
#define GL_CONVOLUTION_1D                       0x8010
#define GL_CONVOLUTION_2D                       0x8011
#define GL_SEPARABLE_2D                         0x8012
#define GL_CONVOLUTION_BORDER_MODE              0x8013
#define GL_CONVOLUTION_FILTER_SCALE             0x8014
#define GL_CONVOLUTION_FILTER_BIAS              0x8015
#define GL_REDUCE                               0x8016
#define GL_CONVOLUTION_FORMAT                   0x8017
#define GL_CONVOLUTION_WIDTH                    0x8018
#define GL_CONVOLUTION_HEIGHT                   0x8019
#define GL_MAX_CONVOLUTION_WIDTH                0x801A
#define GL_MAX_CONVOLUTION_HEIGHT               0x801B
#define GL_POST_CONVOLUTION_RED_SCALE           0x801C
#define GL_POST_CONVOLUTION_GREEN_SCALE         0x801D
#define GL_POST_CONVOLUTION_BLUE_SCALE          0x801E
#define GL_POST_CONVOLUTION_ALPHA_SCALE         0x801F
#define GL_POST_CONVOLUTION_RED_BIAS            0x8020
#define GL_POST_CONVOLUTION_GREEN_BIAS          0x8021
#define GL_POST_CONVOLUTION_BLUE_BIAS           0x8022
#define GL_POST_CONVOLUTION_ALPHA_BIAS          0x8023
#define GL_CONSTANT_BORDER                      0x8151
#define GL_REPLICATE_BORDER                     0x8153
#define GL_CONVOLUTION_BORDER_COLOR             0x8154
#define GL_COLOR_MATRIX                         0x80B1
#define GL_COLOR_MATRIX_STACK_DEPTH             0x80B2
#define GL_MAX_COLOR_MATRIX_STACK_DEPTH         0x80B3
#define GL_POST_COLOR_MATRIX_RED_SCALE          0x80B4
#define GL_POST_COLOR_MATRIX_GREEN_SCALE        0x80B5
#define GL_POST_COLOR_MATRIX_BLUE_SCALE         0x80B6
#define GL_POST_COLOR_MATRIX_ALPHA_SCALE        0x80B7
#define GL_POST_COLOR_MATRIX_RED_BIAS           0x80B8
#define GL_POST_COLOR_MATRIX_GREEN_BIAS         0x80B9
#define GL_POST_COLOR_MATRIX_BLUE_BIAS          0x80BA
#define GL_POST_COLOR_MATRIX_ALPHA_BIAS         0x80BB
#define GL_HISTOGRAM                            0x8024
#define GL_PROXY_HISTOGRAM                      0x8025
#define GL_HISTOGRAM_WIDTH                      0x8026
#define GL_HISTOGRAM_FORMAT                     0x8027
#define GL_HISTOGRAM_RED_SIZE                   0x8028
#define GL_HISTOGRAM_GREEN_SIZE                 0x8029
#define GL_HISTOGRAM_BLUE_SIZE                  0x802A
#define GL_HISTOGRAM_ALPHA_SIZE                 0x802B
#define GL_HISTOGRAM_LUMINANCE_SIZE             0x802C
#define GL_HISTOGRAM_SINK                       0x802D
#define GL_MINMAX                               0x802E
#define GL_MINMAX_FORMAT                        0x802F
#define GL_MINMAX_SINK                          0x8030
#define GL_TABLE_TOO_LARGE                      0x8031
#define GL_BLEND_EQUATION                       0x8009
#define GL_MIN                                  0x8007
#define GL_MAX                                  0x8008
#define GL_FUNC_ADD                             0x8006
#define GL_FUNC_SUBTRACT                        0x800A
#define GL_FUNC_REVERSE_SUBTRACT                0x800B
#define GL_BLEND_COLOR                          0x8005
#define GL_TEXTURE0                             0x84C0
#define GL_TEXTURE1                             0x84C1
#define GL_TEXTURE2                             0x84C2
#define GL_TEXTURE3                             0x84C3
#define GL_TEXTURE4                             0x84C4
#define GL_TEXTURE5                             0x84C5
#define GL_TEXTURE6                             0x84C6
#define GL_TEXTURE7                             0x84C7
#define GL_TEXTURE8                             0x84C8
#define GL_TEXTURE9                             0x84C9
#define GL_TEXTURE10                            0x84CA
#define GL_TEXTURE11                            0x84CB
#define GL_TEXTURE12                            0x84CC
#define GL_TEXTURE13                            0x84CD
#define GL_TEXTURE14                            0x84CE
#define GL_TEXTURE15                            0x84CF
#define GL_TEXTURE16                            0x84D0
#define GL_TEXTURE17                            0x84D1
#define GL_TEXTURE18                            0x84D2
#define GL_TEXTURE19                            0x84D3
#define GL_TEXTURE20                            0x84D4
#define GL_TEXTURE21                            0x84D5
#define GL_TEXTURE22                            0x84D6
#define GL_TEXTURE23                            0x84D7
#define GL_TEXTURE24                            0x84D8
#define GL_TEXTURE25                            0x84D9
#define GL_TEXTURE26                            0x84DA
#define GL_TEXTURE27                            0x84DB
#define GL_TEXTURE28                            0x84DC
#define GL_TEXTURE29                            0x84DD
#define GL_TEXTURE30                            0x84DE
#define GL_TEXTURE31                            0x84DF
#define GL_ACTIVE_TEXTURE                       0x84E0
#define GL_CLIENT_ACTIVE_TEXTURE                0x84E1
#define GL_MAX_TEXTURE_UNITS                    0x84E2
#define GL_NORMAL_MAP                           0x8511
#define GL_REFLECTION_MAP                       0x8512
#define GL_TEXTURE_CUBE_MAP                     0x8513
#define GL_TEXTURE_BINDING_CUBE_MAP             0x8514
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X          0x8515
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X          0x8516
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y          0x8517
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y          0x8518
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z          0x8519
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z          0x851A
#define GL_PROXY_TEXTURE_CUBE_MAP               0x851B
#define GL_MAX_CUBE_MAP_TEXTURE_SIZE            0x851C
#define GL_COMPRESSED_ALPHA                     0x84E9
#define GL_COMPRESSED_LUMINANCE                 0x84EA
#define GL_COMPRESSED_LUMINANCE_ALPHA           0x84EB
#define GL_COMPRESSED_INTENSITY                 0x84EC
#define GL_COMPRESSED_RGB                       0x84ED
#define GL_COMPRESSED_RGBA                      0x84EE
#define GL_TEXTURE_COMPRESSION_HINT             0x84EF
#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE        0x86A0
#define GL_TEXTURE_COMPRESSED                   0x86A1
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS       0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS           0x86A3
#define GL_MULTISAMPLE                          0x809D
#define GL_SAMPLE_ALPHA_TO_COVERAGE             0x809E
#define GL_SAMPLE_ALPHA_TO_ONE                  0x809F
#define GL_SAMPLE_COVERAGE                      0x80A0
#define GL_SAMPLE_BUFFERS                       0x80A8
#define GL_SAMPLES                              0x80A9
#define GL_SAMPLE_COVERAGE_VALUE                0x80AA
#define GL_SAMPLE_COVERAGE_INVERT               0x80AB
#define GL_MULTISAMPLE_BIT                      0x20000000
#define GL_TRANSPOSE_MODELVIEW_MATRIX           0x84E3
#define GL_TRANSPOSE_PROJECTION_MATRIX          0x84E4
#define GL_TRANSPOSE_TEXTURE_MATRIX             0x84E5
#define GL_TRANSPOSE_COLOR_MATRIX               0x84E6
#define GL_COMBINE                              0x8570
#define GL_COMBINE_RGB                          0x8571
#define GL_COMBINE_ALPHA                        0x8572
#define GL_SOURCE0_RGB                          0x8580
#define GL_SOURCE1_RGB                          0x8581
#define GL_SOURCE2_RGB                          0x8582
#define GL_SOURCE0_ALPHA                        0x8588
#define GL_SOURCE1_ALPHA                        0x8589
#define GL_SOURCE2_ALPHA                        0x858A
#define GL_OPERAND0_RGB                         0x8590
#define GL_OPERAND1_RGB                         0x8591
#define GL_OPERAND2_RGB                         0x8592
#define GL_OPERAND0_ALPHA                       0x8598
#define GL_OPERAND1_ALPHA                       0x8599
#define GL_OPERAND2_ALPHA                       0x859A
#define GL_RGB_SCALE                            0x8573
#define GL_ADD_SIGNED                           0x8574
#define GL_INTERPOLATE                          0x8575
#define GL_SUBTRACT                             0x84E7
#define GL_CONSTANT                             0x8576
#define GL_PRIMARY_COLOR                        0x8577
#define GL_PREVIOUS                             0x8578
#define GL_DOT3_RGB                             0x86AE
#define GL_DOT3_RGBA                            0x86AF
#define GL_CLAMP_TO_BORDER                      0x812D
#define GL_ARB_multitexture 1
#define GL_TEXTURE0_ARB                         0x84C0
#define GL_TEXTURE1_ARB                         0x84C1
#define GL_TEXTURE2_ARB                         0x84C2
#define GL_TEXTURE3_ARB                         0x84C3
#define GL_TEXTURE4_ARB                         0x84C4
#define GL_TEXTURE5_ARB                         0x84C5
#define GL_TEXTURE6_ARB                         0x84C6
#define GL_TEXTURE7_ARB                         0x84C7
#define GL_TEXTURE8_ARB                         0x84C8
#define GL_TEXTURE9_ARB                         0x84C9
#define GL_TEXTURE10_ARB                        0x84CA
#define GL_TEXTURE11_ARB                        0x84CB
#define GL_TEXTURE12_ARB                        0x84CC
#define GL_TEXTURE13_ARB                        0x84CD
#define GL_TEXTURE14_ARB                        0x84CE
#define GL_TEXTURE15_ARB                        0x84CF
#define GL_TEXTURE16_ARB                        0x84D0
#define GL_TEXTURE17_ARB                        0x84D1
#define GL_TEXTURE18_ARB                        0x84D2
#define GL_TEXTURE19_ARB                        0x84D3
#define GL_TEXTURE20_ARB                        0x84D4
#define GL_TEXTURE21_ARB                        0x84D5
#define GL_TEXTURE22_ARB                        0x84D6
#define GL_TEXTURE23_ARB                        0x84D7
#define GL_TEXTURE24_ARB                        0x84D8
#define GL_TEXTURE25_ARB                        0x84D9
#define GL_TEXTURE26_ARB                        0x84DA
#define GL_TEXTURE27_ARB                        0x84DB
#define GL_TEXTURE28_ARB                        0x84DC
#define GL_TEXTURE29_ARB                        0x84DD
#define GL_TEXTURE30_ARB                        0x84DE
#define GL_TEXTURE31_ARB                        0x84DF
#define GL_ACTIVE_TEXTURE_ARB                   0x84E0
#define GL_CLIENT_ACTIVE_TEXTURE_ARB            0x84E1
#define GL_MAX_TEXTURE_UNITS_ARB                0x84E2
#define GL_MESA_packed_depth_stencil 1
#define GL_DEPTH_STENCIL_MESA                   0x8750
#define GL_UNSIGNED_INT_24_8_MESA               0x8751
#define GL_UNSIGNED_INT_8_24_REV_MESA           0x8752
#define GL_UNSIGNED_SHORT_15_1_MESA             0x8753
#define GL_UNSIGNED_SHORT_1_15_REV_MESA         0x8754
#define GL_ATI_blend_equation_separate 1
#define GL_ALPHA_BLEND_EQUATION_ATI             0x883D
#define GL_OES_EGL_image 1

#ifdef __cplusplus
}
#endif

#endif /* __NX_GL_H__ */</pre>
<h2>./include/libretro-common/include/glsym/switch/nx_glsym.h</h2>
<pre>#ifndef __NX_GLSYM_H__
#define __NX_GLSYM_H__

#ifdef __cplusplus
extern "C" {
#endif

typedef void *GLeglImageOES;
typedef void (APIENTRYP RGLSYMGLCLEARINDEXPROC) ( GLfloat c );
typedef void (APIENTRYP RGLSYMGLCLEARCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
typedef void (APIENTRYP RGLSYMGLCLEARPROC) ( GLbitfield mask );
typedef void (APIENTRYP RGLSYMGLINDEXMASKPROC) ( GLuint mask );
typedef void (APIENTRYP RGLSYMGLCOLORMASKPROC) ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha );
typedef void (APIENTRYP RGLSYMGLALPHAFUNCPROC) ( GLenum func, GLclampf ref );
typedef void (APIENTRYP RGLSYMGLBLENDFUNCPROC) ( GLenum sfactor, GLenum dfactor );
typedef void (APIENTRYP RGLSYMGLLOGICOPPROC) ( GLenum opcode );
typedef void (APIENTRYP RGLSYMGLCULLFACEPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLFRONTFACEPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLPOINTSIZEPROC) ( GLfloat size );
typedef void (APIENTRYP RGLSYMGLLINEWIDTHPROC) ( GLfloat width );
typedef void (APIENTRYP RGLSYMGLLINESTIPPLEPROC) ( GLint factor, GLushort pattern );
typedef void (APIENTRYP RGLSYMGLPOLYGONMODEPROC) ( GLenum face, GLenum mode );
typedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETPROC) ( GLfloat factor, GLfloat units );
typedef void (APIENTRYP RGLSYMGLPOLYGONSTIPPLEPROC) ( const GLubyte *mask );
typedef void (APIENTRYP RGLSYMGLGETPOLYGONSTIPPLEPROC) ( GLubyte *mask );
typedef void (APIENTRYP RGLSYMGLEDGEFLAGPROC) ( GLboolean flag );
typedef void (APIENTRYP RGLSYMGLEDGEFLAGVPROC) ( const GLboolean *flag );
typedef void (APIENTRYP RGLSYMGLSCISSORPROC) ( GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP RGLSYMGLCLIPPLANEPROC) ( GLenum plane, const GLdouble *equation );
typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEPROC) ( GLenum plane, GLdouble *equation );
typedef void (APIENTRYP RGLSYMGLDRAWBUFFERPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLREADBUFFERPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLENABLEPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLDISABLEPROC) ( GLenum cap );
typedef GLboolean (APIENTRYP RGLSYMGLISENABLEDPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLENABLECLIENTSTATEPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLDISABLECLIENTSTATEPROC) ( GLenum cap );
typedef void (APIENTRYP RGLSYMGLGETBOOLEANVPROC) ( GLenum pname, GLboolean *params );
typedef void (APIENTRYP RGLSYMGLGETDOUBLEVPROC) ( GLenum pname, GLdouble *params );
typedef void (APIENTRYP RGLSYMGLGETFLOATVPROC) ( GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETINTEGERVPROC) ( GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLPUSHATTRIBPROC) ( GLbitfield mask );
typedef void (APIENTRYP RGLSYMGLPOPATTRIBPROC) ( void );
typedef void (APIENTRYP RGLSYMGLPUSHCLIENTATTRIBPROC) ( GLbitfield mask );
typedef void (APIENTRYP RGLSYMGLPOPCLIENTATTRIBPROC) ( void );
typedef GLint (APIENTRYP RGLSYMGLRENDERMODEPROC) ( GLenum mode );
typedef GLenum (APIENTRYP RGLSYMGLGETERRORPROC) ( void );
typedef const GLubyte * (APIENTRYP RGLSYMGLGETSTRINGPROC) ( GLenum name );
typedef void (APIENTRYP RGLSYMGLFINISHPROC) ( void );
typedef void (APIENTRYP RGLSYMGLFLUSHPROC) ( void );
typedef void (APIENTRYP RGLSYMGLHINTPROC) ( GLenum target, GLenum mode );
typedef void (APIENTRYP RGLSYMGLCLEARDEPTHPROC) ( GLclampd depth );
typedef void (APIENTRYP RGLSYMGLDEPTHFUNCPROC) ( GLenum func );
typedef void (APIENTRYP RGLSYMGLDEPTHMASKPROC) ( GLboolean flag );
typedef void (APIENTRYP RGLSYMGLDEPTHRANGEPROC) ( GLclampd near_val, GLclampd far_val );
typedef void (APIENTRYP RGLSYMGLCLEARACCUMPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
typedef void (APIENTRYP RGLSYMGLACCUMPROC) ( GLenum op, GLfloat value );
typedef void (APIENTRYP RGLSYMGLMATRIXMODEPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLORTHOPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );
typedef void (APIENTRYP RGLSYMGLFRUSTUMPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );
typedef void (APIENTRYP RGLSYMGLVIEWPORTPROC) ( GLint x, GLint y, GLsizei width, GLsizei height );
typedef void (APIENTRYP RGLSYMGLPUSHMATRIXPROC) ( void );
typedef void (APIENTRYP RGLSYMGLPOPMATRIXPROC) ( void );
typedef void (APIENTRYP RGLSYMGLLOADIDENTITYPROC) ( void );
typedef void (APIENTRYP RGLSYMGLLOADMATRIXDPROC) ( const GLdouble *m );
typedef void (APIENTRYP RGLSYMGLLOADMATRIXFPROC) ( const GLfloat *m );
typedef void (APIENTRYP RGLSYMGLMULTMATRIXDPROC) ( const GLdouble *m );
typedef void (APIENTRYP RGLSYMGLMULTMATRIXFPROC) ( const GLfloat *m );
typedef void (APIENTRYP RGLSYMGLROTATEDPROC) ( GLdouble angle, GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLROTATEFPROC) ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLSCALEDPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLSCALEFPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLTRANSLATEDPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLTRANSLATEFPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef GLboolean (APIENTRYP RGLSYMGLISLISTPROC) ( GLuint list );
typedef void (APIENTRYP RGLSYMGLDELETELISTSPROC) ( GLuint list, GLsizei range );
typedef GLuint (APIENTRYP RGLSYMGLGENLISTSPROC) ( GLsizei range );
typedef void (APIENTRYP RGLSYMGLNEWLISTPROC) ( GLuint list, GLenum mode );
typedef void (APIENTRYP RGLSYMGLENDLISTPROC) ( void );
typedef void (APIENTRYP RGLSYMGLCALLLISTPROC) ( GLuint list );
typedef void (APIENTRYP RGLSYMGLCALLLISTSPROC) ( GLsizei n, GLenum type, const GLvoid *lists );
typedef void (APIENTRYP RGLSYMGLLISTBASEPROC) ( GLuint base );
typedef void (APIENTRYP RGLSYMGLBEGINPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLENDPROC) ( void );
typedef void (APIENTRYP RGLSYMGLVERTEX2DPROC) ( GLdouble x, GLdouble y );
typedef void (APIENTRYP RGLSYMGLVERTEX2FPROC) ( GLfloat x, GLfloat y );
typedef void (APIENTRYP RGLSYMGLVERTEX2IPROC) ( GLint x, GLint y );
typedef void (APIENTRYP RGLSYMGLVERTEX2SPROC) ( GLshort x, GLshort y );
typedef void (APIENTRYP RGLSYMGLVERTEX3DPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLVERTEX3FPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLVERTEX3IPROC) ( GLint x, GLint y, GLint z );
typedef void (APIENTRYP RGLSYMGLVERTEX3SPROC) ( GLshort x, GLshort y, GLshort z );
typedef void (APIENTRYP RGLSYMGLVERTEX4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
typedef void (APIENTRYP RGLSYMGLVERTEX4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
typedef void (APIENTRYP RGLSYMGLVERTEX4IPROC) ( GLint x, GLint y, GLint z, GLint w );
typedef void (APIENTRYP RGLSYMGLVERTEX4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );
typedef void (APIENTRYP RGLSYMGLVERTEX2DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLVERTEX2FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLVERTEX2IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLVERTEX2SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLVERTEX3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLVERTEX4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3BPROC) ( GLbyte nx, GLbyte ny, GLbyte nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3DPROC) ( GLdouble nx, GLdouble ny, GLdouble nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3FPROC) ( GLfloat nx, GLfloat ny, GLfloat nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3IPROC) ( GLint nx, GLint ny, GLint nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3SPROC) ( GLshort nx, GLshort ny, GLshort nz );
typedef void (APIENTRYP RGLSYMGLNORMAL3BVPROC) ( const GLbyte *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLNORMAL3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLINDEXDPROC) ( GLdouble c );
typedef void (APIENTRYP RGLSYMGLINDEXFPROC) ( GLfloat c );
typedef void (APIENTRYP RGLSYMGLINDEXIPROC) ( GLint c );
typedef void (APIENTRYP RGLSYMGLINDEXSPROC) ( GLshort c );
typedef void (APIENTRYP RGLSYMGLINDEXUBPROC) ( GLubyte c );
typedef void (APIENTRYP RGLSYMGLINDEXDVPROC) ( const GLdouble *c );
typedef void (APIENTRYP RGLSYMGLINDEXFVPROC) ( const GLfloat *c );
typedef void (APIENTRYP RGLSYMGLINDEXIVPROC) ( const GLint *c );
typedef void (APIENTRYP RGLSYMGLINDEXSVPROC) ( const GLshort *c );
typedef void (APIENTRYP RGLSYMGLINDEXUBVPROC) ( const GLubyte *c );
typedef void (APIENTRYP RGLSYMGLCOLOR3BPROC) ( GLbyte red, GLbyte green, GLbyte blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3DPROC) ( GLdouble red, GLdouble green, GLdouble blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3FPROC) ( GLfloat red, GLfloat green, GLfloat blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3IPROC) ( GLint red, GLint green, GLint blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3SPROC) ( GLshort red, GLshort green, GLshort blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3UBPROC) ( GLubyte red, GLubyte green, GLubyte blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3UIPROC) ( GLuint red, GLuint green, GLuint blue );
typedef void (APIENTRYP RGLSYMGLCOLOR3USPROC) ( GLushort red, GLushort green, GLushort blue );
typedef void (APIENTRYP RGLSYMGLCOLOR4BPROC) ( GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4DPROC) ( GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4FPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4IPROC) ( GLint red, GLint green, GLint blue, GLint alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4SPROC) ( GLshort red, GLshort green, GLshort blue, GLshort alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4UBPROC) ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4UIPROC) ( GLuint red, GLuint green, GLuint blue, GLuint alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR4USPROC) ( GLushort red, GLushort green, GLushort blue, GLushort alpha );
typedef void (APIENTRYP RGLSYMGLCOLOR3BVPROC) ( const GLbyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3UBVPROC) ( const GLubyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3UIVPROC) ( const GLuint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR3USVPROC) ( const GLushort *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4BVPROC) ( const GLbyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4UBVPROC) ( const GLubyte *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4UIVPROC) ( const GLuint *v );
typedef void (APIENTRYP RGLSYMGLCOLOR4USVPROC) ( const GLushort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1DPROC) ( GLdouble s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1FPROC) ( GLfloat s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1IPROC) ( GLint s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1SPROC) ( GLshort s );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2DPROC) ( GLdouble s, GLdouble t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2FPROC) ( GLfloat s, GLfloat t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2IPROC) ( GLint s, GLint t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2SPROC) ( GLshort s, GLshort t );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3DPROC) ( GLdouble s, GLdouble t, GLdouble r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3FPROC) ( GLfloat s, GLfloat t, GLfloat r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3IPROC) ( GLint s, GLint t, GLint r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3SPROC) ( GLshort s, GLshort t, GLshort r );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4DPROC) ( GLdouble s, GLdouble t, GLdouble r, GLdouble q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4FPROC) ( GLfloat s, GLfloat t, GLfloat r, GLfloat q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4IPROC) ( GLint s, GLint t, GLint r, GLint q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4SPROC) ( GLshort s, GLshort t, GLshort r, GLshort q );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD1SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD2SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLTEXCOORD4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2DPROC) ( GLdouble x, GLdouble y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2FPROC) ( GLfloat x, GLfloat y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2IPROC) ( GLint x, GLint y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2SPROC) ( GLshort x, GLshort y );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3DPROC) ( GLdouble x, GLdouble y, GLdouble z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3FPROC) ( GLfloat x, GLfloat y, GLfloat z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3IPROC) ( GLint x, GLint y, GLint z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3SPROC) ( GLshort x, GLshort y, GLshort z );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4IPROC) ( GLint x, GLint y, GLint z, GLint w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS2SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS3SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4DVPROC) ( const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4FVPROC) ( const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4IVPROC) ( const GLint *v );
typedef void (APIENTRYP RGLSYMGLRASTERPOS4SVPROC) ( const GLshort *v );
typedef void (APIENTRYP RGLSYMGLRECTDPROC) ( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 );
typedef void (APIENTRYP RGLSYMGLRECTFPROC) ( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 );
typedef void (APIENTRYP RGLSYMGLRECTIPROC) ( GLint x1, GLint y1, GLint x2, GLint y2 );
typedef void (APIENTRYP RGLSYMGLRECTSPROC) ( GLshort x1, GLshort y1, GLshort x2, GLshort y2 );
typedef void (APIENTRYP RGLSYMGLRECTDVPROC) ( const GLdouble *v1, const GLdouble *v2 );
typedef void (APIENTRYP RGLSYMGLRECTFVPROC) ( const GLfloat *v1, const GLfloat *v2 );
typedef void (APIENTRYP RGLSYMGLRECTIVPROC) ( const GLint *v1, const GLint *v2 );
typedef void (APIENTRYP RGLSYMGLRECTSVPROC) ( const GLshort *v1, const GLshort *v2 );
typedef void (APIENTRYP RGLSYMGLVERTEXPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLNORMALPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLCOLORPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLINDEXPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLTEXCOORDPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLEDGEFLAGPOINTERPROC) ( GLsizei stride, const GLvoid *ptr );
typedef void (APIENTRYP RGLSYMGLGETPOINTERVPROC) ( GLenum pname, GLvoid **params );
typedef void (APIENTRYP RGLSYMGLARRAYELEMENTPROC) ( GLint i );
typedef void (APIENTRYP RGLSYMGLDRAWARRAYSPROC) ( GLenum mode, GLint first, GLsizei count );
typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSPROC) ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices );
typedef void (APIENTRYP RGLSYMGLINTERLEAVEDARRAYSPROC) ( GLenum format, GLsizei stride, const GLvoid *pointer );
typedef void (APIENTRYP RGLSYMGLSHADEMODELPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLLIGHTFPROC) ( GLenum light, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLLIGHTIPROC) ( GLenum light, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLLIGHTFVPROC) ( GLenum light, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLLIGHTIVPROC) ( GLenum light, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETLIGHTFVPROC) ( GLenum light, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETLIGHTIVPROC) ( GLenum light, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELFVPROC) ( GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLLIGHTMODELIVPROC) ( GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLMATERIALFPROC) ( GLenum face, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLMATERIALIPROC) ( GLenum face, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLMATERIALFVPROC) ( GLenum face, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLMATERIALIVPROC) ( GLenum face, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETMATERIALFVPROC) ( GLenum face, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETMATERIALIVPROC) ( GLenum face, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLCOLORMATERIALPROC) ( GLenum face, GLenum mode );
typedef void (APIENTRYP RGLSYMGLPIXELZOOMPROC) ( GLfloat xfactor, GLfloat yfactor );
typedef void (APIENTRYP RGLSYMGLPIXELSTOREFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLPIXELSTOREIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLPIXELMAPFVPROC) ( GLenum map, GLsizei mapsize, const GLfloat *values );
typedef void (APIENTRYP RGLSYMGLPIXELMAPUIVPROC) ( GLenum map, GLsizei mapsize, const GLuint *values );
typedef void (APIENTRYP RGLSYMGLPIXELMAPUSVPROC) ( GLenum map, GLsizei mapsize, const GLushort *values );
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPFVPROC) ( GLenum map, GLfloat *values );
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPUIVPROC) ( GLenum map, GLuint *values );
typedef void (APIENTRYP RGLSYMGLGETPIXELMAPUSVPROC) ( GLenum map, GLushort *values );
typedef void (APIENTRYP RGLSYMGLBITMAPPROC) ( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap );
typedef void (APIENTRYP RGLSYMGLREADPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLDRAWPIXELSPROC) ( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLCOPYPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type );
typedef void (APIENTRYP RGLSYMGLSTENCILFUNCPROC) ( GLenum func, GLint ref, GLuint mask );
typedef void (APIENTRYP RGLSYMGLSTENCILMASKPROC) ( GLuint mask );
typedef void (APIENTRYP RGLSYMGLSTENCILOPPROC) ( GLenum fail, GLenum zfail, GLenum zpass );
typedef void (APIENTRYP RGLSYMGLCLEARSTENCILPROC) ( GLint s );
typedef void (APIENTRYP RGLSYMGLTEXGENDPROC) ( GLenum coord, GLenum pname, GLdouble param );
typedef void (APIENTRYP RGLSYMGLTEXGENFPROC) ( GLenum coord, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLTEXGENIPROC) ( GLenum coord, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLTEXGENDVPROC) ( GLenum coord, GLenum pname, const GLdouble *params );
typedef void (APIENTRYP RGLSYMGLTEXGENFVPROC) ( GLenum coord, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLTEXGENIVPROC) ( GLenum coord, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXGENDVPROC) ( GLenum coord, GLenum pname, GLdouble *params );
typedef void (APIENTRYP RGLSYMGLGETTEXGENFVPROC) ( GLenum coord, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETTEXGENIVPROC) ( GLenum coord, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLTEXENVFPROC) ( GLenum target, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLTEXENVIPROC) ( GLenum target, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLTEXENVFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLTEXENVIVPROC) ( GLenum target, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXENVFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETTEXENVIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERFPROC) ( GLenum target, GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIPROC) ( GLenum target, GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params);
typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERFVPROC) ( GLenum target, GLint level, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERIVPROC) ( GLenum target, GLint level, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLTEXIMAGE1DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLTEXIMAGE2DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLGETTEXIMAGEPROC) ( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLGENTEXTURESPROC) ( GLsizei n, GLuint *textures );
typedef void (APIENTRYP RGLSYMGLDELETETEXTURESPROC) ( GLsizei n, const GLuint *textures);
typedef void (APIENTRYP RGLSYMGLBINDTEXTUREPROC) ( GLenum target, GLuint texture );
typedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESPROC) ( GLsizei n, const GLuint *textures, const GLclampf *priorities );
typedef GLboolean (APIENTRYP RGLSYMGLARETEXTURESRESIDENTPROC) ( GLsizei n, const GLuint *textures, GLboolean *residences );
typedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREPROC) ( GLuint texture );
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border );
typedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border );
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height );
typedef void (APIENTRYP RGLSYMGLMAP1DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points );
typedef void (APIENTRYP RGLSYMGLMAP1FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points );
typedef void (APIENTRYP RGLSYMGLMAP2DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points );
typedef void (APIENTRYP RGLSYMGLMAP2FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points );
typedef void (APIENTRYP RGLSYMGLGETMAPDVPROC) ( GLenum target, GLenum query, GLdouble *v );
typedef void (APIENTRYP RGLSYMGLGETMAPFVPROC) ( GLenum target, GLenum query, GLfloat *v );
typedef void (APIENTRYP RGLSYMGLGETMAPIVPROC) ( GLenum target, GLenum query, GLint *v );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1DPROC) ( GLdouble u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1FPROC) ( GLfloat u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1DVPROC) ( const GLdouble *u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD1FVPROC) ( const GLfloat *u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2DPROC) ( GLdouble u, GLdouble v );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2FPROC) ( GLfloat u, GLfloat v );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2DVPROC) ( const GLdouble *u );
typedef void (APIENTRYP RGLSYMGLEVALCOORD2FVPROC) ( const GLfloat *u );
typedef void (APIENTRYP RGLSYMGLMAPGRID1DPROC) ( GLint un, GLdouble u1, GLdouble u2 );
typedef void (APIENTRYP RGLSYMGLMAPGRID1FPROC) ( GLint un, GLfloat u1, GLfloat u2 );
typedef void (APIENTRYP RGLSYMGLMAPGRID2DPROC) ( GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2 );
typedef void (APIENTRYP RGLSYMGLMAPGRID2FPROC) ( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 );
typedef void (APIENTRYP RGLSYMGLEVALPOINT1PROC) ( GLint i );
typedef void (APIENTRYP RGLSYMGLEVALPOINT2PROC) ( GLint i, GLint j );
typedef void (APIENTRYP RGLSYMGLEVALMESH1PROC) ( GLenum mode, GLint i1, GLint i2 );
typedef void (APIENTRYP RGLSYMGLEVALMESH2PROC) ( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 );
typedef void (APIENTRYP RGLSYMGLFOGFPROC) ( GLenum pname, GLfloat param );
typedef void (APIENTRYP RGLSYMGLFOGIPROC) ( GLenum pname, GLint param );
typedef void (APIENTRYP RGLSYMGLFOGFVPROC) ( GLenum pname, const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLFOGIVPROC) ( GLenum pname, const GLint *params );
typedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERPROC) ( GLsizei size, GLenum type, GLfloat *buffer );
typedef void (APIENTRYP RGLSYMGLPASSTHROUGHPROC) ( GLfloat token );
typedef void (APIENTRYP RGLSYMGLSELECTBUFFERPROC) ( GLsizei size, GLuint *buffer );
typedef void (APIENTRYP RGLSYMGLINITNAMESPROC) ( void );
typedef void (APIENTRYP RGLSYMGLLOADNAMEPROC) ( GLuint name );
typedef void (APIENTRYP RGLSYMGLPUSHNAMEPROC) ( GLuint name );
typedef void (APIENTRYP RGLSYMGLPOPNAMEPROC) ( void );
typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) ( GLenum mode, GLuint start,GLuint end, GLsizei count, GLenum type, const GLvoid *indices );
typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height );
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table );
typedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) ( GLenum target, GLenum format, GLenum type, GLvoid *table );
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) ( GLenum mode );
typedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
typedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) ( GLenum target, GLsizei width, GLenum internalformat, GLboolean sink );
typedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) ( GLenum target );
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values );
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLMINMAXPROC) ( GLenum target, GLenum internalformat,GLboolean sink );
typedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) ( GLenum target );
typedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values );
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLenum format, GLenum type,const GLvoid *image );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *image );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) ( GLenum target, GLenum pname,GLfloat params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,const GLfloat *params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) ( GLenum target, GLenum pname,GLint params );
typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,const GLint *params );
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width );
typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width,GLsizei height);
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *image );
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,GLfloat *params );
typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,GLint *params );
typedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *row, const GLvoid *column );
typedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *row, GLvoid *column, GLvoid *span );
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) ( GLenum texture );
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) ( GLenum texture );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data );
typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) ( GLenum target, GLint lod, GLvoid *img );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) ( GLenum target, GLdouble s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) ( GLenum target, GLfloat s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) ( GLenum target, GLint s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) ( GLenum target, GLshort s );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) ( GLenum target, GLdouble s, GLdouble t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) ( GLenum target, GLfloat s, GLfloat t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) ( GLenum target, GLint s, GLint t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) ( GLenum target, GLshort s, GLshort t );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) ( GLenum target, GLint s, GLint t, GLint r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) ( GLenum target, const GLdouble *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) ( GLenum target, const GLfloat *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) ( GLenum target, GLint s, GLint t, GLint r, GLint q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) ( GLenum target, const GLint *v );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r, GLshort q );
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) ( GLenum target, const GLshort *v );
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );
typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );
typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );
typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) ( GLclampf value, GLboolean invert );
typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
typedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
typedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);

RGLSYMGLCLEARINDEXPROC glClearIndex;
RGLSYMGLCLEARCOLORPROC glClearColor;
RGLSYMGLCLEARPROC glClear;
RGLSYMGLINDEXMASKPROC glIndexMask;
RGLSYMGLCOLORMASKPROC glColorMask;
RGLSYMGLALPHAFUNCPROC glAlphaFunc;
RGLSYMGLBLENDFUNCPROC glBlendFunc;
RGLSYMGLLOGICOPPROC glLogicOp;
RGLSYMGLCULLFACEPROC glCullFace;
RGLSYMGLFRONTFACEPROC glFrontFace;
RGLSYMGLPOINTSIZEPROC glPointSize;
RGLSYMGLLINEWIDTHPROC glLineWidth;
RGLSYMGLLINESTIPPLEPROC glLineStipple;
RGLSYMGLPOLYGONMODEPROC glPolygonMode;
RGLSYMGLPOLYGONOFFSETPROC glPolygonOffset;
RGLSYMGLPOLYGONSTIPPLEPROC glPolygonStipple;
RGLSYMGLGETPOLYGONSTIPPLEPROC glGetPolygonStipple;
RGLSYMGLEDGEFLAGPROC glEdgeFlag;
RGLSYMGLEDGEFLAGVPROC glEdgeFlagv;
RGLSYMGLSCISSORPROC glScissor;
RGLSYMGLCLIPPLANEPROC glClipPlane;
RGLSYMGLGETCLIPPLANEPROC glGetClipPlane;
RGLSYMGLDRAWBUFFERPROC glDrawBuffer;
RGLSYMGLREADBUFFERPROC glReadBuffer;
RGLSYMGLENABLEPROC glEnable;
RGLSYMGLDISABLEPROC glDisable;
RGLSYMGLISENABLEDPROC glIsEnabled;
RGLSYMGLENABLECLIENTSTATEPROC glEnableClientState;
RGLSYMGLDISABLECLIENTSTATEPROC glDisableClientState;
RGLSYMGLGETBOOLEANVPROC glGetBooleanv;
RGLSYMGLGETDOUBLEVPROC glGetDoublev;
RGLSYMGLGETFLOATVPROC glGetFloatv;
RGLSYMGLGETINTEGERVPROC glGetIntegerv;
RGLSYMGLPUSHATTRIBPROC glPushAttrib;
RGLSYMGLPOPATTRIBPROC glPopAttrib;
RGLSYMGLPUSHCLIENTATTRIBPROC glPushClientAttrib;
RGLSYMGLPOPCLIENTATTRIBPROC glPopClientAttrib;
RGLSYMGLRENDERMODEPROC glRenderMode;
RGLSYMGLGETERRORPROC glGetError;
RGLSYMGLGETSTRINGPROC glGetString;
RGLSYMGLFINISHPROC glFinish;
RGLSYMGLFLUSHPROC glFlush;
RGLSYMGLHINTPROC glHint;
RGLSYMGLCLEARDEPTHPROC glClearDepth;
RGLSYMGLDEPTHFUNCPROC glDepthFunc;
RGLSYMGLDEPTHMASKPROC glDepthMask;
RGLSYMGLDEPTHRANGEPROC glDepthRange;
RGLSYMGLCLEARACCUMPROC glClearAccum;
RGLSYMGLACCUMPROC glAccum;
RGLSYMGLMATRIXMODEPROC glMatrixMode;
RGLSYMGLORTHOPROC glOrtho;
RGLSYMGLFRUSTUMPROC glFrustum;
RGLSYMGLVIEWPORTPROC glViewport;
RGLSYMGLPUSHMATRIXPROC glPushMatrix;
RGLSYMGLPOPMATRIXPROC glPopMatrix;
RGLSYMGLLOADIDENTITYPROC glLoadIdentity;
RGLSYMGLLOADMATRIXDPROC glLoadMatrixd;
RGLSYMGLLOADMATRIXFPROC glLoadMatrixf;
RGLSYMGLMULTMATRIXDPROC glMultMatrixd;
RGLSYMGLMULTMATRIXFPROC glMultMatrixf;
RGLSYMGLROTATEDPROC glRotated;
RGLSYMGLROTATEFPROC glRotatef;
RGLSYMGLSCALEDPROC glScaled;
RGLSYMGLSCALEFPROC glScalef;
RGLSYMGLTRANSLATEDPROC glTranslated;
RGLSYMGLTRANSLATEFPROC glTranslatef;
RGLSYMGLISLISTPROC glIsList;
RGLSYMGLDELETELISTSPROC glDeleteLists;
RGLSYMGLGENLISTSPROC glGenLists;
RGLSYMGLNEWLISTPROC glNewList;
RGLSYMGLENDLISTPROC glEndList;
RGLSYMGLCALLLISTPROC glCallList;
RGLSYMGLCALLLISTSPROC glCallLists;
RGLSYMGLLISTBASEPROC glListBase;
RGLSYMGLBEGINPROC glBegin;
RGLSYMGLENDPROC glEnd;
RGLSYMGLVERTEX2DPROC glVertex2d;
RGLSYMGLVERTEX2FPROC glVertex2f;
RGLSYMGLVERTEX2IPROC glVertex2i;
RGLSYMGLVERTEX2SPROC glVertex2s;
RGLSYMGLVERTEX3DPROC glVertex3d;
RGLSYMGLVERTEX3FPROC glVertex3f;
RGLSYMGLVERTEX3IPROC glVertex3i;
RGLSYMGLVERTEX3SPROC glVertex3s;
RGLSYMGLVERTEX4DPROC glVertex4d;
RGLSYMGLVERTEX4FPROC glVertex4f;
RGLSYMGLVERTEX4IPROC glVertex4i;
RGLSYMGLVERTEX4SPROC glVertex4s;
RGLSYMGLVERTEX2DVPROC glVertex2dv;
RGLSYMGLVERTEX2FVPROC glVertex2fv;
RGLSYMGLVERTEX2IVPROC glVertex2iv;
RGLSYMGLVERTEX2SVPROC glVertex2sv;
RGLSYMGLVERTEX3DVPROC glVertex3dv;
RGLSYMGLVERTEX3FVPROC glVertex3fv;
RGLSYMGLVERTEX3IVPROC glVertex3iv;
RGLSYMGLVERTEX3SVPROC glVertex3sv;
RGLSYMGLVERTEX4DVPROC glVertex4dv;
RGLSYMGLVERTEX4FVPROC glVertex4fv;
RGLSYMGLVERTEX4IVPROC glVertex4iv;
RGLSYMGLVERTEX4SVPROC glVertex4sv;
RGLSYMGLNORMAL3BPROC glNormal3b;
RGLSYMGLNORMAL3DPROC glNormal3d;
RGLSYMGLNORMAL3FPROC glNormal3f;
RGLSYMGLNORMAL3IPROC glNormal3i;
RGLSYMGLNORMAL3SPROC glNormal3s;
RGLSYMGLNORMAL3BVPROC glNormal3bv;
RGLSYMGLNORMAL3DVPROC glNormal3dv;
RGLSYMGLNORMAL3FVPROC glNormal3fv;
RGLSYMGLNORMAL3IVPROC glNormal3iv;
RGLSYMGLNORMAL3SVPROC glNormal3sv;
RGLSYMGLINDEXDPROC glIndexd;
RGLSYMGLINDEXFPROC glIndexf;
RGLSYMGLINDEXIPROC glIndexi;
RGLSYMGLINDEXSPROC glIndexs;
RGLSYMGLINDEXUBPROC glIndexub;
RGLSYMGLINDEXDVPROC glIndexdv;
RGLSYMGLINDEXFVPROC glIndexfv;
RGLSYMGLINDEXIVPROC glIndexiv;
RGLSYMGLINDEXSVPROC glIndexsv;
RGLSYMGLINDEXUBVPROC glIndexubv;
RGLSYMGLCOLOR3BPROC glColor3b;
RGLSYMGLCOLOR3DPROC glColor3d;
RGLSYMGLCOLOR3FPROC glColor3f;
RGLSYMGLCOLOR3IPROC glColor3i;
RGLSYMGLCOLOR3SPROC glColor3s;
RGLSYMGLCOLOR3UBPROC glColor3ub;
RGLSYMGLCOLOR3UIPROC glColor3ui;
RGLSYMGLCOLOR3USPROC glColor3us;
RGLSYMGLCOLOR4BPROC glColor4b;
RGLSYMGLCOLOR4DPROC glColor4d;
RGLSYMGLCOLOR4FPROC glColor4f;
RGLSYMGLCOLOR4IPROC glColor4i;
RGLSYMGLCOLOR4SPROC glColor4s;
RGLSYMGLCOLOR4UBPROC glColor4ub;
RGLSYMGLCOLOR4UIPROC glColor4ui;
RGLSYMGLCOLOR4USPROC glColor4us;
RGLSYMGLCOLOR3BVPROC glColor3bv;
RGLSYMGLCOLOR3DVPROC glColor3dv;
RGLSYMGLCOLOR3FVPROC glColor3fv;
RGLSYMGLCOLOR3IVPROC glColor3iv;
RGLSYMGLCOLOR3SVPROC glColor3sv;
RGLSYMGLCOLOR3UBVPROC glColor3ubv;
RGLSYMGLCOLOR3UIVPROC glColor3uiv;
RGLSYMGLCOLOR3USVPROC glColor3usv;
RGLSYMGLCOLOR4BVPROC glColor4bv;
RGLSYMGLCOLOR4DVPROC glColor4dv;
RGLSYMGLCOLOR4FVPROC glColor4fv;
RGLSYMGLCOLOR4IVPROC glColor4iv;
RGLSYMGLCOLOR4SVPROC glColor4sv;
RGLSYMGLCOLOR4UBVPROC glColor4ubv;
RGLSYMGLCOLOR4UIVPROC glColor4uiv;
RGLSYMGLCOLOR4USVPROC glColor4usv;
RGLSYMGLTEXCOORD1DPROC glTexCoord1d;
RGLSYMGLTEXCOORD1FPROC glTexCoord1f;
RGLSYMGLTEXCOORD1IPROC glTexCoord1i;
RGLSYMGLTEXCOORD1SPROC glTexCoord1s;
RGLSYMGLTEXCOORD2DPROC glTexCoord2d;
RGLSYMGLTEXCOORD2FPROC glTexCoord2f;
RGLSYMGLTEXCOORD2IPROC glTexCoord2i;
RGLSYMGLTEXCOORD2SPROC glTexCoord2s;
RGLSYMGLTEXCOORD3DPROC glTexCoord3d;
RGLSYMGLTEXCOORD3FPROC glTexCoord3f;
RGLSYMGLTEXCOORD3IPROC glTexCoord3i;
RGLSYMGLTEXCOORD3SPROC glTexCoord3s;
RGLSYMGLTEXCOORD4DPROC glTexCoord4d;
RGLSYMGLTEXCOORD4FPROC glTexCoord4f;
RGLSYMGLTEXCOORD4IPROC glTexCoord4i;
RGLSYMGLTEXCOORD4SPROC glTexCoord4s;
RGLSYMGLTEXCOORD1DVPROC glTexCoord1dv;
RGLSYMGLTEXCOORD1FVPROC glTexCoord1fv;
RGLSYMGLTEXCOORD1IVPROC glTexCoord1iv;
RGLSYMGLTEXCOORD1SVPROC glTexCoord1sv;
RGLSYMGLTEXCOORD2DVPROC glTexCoord2dv;
RGLSYMGLTEXCOORD2FVPROC glTexCoord2fv;
RGLSYMGLTEXCOORD2IVPROC glTexCoord2iv;
RGLSYMGLTEXCOORD2SVPROC glTexCoord2sv;
RGLSYMGLTEXCOORD3DVPROC glTexCoord3dv;
RGLSYMGLTEXCOORD3FVPROC glTexCoord3fv;
RGLSYMGLTEXCOORD3IVPROC glTexCoord3iv;
RGLSYMGLTEXCOORD3SVPROC glTexCoord3sv;
RGLSYMGLTEXCOORD4DVPROC glTexCoord4dv;
RGLSYMGLTEXCOORD4FVPROC glTexCoord4fv;
RGLSYMGLTEXCOORD4IVPROC glTexCoord4iv;
RGLSYMGLTEXCOORD4SVPROC glTexCoord4sv;
RGLSYMGLRASTERPOS2DPROC glRasterPos2d;
RGLSYMGLRASTERPOS2FPROC glRasterPos2f;
RGLSYMGLRASTERPOS2IPROC glRasterPos2i;
RGLSYMGLRASTERPOS2SPROC glRasterPos2s;
RGLSYMGLRASTERPOS3DPROC glRasterPos3d;
RGLSYMGLRASTERPOS3FPROC glRasterPos3f;
RGLSYMGLRASTERPOS3IPROC glRasterPos3i;
RGLSYMGLRASTERPOS3SPROC glRasterPos3s;
RGLSYMGLRASTERPOS4DPROC glRasterPos4d;
RGLSYMGLRASTERPOS4FPROC glRasterPos4f;
RGLSYMGLRASTERPOS4IPROC glRasterPos4i;
RGLSYMGLRASTERPOS4SPROC glRasterPos4s;
RGLSYMGLRASTERPOS2DVPROC glRasterPos2dv;
RGLSYMGLRASTERPOS2FVPROC glRasterPos2fv;
RGLSYMGLRASTERPOS2IVPROC glRasterPos2iv;
RGLSYMGLRASTERPOS2SVPROC glRasterPos2sv;
RGLSYMGLRASTERPOS3DVPROC glRasterPos3dv;
RGLSYMGLRASTERPOS3FVPROC glRasterPos3fv;
RGLSYMGLRASTERPOS3IVPROC glRasterPos3iv;
RGLSYMGLRASTERPOS3SVPROC glRasterPos3sv;
RGLSYMGLRASTERPOS4DVPROC glRasterPos4dv;
RGLSYMGLRASTERPOS4FVPROC glRasterPos4fv;
RGLSYMGLRASTERPOS4IVPROC glRasterPos4iv;
RGLSYMGLRASTERPOS4SVPROC glRasterPos4sv;
RGLSYMGLRECTDPROC glRectd;
RGLSYMGLRECTFPROC glRectf;
RGLSYMGLRECTIPROC glRecti;
RGLSYMGLRECTSPROC glRects;
RGLSYMGLRECTDVPROC glRectdv;
RGLSYMGLRECTFVPROC glRectfv;
RGLSYMGLRECTIVPROC glRectiv;
RGLSYMGLRECTSVPROC glRectsv;
RGLSYMGLVERTEXPOINTERPROC glVertexPointer;
RGLSYMGLNORMALPOINTERPROC glNormalPointer;
RGLSYMGLCOLORPOINTERPROC glColorPointer;
RGLSYMGLINDEXPOINTERPROC glIndexPointer;
RGLSYMGLTEXCOORDPOINTERPROC glTexCoordPointer;
RGLSYMGLEDGEFLAGPOINTERPROC glEdgeFlagPointer;
RGLSYMGLGETPOINTERVPROC glGetPointerv;
RGLSYMGLARRAYELEMENTPROC glArrayElement;
RGLSYMGLDRAWARRAYSPROC glDrawArrays;
RGLSYMGLDRAWELEMENTSPROC glDrawElements;
RGLSYMGLINTERLEAVEDARRAYSPROC glInterleavedArrays;
RGLSYMGLSHADEMODELPROC glShadeModel;
RGLSYMGLLIGHTFPROC glLightf;
RGLSYMGLLIGHTIPROC glLighti;
RGLSYMGLLIGHTFVPROC glLightfv;
RGLSYMGLLIGHTIVPROC glLightiv;
RGLSYMGLGETLIGHTFVPROC glGetLightfv;
RGLSYMGLGETLIGHTIVPROC glGetLightiv;
RGLSYMGLLIGHTMODELFPROC glLightModelf;
RGLSYMGLLIGHTMODELIPROC glLightModeli;
RGLSYMGLLIGHTMODELFVPROC glLightModelfv;
RGLSYMGLLIGHTMODELIVPROC glLightModeliv;
RGLSYMGLMATERIALFPROC glMaterialf;
RGLSYMGLMATERIALIPROC glMateriali;
RGLSYMGLMATERIALFVPROC glMaterialfv;
RGLSYMGLMATERIALIVPROC glMaterialiv;
RGLSYMGLGETMATERIALFVPROC glGetMaterialfv;
RGLSYMGLGETMATERIALIVPROC glGetMaterialiv;
RGLSYMGLCOLORMATERIALPROC glColorMaterial;
RGLSYMGLPIXELZOOMPROC glPixelZoom;
RGLSYMGLPIXELSTOREFPROC glPixelStoref;
RGLSYMGLPIXELSTOREIPROC glPixelStorei;
RGLSYMGLPIXELTRANSFERFPROC glPixelTransferf;
RGLSYMGLPIXELTRANSFERIPROC glPixelTransferi;
RGLSYMGLPIXELMAPFVPROC glPixelMapfv;
RGLSYMGLPIXELMAPUIVPROC glPixelMapuiv;
RGLSYMGLPIXELMAPUSVPROC glPixelMapusv;
RGLSYMGLGETPIXELMAPFVPROC glGetPixelMapfv;
RGLSYMGLGETPIXELMAPUIVPROC glGetPixelMapuiv;
RGLSYMGLGETPIXELMAPUSVPROC glGetPixelMapusv;
RGLSYMGLBITMAPPROC glBitmap;
RGLSYMGLREADPIXELSPROC glReadPixels;
RGLSYMGLDRAWPIXELSPROC glDrawPixels;
RGLSYMGLCOPYPIXELSPROC glCopyPixels;
RGLSYMGLSTENCILFUNCPROC glStencilFunc;
RGLSYMGLSTENCILMASKPROC glStencilMask;
RGLSYMGLSTENCILOPPROC glStencilOp;
RGLSYMGLCLEARSTENCILPROC glClearStencil;
RGLSYMGLTEXGENDPROC glTexGend;
RGLSYMGLTEXGENFPROC glTexGenf;
RGLSYMGLTEXGENIPROC glTexGeni;
RGLSYMGLTEXGENDVPROC glTexGendv;
RGLSYMGLTEXGENFVPROC glTexGenfv;
RGLSYMGLTEXGENIVPROC glTexGeniv;
RGLSYMGLGETTEXGENDVPROC glGetTexGendv;
RGLSYMGLGETTEXGENFVPROC glGetTexGenfv;
RGLSYMGLGETTEXGENIVPROC glGetTexGeniv;
RGLSYMGLTEXENVFPROC glTexEnvf;
RGLSYMGLTEXENVIPROC glTexEnvi;
RGLSYMGLTEXENVFVPROC glTexEnvfv;
RGLSYMGLTEXENVIVPROC glTexEnviv;
RGLSYMGLGETTEXENVFVPROC glGetTexEnvfv;
RGLSYMGLGETTEXENVIVPROC glGetTexEnviv;
RGLSYMGLTEXPARAMETERFPROC glTexParameterf;
RGLSYMGLTEXPARAMETERIPROC glTexParameteri;
RGLSYMGLTEXPARAMETERFVPROC glTexParameterfv;
RGLSYMGLTEXPARAMETERIVPROC glTexParameteriv;
RGLSYMGLGETTEXPARAMETERFVPROC glGetTexParameterfv;
RGLSYMGLGETTEXPARAMETERIVPROC glGetTexParameteriv;
RGLSYMGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv;
RGLSYMGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv;
RGLSYMGLTEXIMAGE1DPROC glTexImage1D;
RGLSYMGLTEXIMAGE2DPROC glTexImage2D;
RGLSYMGLGETTEXIMAGEPROC glGetTexImage;
RGLSYMGLGENTEXTURESPROC glGenTextures;
RGLSYMGLDELETETEXTURESPROC glDeleteTextures;
RGLSYMGLBINDTEXTUREPROC glBindTexture;
RGLSYMGLPRIORITIZETEXTURESPROC glPrioritizeTextures;
RGLSYMGLARETEXTURESRESIDENTPROC glAreTexturesResident;
RGLSYMGLISTEXTUREPROC glIsTexture;
RGLSYMGLTEXSUBIMAGE1DPROC glTexSubImage1D;
RGLSYMGLTEXSUBIMAGE2DPROC glTexSubImage2D;
RGLSYMGLCOPYTEXIMAGE1DPROC glCopyTexImage1D;
RGLSYMGLCOPYTEXIMAGE2DPROC glCopyTexImage2D;
RGLSYMGLCOPYTEXSUBIMAGE1DPROC glCopyTexSubImage1D;
RGLSYMGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D;
RGLSYMGLMAP1DPROC glMap1d;
RGLSYMGLMAP1FPROC glMap1f;
RGLSYMGLMAP2DPROC glMap2d;
RGLSYMGLMAP2FPROC glMap2f;
RGLSYMGLGETMAPDVPROC glGetMapdv;
RGLSYMGLGETMAPFVPROC glGetMapfv;
RGLSYMGLGETMAPIVPROC glGetMapiv;
RGLSYMGLEVALCOORD1DPROC glEvalCoord1d;
RGLSYMGLEVALCOORD1FPROC glEvalCoord1f;
RGLSYMGLEVALCOORD1DVPROC glEvalCoord1dv;
RGLSYMGLEVALCOORD1FVPROC glEvalCoord1fv;
RGLSYMGLEVALCOORD2DPROC glEvalCoord2d;
RGLSYMGLEVALCOORD2FPROC glEvalCoord2f;
RGLSYMGLEVALCOORD2DVPROC glEvalCoord2dv;
RGLSYMGLEVALCOORD2FVPROC glEvalCoord2fv;
RGLSYMGLMAPGRID1DPROC glMapGrid1d;
RGLSYMGLMAPGRID1FPROC glMapGrid1f;
RGLSYMGLMAPGRID2DPROC glMapGrid2d;
RGLSYMGLMAPGRID2FPROC glMapGrid2f;
RGLSYMGLEVALPOINT1PROC glEvalPoint1;
RGLSYMGLEVALPOINT2PROC glEvalPoint2;
RGLSYMGLEVALMESH1PROC glEvalMesh1;
RGLSYMGLEVALMESH2PROC glEvalMesh2;
RGLSYMGLFOGFPROC glFogf;
RGLSYMGLFOGIPROC glFogi;
RGLSYMGLFOGFVPROC glFogfv;
RGLSYMGLFOGIVPROC glFogiv;
RGLSYMGLFEEDBACKBUFFERPROC glFeedbackBuffer;
RGLSYMGLPASSTHROUGHPROC glPassThrough;
RGLSYMGLSELECTBUFFERPROC glSelectBuffer;
RGLSYMGLINITNAMESPROC glInitNames;
RGLSYMGLLOADNAMEPROC glLoadName;
RGLSYMGLPUSHNAMEPROC glPushName;
RGLSYMGLPOPNAMEPROC glPopName;
RGLSYMGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
RGLSYMGLTEXIMAGE3DPROC glTexImage3D;
RGLSYMGLTEXSUBIMAGE3DPROC glTexSubImage3D;
RGLSYMGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D;
RGLSYMGLCOLORTABLEPROC glColorTable;
RGLSYMGLCOLORSUBTABLEPROC glColorSubTable;
RGLSYMGLCOLORTABLEPARAMETERIVPROC glColorTableParameteriv;
RGLSYMGLCOLORTABLEPARAMETERFVPROC glColorTableParameterfv;
RGLSYMGLCOPYCOLORSUBTABLEPROC glCopyColorSubTable;
RGLSYMGLCOPYCOLORTABLEPROC glCopyColorTable;
RGLSYMGLGETCOLORTABLEPROC glGetColorTable;
RGLSYMGLGETCOLORTABLEPARAMETERFVPROC glGetColorTableParameterfv;
RGLSYMGLGETCOLORTABLEPARAMETERIVPROC glGetColorTableParameteriv;
RGLSYMGLBLENDEQUATIONPROC glBlendEquation;
RGLSYMGLBLENDCOLORPROC glBlendColor;
RGLSYMGLHISTOGRAMPROC glHistogram;
RGLSYMGLRESETHISTOGRAMPROC glResetHistogram;
RGLSYMGLGETHISTOGRAMPROC glGetHistogram;
RGLSYMGLGETHISTOGRAMPARAMETERFVPROC glGetHistogramParameterfv;
RGLSYMGLGETHISTOGRAMPARAMETERIVPROC glGetHistogramParameteriv;
RGLSYMGLMINMAXPROC glMinmax;
RGLSYMGLRESETMINMAXPROC glResetMinmax;
RGLSYMGLGETMINMAXPROC glGetMinmax;
RGLSYMGLGETMINMAXPARAMETERFVPROC glGetMinmaxParameterfv;
RGLSYMGLGETMINMAXPARAMETERIVPROC glGetMinmaxParameteriv;
RGLSYMGLCONVOLUTIONFILTER1DPROC glConvolutionFilter1D;
RGLSYMGLCONVOLUTIONFILTER2DPROC glConvolutionFilter2D;
RGLSYMGLCONVOLUTIONPARAMETERFPROC glConvolutionParameterf;
RGLSYMGLCONVOLUTIONPARAMETERFVPROC glConvolutionParameterfv;
RGLSYMGLCONVOLUTIONPARAMETERIPROC glConvolutionParameteri;
RGLSYMGLCONVOLUTIONPARAMETERIVPROC glConvolutionParameteriv;
RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC glCopyConvolutionFilter1D;
RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC glCopyConvolutionFilter2D;
RGLSYMGLGETCONVOLUTIONFILTERPROC glGetConvolutionFilter;
RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC glGetConvolutionParameterfv;
RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC glGetConvolutionParameteriv;
RGLSYMGLSEPARABLEFILTER2DPROC glSeparableFilter2D;
RGLSYMGLGETSEPARABLEFILTERPROC glGetSeparableFilter;
RGLSYMGLACTIVETEXTUREPROC glActiveTexture;
RGLSYMGLCLIENTACTIVETEXTUREPROC glClientActiveTexture;
RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;
RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D;
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D;
RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
RGLSYMGLMULTITEXCOORD1DPROC glMultiTexCoord1d;
RGLSYMGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv;
RGLSYMGLMULTITEXCOORD1FPROC glMultiTexCoord1f;
RGLSYMGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv;
RGLSYMGLMULTITEXCOORD1IPROC glMultiTexCoord1i;
RGLSYMGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv;
RGLSYMGLMULTITEXCOORD1SPROC glMultiTexCoord1s;
RGLSYMGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv;
RGLSYMGLMULTITEXCOORD2DPROC glMultiTexCoord2d;
RGLSYMGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv;
RGLSYMGLMULTITEXCOORD2FPROC glMultiTexCoord2f;
RGLSYMGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv;
RGLSYMGLMULTITEXCOORD2IPROC glMultiTexCoord2i;
RGLSYMGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv;
RGLSYMGLMULTITEXCOORD2SPROC glMultiTexCoord2s;
RGLSYMGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv;
RGLSYMGLMULTITEXCOORD3DPROC glMultiTexCoord3d;
RGLSYMGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv;
RGLSYMGLMULTITEXCOORD3FPROC glMultiTexCoord3f;
RGLSYMGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv;
RGLSYMGLMULTITEXCOORD3IPROC glMultiTexCoord3i;
RGLSYMGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv;
RGLSYMGLMULTITEXCOORD3SPROC glMultiTexCoord3s;
RGLSYMGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv;
RGLSYMGLMULTITEXCOORD4DPROC glMultiTexCoord4d;
RGLSYMGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv;
RGLSYMGLMULTITEXCOORD4FPROC glMultiTexCoord4f;
RGLSYMGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv;
RGLSYMGLMULTITEXCOORD4IPROC glMultiTexCoord4i;
RGLSYMGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv;
RGLSYMGLMULTITEXCOORD4SPROC glMultiTexCoord4s;
RGLSYMGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv;
RGLSYMGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd;
RGLSYMGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf;
RGLSYMGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd;
RGLSYMGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf;
RGLSYMGLSAMPLECOVERAGEPROC glSampleCoverage;
RGLSYMGLACTIVETEXTUREARBPROC glActiveTextureARB;
RGLSYMGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
RGLSYMGLMULTITEXCOORD1DARBPROC glMultiTexCoord1dARB;
RGLSYMGLMULTITEXCOORD1DVARBPROC glMultiTexCoord1dvARB;
RGLSYMGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB;
RGLSYMGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fvARB;
RGLSYMGLMULTITEXCOORD1IARBPROC glMultiTexCoord1iARB;
RGLSYMGLMULTITEXCOORD1IVARBPROC glMultiTexCoord1ivARB;
RGLSYMGLMULTITEXCOORD1SARBPROC glMultiTexCoord1sARB;
RGLSYMGLMULTITEXCOORD1SVARBPROC glMultiTexCoord1svARB;
RGLSYMGLMULTITEXCOORD2DARBPROC glMultiTexCoord2dARB;
RGLSYMGLMULTITEXCOORD2DVARBPROC glMultiTexCoord2dvARB;
RGLSYMGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;
RGLSYMGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB;
RGLSYMGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB;
RGLSYMGLMULTITEXCOORD2IVARBPROC glMultiTexCoord2ivARB;
RGLSYMGLMULTITEXCOORD2SARBPROC glMultiTexCoord2sARB;
RGLSYMGLMULTITEXCOORD2SVARBPROC glMultiTexCoord2svARB;
RGLSYMGLMULTITEXCOORD3DARBPROC glMultiTexCoord3dARB;
RGLSYMGLMULTITEXCOORD3DVARBPROC glMultiTexCoord3dvARB;
RGLSYMGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB;
RGLSYMGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB;
RGLSYMGLMULTITEXCOORD3IARBPROC glMultiTexCoord3iARB;
RGLSYMGLMULTITEXCOORD3IVARBPROC glMultiTexCoord3ivARB;
RGLSYMGLMULTITEXCOORD3SARBPROC glMultiTexCoord3sARB;
RGLSYMGLMULTITEXCOORD3SVARBPROC glMultiTexCoord3svARB;
RGLSYMGLMULTITEXCOORD4DARBPROC glMultiTexCoord4dARB;
RGLSYMGLMULTITEXCOORD4DVARBPROC glMultiTexCoord4dvARB;
RGLSYMGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB;
RGLSYMGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB;
RGLSYMGLMULTITEXCOORD4IARBPROC glMultiTexCoord4iARB;
RGLSYMGLMULTITEXCOORD4IVARBPROC glMultiTexCoord4ivARB;
RGLSYMGLMULTITEXCOORD4SARBPROC glMultiTexCoord4sARB;
RGLSYMGLMULTITEXCOORD4SVARBPROC glMultiTexCoord4svARB;
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
RGLSYMGLBINDTEXTURESPROC glBindTextures;

#ifdef __cplusplus
}
#endif
#endif /* __NX_GLSYM_H__ */</pre>
<h2>./include/libretro-common/include/libchdr/bitstream.h</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    bitstream.h

    Helper classes for reading/writing at the bit level.

***************************************************************************/

#pragma once

#ifndef __BITSTREAM_H__
#define __BITSTREAM_H__

#include &lt;stdint.h&gt;

/***************************************************************************
 *  TYPE DEFINITIONS
 ***************************************************************************
 */

/* helper class for reading from a bit buffer */
struct bitstream
{
	uint32_t          buffer;       /* current bit accumulator */
	int               bits;         /* number of bits in the accumulator */
	const uint8_t *   read;         /* read pointer */
	uint32_t          doffset;      /* byte offset within the data */
	uint32_t          dlength;      /* length of the data */
};

struct bitstream* 	create_bitstream(const void *src, uint32_t srclength);
int 				bitstream_overflow(struct bitstream* bitstream);
uint32_t 			bitstream_read_offset(struct bitstream* bitstream);

uint32_t 			bitstream_read(struct bitstream* bitstream, int numbits);
uint32_t 			bitstream_peek(struct bitstream* bitstream, int numbits);
void 				bitstream_remove(struct bitstream* bitstream, int numbits);
uint32_t 			bitstream_flush(struct bitstream* bitstream);

#endif</pre>
<h2>./include/libretro-common/include/libchdr/cdrom.h</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
***************************************************************************

    cdrom.h

    Generic MAME cd-rom implementation

***************************************************************************/

#pragma once

#ifndef __CDROM_H__
#define __CDROM_H__

#include &lt;stdint.h&gt;
#include &lt;libchdr/chdconfig.h&gt;

/***************************************************************************
    CONSTANTS
***************************************************************************/

/* tracks are padded to a multiple of this many frames */
#define CD_TRACK_PADDING   	(4)
#define CD_MAX_TRACKS           (99)    /* AFAIK the theoretical limit */
#define CD_MAX_SECTOR_DATA      (2352)
#define CD_MAX_SUBCODE_DATA     (96)

#define CD_FRAME_SIZE           (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)
#define CD_FRAMES_PER_HUNK      (8)

#define CD_METADATA_WORDS       (1+(CD_MAX_TRACKS * 6))

enum
{
	CD_TRACK_MODE1 = 0,         /* mode 1 2048 bytes/sector */
	CD_TRACK_MODE1_RAW,         /* mode 1 2352 bytes/sector */
	CD_TRACK_MODE2,             /* mode 2 2336 bytes/sector */
	CD_TRACK_MODE2_FORM1,       /* mode 2 2048 bytes/sector */
	CD_TRACK_MODE2_FORM2,       /* mode 2 2324 bytes/sector */
	CD_TRACK_MODE2_FORM_MIX,    /* mode 2 2336 bytes/sector */
	CD_TRACK_MODE2_RAW,         /* mode 2 2352 bytes / sector */
	CD_TRACK_AUDIO,         /* redbook audio track 2352 bytes/sector (588 samples) */

	CD_TRACK_RAW_DONTCARE       /* special flag for cdrom_read_data: just return me whatever is there */
};

enum
{
	CD_SUB_NORMAL = 0,          /* "cooked" 96 bytes per sector */
	CD_SUB_RAW,                 /* raw uninterleaved 96 bytes per sector */
	CD_SUB_NONE                 /* no subcode data stored */
};

#define CD_FLAG_GDROM   0x00000001  /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */
#define CD_FLAG_GDROMLE 0x00000002  /* legacy GD-ROM, with little-endian CDDA data */

/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

#ifdef WANT_RAW_DATA_SECTOR
/* ECC utilities */
int ecc_verify(const uint8_t *sector);
void ecc_generate(uint8_t *sector);
void ecc_clear(uint8_t *sector);
#endif



/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

static INLINE uint32_t msf_to_lba(uint32_t msf)
{
	return ( ((msf&amp;0x00ff0000)&gt;&gt;16) * 60 * 75) + (((msf&amp;0x0000ff00)&gt;&gt;8) * 75) + ((msf&amp;0x000000ff)&gt;&gt;0);
}

static INLINE uint32_t lba_to_msf(uint32_t lba)
{
	uint8_t m, s, f;

	m = lba / (60 * 75);
	lba -= m * (60 * 75);
	s = lba / 75;
	f = lba % 75;

	return ((m / 10) &lt;&lt; 20) | ((m % 10) &lt;&lt; 16) |
			((s / 10) &lt;&lt; 12) | ((s % 10) &lt;&lt;  8) |
			((f / 10) &lt;&lt;  4) | ((f % 10) &lt;&lt;  0);
}

/**
 * segacd needs it like this.. investigate
 * Angelo also says PCE tracks often start playing at the
 * wrong address.. related?
 **/
static INLINE uint32_t lba_to_msf_alt(int lba)
{
	uint32_t ret = 0;

	ret |= ((lba / (60 * 75))&amp;0xff)&lt;&lt;16;
	ret |= (((lba / 75) % 60)&amp;0xff)&lt;&lt;8;
	ret |= ((lba % 75)&amp;0xff)&lt;&lt;0;

	return ret;
}

#endif  /* __CDROM_H__ */</pre>
<h2>./include/libretro-common/include/libchdr/chd.h</h2>
<pre>/***************************************************************************

    chd.h

    MAME Compressed Hunks of Data file format

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

***************************************************************************/

#pragma once

#ifndef __CHD_H__
#define __CHD_H__

#ifdef __cplusplus
extern "C" {
#endif

#include &lt;libchdr/coretypes.h&gt;
#include &lt;libchdr/chdconfig.h&gt;

/***************************************************************************

    Compressed Hunks of Data header format. All numbers are stored in
    Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2)
    bytes long.

    V1 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t hunksize;      // 512-byte sectors per hunk
    [ 28] uint32_t totalhunks;    // total # of hunks represented
    [ 32] uint32_t cylinders;     // number of cylinders on hard disk
    [ 36] uint32_t heads;         // number of heads on hard disk
    [ 40] uint32_t sectors;       // number of sectors on hard disk
    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data
    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file
    [ 76] (V1 header length)

    V2 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t hunksize;      // seclen-byte sectors per hunk
    [ 28] uint32_t totalhunks;    // total # of hunks represented
    [ 32] uint32_t cylinders;     // number of cylinders on hard disk
    [ 36] uint32_t heads;         // number of heads on hard disk
    [ 40] uint32_t sectors;       // number of sectors on hard disk
    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data
    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file
    [ 76] uint32_t seclen;        // number of bytes per sector
    [ 80] (V2 header length)

    V3 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t totalhunks;    // total # of hunks represented
    [ 28] uint64_t logicalbytes;  // logical size of the data (in bytes)
    [ 36] uint64_t metaoffset;    // offset to the first blob of metadata
    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data
    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file
    [ 76] uint32_t hunkbytes;     // number of bytes per hunk
    [ 80] uint8_t  sha1[20];      // SHA1 checksum of raw data
    [100] uint8_t  parentsha1[20];// SHA1 checksum of parent file
    [120] (V3 header length)

    V4 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t version;       // drive format version
    [ 16] uint32_t flags;         // flags (see below)
    [ 20] uint32_t compression;   // compression type
    [ 24] uint32_t totalhunks;    // total # of hunks represented
    [ 28] uint64_t logicalbytes;  // logical size of the data (in bytes)
    [ 36] uint64_t metaoffset;    // offset to the first blob of metadata
    [ 44] uint32_t hunkbytes;     // number of bytes per hunk
    [ 48] uint8_t  sha1[20];      // combined raw+meta SHA1
    [ 68] uint8_t  parentsha1[20];// combined raw+meta SHA1 of parent
    [ 88] uint8_t  rawsha1[20];   // raw data SHA1
    [108] (V4 header length)

    Flags:
        0x00000001 - set if this drive has a parent
        0x00000002 - set if this drive allows writes

   =========================================================================

    V5 header:

    [  0] char   tag[8];        // 'MComprHD'
    [  8] uint32_t_t length;        // length of header (including tag and length fields)
    [ 12] uint32_t_t version;       // drive format version
    [ 16] uint32_t_t compressors[4];// which custom compressors are used?
    [ 32] uint64_t_t logicalbytes;  // logical size of the data (in bytes)
    [ 40] uint64_t_t mapoffset;     // offset to the map
    [ 48] uint64_t_t metaoffset;    // offset to the first blob of metadata
    [ 56] uint32_t_t hunkbytes;     // number of bytes per hunk (512k maximum)
    [ 60] uint32_t_t unitbytes;     // number of bytes per unit within each hunk
    [ 64] uint8_t_t  rawsha1[20];   // raw data SHA1
    [ 84] uint8_t_t  sha1[20];      // combined raw+meta SHA1
    [104] uint8_t_t  parentsha1[20];// combined raw+meta SHA1 of parent
    [124] (V5 header length)

    If parentsha1 != 0, we have a parent (no need for flags)
    If compressors[0] == 0, we are uncompressed (including maps)

    V5 uncompressed map format:

    [  0] uint32_t_t offset;        // starting offset / hunk size

    V5 compressed map format header:

    [  0] uint32_t_t length;        // length of compressed map
    [  4] UINT48 datastart;     // offset of first block
    [ 10] uint16_t crc;           // crc-16 of the map
    [ 12] uint8_t_t lengthbits;     // bits used to encode complength
    [ 13] uint8_t_t hunkbits;       // bits used to encode self-refs
    [ 14] uint8_t_t parentunitbits; // bits used to encode parent unit refs
    [ 15] uint8_t_t reserved;       // future use
    [ 16] (compressed header length)

    Each compressed map entry, once expanded, looks like:

    [  0] uint8_t_t compression;    // compression type
    [  1] UINT24 complength;    // compressed length
    [  4] UINT48 offset;        // offset
    [ 10] uint16_t crc;           // crc-16 of the data

***************************************************************************/


/***************************************************************************
    CONSTANTS
***************************************************************************/

/* header information */
#define CHD_HEADER_VERSION			5
#define CHD_V1_HEADER_SIZE			76
#define CHD_V2_HEADER_SIZE			80
#define CHD_V3_HEADER_SIZE			120
#define CHD_V4_HEADER_SIZE			108
#define CHD_V5_HEADER_SIZE          124

#define CHD_MAX_HEADER_SIZE			CHD_V5_HEADER_SIZE

/* checksumming information */
#define CHD_MD5_BYTES				16
#define CHD_SHA1_BYTES				20

/* CHD global flags */
#define CHDFLAGS_HAS_PARENT			0x00000001
#define CHDFLAGS_IS_WRITEABLE		0x00000002
#define CHDFLAGS_UNDEFINED			0xfffffffc

#define CHD_MAKE_TAG(a,b,c,d)       (((a) &lt;&lt; 24) | ((b) &lt;&lt; 16) | ((c) &lt;&lt; 8) | (d))

/* compression types */
#define CHDCOMPRESSION_NONE			0
#define CHDCOMPRESSION_ZLIB			1
#define CHDCOMPRESSION_ZLIB_PLUS	2
#define CHDCOMPRESSION_AV			3

#define CHD_CODEC_NONE 0
#define CHD_CODEC_ZLIB				CHD_MAKE_TAG('z','l','i','b')
#define CHD_CODEC_LZMA				CHD_MAKE_TAG('l','z','m','a')
#define CHD_CODEC_HUFFMAN 			CHD_MAKE_TAG('h','u','f','f')
#define CHD_CODEC_FLAC				CHD_MAKE_TAG('f','l','a','c')
#define CHD_CODEC_ZSTD				CHD_MAKE_TAG('z', 's', 't', 'd')
/* general codecs with CD frontend */
#define CHD_CODEC_CD_ZLIB			CHD_MAKE_TAG('c','d','z','l')
#define CHD_CODEC_CD_LZMA			CHD_MAKE_TAG('c','d','l','z')
#define CHD_CODEC_CD_FLAC			CHD_MAKE_TAG('c','d','f','l')
#define CHD_CODEC_CD_ZSTD			CHD_MAKE_TAG('c','d','z','s')

/* A/V codec configuration parameters */
#define AV_CODEC_COMPRESS_CONFIG	1
#define AV_CODEC_DECOMPRESS_CONFIG	2

/* metadata parameters */
#define CHDMETATAG_WILDCARD			0
#define CHD_METAINDEX_APPEND		((uint32_t)-1)

/* metadata flags */
#define CHD_MDFLAGS_CHECKSUM		0x01		/* indicates data is checksummed */

/* standard hard disk metadata */
#define HARD_DISK_METADATA_TAG		CHD_MAKE_TAG('G','D','D','D')
#define HARD_DISK_METADATA_FORMAT	"CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"

/* hard disk identify information */
#define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T')

/* hard disk key information */
#define HARD_DISK_KEY_METADATA_TAG	CHD_MAKE_TAG('K','E','Y',' ')

/* pcmcia CIS information */
#define PCMCIA_CIS_METADATA_TAG		CHD_MAKE_TAG('C','I','S',' ')

/* standard CD-ROM metadata */
#define CDROM_OLD_METADATA_TAG		CHD_MAKE_TAG('C','H','C','D')
#define CDROM_TRACK_METADATA_TAG	CHD_MAKE_TAG('C','H','T','R')
#define CDROM_TRACK_METADATA_FORMAT	"TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
#define CDROM_TRACK_METADATA2_TAG	CHD_MAKE_TAG('C','H','T','2')
#define CDROM_TRACK_METADATA2_FORMAT	"TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
#define GDROM_OLD_METADATA_TAG		CHD_MAKE_TAG('C','H','G','T')
#define GDROM_TRACK_METADATA_TAG	CHD_MAKE_TAG('C', 'H', 'G', 'D')
#define GDROM_TRACK_METADATA_FORMAT	"TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"

/* standard A/V metadata */
#define AV_METADATA_TAG				CHD_MAKE_TAG('A','V','A','V')
#define AV_METADATA_FORMAT			"FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"

/* A/V laserdisc frame metadata */
#define AV_LD_METADATA_TAG			CHD_MAKE_TAG('A','V','L','D')

/* DVD metadata */
#define DVD_METADATA_TAG			CHD_MAKE_TAG('D','V','D',' ')

/* CHD open values */
#define CHD_OPEN_READ				1
#define CHD_OPEN_READWRITE			2

/* error types */
enum _chd_error
{
	CHDERR_NONE,
	CHDERR_NO_INTERFACE,
	CHDERR_OUT_OF_MEMORY,
	CHDERR_INVALID_FILE,
	CHDERR_INVALID_PARAMETER,
	CHDERR_INVALID_DATA,
	CHDERR_FILE_NOT_FOUND,
	CHDERR_REQUIRES_PARENT,
	CHDERR_FILE_NOT_WRITEABLE,
	CHDERR_READ_ERROR,
	CHDERR_WRITE_ERROR,
	CHDERR_CODEC_ERROR,
	CHDERR_INVALID_PARENT,
	CHDERR_HUNK_OUT_OF_RANGE,
	CHDERR_DECOMPRESSION_ERROR,
	CHDERR_COMPRESSION_ERROR,
	CHDERR_CANT_CREATE_FILE,
	CHDERR_CANT_VERIFY,
	CHDERR_NOT_SUPPORTED,
	CHDERR_METADATA_NOT_FOUND,
	CHDERR_INVALID_METADATA_SIZE,
	CHDERR_UNSUPPORTED_VERSION,
	CHDERR_VERIFY_INCOMPLETE,
	CHDERR_INVALID_METADATA,
	CHDERR_INVALID_STATE,
	CHDERR_OPERATION_PENDING,
	CHDERR_NO_ASYNC_OPERATION,
	CHDERR_UNSUPPORTED_FORMAT
};
typedef enum _chd_error chd_error;



/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

/* opaque types */
typedef struct _chd_file chd_file;


/* extract header structure (NOT the on-disk header structure) */
typedef struct _chd_header chd_header;
struct _chd_header
{
	uint32_t		length;						/* length of header data */
	uint32_t		version;					/* drive format version */
	uint32_t		flags;						/* flags field */
	uint32_t		compression[4];				/* compression type */
	uint32_t		hunkbytes;					/* number of bytes per hunk */
	uint32_t		totalhunks;					/* total # of hunks represented */
	uint64_t		logicalbytes;				/* logical size of the data */
	uint64_t		metaoffset;					/* offset in file of first metadata */
	uint64_t		mapoffset;					/* TOOD V5 */
	uint8_t		md5[CHD_MD5_BYTES];			/* overall MD5 checksum */
	uint8_t		parentmd5[CHD_MD5_BYTES];	/* overall MD5 checksum of parent */
	uint8_t		sha1[CHD_SHA1_BYTES];		/* overall SHA1 checksum */
	uint8_t		rawsha1[CHD_SHA1_BYTES];	/* SHA1 checksum of raw data */
	uint8_t		parentsha1[CHD_SHA1_BYTES];	/* overall SHA1 checksum of parent */
	uint32_t		unitbytes;					/* TODO V5 */
	uint64_t		unitcount;					/* TODO V5 */
    uint32_t      hunkcount;                  /* TODO V5 */

    /* map information */
    uint32_t      mapentrybytes;              /* length of each entry in a map (V5) */
    uint8_t*      rawmap;                     /* raw map data */

	uint32_t		obsolete_cylinders;			/* obsolete field -- do not use! */
	uint32_t		obsolete_sectors;			/* obsolete field -- do not use! */
	uint32_t		obsolete_heads;				/* obsolete field -- do not use! */
	uint32_t		obsolete_hunksize;			/* obsolete field -- do not use! */
};


/* structure for returning information about a verification pass */
typedef struct _chd_verify_result chd_verify_result;
struct _chd_verify_result
{
	uint8_t		md5[CHD_MD5_BYTES];			/* overall MD5 checksum */
	uint8_t		sha1[CHD_SHA1_BYTES];		/* overall SHA1 checksum */
	uint8_t		rawsha1[CHD_SHA1_BYTES];	/* SHA1 checksum of raw data */
	uint8_t		metasha1[CHD_SHA1_BYTES];	/* SHA1 checksum of metadata */
};



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

#ifdef _MSC_VER
#ifdef CHD_DLL
#ifdef CHD_DLL_EXPORTS
#define CHD_EXPORT __declspec(dllexport)
#else
#define CHD_EXPORT __declspec(dllimport)
#endif
#else
#define CHD_EXPORT
#endif
#else
#define CHD_EXPORT __attribute__ ((visibility("default")))
#endif

/* ----- CHD file management ----- */

/* create a new CHD file fitting the given description */
/* chd_error chd_create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */

/* same as chd_create(), but accepts an already-opened core_file object */
/* chd_error chd_create_file(core_file *file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */

/* open an existing CHD file */
CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd);
CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd);
CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);

/* precache underlying file */
CHD_EXPORT chd_error chd_precache(chd_file *chd);

/* close a CHD file */
CHD_EXPORT void chd_close(chd_file *chd);

/* return the associated core_file */
CHD_EXPORT core_file *chd_core_file(chd_file *chd);

/* return an error string for the given CHD error */
CHD_EXPORT const char *chd_error_string(chd_error err);



/* ----- CHD header management ----- */

/* return a pointer to the extracted CHD header data */
CHD_EXPORT const chd_header *chd_get_header(chd_file *chd);

/* read CHD header data from file into the pointed struct */
CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header);



/* ----- core data read/write ----- */

/* read one hunk from the CHD file */
CHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer);



/* ----- metadata management ----- */

/* get indexed metadata of a particular sort */
CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, uint32_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags);




/* ----- codec interfaces ----- */

/* set internal codec parameters */
CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config);

/* return a string description of a codec */
CHD_EXPORT const char *chd_get_codec_name(uint32_t codec);

#ifdef __cplusplus
}
#endif

#endif /* __CHD_H__ */</pre>
<h2>./include/libretro-common/include/libchdr/coretypes.h</h2>
<pre>#ifndef __CORETYPES_H__
#define __CORETYPES_H__

#include &lt;stdint.h&gt;
#include &lt;stdio.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#ifdef USE_LIBRETRO_VFS
#include &lt;streams/file_stream_transforms.h&gt;
#endif

typedef uint64_t UINT64;
#ifndef OSD_CPU_H
typedef uint32_t UINT32;
typedef uint16_t UINT16;
typedef uint8_t UINT8;
#endif

typedef int64_t INT64;
#ifndef OSD_CPU_H
typedef int32_t INT32;
typedef int16_t INT16;
typedef int8_t INT8;
#endif

#ifndef ARRAY_LENGTH
#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))
#endif

typedef struct chd_core_file {
	/*
	 * arbitrary pointer to data the implementation uses to implement the below functions
	 */
	void *argp;

	/*
	 * return the size of a given file as a 64-bit unsigned integer.
	 * the position of the file pointer after calling this function is
	 * undefined because many implementations will seek to the end of the
	 * file and call ftell.
	 *
	 * on error, (uint64_t)-1 is returned.
	 */
	uint64_t(*fsize)(struct chd_core_file*);

	/*
	 * should match the behavior of fread, except the FILE* argument at the end
	 * will be replaced with a struct chd_core_file*.
	 */
	size_t(*fread)(void*,size_t,size_t,struct chd_core_file*);

	/* closes the given file. */
	int (*fclose)(struct chd_core_file*);

	/* fseek clone. */
	int (*fseek)(struct chd_core_file*, int64_t, int);
} core_file;

static INLINE int core_fclose(core_file *fp) {
	return fp-&gt;fclose(fp);
}

static INLINE size_t core_fread(core_file *fp, void *ptr, size_t len) {
	return fp-&gt;fread(ptr, 1, len, fp);
}

static INLINE int core_fseek(core_file* fp, int64_t offset, int whence) {
	return fp-&gt;fseek(fp, offset, whence);
}

static INLINE uint64_t core_fsize(core_file *fp)
{
	return fp-&gt;fsize(fp);
}

#endif</pre>
<h2>./include/libretro-common/include/libchdr/flac.h</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    flac.h

    FLAC compression wrappers

***************************************************************************/

#pragma once

#ifndef __FLAC_H__
#define __FLAC_H__

#include &lt;stdint.h&gt;

#include &lt;libchdr/libchdr_zlib.h&gt;

/***************************************************************************
 *  TYPE DEFINITIONS
 ***************************************************************************
 */

typedef struct _flac_decoder flac_decoder;
struct _flac_decoder {
		/* output state */
	void *                  decoder;				/* actual encoder */
	uint32_t                sample_rate;			/* decoded sample rate */
	uint8_t                 channels;				/* decoded number of channels */
	uint8_t                 bits_per_sample;		/* decoded bits per sample */
	uint32_t                compressed_offset;		/* current offset in compressed data */
	const uint8_t *         compressed_start;		/* start of compressed data */
	uint32_t                compressed_length;		/* length of compressed data */
	const uint8_t *         compressed2_start;		/* start of compressed data */
	uint32_t                compressed2_length;		/* length of compressed data */
	int16_t *               uncompressed_start[8];	/* pointer to start of uncompressed data (up to 8 streams) */
	uint32_t                uncompressed_offset;	/* current position in uncompressed data */
	uint32_t                uncompressed_length;	/* length of uncompressed data */
	int                    	uncompressed_swap;		/* swap uncompressed sample data */
	uint8_t                 custom_header[0x2a];	/* custom header */
};

/* ======================&gt; flac_decoder */

int 		flac_decoder_init(flac_decoder* decoder);
void 		flac_decoder_free(flac_decoder* decoder);
int 		flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);
int 		flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);
uint32_t 	flac_decoder_finish(flac_decoder* decoder);

/* codec-private data for the FLAC codec */
typedef struct _flac_codec_data flac_codec_data;
struct _flac_codec_data {
	/* internal state */
	int		native_endian;
	flac_decoder	decoder;
};

/* codec-private data for the CDFL codec */
typedef struct _cdfl_codec_data cdfl_codec_data;
struct _cdfl_codec_data {
	/* internal state */
	int		swap_endian;
	flac_decoder	decoder;
#ifdef WANT_SUBCODE
	zlib_codec_data		subcode_decompressor;
#endif
	uint8_t*	buffer;
};

#endif /* __FLAC_H__ */</pre>
<h2>./include/libretro-common/include/libchdr/huffman.h</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    huffman.h

    Static Huffman compression and decompression helpers.

***************************************************************************/

#pragma once

#ifndef __HUFFMAN_H__
#define __HUFFMAN_H__

#include &lt;libchdr/bitstream.h&gt;


/***************************************************************************
 *  CONSTANTS
 ***************************************************************************
 */

enum huffman_error
{
	HUFFERR_NONE = 0,
	HUFFERR_TOO_MANY_BITS,
	HUFFERR_INVALID_DATA,
	HUFFERR_INPUT_BUFFER_TOO_SMALL,
	HUFFERR_OUTPUT_BUFFER_TOO_SMALL,
	HUFFERR_INTERNAL_INCONSISTENCY,
	HUFFERR_TOO_MANY_CONTEXTS
};

/***************************************************************************
 *  TYPE DEFINITIONS
 ***************************************************************************
 */

typedef uint16_t lookup_value;

/* a node in the huffman tree */
struct node_t
{
	struct node_t*		parent;		/* pointer to parent node */
	uint32_t			count;		/* number of hits on this node */
	uint32_t			weight;		/* assigned weight of this node */
	uint32_t			bits;		/* bits used to encode the node */
	uint8_t				numbits;	/* number of bits needed for this node */
};

/* ======================&gt; huffman_context_base */

/* context class for decoding */
struct huffman_decoder
{
	/* internal state */
	uint32_t			numcodes;             /* number of total codes being processed */
	uint8_t				maxbits;           /* maximum bits per code */
	uint8_t 			prevdata;             /* value of the previous data (for delta-RLE encoding) */
	int             	rleremaining;         /* number of RLE bytes remaining (for delta-RLE encoding) */
	lookup_value *  	lookup;               /* pointer to the lookup table */
	struct node_t *     huffnode;             /* array of nodes */
	uint32_t *      	datahisto;            /* histogram of data values */

	/* array versions of the info we need */
#if 0
	node_t*			huffnode_array; /* [_NumCodes]; */
	lookup_value*	lookup_array; /* [1 &lt;&lt; _MaxBits]; */
#endif
};

/* ======================&gt; huffman_decoder */

struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);
void delete_huffman_decoder(struct huffman_decoder* decoder);

/* single item operations */
uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);

enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);
enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf);

int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight);
enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder);
enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder);

void huffman_build_lookup_table(struct huffman_decoder* decoder);

#endif</pre>
<h2>./include/libretro-common/include/libchdr/libchdr_zlib.h</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    libchr_zlib.h

    Zlib compression wrappers

***************************************************************************/

#pragma once

#ifndef __LIBCHDR_ZLIB_H__
#define __LIBCHDR_ZLIB_H__

#include &lt;stdint.h&gt;

#include &lt;zlib.h&gt;
#include "coretypes.h"
#include "chd.h"

#define MAX_ZLIB_ALLOCS				64

/* codec-private data for the ZLIB codec */

typedef struct _zlib_allocator zlib_allocator;
struct _zlib_allocator
{
	uint32_t *				allocptr[MAX_ZLIB_ALLOCS];
	uint32_t *				allocptr2[MAX_ZLIB_ALLOCS];
};

typedef struct _zlib_codec_data zlib_codec_data;
struct _zlib_codec_data
{
	z_stream				inflater;
	zlib_allocator			allocator;
};

/* codec-private data for the CDZL codec */
typedef struct _cdzl_codec_data cdzl_codec_data;
struct _cdzl_codec_data {
	/* internal state */
	zlib_codec_data		base_decompressor;
#ifdef WANT_SUBCODE
	zlib_codec_data		subcode_decompressor;
#endif
	uint8_t*			buffer;
};

extern chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
extern void zlib_codec_free(void *codec);
extern chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
extern void zlib_allocator_free(voidpf opaque);

/* zlib compression codec */
chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);

void zlib_codec_free(void *codec);

chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);

void zlib_fast_free(voidpf opaque, voidpf address);

/* cdzl compression codec */
chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);

void cdzl_codec_free(void* codec);

chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

#endif /* __LIBCHDR_ZLIB_H__ */</pre>
<h2>./include/libretro-common/include/libchdr/lzma.h</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    lzma.h

    LZMA compression wrappers

***************************************************************************/

#pragma once

#ifndef __LIBCHDR_LZMA_H__
#define __LIBCHDR_LZMA_H__

#include &lt;stdint.h&gt;

#include &lt;LzmaEnc.h&gt;
#include &lt;LzmaDec.h&gt;

#include &lt;libchdr/libchdr_zlib.h&gt;

/* codec-private data for the LZMA codec */
#define MAX_LZMA_ALLOCS 64

typedef struct _lzma_allocator lzma_allocator;
struct _lzma_allocator
{
	void *(*Alloc)(void *p, size_t size);
 	void (*Free)(void *p, void *address); /* address can be 0 */
	void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
	uint32_t*	allocptr[MAX_LZMA_ALLOCS];
	uint32_t*	allocptr2[MAX_LZMA_ALLOCS];
};

typedef struct _lzma_codec_data lzma_codec_data;
struct _lzma_codec_data
{
	CLzmaDec		decoder;
	lzma_allocator	allocator;
};

/* codec-private data for the CDLZ codec */
typedef struct _cdlz_codec_data cdlz_codec_data;
struct _cdlz_codec_data {
	/* internal state */
	lzma_codec_data		base_decompressor;
#ifdef WANT_SUBCODE
	zlib_codec_data		subcode_decompressor;
#endif
	uint8_t*			buffer;
};

chd_error lzma_codec_init(void* codec, uint32_t hunkbytes);

void lzma_codec_free(void* codec);

/*-------------------------------------------------
 *  decompress - decompress data using the LZMA
 *  codec
 *-------------------------------------------------
 */

chd_error lzma_codec_decompress(void* codec, const uint8_t *src,
      uint32_t complen, uint8_t *dest, uint32_t destlen);

chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);

void cdlz_codec_free(void* codec);

chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);

#endif /* __LIBCHDR_LZMA_H__ */</pre>
<h2>./include/libretro-common/include/libchdr/minmax.h</h2>
<pre>/* license:BSD-3-Clause
 * copyright-holders:Aaron Giles
 ***************************************************************************

    minmax.h

***************************************************************************/

#pragma once

#ifndef __MINMAX_H__
#define __MINMAX_H__

#if defined(RARCH_INTERNAL) || defined(__LIBRETRO__)
#include &lt;retro_miscellaneous.h&gt;
#else
#define MAX(x, y) (((x) &gt; (y)) ? (x) : (y))
#define MIN(x, y) ((x) &lt; (y) ? (x) : (y))
#endif

#endif</pre>
<h2>./include/libretro-common/include/libco.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (libco.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBCO_H
#define LIBCO_H

#include &lt;retro_common_api.h&gt;

#ifdef LIBCO_C
  #ifdef LIBCO_MP
    #define thread_local __thread
  #else
    #define thread_local
  #endif
#endif

RETRO_BEGIN_DECLS

typedef void* cothread_t;

/**
 * co_active:
 *
 * Gets the currently active context.
 *
 * Returns: active context.
 **/
cothread_t co_active(void);

/**
 * co_create:
 * @int                : stack size
 * @funcptr            : thread entry function callback
 *
 * Create a co_thread.
 *
 * Returns: cothread if successful, otherwise NULL.
 */
cothread_t co_create(unsigned int, void (*)(void));

/**
 * co_delete:
 * @cothread           : cothread object
 *
 * Frees a co_thread.
 */
void co_delete(cothread_t cothread);

/**
 * co_switch:
 * @cothread           : cothread object to switch to
 *
 * Do a context switch to @cothread.
 */
void co_switch(cothread_t cothread);

RETRO_END_DECLS

/* ifndef LIBCO_H */
#endif</pre>
<h2>./include/libretro-common/include/libretro_d3d.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_d3d.h)
 * ---------------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the
 * "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_DIRECT3D_H__
#define LIBRETRO_DIRECT3D_H__

#include "libretro.h"

#ifdef HAVE_D3D11
#include "libretro_d3d11.h"
#endif

#ifdef HAVE_D3D12
#include "libretro_d3d12.h"
#endif

#endif /* LIBRETRO_DIRECT3D_H__ */</pre>
<h2>./include/libretro-common/include/libretro_dspfilter.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_dspfilter.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_DSPFILTER_API_H__
#define LIBRETRO_DSPFILTER_API_H__

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#define DSPFILTER_SIMD_SSE      (1 &lt;&lt; 0)
#define DSPFILTER_SIMD_SSE2     (1 &lt;&lt; 1)
#define DSPFILTER_SIMD_VMX      (1 &lt;&lt; 2)
#define DSPFILTER_SIMD_VMX128   (1 &lt;&lt; 3)
#define DSPFILTER_SIMD_AVX      (1 &lt;&lt; 4)
#define DSPFILTER_SIMD_NEON     (1 &lt;&lt; 5)
#define DSPFILTER_SIMD_SSE3     (1 &lt;&lt; 6)
#define DSPFILTER_SIMD_SSSE3    (1 &lt;&lt; 7)
#define DSPFILTER_SIMD_MMX      (1 &lt;&lt; 8)
#define DSPFILTER_SIMD_MMXEXT   (1 &lt;&lt; 9)
#define DSPFILTER_SIMD_SSE4     (1 &lt;&lt; 10)
#define DSPFILTER_SIMD_SSE42    (1 &lt;&lt; 11)
#define DSPFILTER_SIMD_AVX2     (1 &lt;&lt; 12)
#define DSPFILTER_SIMD_VFPU     (1 &lt;&lt; 13)
#define DSPFILTER_SIMD_PS       (1 &lt;&lt; 14)

/* A bit-mask of all supported SIMD instruction sets.
 * Allows an implementation to pick different
 * dspfilter_implementation structs.
 */
typedef unsigned dspfilter_simd_mask_t;

/* Dynamic library endpoint. */
typedef const struct dspfilter_implementation *(
      *dspfilter_get_implementation_t)(dspfilter_simd_mask_t mask);

/* The same SIMD mask argument is forwarded to create() callback
 * as well to avoid having to keep lots of state around. */
const struct dspfilter_implementation *dspfilter_get_implementation(
      dspfilter_simd_mask_t mask);

#define DSPFILTER_API_VERSION 1

struct dspfilter_info
{
   /* Input sample rate that the DSP plugin receives. */
   float input_rate;
};

struct dspfilter_output
{
   /* The DSP plugin has to provide the buffering for the
    * output samples or reuse the input buffer directly.
    *
    * The samples are laid out in interleaving order: LRLRLRLR
    * The range of the samples are [-1.0, 1.0].
    *
    * It is not necessary to manually clip values. */
   float *samples;

   /* Frames which the DSP plugin outputted for the current process.
    *
    * One frame is here defined as a combined sample of
    * left and right channels.
    *
    * (I.e. 44.1kHz, 16bit stereo will have
    * 88.2k samples/sec and 44.1k frames/sec.)
    */
   unsigned frames;
};

struct dspfilter_input
{
   /* Input data for the DSP. The samples are interleaved in order: LRLRLRLR
    *
    * It is valid for a DSP plug to use this buffer for output as long as
    * the output size is less or equal to the input.
    *
    * This is useful for filters which can output one sample for each
    * input sample and do not need to maintain its own buffers.
    *
    * Block based filters must provide their own buffering scheme.
    *
    * The input size is not bound, but it can be safely assumed that it
    * will not exceed ~100ms worth of audio at a time. */
   float *samples;

   /* Number of frames for input data.
    * One frame is here defined as a combined sample of
    * left and right channels.
    *
    * (I.e. 44.1kHz, 16bit stereo will have
    * 88.2k samples/sec and 44.1k frames/sec.)
    */
   unsigned frames;
};

/* Returns true if config key was found. Otherwise,
 * returns false, and sets value to default value.
 */
typedef int (*dspfilter_config_get_float_t)(void *userdata,
      const char *key, float *value, float default_value);

typedef int (*dspfilter_config_get_int_t)(void *userdata,
      const char *key, int *value, int default_value);

/* Allocates an array with values. free() with dspfilter_config_free_t. */
typedef int (*dspfilter_config_get_float_array_t)(void *userdata,
      const char *key, float **values, unsigned *out_num_values,
      const float *default_values, unsigned num_default_values);

typedef int (*dspfilter_config_get_int_array_t)(void *userdata,
      const char *key, int **values, unsigned *out_num_values,
      const int *default_values, unsigned num_default_values);

typedef int (*dspfilter_config_get_string_t)(void *userdata,
      const char *key, char **output, const char *default_output);

/* Calls free() in host runtime. Sometimes needed on Windows.
 * free() on NULL is fine. */
typedef void (*dspfilter_config_free_t)(void *ptr);

struct dspfilter_config
{
   dspfilter_config_get_float_t get_float;
   dspfilter_config_get_int_t get_int;

   dspfilter_config_get_float_array_t get_float_array;
   dspfilter_config_get_int_array_t get_int_array;

   dspfilter_config_get_string_t get_string;
   /* Avoid problems where DSP plug and host are
    * linked against different C runtimes. */
   dspfilter_config_free_t free;
};

/* Creates a handle of the plugin. Returns NULL if failed. */
typedef void *(*dspfilter_init_t)(const struct dspfilter_info *info,
      const struct dspfilter_config *config, void *userdata);

/* Frees the handle. */
typedef void (*dspfilter_free_t)(void *data);

/* Processes input data.
 * The plugin is allowed to return variable sizes for output data. */
typedef void (*dspfilter_process_t)(void *data,
      struct dspfilter_output *output, const struct dspfilter_input *input);

struct dspfilter_implementation
{
   dspfilter_init_t     init;
   dspfilter_process_t  process;
   dspfilter_free_t     free;

   /* Must be DSPFILTER_API_VERSION */
   unsigned api_version;

   /* Human readable identifier of implementation. */
   const char *ident;

   /* Computer-friendly short version of ident.
    * Lower case, no spaces and special characters, etc. */
   const char *short_ident;
};

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/libretro_gskit_ps2.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_d3d.h)
 * ---------------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the
 * "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_GSKIT_PS2_H_
#define LIBRETRO_GSKIT_PS2_H_

#include "libretro.h"

#if defined(PS2)

#include &lt;gsKit.h&gt;

#define RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION 2

struct retro_hw_ps2_insets
{
  float top;
  float left;
  float bottom;
  float right;
};

#define empty_ps2_insets (struct retro_hw_ps2_insets){0.f, 0.f, 0.f, 0.f}

struct retro_hw_render_interface_gskit_ps2
{
  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2. */
  enum retro_hw_render_interface_type interface_type;
  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION. */
  unsigned interface_version;

  /* Opaque handle to the GSKit_PS2 backend in the frontend
   * which must be passed along to all function pointers
   * in this interface.
   */
   GSTEXTURE *coreTexture;
   struct retro_hw_ps2_insets padding;
};
typedef struct retro_hw_render_interface_gskit_ps2 RETRO_HW_RENDER_INTEFACE_GSKIT_PS2;

#endif

#endif /* LIBRETRO_GSKIT_PS2_H_ */</pre>
<h2>./include/libretro-common/include/libretro.h</h2>
<pre>/*!
 * libretro.h is a simple API that allows for the creation of games and emulators.
 *
 * @file libretro.h
 * @version 1
 * @author libretro
 * @copyright Copyright (C) 2010-2024 The RetroArch team
 *
 * @paragraph LICENSE
 * The following license statement only applies to this libretro API header (libretro.h).
 *
 * Copyright (C) 2010-2024 The RetroArch team
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_H__
#define LIBRETRO_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;limits.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

#ifndef __cplusplus
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &lt; 1800 &amp;&amp; !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode
 * as it isn't C99-compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include &lt;stdbool.h&gt;
#endif
#endif

#ifndef RETRO_CALLCONV
#  if defined(__GNUC__) &amp;&amp; defined(__i386__) &amp;&amp; !defined(__x86_64__)
#    define RETRO_CALLCONV __attribute__((cdecl))
#  elif defined(_MSC_VER) &amp;&amp; defined(_M_X86) &amp;&amp; !defined(_M_X64)
#    define RETRO_CALLCONV __cdecl
#  else
#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */
#  endif
#endif

#ifndef RETRO_API
#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
#    ifdef RETRO_IMPORT_SYMBOLS
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)
#      endif
#    else
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)
#      endif
#    endif
#  else
#      if defined(__GNUC__) &amp;&amp; __GNUC__ &gt;= 4
#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
#      else
#        define RETRO_API RETRO_CALLCONV
#      endif
#  endif
#endif

/**
 * The major version of the libretro API and ABI.
 * Cores may support multiple versions,
 * or they may reject cores with unsupported versions.
 * It is only incremented for incompatible API/ABI changes;
 * this generally implies a function was removed or changed,
 * or that a \c struct had fields removed or changed.
 * @note A design goal of libretro is to avoid having to increase this value at all costs.
 * This is why there are APIs that are "extended" or "V2".
 */
#define RETRO_API_VERSION         1

/**
 * @defgroup RETRO_DEVICE Input Devices
 * @brief Libretro's fundamental device abstractions.
 *
 * Libretro's input system consists of abstractions over standard device types,
 * such as a joypad (with or without analog), mouse, keyboard, light gun, or an abstract pointer.
 * Instead of managing input devices themselves,
 * cores need only to map their own concept of a controller to libretro's abstractions.
 * This makes it possible for frontends to map the abstract types to a real input device
 * without having to worry about the correct use of arbitrary (real) controller layouts.
 * @{
 */

#define RETRO_DEVICE_TYPE_SHIFT         8
#define RETRO_DEVICE_MASK               ((1 &lt;&lt; RETRO_DEVICE_TYPE_SHIFT) - 1)

/**
 * Defines an ID for a subclass of a known device type.
 *
 * To define a subclass ID, use this macro like so:
 * @code{c}
 * #define RETRO_DEVICE_SUPER_SCOPE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)
 * #define RETRO_DEVICE_JUSTIFIER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)
 * @endcode
 *
 * Correct use of this macro allows a frontend to select a suitable physical device
 * to map to the emulated device.
 *
 * @note Cores must use the base ID when polling for input,
 * and frontends must only accept the base ID for this purpose.
 * Polling for input using subclass IDs is reserved for future definition.
 *
 * @param base One of the \ref RETRO_DEVICE "base device types".
 * @param id A unique ID, with respect to \c base.
 * Must be a non-negative integer.
 * @return A unique subclass ID.
 * @see retro_controller_description
 * @see retro_set_controller_port_device
 */
#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) &lt;&lt; RETRO_DEVICE_TYPE_SHIFT) | base)

/**
 * @defgroup RETRO_DEVICE Input Device Classes
 * @{
 */

/**
 * Indicates no input.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * all other arguments are ignored and zero is returned.
 *
 * @see retro_input_state_t
 */
#define RETRO_DEVICE_NONE         0

/**
 * An abstraction around a game controller, known as a "RetroPad".
 *
 * The RetroPad is modelled after a SNES controller,
 * but with additional L2/R2/L3/R3 buttons
 * (similar to a PlayStation controller).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button (including D-Pad directions) to query.
 * The result of said query will be 1 if the button is down, 0 if not.
 *
 * There is one exception; if \c RETRO_DEVICE_ID_JOYPAD_MASK is queried
 * (and the frontend supports this query),
 * the result will be a bitmask of all pressed buttons.
 *
 * @see retro_input_state_t
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_ID_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 */
#define RETRO_DEVICE_JOYPAD       1

/**
 * An abstraction around a mouse, similar to the SNES Mouse but with more buttons.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button or axis to query.
 * For buttons, the result of said query
 * will be 1 if the button is down or 0 if not.
 * For mouse wheel axes, the result
 * will be 1 if the wheel was rotated in that direction and 0 if not.
 * For the mouse pointer axis, the result will be thee mouse's movement
 * relative to the last poll.
 * The core is responsible for tracking the mouse's position,
 * and the frontend is responsible for preventing interference
 * by the real hardware pointer (if applicable).
 *
 * @note This should only be used for cores that emulate mouse input,
 * such as for home computers
 * or consoles with mouse attachments.
 * Cores that emulate light guns should use \c RETRO_DEVICE_LIGHTGUN,
 * and cores that emulate touch screens should use \c RETRO_DEVICE_POINTER.
 *
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_DEVICE_LIGHTGUN
 */
#define RETRO_DEVICE_MOUSE        2

/**
 * An abstraction around a keyboard.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the key to poll.
 *
 * @note This should only be used for cores that emulate keyboard input,
 * such as for home computers
 * or consoles with keyboard attachments.
 * Cores that emulate gamepads should use \c RETRO_DEVICE_JOYPAD or \c RETRO_DEVICE_ANALOG,
 * and leave keyboard compatibility to the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK
 * @see retro_key
 */
#define RETRO_DEVICE_KEYBOARD     3

/**
 * An abstraction around a light gun, similar to the PlayStation's Guncon.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes one of several possible inputs.
 *
 * The gun's coordinates are reported in screen space (similar to the pointer)
 * in the range of [-0x8000, 0x7fff].
 * Zero is the center of the game's screen
 * and -0x8000 represents out-of-bounds.
 * The trigger and various auxiliary buttons are also reported.
 *
 * @note A forced off-screen shot can be requested for auto-reloading
 * function in some games.
 *
 * @see RETRO_DEVICE_POINTER
 */
#define RETRO_DEVICE_LIGHTGUN     4

/**
 * An extension of the RetroPad that supports analog input.
 *
 * The analog RetroPad provides two virtual analog sticks (similar to DualShock controllers)
 * and allows any button to be treated as analog (similar to Xbox shoulder triggers).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes an analog axis or an analog button.
 *
 * Analog axes are reported in the range of [-0x8000, 0x7fff],
 * with the X axis being positive towards the right
 * and the Y axis being positive towards the bottom.
 *
 * Analog buttons are reported in the range of [0, 0x7fff],
 * where 0 is unpressed and 0x7fff is fully pressed.
 *
 * @note Cores should only use this type if they need analog input.
 * Otherwise, \c RETRO_DEVICE_JOYPAD should be used.
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ANALOG       5

/**
 * Input Device: Pointer.
 *
 * Abstracts the concept of a pointing mechanism, e.g. touch.
 * This allows libretro to query in absolute coordinates where on the
 * screen a mouse (or something similar) is being placed.
 * For a touch centric device, coordinates reported are the coordinates
 * of the press.
 *
 * Coordinates in X and Y are reported as:
 * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
 * and 0x7fff corresponds to the far right/bottom of the screen.
 * The "screen" is here defined as area that is passed to the frontend and
 * later displayed on the monitor. If the pointer is outside this screen,
 * such as in the black surrounding areas when actual display is larger,
 * edge position is reported. An explicit edge detection is also provided,
 * that will return 1 if the pointer is near the screen edge or actually outside it.
 *
 * The frontend is free to scale/resize this screen as it sees fit, however,
 * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
 * game image, etc.
 *
 * To check if the pointer coordinates are valid (e.g. a touch display
 * actually being touched), \c RETRO_DEVICE_ID_POINTER_PRESSED returns 1 or 0.
 *
 * If using a mouse on a desktop, \c RETRO_DEVICE_ID_POINTER_PRESSED will
 * usually correspond to the left mouse button, but this is a frontend decision.
 * \c RETRO_DEVICE_ID_POINTER_PRESSED will only return 1 if the pointer is
 * inside the game screen.
 *
 * For multi-touch, the index variable can be used to successively query
 * more presses.
 * If index = 0 returns true for \c _PRESSED, coordinates can be extracted
 * with \c _X, \c _Y for index = 0. One can then query \c _PRESSED, \c _X, \c _Y with
 * index = 1, and so on.
 * Eventually \c _PRESSED will return false for an index. No further presses
 * are registered at this point.
 *
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_ID_POINTER_X
 * @see RETRO_DEVICE_ID_POINTER_Y
 * @see RETRO_DEVICE_ID_POINTER_PRESSED
 */
#define RETRO_DEVICE_POINTER      6

/** @} */

/** @defgroup RETRO_DEVICE_ID_JOYPAD RetroPad Input
 * @brief Digital buttons for the RetroPad.
 *
 * Button placement is comparable to that of a SNES controller,
 * combined with the shoulder buttons of a PlayStation controller.
 * These values can also be used for the \c id field of \c RETRO_DEVICE_INDEX_ANALOG_BUTTON
 * to represent analog buttons (usually shoulder triggers).
 * @{
 */

/** The equivalent of the SNES controller's south face button. */
#define RETRO_DEVICE_ID_JOYPAD_B        0

/** The equivalent of the SNES controller's west face button. */
#define RETRO_DEVICE_ID_JOYPAD_Y        1

/** The equivalent of the SNES controller's left-center button. */
#define RETRO_DEVICE_ID_JOYPAD_SELECT   2

/** The equivalent of the SNES controller's right-center button. */
#define RETRO_DEVICE_ID_JOYPAD_START    3

/** Up on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_UP       4

/** Down on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_DOWN     5

/** Left on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_LEFT     6

/** Right on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7

/** The equivalent of the SNES controller's east face button. */
#define RETRO_DEVICE_ID_JOYPAD_A        8

/** The equivalent of the SNES controller's north face button. */
#define RETRO_DEVICE_ID_JOYPAD_X        9

/** The equivalent of the SNES controller's left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L       10

/** The equivalent of the SNES controller's right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R       11

/** The equivalent of the PlayStation's rear left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L2      12

/** The equivalent of the PlayStation's rear right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R2      13

/**
 * The equivalent of the PlayStation's left analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_L3      14

/**
 * The equivalent of the PlayStation's right analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_R3      15

/**
 * Represents a bitmask that describes the state of all \c RETRO_DEVICE_ID_JOYPAD button constants,
 * rather than the state of a single button.
 *
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ID_JOYPAD_MASK    256

/** @} */

/** @defgroup RETRO_DEVICE_ID_ANALOG Analog RetroPad Input
 * @{
 */

/* Index / Id values for ANALOG device. */
#define RETRO_DEVICE_INDEX_ANALOG_LEFT       0
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT      1
#define RETRO_DEVICE_INDEX_ANALOG_BUTTON     2
#define RETRO_DEVICE_ID_ANALOG_X             0
#define RETRO_DEVICE_ID_ANALOG_Y             1

/** @} */

/* Id values for MOUSE. */
#define RETRO_DEVICE_ID_MOUSE_X                0
#define RETRO_DEVICE_ID_MOUSE_Y                1
#define RETRO_DEVICE_ID_MOUSE_LEFT             2
#define RETRO_DEVICE_ID_MOUSE_RIGHT            3
#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4
#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5
#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8
#define RETRO_DEVICE_ID_MOUSE_BUTTON_4         9
#define RETRO_DEVICE_ID_MOUSE_BUTTON_5         10

/* Id values for LIGHTGUN. */
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X        13 /*Absolute Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y        14 /*Absolute Position*/
/** Indicates if lightgun points off the screen or near the edge */
#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN    15 /*Status Check*/
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER          2
#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD          16 /*Forced off-screen shot*/
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A            3
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B            4
#define RETRO_DEVICE_ID_LIGHTGUN_START            6
#define RETRO_DEVICE_ID_LIGHTGUN_SELECT           7
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C            8
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP          9
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN       10
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT       11
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT      12
/* deprecated */
#define RETRO_DEVICE_ID_LIGHTGUN_X                0 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_Y                1 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR           3 /*Use Aux:A instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO            4 /*Use Aux:B instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE            5 /*Use Start instead*/

/* Id values for POINTER. */
#define RETRO_DEVICE_ID_POINTER_X             0
#define RETRO_DEVICE_ID_POINTER_Y             1
#define RETRO_DEVICE_ID_POINTER_PRESSED       2
#define RETRO_DEVICE_ID_POINTER_COUNT         3
/** Indicates if pointer is off the screen or near the edge */
#define RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN 15
/** @} */

/* Returned from retro_get_region(). */
#define RETRO_REGION_NTSC  0
#define RETRO_REGION_PAL   1

/**
 * Identifiers for supported languages.
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 */
enum retro_language
{
   RETRO_LANGUAGE_ENGLISH             = 0,
   RETRO_LANGUAGE_JAPANESE            = 1,
   RETRO_LANGUAGE_FRENCH              = 2,
   RETRO_LANGUAGE_SPANISH             = 3,
   RETRO_LANGUAGE_GERMAN              = 4,
   RETRO_LANGUAGE_ITALIAN             = 5,
   RETRO_LANGUAGE_DUTCH               = 6,
   RETRO_LANGUAGE_PORTUGUESE_BRAZIL   = 7,
   RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,
   RETRO_LANGUAGE_RUSSIAN             = 9,
   RETRO_LANGUAGE_KOREAN              = 10,
   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,
   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 12,
   RETRO_LANGUAGE_ESPERANTO           = 13,
   RETRO_LANGUAGE_POLISH              = 14,
   RETRO_LANGUAGE_VIETNAMESE          = 15,
   RETRO_LANGUAGE_ARABIC              = 16,
   RETRO_LANGUAGE_GREEK               = 17,
   RETRO_LANGUAGE_TURKISH             = 18,
   RETRO_LANGUAGE_SLOVAK              = 19,
   RETRO_LANGUAGE_PERSIAN             = 20,
   RETRO_LANGUAGE_HEBREW              = 21,
   RETRO_LANGUAGE_ASTURIAN            = 22,
   RETRO_LANGUAGE_FINNISH             = 23,
   RETRO_LANGUAGE_INDONESIAN          = 24,
   RETRO_LANGUAGE_SWEDISH             = 25,
   RETRO_LANGUAGE_UKRAINIAN           = 26,
   RETRO_LANGUAGE_CZECH               = 27,
   RETRO_LANGUAGE_CATALAN_VALENCIA    = 28,
   RETRO_LANGUAGE_CATALAN             = 29,
   RETRO_LANGUAGE_BRITISH_ENGLISH     = 30,
   RETRO_LANGUAGE_HUNGARIAN           = 31,
   RETRO_LANGUAGE_BELARUSIAN          = 32,
   RETRO_LANGUAGE_GALICIAN            = 33,
   RETRO_LANGUAGE_NORWEGIAN           = 34,
   RETRO_LANGUAGE_IRISH               = 35,
   RETRO_LANGUAGE_LAST,

   /** Defined to ensure that &lt;tt&gt;sizeof(retro_language) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_LANGUAGE_DUMMY          = INT_MAX
};

/** @defgroup RETRO_MEMORY Memory Types
 * @{
 */

/* Passed to retro_get_memory_data/size().
 * If the memory type doesn't apply to the
 * implementation NULL/0 can be returned.
 */
#define RETRO_MEMORY_MASK        0xff

/* Regular save RAM. This RAM is usually found on a game cartridge,
 * backed up by a battery.
 * If save game data is too complex for a single memory buffer,
 * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
 * callback can be used. */
#define RETRO_MEMORY_SAVE_RAM    0

/* Some games have a built-in clock to keep track of time.
 * This memory is usually just a couple of bytes to keep track of time.
 */
#define RETRO_MEMORY_RTC         1

/* System ram lets a frontend peek into a game systems main RAM. */
#define RETRO_MEMORY_SYSTEM_RAM  2

/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
#define RETRO_MEMORY_VIDEO_RAM   3

/** @} */

/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
enum retro_key
{
   RETROK_UNKNOWN        = 0,
   RETROK_FIRST          = 0,
   RETROK_BACKSPACE      = 8,
   RETROK_TAB            = 9,
   RETROK_CLEAR          = 12,
   RETROK_RETURN         = 13,
   RETROK_PAUSE          = 19,
   RETROK_ESCAPE         = 27,
   RETROK_SPACE          = 32,
   RETROK_EXCLAIM        = 33,
   RETROK_QUOTEDBL       = 34,
   RETROK_HASH           = 35,
   RETROK_DOLLAR         = 36,
   RETROK_AMPERSAND      = 38,
   RETROK_QUOTE          = 39,
   RETROK_LEFTPAREN      = 40,
   RETROK_RIGHTPAREN     = 41,
   RETROK_ASTERISK       = 42,
   RETROK_PLUS           = 43,
   RETROK_COMMA          = 44,
   RETROK_MINUS          = 45,
   RETROK_PERIOD         = 46,
   RETROK_SLASH          = 47,
   RETROK_0              = 48,
   RETROK_1              = 49,
   RETROK_2              = 50,
   RETROK_3              = 51,
   RETROK_4              = 52,
   RETROK_5              = 53,
   RETROK_6              = 54,
   RETROK_7              = 55,
   RETROK_8              = 56,
   RETROK_9              = 57,
   RETROK_COLON          = 58,
   RETROK_SEMICOLON      = 59,
   RETROK_LESS           = 60,
   RETROK_EQUALS         = 61,
   RETROK_GREATER        = 62,
   RETROK_QUESTION       = 63,
   RETROK_AT             = 64,
   RETROK_LEFTBRACKET    = 91,
   RETROK_BACKSLASH      = 92,
   RETROK_RIGHTBRACKET   = 93,
   RETROK_CARET          = 94,
   RETROK_UNDERSCORE     = 95,
   RETROK_BACKQUOTE      = 96,
   RETROK_a              = 97,
   RETROK_b              = 98,
   RETROK_c              = 99,
   RETROK_d              = 100,
   RETROK_e              = 101,
   RETROK_f              = 102,
   RETROK_g              = 103,
   RETROK_h              = 104,
   RETROK_i              = 105,
   RETROK_j              = 106,
   RETROK_k              = 107,
   RETROK_l              = 108,
   RETROK_m              = 109,
   RETROK_n              = 110,
   RETROK_o              = 111,
   RETROK_p              = 112,
   RETROK_q              = 113,
   RETROK_r              = 114,
   RETROK_s              = 115,
   RETROK_t              = 116,
   RETROK_u              = 117,
   RETROK_v              = 118,
   RETROK_w              = 119,
   RETROK_x              = 120,
   RETROK_y              = 121,
   RETROK_z              = 122,
   RETROK_LEFTBRACE      = 123,
   RETROK_BAR            = 124,
   RETROK_RIGHTBRACE     = 125,
   RETROK_TILDE          = 126,
   RETROK_DELETE         = 127,

   RETROK_KP0            = 256,
   RETROK_KP1            = 257,
   RETROK_KP2            = 258,
   RETROK_KP3            = 259,
   RETROK_KP4            = 260,
   RETROK_KP5            = 261,
   RETROK_KP6            = 262,
   RETROK_KP7            = 263,
   RETROK_KP8            = 264,
   RETROK_KP9            = 265,
   RETROK_KP_PERIOD      = 266,
   RETROK_KP_DIVIDE      = 267,
   RETROK_KP_MULTIPLY    = 268,
   RETROK_KP_MINUS       = 269,
   RETROK_KP_PLUS        = 270,
   RETROK_KP_ENTER       = 271,
   RETROK_KP_EQUALS      = 272,

   RETROK_UP             = 273,
   RETROK_DOWN           = 274,
   RETROK_RIGHT          = 275,
   RETROK_LEFT           = 276,
   RETROK_INSERT         = 277,
   RETROK_HOME           = 278,
   RETROK_END            = 279,
   RETROK_PAGEUP         = 280,
   RETROK_PAGEDOWN       = 281,

   RETROK_F1             = 282,
   RETROK_F2             = 283,
   RETROK_F3             = 284,
   RETROK_F4             = 285,
   RETROK_F5             = 286,
   RETROK_F6             = 287,
   RETROK_F7             = 288,
   RETROK_F8             = 289,
   RETROK_F9             = 290,
   RETROK_F10            = 291,
   RETROK_F11            = 292,
   RETROK_F12            = 293,
   RETROK_F13            = 294,
   RETROK_F14            = 295,
   RETROK_F15            = 296,

   RETROK_NUMLOCK        = 300,
   RETROK_CAPSLOCK       = 301,
   RETROK_SCROLLOCK      = 302,
   RETROK_RSHIFT         = 303,
   RETROK_LSHIFT         = 304,
   RETROK_RCTRL          = 305,
   RETROK_LCTRL          = 306,
   RETROK_RALT           = 307,
   RETROK_LALT           = 308,
   RETROK_RMETA          = 309,
   RETROK_LMETA          = 310,
   RETROK_LSUPER         = 311,
   RETROK_RSUPER         = 312,
   RETROK_MODE           = 313,
   RETROK_COMPOSE        = 314,

   RETROK_HELP           = 315,
   RETROK_PRINT          = 316,
   RETROK_SYSREQ         = 317,
   RETROK_BREAK          = 318,
   RETROK_MENU           = 319,
   RETROK_POWER          = 320,
   RETROK_EURO           = 321,
   RETROK_UNDO           = 322,
   RETROK_OEM_102        = 323,

   RETROK_BROWSER_BACK      = 324,
   RETROK_BROWSER_FORWARD   = 325,
   RETROK_BROWSER_REFRESH   = 326,
   RETROK_BROWSER_STOP      = 327,
   RETROK_BROWSER_SEARCH    = 328,
   RETROK_BROWSER_FAVORITES = 329,
   RETROK_BROWSER_HOME      = 330,
   RETROK_VOLUME_MUTE       = 331,
   RETROK_VOLUME_DOWN       = 332,
   RETROK_VOLUME_UP         = 333,
   RETROK_MEDIA_NEXT        = 334,
   RETROK_MEDIA_PREV        = 335,
   RETROK_MEDIA_STOP        = 336,
   RETROK_MEDIA_PLAY_PAUSE  = 337,
   RETROK_LAUNCH_MAIL       = 338,
   RETROK_LAUNCH_MEDIA      = 339,
   RETROK_LAUNCH_APP1       = 340,
   RETROK_LAUNCH_APP2       = 341,

   RETROK_LAST,

   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

enum retro_mod
{
   RETROKMOD_NONE       = 0x0000,

   RETROKMOD_SHIFT      = 0x01,
   RETROKMOD_CTRL       = 0x02,
   RETROKMOD_ALT        = 0x04,
   RETROKMOD_META       = 0x08,

   RETROKMOD_NUMLOCK    = 0x10,
   RETROKMOD_CAPSLOCK   = 0x20,
   RETROKMOD_SCROLLOCK  = 0x40,

   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

/**
 * @defgroup RETRO_ENVIRONMENT Environment Callbacks
 * @{
 */

/**
 * This bit indicates that the associated environment call is experimental,
 * and may be changed or removed in the future.
 * Frontends should mask out this bit before handling the environment call.
 */
#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000

/** Frontend-internal environment callbacks should include this bit. */
#define RETRO_ENVIRONMENT_PRIVATE 0x20000

/* Environment commands. */
/**
 * Requests the frontend to set the screen rotation.
 *
 * @param[in] data &lt;tt&gt;const unsigned*&lt;/tt&gt;.
 * Valid values are 0, 1, 2, and 3.
 * These numbers respectively set the screen rotation to 0, 90, 180, and 270 degrees counter-clockwise.
 * @returns \c true if the screen rotation was set successfully.
 */
#define RETRO_ENVIRONMENT_SET_ROTATION  1

/**
 * Queries whether the core should use overscan or not.
 *
 * @param[out] data &lt;tt&gt;bool*&lt;/tt&gt;.
 * Set to \c true if the core should use overscan,
 * \c false if it should be cropped away.
 * @returns \c true if the environment call is available.
 * Does \em not indicate whether overscan should be used.
 * @deprecated As of 2019 this callback is considered deprecated in favor of
 * using core options to manage overscan in a more nuanced, core-specific way.
 */
#define RETRO_ENVIRONMENT_GET_OVERSCAN  2

/**
 * Queries whether the frontend supports frame duping,
 * in the form of passing \c NULL to the video frame callback.
 *
 * @param[out] data &lt;tt&gt;bool*&lt;/tt&gt;.
 * Set to \c true if the frontend supports frame duping.
 * @returns \c true if the environment call is available.
 * @see retro_video_refresh_t
 */
#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3

/*
 * Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
 * and reserved to avoid possible ABI clash.
 */

/**
 * @brief Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * \code{.c}
 * void set_message_example(void)
 * {
 *    struct retro_message msg;
 *    msg.frames = 60 * 5; // 5 seconds
 *    msg.msg = "Hello world!";
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &amp;msg);
 * }
 * \endcode
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT for new code,
 * as it offers more features.
 * Only use this environment call for compatibility with older cores or frontends.
 *
 * @param[in] data &lt;tt&gt;const struct retro_message*&lt;/tt&gt;.
 * Details about the message to show to the user.
 * Behavior is undefined if &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see retro_message
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 * @note The frontend must make its own copy of the message and the underlying string.
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE   6

/**
 * Requests the frontend to shutdown the core.
 * Should only be used if the core can exit on its own,
 * such as from a menu item in a game
 * or an emulated power-off in an emulator.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_SHUTDOWN      7

/**
 * Gives a hint to the frontend of how demanding this core is on the system.
 * For example, reporting a level of 2 means that
 * this implementation should run decently on frontends
 * of level 2 and above.
 *
 * It can be used by the frontend to potentially warn
 * about too demanding implementations.
 *
 * The levels are "floating".
 *
 * This function can be called on a per-game basis,
 * as a core may have different demands for different games or settings.
 * If called, it should be called in &lt;tt&gt;retro_load_game()&lt;/tt&gt;.
 * @param[in] data &lt;tt&gt;const unsigned*&lt;/tt&gt;.
*/
#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8

/**
 * Returns the path to the frontend's system directory,
 * which can be used to store system-specific configuration
 * such as BIOS files or cached data.
 *
 * @param[out] data &lt;tt&gt;const char**&lt;/tt&gt;.
 * Pointer to the \c char* in which the system directory will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no system directory is defined,
 * in which case the core should find an alternative directory.
 * @return \c true if the environment call is available,
 * even if the value returned in \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @note Historically, some cores would use this folder for save data such as memory cards or SRAM.
 * This is now discouraged in favor of \c RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY.
 * @see RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9

/**
 * Sets the internal pixel format used by the frontend for rendering.
 * The default pixel format is \c RETRO_PIXEL_FORMAT_0RGB1555 for compatibility reasons,
 * although it's considered deprecated and shouldn't be used by new code.
 *
 * @param[in] data &lt;tt&gt;const enum retro_pixel_format *&lt;/tt&gt;.
 * Pointer to the pixel format to use.
 * @returns \c true if the pixel format was set successfully,
 * \c false if it's not supported or this callback is unavailable.
 * @note This function should be called inside \c retro_load_game()
 * or &lt;tt&gt;retro_get_system_av_info()&lt;/tt&gt;.
 * @see retro_pixel_format
 */
#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10

/**
 * Sets an array of input descriptors for the frontend
 * to present to the user for configuring the core's controls.
 *
 * This function can be called at any time,
 * preferably early in the core's life cycle.
 * Ideally, no later than \c retro_load_game().
 *
 * @param[in] data &lt;tt&gt;const struct retro_input_descriptor *&lt;/tt&gt;.
 * An array of input descriptors terminated by one whose
 * \c retro_input_descriptor::description field is set to \c NULL.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is recognized.
 * @see retro_input_descriptor
 */
#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11

/**
 * Sets a callback function used to notify the core about keyboard events.
 * This should only be used for cores that specifically need keyboard input,
 * such as for home computer emulators or games with text entry.
 *
 * @param[in] data &lt;tt&gt;const struct retro_keyboard_callback *&lt;/tt&gt;.
 * Pointer to the callback function.
 * Behavior is undefined if &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if the environment call is recognized.
 * @see retro_keyboard_callback
 * @see retro_key
 */
#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12

/**
 * Sets an interface that the frontend can use to insert and remove disks
 * from the emulated console's disk drive.
 * Can be used for optical disks, floppy disks, or any other game storage medium
 * that can be swapped at runtime.
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * over this environment call, as it supports additional features.
 * Only use this callback to maintain compatibility
 * with older cores or frontends.
 *
 * @param[in] data &lt;tt&gt;const struct retro_disk_control_callback *&lt;/tt&gt;.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_callback
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13

/**
 * Requests that a frontend enable a particular hardware rendering API.
 *
 * If successful, the frontend will create a context (and other related resources)
 * that the core can use for rendering.
 * The framebuffer will be at least as large as
 * the maximum dimensions provided in &lt;tt&gt;retro_get_system_av_info&lt;/tt&gt;.
 *
 * @param[in, out] data &lt;tt&gt;struct retro_hw_render_callback *&lt;/tt&gt;.
 * Pointer to the hardware render callback struct.
 * Used to define callbacks for the hardware-rendering life cycle,
 * as well as to request a particular rendering API.
 * @return \c true if the environment call is recognized
 * and the requested rendering API is supported.
 * \c false if \c data is \c NULL
 * or the frontend can't provide the requested rendering API.
 * @see retro_hw_render_callback
 * @see retro_video_refresh_t
 * @see RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER
 * @note Should be called in &lt;tt&gt;retro_load_game()&lt;/tt&gt;.
 * @note If HW rendering is used, pass only \c RETRO_HW_FRAME_BUFFER_VALID or
 * \c NULL to &lt;tt&gt;retro_video_refresh_t&lt;/tt&gt;.
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER 14

/**
 * Retrieves a core option's value from the frontend.
 * \c retro_variable::key should be set to an option key
 * that was previously set in \c RETRO_ENVIRONMENT_SET_VARIABLES
 * (or a similar environment call).
 *
 * @param[in,out] data &lt;tt&gt;struct retro_variable *&lt;/tt&gt;.
 * Pointer to a single \c retro_variable struct.
 * See the documentation for \c retro_variable for details
 * on which fields are set by the frontend or core.
 * May be \c NULL.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL or the key it specifies is not found.
 * @note Passing \c NULL in to \c data can be useful to
 * test for support of this environment call without looking up any variables.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE 15

/**
 * Notifies the frontend of the core's available options.
 *
 * The core may check these options later using \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * The frontend may also present these options to the user
 * in its own configuration UI.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment.
 * The core may later call this function again
 * to communicate updated options to the frontend,
 * but the number of core options must not change.
 *
 * Here's an example that sets two options.
 *
 * @code
 * void set_variables_example(void)
 * {
 *    struct retro_variable options[] = {
 *        { "foo_speedhack", "Speed hack; false|true" }, // false by default
 *        { "foo_displayscale", "Display scale factor; 1|2|3|4" }, // 1 by default
 *        { NULL, NULL },
 *    };
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, &amp;options);
 * }
 * @endcode
 *
 * The possible values will generally be displayed and stored as-is by the frontend.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 for new code,
 * as it offers more features such as categories and translation.
 * Only use this environment call to maintain compatibility
 * with older frontends or cores.
 * @note Keep the available options (and their possible values) as low as possible;
 * it should be feasible to cycle through them without a keyboard.
 * @param[in] data &lt;tt&gt;const struct retro_variable *&lt;/tt&gt;.
 * Pointer to an array of \c retro_variable structs that define available core options,
 * terminated by a &lt;tt&gt;{ NULL, NULL }&lt;/tt&gt; element.
 * The frontend must maintain its own copy of this array.
 *
 * @returns \c true if the environment call is available,
 * even if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_VARIABLES 16

/**
 * Queries whether at least one core option was updated by the frontend
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * This typically means that the user opened the core options menu and made some changes.
 *
 * Cores usually call this each frame before the core's main emulation logic.
 * Specific options can then be queried with \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 *
 * @param[out] data &lt;tt&gt;bool *&lt;/tt&gt;.
 * Set to \c true if at least one core option was updated
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * Behavior is undefined if this pointer is \c NULL.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17

/**
 * Notifies the frontend that this core can run without loading any content,
 * such as when emulating a console that has built-in software.
 * When a core is loaded without content,
 * \c retro_load_game receives an argument of &lt;tt&gt;NULL&lt;/tt&gt;.
 * This should be called within \c retro_set_environment() only.
 *
 * @param[in] data &lt;tt&gt;const bool *&lt;/tt&gt;.
 * Pointer to a single \c bool that indicates whether this frontend can run without content.
 * Can point to a value of \c false but this isn't necessary,
 * as contentless support is opt-in.
 * The behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see retro_load_game
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18

/**
 * Retrieves the absolute path from which this core was loaded.
 * Useful when loading assets from paths relative to the core,
 * as is sometimes the case when using &lt;tt&gt;RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME&lt;/tt&gt;.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to a string in which the core's path will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if the core is statically linked to the frontend
 * or if the core's path otherwise cannot be determined.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19

/* Environment call 20 was an obsolete version of SET_AUDIO_CALLBACK.
 * It was not used by any known core at the time, and was removed from the API.
 * The number 20 is reserved to prevent ABI clashes.
 */

/**
 * Sets a callback that notifies the core of how much time has passed
 * since the last iteration of &lt;tt&gt;retro_run&lt;/tt&gt;.
 * If the frontend is not running the core in real time
 * (e.g. it's frame-stepping or running in slow motion),
 * then the reference value will be provided to the callback instead.
 *
 * @param[in] data &lt;tt&gt;const struct retro_frame_time_callback *&lt;/tt&gt;.
 * Pointer to a single \c retro_frame_time_callback struct.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @note Frontends may disable this environment call in certain situations.
 * It will return \c false in those cases.
 * @see retro_frame_time_callback
 */
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21

/**
 * Registers a set of functions that the frontend can use
 * to tell the core it's ready for audio output.
 *
 * It is intended for games that feature asynchronous audio.
 * It should not be used for emulators unless their audio is asynchronous.
 *
 *
 * The callback only notifies about writability; the libretro core still
 * has to call the normal audio callbacks
 * to write audio. The audio callbacks must be called from within the
 * notification callback.
 * The amount of audio data to write is up to the core.
 * Generally, the audio callback will be called continuously in a loop.
 *
 * A frontend may disable this callback in certain situations.
 * The core must be able to render audio with the "normal" interface.
 *
 * @param[in] data &lt;tt&gt;const struct retro_audio_callback *&lt;/tt&gt;.
 * Pointer to a set of functions that the frontend will call to notify the core
 * when it's ready to receive audio data.
 * May be \c NULL, in which case the frontend will return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @warning The provided callbacks can be invoked from any thread,
 * so their implementations \em must be thread-safe.
 * @note If a core uses this callback,
 * it should also use &lt;tt&gt;RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK&lt;/tt&gt;.
 * @see retro_audio_callback
 * @see retro_audio_sample_t
 * @see retro_audio_sample_batch_t
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22

/**
 * Gets an interface that a core can use to access a controller's rumble motors.
 *
 * The interface supports two independently-controlled motors,
 * one strong and one weak.
 *
 * Should be called from either \c retro_init() or \c retro_load_game(),
 * but not from \c retro_set_environment().
 *
 * @param[out] data &lt;tt&gt;struct retro_rumble_interface *&lt;/tt&gt;.
 * Pointer to the interface struct.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the current device doesn't support vibration.
 * @see retro_rumble_interface
 * @defgroup GET_RUMBLE_INTERFACE Rumble Interface
 */
#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23

/**
 * Returns the frontend's supported input device types.
 *
 * The supported device types are returned as a bitmask,
 * with each value of \ref RETRO_DEVICE corresponding to a bit.
 *
 * Should only be called in \c retro_run().
 *
 * @code
 * #define REQUIRED_DEVICES ((1 &lt;&lt; RETRO_DEVICE_JOYPAD) | (1 &lt;&lt; RETRO_DEVICE_ANALOG))
 * void get_input_device_capabilities_example(void)
 * {
 *    uint64_t capabilities;
 *    environ_cb(RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES, &amp;capabilities);
 *    if ((capabilities &amp; REQUIRED_DEVICES) == REQUIRED_DEVICES)
 *      printf("Joypad and analog device types are supported");
 * }
 * @endcode
 *
 * @param[out] data &lt;tt&gt;uint64_t *&lt;/tt&gt;.
 * Pointer to a bitmask of supported input device types.
 * If the frontend supports a particular \c RETRO_DEVICE_* type,
 * then the bit &lt;tt&gt;(1 &lt;&lt; RETRO_DEVICE_*)&lt;/tt&gt; will be set.
 *
 * Each bit represents a \c RETRO_DEVICE constant,
 * e.g. bit 1 represents \c RETRO_DEVICE_JOYPAD,
 * bit 2 represents \c RETRO_DEVICE_MOUSE, and so on.
 *
 * Bits that do not correspond to known device types will be set to zero
 * and are reserved for future use.
 *
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note If the frontend supports multiple input drivers,
 * availability of this environment call (and the reported capabilities)
 * may depend on the active driver.
 * @see RETRO_DEVICE
 */
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24

/**
 * Returns an interface that the core can use to access and configure available sensors,
 * such as an accelerometer or gyroscope.
 *
 * @param[out] data &lt;tt&gt;struct retro_sensor_interface *&lt;/tt&gt;.
 * Pointer to the sensor interface that the frontend will populate.
 * Behavior is undefined if is \c NULL.
 * @returns \c true if the environment call is available,
 * even if the device doesn't have any supported sensors.
 * @see retro_sensor_interface
 * @see retro_sensor_action
 * @see RETRO_SENSOR
 * @addtogroup RETRO_SENSOR
 */
#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface to the device's video camera.
 *
 * The frontend delivers new video frames via a user-defined callback
 * that runs in the same thread as \c retro_run().
 * Should be called in \c retro_load_game().
 *
 * @param[in,out] data &lt;tt&gt;struct retro_camera_callback *&lt;/tt&gt;.
 * Pointer to the camera driver interface.
 * Some fields in the struct must be filled in by the core,
 * others are provided by the frontend.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available,
 * even if an actual camera isn't.
 * @note This API only supports one video camera at a time.
 * If the device provides multiple cameras (e.g. inner/outer cameras on a phone),
 * the frontend will choose one to use.
 * @see retro_camera_callback
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for cross-platform logging.
 * Certain platforms don't have a console or &lt;tt&gt;stderr&lt;/tt&gt;,
 * or they have their own preferred logging methods.
 * The frontend itself may also display log output.
 *
 * @attention This should not be used for information that the player must immediately see,
 * such as major errors or warnings.
 * In most cases, this is best for information that will help you (the developer)
 * identify problems when debugging or providing support.
 * Unless a core or frontend is intended for advanced users,
 * the player might not check (or even know about) their logs.
 *
 * @param[out] data &lt;tt&gt;struct retro_log_callback *&lt;/tt&gt;.
 * Pointer to the callback where the function pointer will be saved.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see retro_log_callback
 * @note Cores can fall back to \c stderr if this interface is not available.
 */
#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27

/**
 * Returns an interface that the core can use for profiling code
 * and to access performance-related information.
 *
 * This callback supports performance counters, a high-resolution timer,
 * and listing available CPU features (mostly SIMD instructions).
 *
 * @param[out] data &lt;tt&gt;struct retro_perf_callback *&lt;/tt&gt;.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @see retro_perf_callback
 */
#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28

/**
 * Returns an interface that the core can use to retrieve the device's location,
 * including its current latitude and longitude.
 *
 * @param[out] data &lt;tt&gt;struct retro_location_callback *&lt;/tt&gt;.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is available,
 * even if there's no location information available.
 * @see retro_location_callback
 */
#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29

/**
 * @deprecated An obsolete alias to \c RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY kept for compatibility.
 * @see RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY
 **/
#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30

/**
 * Returns the frontend's "core assets" directory,
 * which can be used to store assets that the core needs
 * such as art assets or level data.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to a string in which the core assets directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no core assets directory is defined,
 * in which case the core should find an alternative directory.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 */
#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30

/**
 * Returns the frontend's save data directory, if available.
 * This directory should be used to store game-specific save data,
 * including memory card images.
 *
 * Although libretro provides an interface for cores to expose SRAM to the frontend,
 * not all cores can support it correctly.
 * In this case, cores should use this environment callback
 * to save their game data to disk manually.
 *
 * Cores that use this environment callback
 * should flush their save data to disk periodically and when unloading.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to the string in which the save data directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May return \c NULL if no save data directory is defined.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @note Early libretro cores used \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY for save data.
 * This is still supported for backwards compatibility,
 * but new cores should use this environment call instead.
 * \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY should be used for game-agnostic data
 * such as BIOS files or core-specific configuration.
 * @note The returned directory may or may not be the same
 * as the one used for \c retro_get_memory_data.
 *
 * @see retro_get_memory_data
 * @see RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31

/**
 * Sets new video and audio parameters for the core.
 * This can only be called from within &lt;tt&gt;retro_run&lt;/tt&gt;.
 *
 * This environment call may entail a full reinitialization of the frontend's audio/video drivers,
 * hence it should \em only be used if the core needs to make drastic changes
 * to audio/video parameters.
 *
 * This environment call should \em not be used when:
 * &lt;ul&gt;
 * &lt;li&gt;Changing the emulated system's internal resolution,
 * within the limits defined by the existing values of \c max_width and \c max_height.
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY instead,
 * and adjust \c retro_get_system_av_info to account for
 * supported scale factors and screen layouts
 * when computing \c max_width and \c max_height.
 * Only use this environment call if \c max_width or \c max_height needs to increase.
 * &lt;li&gt;Adjusting the screen's aspect ratio,
 * e.g. when changing the layout of the screen(s).
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY or \c RETRO_ENVIRONMENT_SET_ROTATION instead.
 * &lt;/ul&gt;
 *
 * The frontend will reinitialize its audio and video drivers within this callback;
 * after that happens, audio and video callbacks will target the newly-initialized driver,
 * even within the same \c retro_run call.
 *
 * This callback makes it possible to support configurable resolutions
 * while avoiding the need to compute the "worst case" values of \c max_width and \c max_height.
 *
 * @param[in] data &lt;tt&gt;const struct retro_system_av_info *&lt;/tt&gt;.
 * Pointer to the new video and audio parameters that the frontend should adopt.
 * @returns \c true if the environment call is available
 * and the new av_info struct was accepted.
 * \c false if the environment call is unavailable or \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 */
#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32

/**
 * Provides an interface that a frontend can use
 * to get function pointers from the core.
 *
 * This allows cores to define their own extensions to the libretro API,
 * or to expose implementations of a frontend's libretro extensions.
 *
 * @param[in] data &lt;tt&gt;const struct retro_get_proc_address_interface *&lt;/tt&gt;.
 * Pointer to the interface that the frontend can use to get function pointers from the core.
 * The frontend must maintain its own copy of this interface.
 * @returns \c true if the environment call is available
 * and the returned interface was accepted.
 * @note The provided interface may be called at any time,
 * even before this environment call returns.
 * @note Extensions should be prefixed with the name of the frontend or core that defines them.
 * For example, a frontend named "foo" that defines a debugging extension
 * should expect the core to define functions prefixed with "foo_debug_".
 * @warning If a core wants to use this environment call,
 * it \em must do so from within \c retro_set_environment().
 * @see retro_get_proc_address_interface
 */
#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33

/**
 * Registers a core's ability to handle "subsystems",
 * which are secondary platforms that augment a core's primary emulated hardware.
 *
 * A core doesn't need to emulate a secondary platform
 * in order to use it as a subsystem;
 * as long as it can load a secondary file for some practical use,
 * then this environment call is most likely suitable.
 *
 * Possible use cases of a subsystem include:
 *
 * \li Installing software onto an emulated console's internal storage,
 * such as the Nintendo DSi.
 * \li Emulating accessories that are used to support another console's games,
 * such as the Super Game Boy or the N64 Transfer Pak.
 * \li Inserting a secondary ROM into a console
 * that features multiple cartridge ports,
 * such as the Nintendo DS's Slot-2.
 * \li Loading a save data file created and used by another core.
 *
 * Cores should \em not use subsystems for:
 *
 * \li Emulators that support multiple "primary" platforms,
 * such as a Game Boy/Game Boy Advance core
 * or a Sega Genesis/Sega CD/32X core.
 * Use \c retro_system_content_info_override, \c retro_system_info,
 * and/or runtime detection instead.
 * \li Selecting different memory card images.
 * Use dynamically-populated core options instead.
 * \li Different variants of a single console,
 * such the Game Boy vs. the Game Boy Color.
 * Use core options or runtime detection instead.
 * \li Games that span multiple disks.
 * Use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * and m3u-formatted playlists instead.
 * \li Console system files (BIOS, firmware, etc.).
 * Use \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 * and a common naming convention instead.
 *
 * When the frontend loads a game via a subsystem,
 * it must call \c retro_load_game_special() instead of \c retro_load_game().
 *
 * @param[in] data &lt;tt&gt;const struct retro_subsystem_info *&lt;/tt&gt;.
 * Pointer to an array of subsystem descriptors,
 * terminated by a zeroed-out \c retro_subsystem_info struct.
 * The frontend should maintain its own copy
 * of this array and the strings within it.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @note This environment call \em must be called from within \c retro_set_environment(),
 * as frontends may need the registered information before loading a game.
 * @see retro_subsystem_info
 * @see retro_load_game_special
 */
#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34

/**
 * Declares one or more types of controllers supported by this core.
 * The frontend may then allow the player to select one of these controllers in its menu.
 *
 * Many consoles had controllers that came in different versions,
 * were extensible with peripherals,
 * or could be held in multiple ways;
 * this environment call can be used to represent these differences
 * and adjust the core's behavior to match.
 *
 * Possible use cases include:
 *
 * \li Supporting different classes of a single controller that supported their own sets of games.
 *     For example, the SNES had two different lightguns (the Super Scope and the Justifier)
 *     whose games were incompatible with each other.
 * \li Representing a platform's alternative controllers.
 *     For example, several platforms had music/rhythm games that included controllers
 *     shaped like musical instruments.
 * \li Representing variants of a standard controller with additional inputs.
 *     For example, numerous consoles in the 90's introduced 6-button controllers for fighting games,
 *     steering wheels for racing games,
 *     or analog sticks for 3D platformers.
 * \li Representing add-ons for consoles or standard controllers.
 *     For example, the 3DS had a Circle Pad Pro attachment that added a second analog stick.
 * \li Selecting different configurations for a single controller.
 *     For example, the Wii Remote could be held sideways like a traditional game pad
 *     or in one hand like a wand.
 * \li Providing multiple ways to simulate the experience of using a particular controller.
 *     For example, the Game Boy Advance featured several games
 *     with motion or light sensors in their cartridges;
 *     a core could provide controller configurations
 *     that allow emulating the sensors with either analog axes
 *     or with their host device's sensors.
 *
 * Should be called in retro_load_game.
 * The frontend must maintain its own copy of the provided array,
 * including all strings and subobjects.
 * A core may exclude certain controllers for known incompatible games.
 *
 * When the frontend changes the active device for a particular port,
 * it must call \c retro_set_controller_port_device() with that port's index
 * and one of the IDs defined in its retro_controller_info::types field.
 *
 * Input ports are generally associated with different players
 * (and the frontend's UI may reflect this with "Player 1" labels),
 * but this is not required.
 * Some games use multiple controllers for a single player,
 * or some cores may use port indexes to represent an emulated console's
 * alternative input peripherals.
 *
 * @param[in] data &lt;tt&gt;const struct retro_controller_info *&lt;/tt&gt;.
 * Pointer to an array of controller types defined by this core,
 * terminated by a zeroed-out \c retro_controller_info.
 * Each element of this array represents a controller port on the emulated device.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_controller_info
 * @see retro_set_controller_port_device
 * @see RETRO_DEVICE_SUBCLASS
 */
#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35

/**
 * Notifies the frontend of the address spaces used by the core's emulated hardware,
 * and of the memory maps within these spaces.
 * This can be used by the frontend to provide cheats, achievements, or debugging capabilities.
 * Should only be used by emulators, as it makes little sense for game engines.
 *
 * @note Cores should also expose these address spaces
 * through retro_get_memory_data and \c retro_get_memory_size if applicable;
 * this environment call is not intended to replace those two functions,
 * as the emulated hardware may feature memory regions outside of its own address space
 * that are nevertheless useful for the frontend.
 *
 * @param[in] data &lt;tt&gt;const struct retro_memory_map *&lt;/tt&gt;.
 * Pointer to a single memory-map listing.
 * The frontend must maintain its own copy of this object and its contents,
 * including strings and nested objects.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_memory_map
 * @see retro_get_memory_data
 * @see retro_memory_descriptor
 */
#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Resizes the viewport without reinitializing the video driver.
 *
 * Similar to \c RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
 * but any changes that would require video reinitialization will not be performed.
 * Can only be called from within \c retro_run().
 *
 * This environment call allows a core to revise the size of the viewport at will,
 * which can be useful for emulated platforms that support dynamic resolution changes
 * or for cores that support multiple screen layouts.
 *
 * A frontend must guarantee that this environment call completes in
 * constant time.
 *
 * @param[in] data &lt;tt&gt;const struct retro_game_geometry *&lt;/tt&gt;.
 * Pointer to the new video parameters that the frontend should adopt.
 * \c retro_game_geometry::max_width and \c retro_game_geometry::max_height
 * will be ignored.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 */
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37

/**
 * Returns the name of the user, if possible.
 * This callback is suitable for cores that offer personalization,
 * such as online facilities or user profiles on the emulated system.
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to the user name string.
 * May be \c NULL, in which case the core should use a default name.
 * The returned pointer is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the frontend couldn't provide a name.
 */
#define RETRO_ENVIRONMENT_GET_USERNAME 38

/**
 * Returns the frontend's configured language.
 * It can be used to localize the core's UI,
 * or to customize the emulated firmware if applicable.
 *
 * @param[out] data &lt;tt&gt;retro_language *&lt;/tt&gt;.
 * Pointer to the language identifier.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note The returned language may not be the same as the operating system's language.
 * Cores should fall back to the operating system's language (or to English)
 * if the environment call is unavailable or the returned language is unsupported.
 * @see retro_language
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_GET_LANGUAGE 39

/**
 * Returns a frontend-managed framebuffer
 * that the core may render directly into
 *
 * This environment call is provided as an optimization
 * for cores that use software rendering
 * (i.e. that don't use \refitem RETRO_ENVIRONMENT_SET_HW_RENDER "a graphics hardware API");
 * specifically, the intended use case is to allow a core
 * to render directly into frontend-managed video memory,
 * avoiding the bandwidth use that copying a whole framebuffer from core to video memory entails.
 *
 * Must be called every frame if used,
 * as this may return a different framebuffer each frame
 * (e.g. for swap chains).
 * However, a core may render to a different buffer even if this call succeeds.
 *
 * @param[in,out] data &lt;tt&gt;struct retro_framebuffer *&lt;/tt&gt;.
 * Pointer to a frontend's frame buffer and accompanying data.
 * Some fields are set by the core, others are set by the frontend.
 * Only guaranteed to be valid for the duration of the current \c retro_run call,
 * and must not be used afterwards.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call was recognized
 * and the framebuffer was successfully returned.
 * @see retro_framebuffer
 */
#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface for accessing the data of specific rendering APIs.
 * Not all hardware rendering APIs support or need this.
 *
 * The details of these interfaces are specific to each rendering API.
 *
 * @note \c retro_hw_render_callback::context_reset must be called by the frontend
 * before this environment call can be used.
 * Additionally, the contents of the returned interface are invalidated
 * after \c retro_hw_render_callback::context_destroyed has been called.
 * @param[out] data &lt;tt&gt;const struct retro_hw_render_interface **&lt;/tt&gt;.
 * The render interface for the currently-enabled hardware rendering API, if any.
 * The frontend will store a pointer to the interface at the address provided here.
 * The returned interface is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available,
 * the active graphics API has a libretro rendering interface,
 * and the frontend is able to return said interface.
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see retro_hw_render_interface
 * @note Since not every libretro-supported hardware rendering API
 * has a \c retro_hw_render_interface implementation,
 * a result of \c false is not necessarily an error.
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Explicitly notifies the frontend of whether this core supports achievements.
 * The core must expose its emulated address space via
 * \c retro_get_memory_data or \c RETRO_ENVIRONMENT_GET_MEMORY_MAPS.
 * Must be called before the first call to &lt;tt&gt;retro_run&lt;/tt&gt;.
 *
 * If \ref retro_get_memory_data returns a valid address
 * but this environment call is not used,
 * the frontend (at its discretion) may or may not opt in the core to its achievements support.
 * whether this core is opted in to the frontend's achievement support
 * is left to the frontend's discretion.
 * @param[in] data &lt;tt&gt;const bool *&lt;/tt&gt;.
 * Pointer to a single \c bool that indicates whether this core supports achievements.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 * @see retro_get_memory_data
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Defines an interface that the frontend can use
 * to ask the core for the parameters it needs for a hardware rendering context.
 * The exact semantics depend on \ref RETRO_ENVIRONMENT_SET_HW_RENDER "the active rendering API".
 * Will be used some time after \c RETRO_ENVIRONMENT_SET_HW_RENDER is called,
 * but before \c retro_hw_render_callback::context_reset is called.
 *
 * @param[in] data &lt;tt&gt;const struct retro_hw_render_context_negotiation_interface *&lt;/tt&gt;.
 * Pointer to the context negotiation interface.
 * Will be populated by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported,
 * even if the current graphics API doesn't use
 * a context negotiation interface (in which case the argument is ignored).
 * @see retro_hw_render_context_negotiation_interface
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Notifies the frontend of any quirks associated with serialization.
 *
 * Should be set in either \c retro_init or \c retro_load_game, but not both.
 * @param[in, out] data &lt;tt&gt;uint64_t *&lt;/tt&gt;.
 * Pointer to the core's serialization quirks.
 * The frontend will set the flags of the quirks it supports
 * and clear the flags of those it doesn't.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported.
 * @see retro_serialize
 * @see retro_unserialize
 * @see RETRO_SERIALIZATION_QUIRK
 */
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44

/**
 * The frontend will try to use a "shared" context when setting up a hardware context.
 * Mostly applicable to OpenGL.
 *
 * In order for this to have any effect,
 * the core must call \c RETRO_ENVIRONMENT_SET_HW_RENDER at some point
 * if it hasn't already.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available
 * and the frontend supports shared hardware contexts.
 */
#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use to access the file system.
 * Should be called as early as possible.
 *
 * @param[in,out] data &lt;tt&gt;struct retro_vfs_interface_info *&lt;/tt&gt;.
 * Information about the desired VFS interface,
 * as well as the interface itself.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available
 * and the frontend can provide a VFS interface of the requested version or newer.
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 */
#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use
 * to set the state of any accessible device LEDs.
 *
 * @param[out] data &lt;tt&gt;struct retro_led_interface *&lt;/tt&gt;.
 * Pointer to the LED interface that the frontend will populate.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL
 * or no LEDs are accessible.
 * @see retro_led_interface
 */
#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns hints about certain steps that the core may skip for this frame.
 *
 * A frontend may not need a core to generate audio or video in certain situations;
 * this environment call sets a bitmask that indicates
 * which steps the core may skip for this frame.
 *
 * This can be used to increase performance for some frontend features.
 *
 * @note Emulation accuracy should not be compromised;
 * for example, if a core emulates a platform that supports display capture
 * (i.e. looking at its own VRAM), then it should perform its rendering as normal
 * unless it can prove that the emulated game is not using display capture.
 *
 * @param[out] data &lt;tt&gt;retro_av_enable_flags *&lt;/tt&gt;.
 * Pointer to the bitmask of steps that the frontend will skip.
 * Other bits are set to zero and are reserved for future use.
 * If \c NULL, the frontend will only return whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * regardless of the value output to \c data.
 * If \c false, the core should assume that the frontend will not skip any steps.
 * @see retro_av_enable_flags
 */
#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for raw MIDI I/O.
 *
 * @param[out] data &lt;tt&gt;struct retro_midi_interface *&lt;/tt&gt;.
 * Pointer to the MIDI interface.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_midi_interface
 */
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend if it's currently in fast-forward mode.
 * @param[out] data &lt;tt&gt;bool *&lt;/tt&gt;.
 * Set to \c true if the frontend is currently fast-forwarding its main loop.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if this environment call is available,
 * regardless of the value returned in \c data.
 *
 * @see RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE
 */
#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the refresh rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal refresh rate.
 *
 * @param[out] data &lt;tt&gt;float *&lt;/tt&gt;.
 * Pointer to the \c float in which the frontend will store its target refresh rate.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns whether the frontend can return the state of all buttons at once as a bitmask,
 * rather than requiring a series of individual calls to \c retro_input_state_t.
 *
 * If this callback returns \c true,
 * you can get the state of all buttons by passing \c RETRO_DEVICE_ID_JOYPAD_MASK
 * as the \c id parameter to \c retro_input_state_t.
 * Bit #N represents the RETRO_DEVICE_ID_JOYPAD constant of value N,
 * e.g. &lt;tt&gt;(1 &lt;&lt; RETRO_DEVICE_ID_JOYPAD_A)&lt;/tt&gt; represents the A button.
 *
 * @param data Ignored.
 * @returns \c true if the frontend can report the complete digital joypad state as a bitmask.
 * @see retro_input_state_t
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 */
#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the version of the core options API supported by the frontend.
 *
 * Over the years, libretro has used several interfaces
 * for allowing cores to define customizable options.
 * \ref SET_CORE_OPTIONS_V2 "Version 2 of the interface"
 * is currently preferred due to its extra features,
 * but cores and frontends should strive to support
 * versions \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS "1"
 * and \ref RETRO_ENVIRONMENT_SET_VARIABLES "0" as well.
 * This environment call provides the information that cores need for that purpose.
 *
 * If this environment call returns \c false,
 * then the core should assume version 0 of the core options API.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the integer that will store the frontend's
 * supported core options API version.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_VARIABLES
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52

/**
 * @copybrief RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 *
 * @deprecated This environment call has been superseded
 * by RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
 * which supports categorizing options into groups.
 * This environment call should only be used to maintain compatibility
 * with older cores and frontends.
 *
 * This environment call is intended to replace \c RETRO_ENVIRONMENT_SET_VARIABLES,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 1.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * Example entry:
 * @code
 * {
 *     "foo_option",
 *     "Speed hack coprocessor X",
 *     "Provides increased performance at the expense of reduced accuracy",
 *     {
 *         { "false",    NULL },
 *         { "true",     NULL },
 *         { "unstable", "Turbo (Unstable)" },
 *         { NULL, NULL },
 *     },
 *     "false"
 * }
 * @endcode
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_option_definition *&lt;/tt&gt;.
 * Pointer to one or more core option definitions,
 * terminated by a \ref retro_core_option_definition whose values are all zero.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available.
 *
 * @see retro_core_option_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * that supports internationalization.
 *
 * @deprecated This environment call has been superseded
 * by \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
 * which supports categorizing options into groups
 * (plus translating the groups themselves).
 * Only use this environment call to maintain compatibility
 * with older cores and frontends.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_intl for some important details.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_intl *&lt;/tt&gt;.
 * Pointer to a core's option values and their translations.
 * @see retro_core_options_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54

/**
 * Notifies the frontend that it should show or hide the named core option.
 *
 * Some core options aren't relevant in all scenarios,
 * such as a submenu for hardware rendering flags
 * when the software renderer is configured.
 * This environment call asks the frontend to stop (or start)
 * showing the named core option to the player.
 * This is only a hint, not a requirement;
 * the frontend may ignore this environment call.
 * By default, all core options are visible.
 *
 * @note This environment call must \em only affect a core option's visibility,
 * not its functionality or availability.
 * \ref RETRO_ENVIRONMENT_GET_VARIABLE "Getting an invisible core option"
 * must behave normally.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_option_display *&lt;/tt&gt;.
 * Pointer to a descriptor for the option that the frontend should show or hide.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL
 * or the specified option doesn't exist.
 * @see retro_core_option_display
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55

/**
 * Returns the frontend's preferred hardware rendering API.
 * Cores should use this information to decide which API to use with \c RETRO_ENVIRONMENT_SET_HW_RENDER.
 * @param[out] data &lt;tt&gt;retro_hw_context_type *&lt;/tt&gt;.
 * Pointer to the hardware context type.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * This value will be set even if the environment call returns &lt;tt&gt;false&lt;/tt&gt;,
 * unless the frontend doesn't implement it.
 * @returns \c true if the environment call is available
 * and the frontend is able to use a hardware rendering API besides the one returned.
 * If \c false is returned and the core cannot use the preferred rendering API,
 * then it should exit or fall back to software rendering.
 * @note The returned value does not indicate which API is currently in use.
 * For example, the frontend may return \c RETRO_HW_CONTEXT_OPENGL
 * while a Direct3D context from a previous session is active;
 * this would signal that the frontend's current preference is for OpenGL,
 * possibly because the user changed their frontend's video driver while a game is running.
 * @see retro_hw_context_type
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56

/**
 * Returns the minimum version of the disk control interface supported by the frontend.
 *
 * If this environment call returns \c false or \c data is 0 or greater,
 * then cores may use disk control callbacks
 * with \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
 * If the reported version is 1 or greater,
 * then cores should use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE instead.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the unsigned integer that the frontend's supported disk control interface version will be stored in.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57

/**
 * @copybrief RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 * This version of the disk control interface provides
 * more information about disk images.
 * Should be called in \c retro_init.
 *
 * @param[in] data &lt;tt&gt;const struct retro_disk_control_ext_callback *&lt;/tt&gt;.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_ext_callback
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58

/**
 * Returns the version of the message interface supported by the frontend.
 *
 * A version of 0 indicates that the frontend
 * only supports the legacy \c RETRO_ENVIRONMENT_SET_MESSAGE interface.
 * A version of 1 indicates that the frontend
 * supports \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT as well.
 * If this environment call returns \c false,
 * the core should behave as if it had returned 0.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 */
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59

/**
 * Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * This environment call supersedes \c RETRO_ENVIRONMENT_SET_MESSAGE,
 * as it provides many more ways to customize
 * how a message is presented to the player.
 * However, a frontend that supports this environment call
 * must still support \c RETRO_ENVIRONMENT_SET_MESSAGE.
 *
 * @param[in] data &lt;tt&gt;const struct retro_message_ext *&lt;/tt&gt;.
 * Pointer to the message to display to the player.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_message_ext
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60

/**
 * Returns the number of active input devices currently provided by the frontend.
 *
 * This may change between frames,
 * but will remain constant for the duration of each frame.
 *
 * If this callback returns \c true,
 * a core need not poll any input device
 * with an index greater than or equal to the returned value.
 *
 * If callback returns \c false,
 * the number of active input devices is unknown.
 * In this case, all input devices should be considered active.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61

/**
 * Registers a callback that the frontend can use to notify the core
 * of the audio output buffer's occupancy.
 * Can be used by a core to attempt frame-skipping to avoid buffer under-runs
 * (i.e. "crackling" sounds).
 *
 * @param[in] data &lt;tt&gt;const struct retro_audio_buffer_status_callback *&lt;/tt&gt;.
 * Pointer to the the buffer status callback,
 * or \c NULL to unregister any existing callback.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_audio_buffer_status_callback
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62

/**
 * Requests a minimum frontend audio latency in milliseconds.
 *
 * This is a hint; the frontend may assign a different audio latency
 * to accommodate hardware limits,
 * although it should try to honor requests up to 512ms.
 *
 * This callback has no effect if the requested latency
 * is less than the frontend's current audio latency.
 * If value is zero or \c data is \c NULL,
 * the frontend should set its default audio latency.
 *
 * May be used by a core to increase audio latency and
 * reduce the risk of buffer under-runs (crackling)
 * when performing 'intensive' operations.
 *
 * A core using RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 * to implement audio-buffer-based frame skipping can get good results
 * by setting the audio latency to a high (typically 6x or 8x)
 * integer multiple of the expected frame time.
 *
 * This can only be called from within \c retro_run().
 *
 * @warning This environment call may require the frontend to reinitialize its audio system.
 * This environment call should be used sparingly.
 * If the driver is reinitialized,
 * \ref retro_audio_callback_t "all audio callbacks" will be updated
 * to target the newly-initialized driver.
 *
 * @param[in] data &lt;tt&gt;const unsigned *&lt;/tt&gt;.
 * Minimum audio latency, in milliseconds.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63

/**
 * Allows the core to tell the frontend when it should enable fast-forwarding,
 * rather than relying solely on the frontend and user interaction.
 *
 * Possible use cases include:
 *
 * \li Temporarily disabling a core's fastforward support
 *     while investigating a related bug.
 * \li Disabling fastforward during netplay sessions,
 *     or when using an emulated console's network features.
 * \li Automatically speeding up the game when in a loading screen
 *     that cannot be shortened with high-level emulation.
 *
 * @param[in] data &lt;tt&gt;const struct retro_fastforwarding_override *&lt;/tt&gt;.
 * Pointer to the parameters that decide when and how
 * the frontend is allowed to enable fast-forward mode.
 * May be \c NULL, in which case the frontend will return \c true
 * without updating the fastforward state,
 * which can be used to detect support for this environment call.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_fastforwarding_override
 * @see RETRO_ENVIRONMENT_GET_FASTFORWARDING
 */
#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64

#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65
                                           /* const struct retro_system_content_info_override * --
                                            * Allows an implementation to override 'global' content
                                            * info parameters reported by retro_get_system_info().
                                            * Overrides also affect subsystem content info parameters
                                            * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.
                                            * This function must be called inside retro_set_environment().
                                            * If callback returns false, content info overrides
                                            * are unsupported by the frontend, and will be ignored.
                                            * If callback returns true, extended game info may be
                                            * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
                                            * in retro_load_game() or retro_load_game_special().
                                            *
                                            * 'data' points to an array of retro_system_content_info_override
                                            * structs terminated by a { NULL, false, false } element.
                                            * If 'data' is NULL, no changes will be made to the frontend;
                                            * a core may therefore pass NULL in order to test whether
                                            * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported
                                            * by the frontend.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_system_content_info_override.
                                            *
                                            * Example:
                                            *
                                            * - struct retro_system_info:
                                            * {
                                            *    "My Core",                      // library_name
                                            *    "v1.0",                         // library_version
                                            *    "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
                                            *    true,                           // need_fullpath
                                            *    false                           // block_extract
                                            * }
                                            *
                                            * - Array of struct retro_system_content_info_override:
                                            * {
                                            *    {
                                            *       "md|sms|gg", // extensions
                                            *       false,       // need_fullpath
                                            *       true         // persistent_data
                                            *    },
                                            *    {
                                            *       "sg",        // extensions
                                            *       false,       // need_fullpath
                                            *       false        // persistent_data
                                            *    },
                                            *    { NULL, false, false }
                                            * }
                                            *
                                            * Result:
                                            * - Files of type m3u, cue, iso, chd will not be
                                            *   loaded by the frontend. Frontend will pass a
                                            *   valid path to the core, and core will handle
                                            *   loading internally
                                            * - Files of type md, sms, gg will be loaded by
                                            *   the frontend. A valid memory buffer will be
                                            *   passed to the core. This memory buffer will
                                            *   remain valid until retro_deinit() returns
                                            * - Files of type sg will be loaded by the frontend.
                                            *   A valid memory buffer will be passed to the core.
                                            *   This memory buffer will remain valid until
                                            *   retro_load_game() (or retro_load_game_special())
                                            *   returns
                                            *
                                            * NOTE: If an extension is listed multiple times in
                                            * an array of retro_system_content_info_override
                                            * structs, only the first instance will be registered
                                            */

#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66
                                           /* const struct retro_game_info_ext ** --
                                            * Allows an implementation to fetch extended game
                                            * information, providing additional content path
                                            * and memory buffer status details.
                                            * This function may only be called inside
                                            * retro_load_game() or retro_load_game_special().
                                            * If callback returns false, extended game information
                                            * is unsupported by the frontend. In this case, only
                                            * regular retro_game_info will be available.
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed
                                            * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
                                            * returns true.
                                            *
                                            * 'data' points to an array of retro_game_info_ext structs.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_game_info_ext.
                                            *
                                            * - If function is called inside retro_load_game(),
                                            *   the retro_game_info_ext array is guaranteed to
                                            *   have a size of 1 - i.e. the returned pointer may
                                            *   be used to access directly the members of the
                                            *   first retro_game_info_ext struct, for example:
                                            *
                                            *      struct retro_game_info_ext *game_info_ext;
                                            *      if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &amp;game_info_ext))
                                            *         printf("Content Directory: %s\n", game_info_ext-&gt;dir);
                                            *
                                            * - If the function is called inside retro_load_game_special(),
                                            *   the retro_game_info_ext array is guaranteed to have a
                                            *   size equal to the num_info argument passed to
                                            *   retro_load_game_special()
                                            */

/**
 * Defines a set of core options that can be shown and configured by the frontend,
 * so that the player may customize their gameplay experience to their liking.
 *
 * @note This environment call is intended to replace
 * \c RETRO_ENVIRONMENT_SET_VARIABLES and \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 2.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_v2 *&lt;/tt&gt;.
 * Pointer to a core's options and their associated categories.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available
 * and the frontend supports categories.
 * Note that this environment call is guaranteed to successfully register
 * the provided core options,
 * so the return value does not indicate success or failure.
 *
 * @see retro_core_options_v2
 * @see retro_core_option_v2_category
 * @see retro_core_option_v2_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 67

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * that supports internationalization.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_v2_intl for some important details.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_v2_intl *&lt;/tt&gt;.
 * Pointer to a core's option values and categories,
 * plus a translation for each option and category.
 * @see retro_core_options_v2_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL 68

/**
 * Registers a callback that the frontend can use
 * to notify the core that at least one core option
 * should be made hidden or visible.
 * Allows a frontend to signal that a core must update
 * the visibility of any dynamically hidden core options,
 * and enables the frontend to detect visibility changes.
 * Used by the frontend to update the menu display status
 * of core options without requiring a call of retro_run().
 * Must be called in retro_set_environment().
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_update_display_callback *&lt;/tt&gt;.
 * The callback that the frontend should use.
 * May be \c NULL, in which case the frontend will unset any existing callback.
 * Can be used to query visibility support.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_core_options_update_display_callback
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69

/**
 * Forcibly sets a core option's value.
 *
 * After changing a core option value with this callback,
 * it will be reflected in the frontend
 * and \ref RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE will return \c true.
 * \ref retro_variable::key must match
 * a \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 "previously-set core option",
 * and \ref retro_variable::value must match one of its defined values.
 *
 * Possible use cases include:
 *
 * @li Allowing the player to set certain core options
 *     without entering the frontend's option menu,
 *     using an in-core hotkey.
 * @li Adjusting invalid combinations of settings.
 * @li Migrating settings from older releases of a core.
 *
 * @param[in] data &lt;tt&gt;const struct retro_variable *&lt;/tt&gt;.
 * Pointer to a single option that the core is changing.
 * May be \c NULL, in which case the frontend will return \c true
 * to indicate that this environment call is available.
 * @return \c true if this environment call is available
 * and the option named by \c key was successfully
 * set to the given \c value.
 * \c false if the \c key or \c value fields are \c NULL, empty,
 * or don't match a previously set option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_SET_VARIABLE 70

#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
                                           /* struct retro_throttle_state * --
                                            * Allows an implementation to get details on the actual rate
                                            * the frontend is attempting to call retro_run().
                                            */

/**
 * Returns information about how the frontend will use savestates.
 *
 * @param[out] data &lt;tt&gt;retro_savestate_context *&lt;/tt&gt;.
 * Pointer to the current savestate context.
 * May be \c NULL, in which case the environment call
 * will return \c true to indicate its availability.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_savestate_context
 */
#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Before calling \c SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, will query which interface is supported.
 *
 * Frontend looks at \c retro_hw_render_interface_type and returns the maximum supported
 * context negotiation interface version. If the \c retro_hw_render_interface_type is not
 * supported or recognized by the frontend, a version of 0 must be returned in
 * \c retro_hw_render_interface's \c interface_version and \c true is returned by frontend.
 *
 * If this environment call returns true with a \c interface_version greater than 0,
 * a core can always use a negotiation interface version larger than what the frontend returns,
 * but only earlier versions of the interface will be used by the frontend.
 *
 * A frontend must not reject a negotiation interface version that is larger than what the
 * frontend supports. Instead, the frontend will use the older entry points that it recognizes.
 * If this is incompatible with a particular core's requirements, it can error out early.
 *
 * @note Regarding backwards compatibility, this environment call was introduced after Vulkan v1
 * context negotiation. If this environment call is not supported by frontend, i.e. the environment
 * call returns \c false , only Vulkan v1 context negotiation is supported (if Vulkan HW rendering
 * is supported at all). If a core uses Vulkan negotiation interface with version &gt; 1, negotiation
 * may fail unexpectedly. All future updates to the context negotiation interface implies that
 * frontend must support this environment call to query support.
 *
 * @param[out] data &lt;tt&gt;struct retro_hw_render_context_negotiation_interface *&lt;/tt&gt;.
 * @return \c true if the environment call is available.
 * @see SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see retro_hw_render_interface_type
 * @see retro_hw_render_context_negotiation_interface
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend whether JIT compilation can be used.
 * Primarily used by iOS and tvOS.
 * @param[out] data &lt;tt&gt;bool *&lt;/tt&gt;.
 * Set to \c true if the frontend has verified that JIT compilation is possible.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74

/**
 * Returns an interface that the core can use to receive microphone input.
 *
 * @param[out] data &lt;tt&gt;retro_microphone_interface *&lt;/tt&gt;.
 * Pointer to the microphone interface.
 * @return \true if microphone support is available,
 * even if no microphones are plugged in.
 * \c false if microphone support is disabled unavailable,
 * or if \c data is \c NULL.
 * @see retro_microphone_interface
 */
#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/* Environment 76 was an obsolete version of RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
* It was not used by any known core at the time, and was removed from the API. */

/**
 * Returns the device's current power state as reported by the frontend.
 *
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
 *
 * @param[out] data &lt;struct retro_device_power *&gt;.
 * Indicates whether the frontend can provide this information, even if the parameter
 * is \c NULL. If the frontend does not support this functionality, then the provided
 * argument will remain unchanged.
 * @return \c true if the environment call is available.
 * @see retro_device_power
 */
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 78
                                           /* const struct retro_netpacket_callback * --
                                            * When set, a core gains control over network packets sent and
                                            * received during a multiplayer session. This can be used to
                                            * emulate multiplayer games that were originally played on two
                                            * or more separate consoles or computers connected together.
                                            *
                                            * The frontend will take care of connecting players together,
                                            * and the core only needs to send the actual data as needed for
                                            * the emulation, while handshake and connection management happen
                                            * in the background.
                                            *
                                            * When two or more players are connected and this interface has
                                            * been set, time manipulation features (such as pausing, slow motion,
                                            * fast forward, rewinding, save state loading, etc.) are disabled to
                                            * avoid interrupting communication.
                                            *
                                            * Should be set in either retro_init or retro_load_game, but not both.
                                            *
                                            * When not set, a frontend may use state serialization-based
                                            * multiplayer, where a deterministic core supporting multiple
                                            * input devices does not need to take any action on its own.
                                            */

/**
 * Returns the device's current power state as reported by the frontend.
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * The return value indicates whether the frontend can provide this information,
 * even if the parameter is \c NULL.
 *
 * If the frontend does not support this functionality,
 * then the provided argument will remain unchanged.
 * @param[out] data &lt;tt&gt;retro_device_power *&lt;/tt&gt;.
 * Pointer to the information that the frontend returns about its power state.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_device_power
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
*/
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the "playlist" directory of the frontend.
 *
 * This directory can be used to store core generated playlists, in case
 * this internal functionality is available (e.g. internal core game detection
 * engine).
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_PLAYLIST_DIRECTORY 79

/**
 * Returns the "file browser" start directory of the frontend.
 *
 * This directory can serve as a start directory for the core in case it
 * provides an internal way of loading content.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY 80

/**
 * Returns the audio sample rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal sample rate.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the \c unsigned integer in which the frontend will store its target sample rate.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_SAMPLE_RATE (81 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**@}*/

/**
 * @defgroup GET_VFS_INTERFACE File System Interface
 * @brief File system functionality.
 *
 * @section File Paths
 * File paths passed to all libretro filesystem APIs shall be well formed UNIX-style,
 * using "/" (unquoted forward slash) as the directory separator
 * regardless of the platform's native separator.
 *
 * Paths shall also include at least one forward slash
 * (e.g. use "./game.bin" instead of "game.bin").
 *
 * Other than the directory separator, cores shall not make assumptions about path format.
 * The following paths are all valid:
 * @li \c C:/path/game.bin
 * @li \c http://example.com/game.bin
 * @li \c #game/game.bin
 * @li \c ./game.bin
 *
 * Cores may replace the basename or remove path components from the end, and/or add new components;
 * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request from the front end.
 *
 * The frontend is encouraged to do the best it can when given an ill-formed path,
 * but it is allowed to give up.
 *
 * Frontends are encouraged, but not required, to support native file system paths
 * (including replacing the directory separator, if applicable).
 *
 * Cores are allowed to try using them, but must remain functional if the frontend rejects such requests.
 *
 * Cores are encouraged to use the libretro-common filestream functions for file I/O,
 * as they seamlessly integrate with VFS,
 * deal with directory separator replacement as appropriate
 * and provide platform-specific fallbacks
 * in cases where front ends do not provide their own VFS interface.
 *
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 *
 * @{
 */

/**
 * Opaque file handle.
 * @since VFS API v1
 */
struct retro_vfs_file_handle;

/**
 * Opaque directory handle.
 * @since VFS API v3
 */
struct retro_vfs_dir_handle;

/** @defgroup RETRO_VFS_FILE_ACCESS File Access Flags
 * File access flags.
 * @since VFS API v1
 * @{
 */

/** Opens a file for read-only access. */
#define RETRO_VFS_FILE_ACCESS_READ            (1 &lt;&lt; 0)

/**
 * Opens a file for write-only access.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_WRITE           (1 &lt;&lt; 1)

/**
 * Opens a file for reading and writing.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_READ_WRITE      (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE)

/**
 * Opens a file without discarding its existing contents.
 * Only meaningful if \c RETRO_VFS_FILE_ACCESS_WRITE is specified.
 */
#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 &lt;&lt; 2) /* Prevents discarding content of existing files opened for writing */

/** @} */

/** @defgroup RETRO_VFS_FILE_ACCESS_HINT File Access Hints
 *
 * Hints to the frontend for how a file will be accessed.
 * The VFS implementation may use these to optimize performance,
 * react to external interference (such as concurrent writes),
 * or it may ignore them entirely.
 *
 * Hint flags do not change the behavior of each VFS function
 * unless otherwise noted.
 * @{
 */

/** No particular hints are given. */
#define RETRO_VFS_FILE_ACCESS_HINT_NONE              (0)

/**
 * Indicates that the file will be accessed frequently.
 *
 * The frontend should cache it or map it into memory.
 */
#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS   (1 &lt;&lt; 0)

/** @} */

/** @defgroup RETRO_VFS_SEEK_POSITION File Seek Positions
 * File access flags and hints.
 * @{
 */

/**
 * Indicates a seek relative to the start of the file.
 */
#define RETRO_VFS_SEEK_POSITION_START    0

/**
 * Indicates a seek relative to the current stream position.
 */
#define RETRO_VFS_SEEK_POSITION_CURRENT  1

/**
 * Indicates a seek relative to the end of the file.
 * @note The offset passed to \c retro_vfs_seek_t should be negative.
 */
#define RETRO_VFS_SEEK_POSITION_END      2

/** @} */

/** @defgroup RETRO_VFS_STAT File Status Flags
 * File stat flags.
 * @see retro_vfs_stat_t
 * @since VFS API v3
 * @{
 */

/** Indicates that the given path refers to a valid file. */
#define RETRO_VFS_STAT_IS_VALID               (1 &lt;&lt; 0)

/** Indicates that the given path refers to a directory. */
#define RETRO_VFS_STAT_IS_DIRECTORY           (1 &lt;&lt; 1)

/**
 * Indicates that the given path refers to a character special file,
 * such as \c /dev/null.
 */
#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL   (1 &lt;&lt; 2)

/** @} */

/**
 * Returns the path that was used to open this file.
 *
 * @param stream The opened file handle to get the path of.
 * Behavior is undefined if \c NULL or closed.
 * @return The path that was used to open \c stream.
 * The string is owned by \c stream and must not be modified.
 * @since VFS API v1
 * @see filestream_get_path
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);

/**
 * Open a file for reading or writing.
 *
 * @param path The path to open.
 * @param mode A bitwise combination of \c RETRO_VFS_FILE_ACCESS flags.
 * At a minimum, one of \c RETRO_VFS_FILE_ACCESS_READ or \c RETRO_VFS_FILE_ACCESS_WRITE must be specified.
 * @param hints A bitwise combination of \c RETRO_VFS_FILE_ACCESS_HINT flags.
 * @return A handle to the opened file,
 * or \c NULL upon failure.
 * Note that this will return \c NULL if \c path names a directory.
 * The returned file handle must be closed with \c retro_vfs_close_t.
 * @since VFS API v1
 * @see File Paths
 * @see RETRO_VFS_FILE_ACCESS
 * @see RETRO_VFS_FILE_ACCESS_HINT
 * @see retro_vfs_close_t
 * @see filestream_open
 */
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);

/**
 * Close the file and release its resources.
 * All files returned by \c retro_vfs_open_t must be closed with this function.
 *
 * @param stream The file handle to close.
 * Behavior is undefined if already closed.
 * Upon completion of this function, \c stream is no longer valid
 * (even if it returns failure).
 * @return 0 on success, -1 on failure or if \c stream is \c NULL.
 * @see retro_vfs_open_t
 * @see filestream_close
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);

/**
 * Return the size of the file in bytes.
 *
 * @param stream The file to query the size of.
 * @return Size of the file in bytes, or -1 if there was an error.
 * @see filestream_get_size
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);

/**
 * Set the file's length.
 *
 * @param stream The file whose length will be adjusted.
 * @param length The new length of the file, in bytes.
 * If shorter than the original length, the extra bytes will be discarded.
 * If longer, the file's padding is unspecified (and likely platform-dependent).
 * @return 0 on success,
 * -1 on failure.
 * @see filestream_truncate
 * @since VFS API v2
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);

/**
 * Gets the given file's current read/write position.
 * This position is advanced with each call to \c retro_vfs_read_t or \c retro_vfs_write_t.
 *
 * @param stream The file to query the position of.
 * @return The current stream position in bytes
 * or -1 if there was an error.
 * @see filestream_tell
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);

/**
 * Sets the given file handle's current read/write position.
 *
 * @param stream The file to set the position of.
 * @param offset The new position, in bytes.
 * @param seek_position The position to seek from.
 * @return The new position,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see File Seek Positions
 * @see filestream_seek
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);

/**
 * Read data from a file, if it was opened for reading.
 *
 * @param stream The file to read from.
 * @param s The buffer to read into.
 * @param len The number of bytes to read.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes read,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_read
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);

/**
 * Write data to a file, if it was opened for writing.
 *
 * @param stream The file handle to write to.
 * @param s The buffer to write from.
 * @param len The number of bytes to write.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes written,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_write
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);

/**
 * Flush pending writes to the file, if applicable.
 *
 * This does not mean that the changes will be immediately persisted to disk;
 * that may be scheduled for later, depending on the platform.
 *
 * @param stream The file handle to flush.
 * @return 0 on success, -1 on failure.
 * @since VFS API v1
 * @see filestream_flush
 */
typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);

/**
 * Deletes the file at the given path.
 *
 * @param path The path to the file that will be deleted.
 * @return 0 on success, -1 on failure.
 * @see filestream_delete
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);

/**
 * Rename the specified file.
 *
 * @param old_path Path to an existing file.
 * @param new_path The destination path.
 * Must not name an existing file.
 * @return 0 on success, -1 on failure
 * @see filestream_rename
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);

/**
 * Gets information about the given file.
 *
 * @param path The path to the file to query.
 * @param[out] size The reported size of the file in bytes.
 * May be \c NULL, in which case this value is ignored.
 * @return A bitmask of \c RETRO_VFS_STAT flags,
 * or 0 if \c path doesn't refer to a valid file.
 * @see path_stat
 * @see path_get_size
 * @see RETRO_VFS_STAT
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);

/**
 * Creates a directory at the given path.
 *
 * @param dir The desired location of the new directory.
 * @return 0 if the directory was created,
 * -2 if the directory already exists,
 * or -1 if some other error occurred.
 * @see path_mkdir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);

/**
 * Opens a handle to a directory so its contents can be inspected.
 *
 * @param dir The path to the directory to open.
 * Must be an existing directory.
 * @param include_hidden Whether to include hidden files in the directory listing.
 * The exact semantics of this flag will depend on the platform.
 * @return A handle to the opened directory,
 * or \c NULL if there was an error.
 * @see retro_opendir
 * @since VFS API v3
 */
typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);

/**
 * Gets the next dirent ("directory entry")
 * within the given directory.
 *
 * @param[in,out] dirstream The directory to read from.
 * Updated to point to the next file, directory, or other path.
 * @return \c true when the next dirent was retrieved,
 * \c false if there are no more dirents to read.
 * @note This API iterates over all files and directories within \c dirstream.
 * Remember to check what the type of the current dirent is.
 * @note This function does not recurse,
 * i.e. it does not return the contents of subdirectories.
 * @note This may include "." and ".." on Unix-like platforms.
 * @see retro_readdir
 * @see retro_vfs_dirent_is_dir_t
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Gets the filename of the current dirent.
 *
 * The returned string pointer is valid
 * until the next call to \c retro_vfs_readdir_t or \c retro_vfs_closedir_t.
 *
 * @param dirstream The directory to read from.
 * @return The current dirent's name,
 * or \c NULL if there was an error.
 * @note This function only returns the file's \em name,
 * not a complete path to it.
 * @see retro_dirent_get_name
 * @since VFS API v3
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Checks whether the current dirent names a directory.
 *
 * @param dirstream The directory to read from.
 * @return \c true if \c dirstream's current dirent points to a directory,
 * \c false if not or if there was an error.
 * @see retro_dirent_is_dir
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Closes the given directory and release its resources.
 *
 * Must be called on any \c retro_vfs_dir_handle returned by \c retro_vfs_open_t.
 *
 * @param dirstream The directory to close.
 * When this function returns (even failure),
 * \c dirstream will no longer be valid and must not be used.
 * @return 0 on success, -1 on failure.
 * @see retro_closedir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * File system interface exposed by the frontend.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface
{
   /* VFS API v1 */
   /** @copydoc retro_vfs_get_path_t */
	retro_vfs_get_path_t get_path;

   /** @copydoc retro_vfs_open_t */
	retro_vfs_open_t open;

   /** @copydoc retro_vfs_close_t */
	retro_vfs_close_t close;

   /** @copydoc retro_vfs_size_t */
	retro_vfs_size_t size;

   /** @copydoc retro_vfs_tell_t */
	retro_vfs_tell_t tell;

   /** @copydoc retro_vfs_seek_t */
	retro_vfs_seek_t seek;

   /** @copydoc retro_vfs_read_t */
	retro_vfs_read_t read;

   /** @copydoc retro_vfs_write_t */
	retro_vfs_write_t write;

   /** @copydoc retro_vfs_flush_t */
	retro_vfs_flush_t flush;

   /** @copydoc retro_vfs_remove_t */
	retro_vfs_remove_t remove;

   /** @copydoc retro_vfs_rename_t */
	retro_vfs_rename_t rename;
   /* VFS API v2 */

   /** @copydoc retro_vfs_truncate_t */
   retro_vfs_truncate_t truncate;
   /* VFS API v3 */

   /** @copydoc retro_vfs_stat_t */
   retro_vfs_stat_t stat;

   /** @copydoc retro_vfs_mkdir_t */
   retro_vfs_mkdir_t mkdir;

   /** @copydoc retro_vfs_opendir_t */
   retro_vfs_opendir_t opendir;

   /** @copydoc retro_vfs_readdir_t */
   retro_vfs_readdir_t readdir;

   /** @copydoc retro_vfs_dirent_get_name_t */
   retro_vfs_dirent_get_name_t dirent_get_name;

   /** @copydoc retro_vfs_dirent_is_dir_t */
   retro_vfs_dirent_is_dir_t dirent_is_dir;

   /** @copydoc retro_vfs_closedir_t */
   retro_vfs_closedir_t closedir;
};

/**
 * Represents a request by the core for the frontend's file system interface,
 * as well as the interface itself returned by the frontend.
 *
 * You do not need to use these functions directly;
 * you may pass this struct to \c dirent_vfs_init,
 * \c filestream_vfs_init, or \c path_vfs_init
 * so that you can use the wrappers provided by these modules.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface_info
{
   /**
    * The minimum version of the VFS API that the core requires.
    * libretro-common's wrapper API initializers will check this value as well.
    *
    * Set to the core's desired VFS version when requesting an interface,
    * and set by the frontend to indicate its actual API version.
    *
    * If the core asks for a newer VFS API version than the frontend supports,
    * the frontend must return \c false within the \c RETRO_ENVIRONMENT_GET_VFS_INTERFACE call.
    * @since VFS API v1
    */
   uint32_t required_interface_version;

   /**
    * Set by the frontend.
    * The frontend will set this to the VFS interface it provides.
    *
    * The interface is owned by the frontend
    * and must not be modified or freed by the core.
    * @since VFS API v1 */
   struct retro_vfs_interface *iface;
};

/** @} */

/** @defgroup GET_HW_RENDER_INTERFACE Hardware Rendering Interface
 * @{
 */

/**
 * Describes the hardware rendering API supported by
 * a particular subtype of \c retro_hw_render_interface.
 *
 * Not every rendering API supported by libretro has its own interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_interface_type
{
   /**
    * Indicates a \c retro_hw_render_interface for Vulkan.
    * @see retro_hw_render_interface_vulkan
    */
   RETRO_HW_RENDER_INTERFACE_VULKAN     = 0,

   /** Indicates a \c retro_hw_render_interface for Direct3D 9. */
   RETRO_HW_RENDER_INTERFACE_D3D9       = 1,

   /** Indicates a \c retro_hw_render_interface for Direct3D 10. */
   RETRO_HW_RENDER_INTERFACE_D3D10      = 2,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 11.
    * @see retro_hw_render_interface_d3d11
    */
   RETRO_HW_RENDER_INTERFACE_D3D11      = 3,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 12.
    * @see retro_hw_render_interface_d3d12
    */
   RETRO_HW_RENDER_INTERFACE_D3D12      = 4,

   /**
    * Indicates a \c retro_hw_render_interface for
    * the PlayStation's 2 PSKit API.
    * @see retro_hw_render_interface_gskit_ps2
    */
   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2  = 5,

   /** @private Defined to ensure &lt;tt&gt;sizeof(retro_hw_render_interface_type) == sizeof(int)&lt;/tt&gt;.
    * Do not use. */
   RETRO_HW_RENDER_INTERFACE_DUMMY      = INT_MAX
};

/**
 * Base render interface type.
 * All \c retro_hw_render_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
struct retro_hw_render_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_interface_type interface_type;

   /**
    * The version of this rendering interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/**
 * @defgroup GET_LED_INTERFACE LED Interface
 * @{
 */

/** @copydoc retro_led_interface::set_led_state */
typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);

/**
 * Interface that the core can use to set the state of available LEDs.
 * @see RETRO_ENVIRONMENT_GET_LED_INTERFACE
 */
struct retro_led_interface
{
   /**
    * Sets the state of an LED.
    *
    * @param led The LED to set the state of.
    * @param state The state to set the LED to.
    * \c true to enable, \c false to disable.
    */
   retro_set_led_state_t set_led_state;
};

/** @} */

/** @defgroup GET_AUDIO_VIDEO_ENABLE Skipped A/V Steps
 * @{
 */

/**
 * Flags that define A/V steps that the core may skip for this frame.
 *
 * @see RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE
 */
enum retro_av_enable_flags
{
   /**
    * If set, the core should render video output with \c retro_video_refresh_t as normal.
    *
    * Otherwise, the frontend will discard any video data received this frame,
    * including frames presented via hardware acceleration.
    * \c retro_video_refresh_t will do nothing.
    *
    * @note After running the frame, the video output of the next frame
    * should be no different than if video was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's graphics pipeline state
    * should not be affected by this flag.
    *
    * @note If emulating a platform that supports display capture
    * (i.e. reading its own VRAM),
    * the core may not be able to completely skip rendering,
    * as the VRAM is part of the graphics pipeline's state.
    */
   RETRO_AV_ENABLE_VIDEO = (1 &lt;&lt; 0),

   /**
    * If set, the core should render audio output
    * with \c retro_audio_sample_t or \c retro_audio_sample_batch_t as normal.
    *
    * Otherwise, the frontend will discard any audio data received this frame.
    * The core should skip audio rendering if possible.
    *
    * @note After running the frame, the audio output of the next frame
    * should be no different than if audio was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's audio pipeline state
    * should not be affected by this flag.
    */
   RETRO_AV_ENABLE_AUDIO = (1 &lt;&lt; 1),

   /**
    * If set, indicates that any savestates taken this frame
    * are guaranteed to be created by the same binary that will load them,
    * and will not be written to or read from the disk.
    *
    * The core may use these guarantees to:
    *
    * @li Assume that loading state will succeed.
    * @li Update its memory buffers in-place if possible.
    * @li Skip clearing memory.
    * @li Skip resetting the system.
    * @li Skip validation steps.
    *
    * @deprecated Use \c RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT instead,
    * except for compatibility purposes.
    */
   RETRO_AV_ENABLE_FAST_SAVESTATES = (1 &lt;&lt; 2),

   /**
    * If set, indicates that the frontend will never need audio from the core.
    * Used by a frontend for implementing runahead via a secondary core instance.
    *
    * The core may stop synthesizing audio if it can do so
    * without compromising emulation accuracy.
    *
    * Audio output for the next frame does not matter,
    * and the frontend will never need an accurate audio state in the future.
    *
    * State will never be saved while this flag is set.
    */
   RETRO_AV_ENABLE_HARD_DISABLE_AUDIO = (1 &lt;&lt; 3),

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(retro_av_enable_flags) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_AV_ENABLE_DUMMY = INT_MAX
};

/** @} */

/**
 * @defgroup GET_MIDI_INTERFACE MIDI Interface
 * @{
 */

/** @copydoc retro_midi_interface::input_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);

/** @copydoc retro_midi_interface::output_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);

/** @copydoc retro_midi_interface::read */
typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);

/** @copydoc retro_midi_interface::write */
typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);

/** @copydoc retro_midi_interface::flush */
typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);

/**
 * Interface that the core can use for raw MIDI I/O.
 */
struct retro_midi_interface
{
   /**
    * Retrieves the current state of MIDI input.
    *
    * @return \c true if MIDI input is enabled.
    */
   retro_midi_input_enabled_t input_enabled;

   /**
    * Retrieves the current state of MIDI output.
    * @return \c true if MIDI output is enabled.
    */
   retro_midi_output_enabled_t output_enabled;

   /**
    * Reads a byte from the MIDI input stream.
    *
    * @param[out] byte The byte received from the input stream.
    * @return \c true if a byte was read,
    * \c false if MIDI input is disabled or \c byte is \c NULL.
    */
   retro_midi_read_t read;

   /**
    * Writes a byte to the output stream.
    *
    * @param byte The byte to write to the output stream.
    * @param delta_time Time since the previous write, in microseconds.
    * @return \c true if c\ byte was written, false otherwise.
    */
   retro_midi_write_t write;

   /**
    * Flushes previously-written data.
    *
    * @return \c true if successful.
    */
   retro_midi_flush_t flush;
};

/** @} */

/** @defgroup SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE Render Context Negotiation
 * @{
 */

/**
 * Describes the hardware rendering API used by
 * a particular subtype of \c retro_hw_render_context_negotiation_interface.
 *
 * Not every rendering API supported by libretro has a context negotiation interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_context_negotiation_interface_type
{
   /**
    * Denotes a context negotiation interface for Vulkan.
    * @see retro_hw_render_context_negotiation_interface_vulkan
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(retro_hw_render_context_negotiation_interface_type) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX
};

/**
 * Base context negotiation interface type.
 * All \c retro_hw_render_context_negotiation_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 */
struct retro_hw_render_context_negotiation_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_context_negotiation_interface_type interface_type;

   /**
    * The version of this negotiation interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/** @defgroup RETRO_SERIALIZATION_QUIRK Serialization Quirks
 * @{
 */

/**
 * Indicates that serialized state is incomplete in some way.
 *
 * Set if serialization is usable for the common case of saving and loading game state,
 * but should not be relied upon for frame-sensitive frontend features
 * such as netplay or rerecording.
 */
#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 &lt;&lt; 0)

/**
 * Indicates that core must spend some time initializing before serialization can be done.
 *
 * \c retro_serialize(), \c retro_unserialize(), and \c retro_serialize_size() will initially fail.
 */
#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 &lt;&lt; 1)

/** Set by the core to indicate that serialization size may change within a session. */
#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 &lt;&lt; 2)

/** Set by the frontend to acknowledge that it supports variable-sized states. */
#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 &lt;&lt; 3)

/** Serialized state can only be loaded during the same session. */
#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 &lt;&lt; 4)

/**
 * Serialized state cannot be loaded on an architecture
 * with a different endianness from the one it was saved on.
 */
#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 &lt;&lt; 5)

/**
 * Serialized state cannot be loaded on a different platform
 * from the one it was saved on for reasons other than endianness,
 * such as word size dependence.
 */
#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 &lt;&lt; 6)

/** @} */

/** @defgroup SET_MEMORY_MAPS Memory Descriptors
 * @{
 */

/** @defgroup RETRO_MEMDESC Memory Descriptor Flags
 * Information about how the emulated hardware uses this portion of its address space.
 * @{
 */

/**
 * Indicates that this memory area won't be modified
 * once \c retro_load_game has returned.
 */
#define RETRO_MEMDESC_CONST      (1 &lt;&lt; 0)

/**
 * Indicates a memory area with big-endian byte ordering,
 * as opposed to the default of little-endian.
 */
#define RETRO_MEMDESC_BIGENDIAN  (1 &lt;&lt; 1)

/**
 * Indicates a memory area that is used for the emulated system's main RAM.
 */
#define RETRO_MEMDESC_SYSTEM_RAM (1 &lt;&lt; 2)

/**
 * Indicates a memory area that is used for the emulated system's save RAM,
 * usually found on a game cartridge as battery-backed RAM or flash memory.
 */
#define RETRO_MEMDESC_SAVE_RAM   (1 &lt;&lt; 3)

/**
 * Indicates a memory area that is used for the emulated system's video RAM,
 * usually found on a console's GPU (or local equivalent).
 */
#define RETRO_MEMDESC_VIDEO_RAM  (1 &lt;&lt; 4)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 2 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_2    (1 &lt;&lt; 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 4 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_4    (2 &lt;&lt; 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 8 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_8    (3 &lt;&lt; 16)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 2 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_2  (1 &lt;&lt; 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 4 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_4  (2 &lt;&lt; 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 8 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_8  (3 &lt;&lt; 24)

/** @} */

/**
 * A mapping from a region of the emulated console's address space
 * to the host's address space.
 *
 * Can be used to map an address in the console's address space
 * to the host's address space, like so:
 *
 * @code
 * void* emu_to_host(void* addr, struct retro_memory_descriptor* descriptor)
 * {
 *     return descriptor-&gt;ptr + (addr &amp; ~descriptor-&gt;disconnect) - descriptor-&gt;start;
 * }
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_descriptor
{
   /**
    * A bitwise \c OR of one or more \ref RETRO_MEMDESC "flags"
    * that describe how the emulated system uses this descriptor's address range.
    *
    * @note If \c ptr is \c NULL,
    * then no flags should be set.
    * @see RETRO_MEMDESC
    */
   uint64_t flags;

   /**
    * Pointer to the start of this memory region's buffer
    * within the \em host's address space.
    * The address listed here must be valid for the duration of the session;
    * it must not be freed or modified by the frontend
    * and it must not be moved by the core.
    *
    * May be \c NULL to indicate a lack of accessible memory
    * at the emulated address given in \c start.
    *
    * @note Overlapping descriptors that include the same byte
    * must have the same \c ptr value.
    */
   void *ptr;

   /**
    * The offset of this memory region,
    * relative to the address given by \c ptr.
    *
    * @note It is recommended to use this field for address calculations
    * instead of performing arithmetic on \c ptr.
    */
   size_t offset;

   /**
    * The starting address of this memory region
    * &lt;em&gt;within the emulated hardware's address space&lt;/em&gt;.
    *
    * @note Not represented as a pointer
    * because it's unlikely to be valid on the host device.
    */
   size_t start;

   /**
    * A bitmask that specifies which bits of an address must match
    * the bits of the \ref start address.
    *
    * Combines with \c disconnect to map an address to a memory block.
    *
    * If multiple memory descriptors can claim a particular byte,
    * the first one defined in the \ref retro_memory_descriptor array applies.
    * A bit which is set in \c start must also be set in this.
    *
    * Can be zero, in which case \c start and \c len represent
    * the complete mapping for this region of memory
    * (i.e. each byte is mapped exactly once).
    * In this case, \c len must be a power of two.
    */
   size_t select;

   /**
    * A bitmask of bits that are \em not used for addressing.
    *
    * Any set bits are assumed to be disconnected from
    * the emulated memory chip's address pins,
    * and are therefore ignored when memory-mapping.
    */
   size_t disconnect;

   /**
    * The length of this memory region, in bytes.
    *
    * If applying \ref start and \ref disconnect to an address
    * results in a value higher than this,
    * the highest bit of the address is cleared.
    *
    * If the address is still too high, the next highest bit is cleared.
    * Can be zero, in which case it's assumed to be
    * bounded only by \ref select and \ref disconnect.
    */
   size_t len;

   /**
    * A short name for this address space.
    *
    * Names must meet the following requirements:
    *
    * \li Characters must be in the set &lt;tt&gt;[a-zA-Z0-9_-]&lt;/tt&gt;.
    * \li No more than 8 characters, plus a \c NULL terminator.
    * \li Names are case-sensitive, but lowercase characters are discouraged.
    * \li A name must not be the same as another name plus a character in the set \c [A-F0-9]
    *     (i.e. if an address space named "RAM" exists,
    *     then the names "RAM0", "RAM1", ..., "RAMF" are forbidden).
    *     This is to allow addresses to be named by each descriptor unambiguously,
    *     even if the areas overlap.
    * \li May be \c NULL or empty (both are considered equivalent).
    *
    * Here are some examples of pairs of address space names:
    *
    * \li \em blank + \em blank: valid (multiple things may be mapped in the same namespace)
    * \li \c Sp + \c Sp: valid (multiple things may be mapped in the same namespace)
    * \li \c SRAM + \c VRAM: valid (neither is a prefix of the other)
    * \li \c V + \em blank: valid (\c V is not in \c [A-F0-9])
    * \li \c a + \em blank: valid but discouraged (\c a is not in \c [A-F0-9])
    * \li \c a + \c A: valid but discouraged (neither is a prefix of the other)
    * \li \c AR + \em blank: valid (\c R is not in \c [A-F0-9])
    * \li \c ARB + \em blank: valid (there's no \c AR namespace,
    *     so the \c B doesn't cause ambiguity).
    * \li \em blank + \c B: invalid, because it's ambiguous which address space \c B1234 would refer to.
    *
    * The length of the address space's name can't be used to disambugiate,
    * as extra information may be appended to it without a separator.
    */
   const char *addrspace;

   /* TODO: When finalizing this one, add a description field, which should be
    * "WRAM" or something roughly equally long. */

   /* TODO: When finalizing this one, replace 'select' with 'limit', which tells
    * which bits can vary and still refer to the same address (limit = ~select).
    * TODO: limit? range? vary? something else? */

   /* TODO: When finalizing this one, if 'len' is above what 'select' (or
    * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'
    * and 'select' != 0, and the mappings don't tell how the system switches the
    * banks. */

   /* TODO: When finalizing this one, fix the 'len' bit removal order.
    * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.
    * Algorithm: Take bits highest to lowest, but if it goes above len, clear
    * the most recent addition and continue on the next bit.
    * TODO: Can the above be optimized? Is "remove the lowest bit set in both
    * pointer and 'len'" equivalent? */

   /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing
    * the emulated memory in 32-bit chunks, native endian. But that's nothing
    * compared to Darek Mihocka &lt;http://www.emulators.com/docs/nx07_vm101.htm&gt;
    * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE
    * RAM backwards! I'll want to represent both of those, via some flags.
    *
    * I suspect MAME either didn't think of that idea, or don't want the #ifdef.
    * Not sure which, nor do I really care. */

   /* TODO: Some of those flags are unused and/or don't really make sense. Clean
    * them up. */
};

/**
 * A list of regions within the emulated console's address space.
 *
 * The frontend may use the largest value of
 * \ref retro_memory_descriptor::start + \ref retro_memory_descriptor::select
 * in a certain namespace to infer the overall size of the address space.
 * If the address space is larger than that,
 * the last mapping in \ref descriptors should have \ref retro_memory_descriptor::ptr set to \c NULL
 * and \ref retro_memory_descriptor::select should have all bits used in the address space set to 1.
 *
 * Here's an example set of descriptors for the SNES.
 *
 * @code{.c}
 * struct retro_memory_map snes_descriptors = retro_memory_map
 * {
 *    .descriptors = (struct retro_memory_descriptor[])
 *    {
 *       // WRAM; must usually be mapped before the ROM,
 *       // as some SNES ROM mappers try to claim 0x7E0000
 *       { .addrspace="WRAM", .start=0x7E0000, .len=0x20000 },
 *
 *       // SPC700 RAM
 *       { .addrspace="SPC700", .len=0x10000 },
 *
 *       // WRAM mirrors
 *       { .addrspace="WRAM", .start=0x000000, .select=0xC0E000, .len=0x2000 },
 *       { .addrspace="WRAM", .start=0x800000, .select=0xC0E000, .len=0x2000 },
 *
 *       // WRAM mirror, alternate equivalent descriptor
 *       // (Various similar constructions can be created by combining parts of the above two.)
 *       { .addrspace="WRAM", .select=0x40E000, .disconnect=~0x1FFF },
 *
 *       // LoROM (512KB, mirrored a couple of times)
 *       { .addrspace="LoROM", .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="LoROM", .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *
 *       // HiROM (4MB)
 *       { .addrspace="HiROM", .start=0x400000, .select=0x400000, .len=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="HiROM", .start=0x008000, .select=0x408000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // ExHiROM (8MB)
 *       { .addrspace="ExHiROM", .start=0xC00000, .select=0xC00000, .len=4*1024*1024, .offset=0, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x400000, .select=0xC00000, .len=4*1024*1024, .offset=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x808000, .select=0xC08000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x008000, .select=0xC08000, .len=4*1024*1024, .offset=4*1024*1024+0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // Clarifying the full size of the address space
 *       { .select=0xFFFFFF, .ptr=NULL },
 *    },
 *    .num_descriptors = 14,
 * };
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_map
{
   /**
    * Pointer to an array of memory descriptors,
    * each of which describes part of the emulated console's address space.
    */
   const struct retro_memory_descriptor *descriptors;

   /** The number of descriptors in \c descriptors. */
   unsigned num_descriptors;
};

/** @} */

/** @defgroup SET_CONTROLLER_INFO Controller Info
 * @{
 */

/**
 * Details about a controller (or controller configuration)
 * supported by one of a core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_description
{
   /**
    * A human-readable label for the controller or configuration
    * represented by this device type.
    * Most likely the device's original brand name.
    */
   const char *desc;

   /**
    * A unique identifier that will be passed to \c retro_set_controller_port_device()'s \c device parameter.
    * May be the ID of one of \ref RETRO_DEVICE "the generic controller types",
    * or a subclass ID defined with \c RETRO_DEVICE_SUBCLASS.
    *
    * @see RETRO_DEVICE_SUBCLASS
    */
   unsigned id;
};

/**
 * Lists the types of controllers supported by
 * one of core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_info
{

   /**
    * A pointer to an array of device types supported by this controller port.
    *
    * @note Ports that support the same devices
    * may share the same underlying array.
    */
   const struct retro_controller_description *types;

   /** The number of elements in \c types. */
   unsigned num_types;
};

/** @} */

/** @defgroup SET_SUBSYSTEM_INFO Subsystems
 * @{
 */

/**
 * Information about a type of memory associated with a subsystem.
 * Usually used for SRAM (save RAM).
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_get_memory_data
 * @see retro_get_memory_size
 */
struct retro_subsystem_memory_info
{
   /**
    * The file extension the frontend should use
    * to save this memory region to disk, e.g. "srm" or "sav".
    */
   const char *extension;

   /**
    * A constant that identifies this type of memory.
    * Should be at least 0x100 (256) to avoid conflict
    * with the standard libretro memory types,
    * unless a subsystem uses the main platform's memory region.
    * @see RETRO_MEMORY
    */
   unsigned type;
};

/**
 * Information about a type of ROM that a subsystem may use.
 * Subsystems may use one or more ROMs at once,
 * possibly of different types.
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_subsystem_info
 */
struct retro_subsystem_rom_info
{
   /**
    * Human-readable description of what the content represents,
    * e.g. "Game Boy ROM".
    */
   const char *desc;

   /** @copydoc retro_system_info::valid_extensions */
   const char *valid_extensions;

   /** @copydoc retro_system_info::need_fullpath */
   bool need_fullpath;

   /** @copydoc retro_system_info::block_extract */
   bool block_extract;

   /**
    * Indicates whether this particular subsystem ROM is required.
    * If \c true and the user doesn't provide a ROM,
    * the frontend should not load the core.
    * If \c false and the user doesn't provide a ROM,
    * the frontend should pass a zeroed-out \c retro_game_info
    * to the corresponding entry in \c retro_load_game_special().
    */
   bool required;

   /**
    * Pointer to an array of memory descriptors that this subsystem ROM type uses.
    * Useful for secondary cartridges that have their own save data.
    * May be \c NULL, in which case this subsystem ROM's memory is not persisted by the frontend
    * and \c num_memory should be zero.
    */
   const struct retro_subsystem_memory_info *memory;

   /** The number of elements in the array pointed to by \c memory. */
   unsigned num_memory;
};

/**
 * Information about a secondary platform that a core supports.
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 */
struct retro_subsystem_info
{
   /**
    * A human-readable description of the subsystem type,
    * usually the brand name of the original platform
    * (e.g. "Super Game Boy").
    */
   const char *desc;

   /**
    * A short machine-friendly identifier for the subsystem,
    * usually an abbreviation of the platform name.
    * For example, a Super Game Boy subsystem for a SNES core
    * might use an identifier of "sgb".
    * This identifier can be used for command-line interfaces,
    * configuration, or other purposes.
    * Must use lower-case alphabetical characters only (i.e. from a-z).
    */
   const char *ident;

   /**
    * The list of ROM types that this subsystem may use.
    *
    * The first entry is considered to be the "most significant" content,
    * for the purposes of the frontend's categorization.
    * E.g. with Super GameBoy, the first content should be the GameBoy ROM,
    * as it is the most "significant" content to a user.
    *
    * If a frontend creates new files based on the content used (e.g. for savestates),
    * it should derive the filenames from the name of the first ROM in this list.
    *
    * @note \c roms can have a single element,
    * but this is usually a sign that the core should broaden its
    * primary system info instead.
    *
    * @see \c retro_system_info
    */
   const struct retro_subsystem_rom_info *roms;

   /** The length of the array given in \c roms. */
   unsigned num_roms;

   /** A unique identifier passed to retro_load_game_special(). */
   unsigned id;
};

/** @} */

/** @defgroup SET_PROC_ADDRESS_CALLBACK Core Function Pointers
 * @{ */

/**
 * The function pointer type that \c retro_get_proc_address_t returns.
 *
 * Despite the signature shown here, the original function may include any parameters and return type
 * that respects the calling convention and C ABI.
 *
 * The frontend is expected to cast the function pointer to the correct type.
 */
typedef void (RETRO_CALLCONV *retro_proc_address_t)(void);

/**
 * Get a symbol from a libretro core.
 *
 * Cores should only return symbols that serve as libretro extensions.
 * Frontends should not use this to obtain symbols to standard libretro entry points;
 * instead, they should link to the core statically or use \c dlsym (or local equivalent).
 *
 * The symbol name must be equal to the function name.
 * e.g. if &lt;tt&gt;void retro_foo(void);&lt;/tt&gt; exists, the symbol in the compiled library must be called \c retro_foo.
 * The returned function pointer must be cast to the corresponding type.
 *
 * @param \c sym The name of the symbol to look up.
 * @return Pointer to the exposed function with the name given in \c sym,
 * or \c NULL if one couldn't be found.
 * @note The frontend is expected to know the returned pointer's type in advance
 * so that it can be cast correctly.
 * @note The core doesn't need to expose every possible function through this interface.
 * It's enough to only expose the ones that it expects the frontend to use.
 * @note The functions exposed through this interface
 * don't need to be publicly exposed in the compiled library
 * (e.g. via \c __declspec(dllexport)).
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);

/**
 * An interface that the frontend can use to get function pointers from the core.
 *
 * @note The returned function pointer will be invalidated once the core is unloaded.
 * How and when that happens is up to the frontend.
 *
 * @see retro_get_proc_address_t
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
struct retro_get_proc_address_interface
{
   /** Set by the core. */
   retro_get_proc_address_t get_proc_address;
};

/** @} */

/** @defgroup GET_LOG_INTERFACE Logging
 * @{
 */

/**
 * The severity of a given message.
 * The frontend may log messages differently depending on the level.
 * It may also ignore log messages of a certain level.
 * @see retro_log_callback
 */
enum retro_log_level
{
   /** The logged message is most likely not interesting to the user. */
   RETRO_LOG_DEBUG = 0,

   /** Information about the core operating normally. */
   RETRO_LOG_INFO,

   /** Indicates a potential problem, possibly one that the core can recover from. */
   RETRO_LOG_WARN,

   /** Indicates a degraded experience, if not failure. */
   RETRO_LOG_ERROR,

   /** Defined to ensure that sizeof(enum retro_log_level) == sizeof(int). Do not use. */
   RETRO_LOG_DUMMY = INT_MAX
};

/**
 * Logs a message to the frontend.
 *
 * @param level The log level of the message.
 * @param fmt The format string to log.
 * Same format as \c printf.
 * Behavior is undefined if this is \c NULL.
 * @param ... Zero or more arguments used by the format string.
 * Behavior is undefined if these don't match the ones expected by \c fmt.
 * @see retro_log_level
 * @see retro_log_callback
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see printf
 */
typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,
      const char *fmt, ...);

/**
 * Details about how to make log messages.
 *
 * @see retro_log_printf_t
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 */
struct retro_log_callback
{
   /**
    * Called when logging a message.
    *
    * @note Set by the frontend.
    */
   retro_log_printf_t log;
};

/** @} */

/** @defgroup GET_PERF_INTERFACE Performance Interface
 * @{
 */

/** @defgroup RETRO_SIMD CPU Features
 * @{
 */

/**
 * Indicates CPU support for the SSE instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE
 */
#define RETRO_SIMD_SSE      (1 &lt;&lt; 0)

/**
 * Indicates CPU support for the SSE2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE2
 */
#define RETRO_SIMD_SSE2     (1 &lt;&lt; 1)

/** Indicates CPU support for the AltiVec (aka VMX or Velocity Engine) instruction set. */
#define RETRO_SIMD_VMX      (1 &lt;&lt; 2)

/** Indicates CPU support for the VMX128 instruction set. Xbox 360 only. */
#define RETRO_SIMD_VMX128   (1 &lt;&lt; 3)

/**
 * Indicates CPU support for the AVX instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX
 */
#define RETRO_SIMD_AVX      (1 &lt;&lt; 4)

/**
 * Indicates CPU support for the NEON instruction set.
 * @see https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[Neon]
 */
#define RETRO_SIMD_NEON     (1 &lt;&lt; 5)

/**
 * Indicates CPU support for the SSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE3
 */
#define RETRO_SIMD_SSE3     (1 &lt;&lt; 6)

/**
 * Indicates CPU support for the SSSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSSE3
 */
#define RETRO_SIMD_SSSE3    (1 &lt;&lt; 7)

/**
 * Indicates CPU support for the MMX instruction set.
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=MMX
 */
#define RETRO_SIMD_MMX      (1 &lt;&lt; 8)

/** Indicates CPU support for the MMXEXT instruction set. */
#define RETRO_SIMD_MMXEXT   (1 &lt;&lt; 9)

/**
 * Indicates CPU support for the SSE4 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_1
 */
#define RETRO_SIMD_SSE4     (1 &lt;&lt; 10)

/**
 * Indicates CPU support for the SSE4.2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_2
 */
#define RETRO_SIMD_SSE42    (1 &lt;&lt; 11)

/**
 * Indicates CPU support for the AVX2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX2
 */
#define RETRO_SIMD_AVX2     (1 &lt;&lt; 12)

/** Indicates CPU support for the VFPU instruction set. PS2 and PSP only.
 *
 * @see https://pspdev.github.io/vfpu-docs
 */
#define RETRO_SIMD_VFPU     (1 &lt;&lt; 13)

/**
 * Indicates CPU support for Gekko SIMD extensions. GameCube only.
 */
#define RETRO_SIMD_PS       (1 &lt;&lt; 14)

/**
 * Indicates CPU support for AES instructions.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#aestechs=AES&amp;othertechs=AES
 */
#define RETRO_SIMD_AES      (1 &lt;&lt; 15)

/**
 * Indicates CPU support for the VFPv3 instruction set.
 */
#define RETRO_SIMD_VFPV3    (1 &lt;&lt; 16)

/**
 * Indicates CPU support for the VFPv4 instruction set.
 */
#define RETRO_SIMD_VFPV4    (1 &lt;&lt; 17)

/** Indicates CPU support for the POPCNT instruction. */
#define RETRO_SIMD_POPCNT   (1 &lt;&lt; 18)

/** Indicates CPU support for the MOVBE instruction. */
#define RETRO_SIMD_MOVBE    (1 &lt;&lt; 19)

/** Indicates CPU support for the CMOV instruction. */
#define RETRO_SIMD_CMOV     (1 &lt;&lt; 20)

/** Indicates CPU support for the ASIMD instruction set. */
#define RETRO_SIMD_ASIMD    (1 &lt;&lt; 21)

/** @} */

/**
 * An abstract unit of ticks.
 *
 * Usually nanoseconds or CPU cycles,
 * but it depends on the platform and the frontend.
 */
typedef uint64_t retro_perf_tick_t;

/** Time in microseconds. */
typedef int64_t retro_time_t;

/**
 * A performance counter.
 *
 * Use this to measure the execution time of a region of code.
 * @see retro_perf_callback
 */
struct retro_perf_counter
{
   /**
    * A human-readable identifier for the counter.
    *
    * May be displayed by the frontend.
    * Behavior is undefined if this is \c NULL.
    */
   const char *ident;

   /**
    * The time of the most recent call to \c retro_perf_callback::perf_start
    * on this performance counter.
    *
    * @see retro_perf_start_t
    */
   retro_perf_tick_t start;

   /**
    * The total time spent within this performance counter's measured code,
    * i.e. between calls to \c retro_perf_callback::perf_start and \c retro_perf_callback::perf_stop.
    *
    * Updated after each call to \c retro_perf_callback::perf_stop.
    * @see retro_perf_stop_t
    */
   retro_perf_tick_t total;

   /**
    * The number of times this performance counter has been started.
    *
    * Updated after each call to \c retro_perf_callback::perf_start.
    * @see retro_perf_start_t
    */
   retro_perf_tick_t call_cnt;

   /**
    * \c true if this performance counter has been registered by the frontend.
    * Must be initialized to \c false by the core before registering it.
    * @see retro_perf_register_t
    */
   bool registered;
};

/**
 * @returns The current system time in microseconds.
 * @note Accuracy may vary by platform.
 * The frontend should use the most accurate timer possible.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);

/**
 * @returns The number of ticks since some unspecified epoch.
 * The exact meaning of a "tick" depends on the platform,
 * but it usually refers to nanoseconds or CPU cycles.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);

/**
 * Returns a bitmask of detected CPU features.
 *
 * Use this for runtime dispatching of CPU-specific code.
 *
 * @returns A bitmask of detected CPU features.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see RETRO_SIMD
 */
typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);

/**
 * Asks the frontend to log or display the state of performance counters.
 * How this is done depends on the frontend.
 * Performance counters can be reviewed manually as well.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see retro_perf_counter
 */
typedef void (RETRO_CALLCONV *retro_perf_log_t)(void);

/**
 * Registers a new performance counter.
 *
 * If \c counter has already been registered beforehand,
 * this function does nothing.
 *
 * @param counter The counter to register.
 * \c counter::ident must be set to a unique identifier,
 * and all other values in \c counter must be set to zero or \c false.
 * Behavior is undefined if \c NULL.
 * @post If \c counter is successfully registered,
 * then \c counter::registered will be set to \c true.
 * Otherwise, it will be set to \c false.
 * Registration may fail if the frontend's maximum number of counters (if any) has been reached.
 * @note The counter is owned by the core and must not be freed by the frontend.
 * The frontend must also clean up any references to a core's performance counters
 * before unloading it, otherwise undefined behavior may occur.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);

/**
 * Starts a registered performance counter.
 *
 * Call this just before the code you want to measure.
 *
 * @param counter The counter to start.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);

/**
 * Stops a registered performance counter.
 *
 * Call this just after the code you want to measure.
 *
 * @param counter The counter to stop.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);

/**
 * An interface that the core can use to get performance information.
 *
 * Here's a usage example:
 *
 * @code{.c}
 * #ifdef PROFILING
 * // Wrapper macros to simplify using performance counters.
 * // Optional; tailor these to your project's needs.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&amp;(name))
 * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&amp;(name))
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&amp;(name))
 * #else
 * // Exclude the performance counters if profiling is disabled.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_START(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) ((void)0)
 * #endif
 *
 * // Defined somewhere else in the core.
 * extern struct retro_perf_callback perf_cb;
 *
 * void retro_run(void)
 * {
 *    RETRO_PERFORMANCE_INIT(cb, interesting);
 *    RETRO_PERFORMANCE_START(cb, interesting);
 *    interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, interesting);
 *
 *    RETRO_PERFORMANCE_INIT(cb, maybe_slow);
 *    RETRO_PERFORMANCE_START(cb, maybe_slow);
 *    more_interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, maybe_slow);
 * }
 *
 * void retro_deinit(void)
 * {
 *    // Asks the frontend to log the results of all performance counters.
 *    perf_cb.perf_log();
 * }
 * @endcode
 *
 * All functions are set by the frontend.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
struct retro_perf_callback
{
   /** @copydoc retro_perf_get_time_usec_t */
   retro_perf_get_time_usec_t    get_time_usec;

   /** @copydoc retro_perf_get_counter_t */
   retro_get_cpu_features_t      get_cpu_features;

   /** @copydoc retro_perf_get_counter_t */
   retro_perf_get_counter_t      get_perf_counter;

   /** @copydoc retro_perf_register_t */
   retro_perf_register_t         perf_register;

   /** @copydoc retro_perf_start_t */
   retro_perf_start_t            perf_start;

   /** @copydoc retro_perf_stop_t */
   retro_perf_stop_t             perf_stop;

   /** @copydoc retro_perf_log_t */
   retro_perf_log_t              perf_log;
};

/** @} */

/**
 * @defgroup RETRO_SENSOR Sensor Interface
 * @{
 */

/**
 * Defines actions that can be performed on sensors.
 * @note Cores should only enable sensors while they're actively being used;
 * depending on the frontend and platform,
 * enabling these sensors may impact battery life.
 *
 * @see RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE
 * @see retro_sensor_interface
 * @see retro_set_sensor_state_t
 */
enum retro_sensor_action
{
   /** Enables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,

   /** Disables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_DISABLE,

   /** Enables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_ENABLE,

   /** Disables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_DISABLE,

   /** Enables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_ENABLE,

   /** Disables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_DISABLE,

   /** @private Defined to ensure &lt;tt&gt;sizeof(enum retro_sensor_action) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_SENSOR_DUMMY = INT_MAX
};

/** @defgroup RETRO_SENSOR_ID Sensor Value IDs
 * @{
 */
/* Id values for SENSOR types. */

/**
 * Returns the device's acceleration along its local X axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating to the right.
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_X 0

/**
 * Returns the device's acceleration along its local Y axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating upwards,
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Y 1

/**
 * Returns the the device's acceleration along its local Z axis minus the effect of gravity, in m/s^2.
 *
 * Positive values indicate forward acceleration towards the user,
 * assuming the user is looking at the device head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Z 2

/**
 * Returns the angular velocity of the device around its local X axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_X 3

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Y 4

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Z 5

/**
 * Returns the ambient illuminance (light intensity) of the device's environment, in lux.
 *
 * @see https://en.wikipedia.org/wiki/Lux for a table of common lux values.
 */
#define RETRO_SENSOR_ILLUMINANCE 6
/** @} */

/**
 * Adjusts the state of a sensor.
 *
 * @param port The device port of the controller that owns the sensor given in \c action.
 * @param action The action to perform on the sensor.
 * Different devices support different sensors.
 * @param rate The rate at which the underlying sensor should be updated, in Hz.
 * This should be treated as a hint,
 * as some device sensors may not support the requested rate
 * (if it's configurable at all).
 * @returns \c true if the sensor state was successfully adjusted, \c false otherwise.
 * @note If one of the \c RETRO_SENSOR_*_ENABLE actions fails,
 * this likely means that the given sensor is not available
 * on the provided \c port.
 * @see retro_sensor_action
 */
typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
      enum retro_sensor_action action, unsigned rate);

/**
 * Retrieves the current value reported by sensor.
 * @param port The device port of the controller that owns the sensor given in \c id.
 * @param id The sensor value to query.
 * @returns The current sensor value.
 * Exact semantics depend on the value given in \c id,
 * but will return 0 for invalid arguments.
 *
 * @see RETRO_SENSOR_ID
 */
typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);

/**
 * An interface that cores can use to access device sensors.
 *
 * All function pointers are set by the frontend.
 */
struct retro_sensor_interface
{
   /** @copydoc retro_set_sensor_state_t */
   retro_set_sensor_state_t set_sensor_state;

   /** @copydoc retro_sensor_get_input_t */
   retro_sensor_get_input_t get_sensor_input;
};

/** @} */

/** @defgroup GET_CAMERA_INTERFACE Camera Interface
 * @{
 */

/**
 * Denotes the type of buffer in which the camera will store its input.
 *
 * Different camera drivers may support different buffer types.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 * @see retro_camera_callback
 */
enum retro_camera_buffer
{
   /**
    * Indicates that camera frames should be delivered to the core as an OpenGL texture.
    *
    * Requires that the core is using an OpenGL context via \c RETRO_ENVIRONMENT_SET_HW_RENDER.
    *
    * @see retro_camera_frame_opengl_texture_t
    */
   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,

   /**
    * Indicates that camera frames should be delivered to the core as a raw buffer in memory.
    *
    * @see retro_camera_frame_raw_framebuffer_t
    */
   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(enum retro_camera_buffer) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
};

/**
 * Starts an initialized camera.
 * The camera is disabled by default,
 * and must be enabled with this function before being used.
 *
 * Set by the frontend.
 *
 * @returns \c true if the camera was successfully started, \c false otherwise.
 * Failure may occur if no actual camera is available,
 * or if the frontend doesn't have permission to access it.
 * @note Must be called in \c retro_run().
 * @see retro_camera_callback
 */
typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);

/**
 * Stops the running camera.
 *
 * Set by the frontend.
 *
 * @note Must be called in \c retro_run().
 * @warning The frontend may close the camera on its own when unloading the core,
 * but this behavior is not guaranteed.
 * Cores should clean up the camera before exiting.
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);

/**
 * Called by the frontend to report the state of the camera driver.
 *
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as a raw buffer in memory.
 *
 * Set by the core.
 *
 * @param buffer Pointer to the camera's most recent video frame.
 * Each pixel is in XRGB8888 format.
 * The first pixel represents the top-left corner of the image
 * (i.e. the Y axis goes downward).
 * @param width The width of the frame given in \c buffer, in pixels.
 * @param height The height of the frame given in \c buffer, in pixels.
 * @param pitch The width of the frame given in \c buffer, in bytes.
 * @warning \c buffer may be invalidated when this function returns,
 * so the core should make its own copy of \c buffer if necessary.
 * @see RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
      unsigned width, unsigned height, size_t pitch);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as an OpenGL texture.
 *
 * @param texture_id The ID of the OpenGL texture that represents the camera's most recent frame.
 * Owned by the frontend, and must not be modified by the core.
 * @param texture_target The type of the texture given in \c texture_id.
 * Usually either \c GL_TEXTURE_2D or \c GL_TEXTURE_RECTANGLE,
 * but other types are allowed.
 * @param affine A pointer to a 3x3 column-major affine matrix
 * that can be used to transform pixel coordinates to texture coordinates.
 * After transformation, the bottom-left corner should have coordinates of &lt;tt&gt;(0, 0)&lt;/tt&gt;
 * and the top-right corner should have coordinates of &lt;tt&gt;(1, 1)&lt;/tt&gt;
 * (or &lt;tt&gt;(width, height)&lt;/tt&gt; for \c GL_TEXTURE_RECTANGLE).
 *
 * @note GL-specific typedefs (e.g. \c GLfloat and \c GLuint) are avoided here
 * so that the API doesn't rely on gl.h.
 * @warning \c texture_id and \c affine may be invalidated when this function returns,
 * so the core should make its own copy of them if necessary.
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,
      unsigned texture_target, const float *affine);

/**
 * An interface that the core can use to access a device's camera.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 */
struct retro_camera_callback
{
   /**
    * Requested camera capabilities,
    * given as a bitmask of \c retro_camera_buffer values.
    * Set by the core.
    *
    * Here's a usage example:
    * @code
    * // Requesting support for camera data delivered as both an OpenGL texture and a pixel buffer:
    * struct retro_camera_callback callback;
    * callback.caps = (1 &lt;&lt; RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 &lt;&lt; RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);
    * @endcode
    */
   uint64_t caps;

   /**
    * The desired width of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
    * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned width;

   /**
    * The desired height of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
     * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned height;

   /**
    * @copydoc retro_camera_start_t
    * @see retro_camera_callback
    */
   retro_camera_start_t start;

   /**
    * @copydoc retro_camera_stop_t
    * @see retro_camera_callback
    */
   retro_camera_stop_t stop;

   /**
    * @copydoc retro_camera_frame_raw_framebuffer_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;

   /**
    * @copydoc retro_camera_frame_opengl_texture_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_opengl_texture_t frame_opengl_texture;

   /**
    * Core-defined callback invoked by the frontend right after the camera driver is initialized
    * (\em not when calling \c start).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t initialized;

   /**
    * Core-defined callback invoked by the frontend
    * right before the video camera driver is deinitialized
    * (\em not when calling \c stop).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t deinitialized;
};

/** @} */

/** @defgroup GET_LOCATION_INTERFACE Location Interface
 * @{
 */

/** @copydoc retro_location_callback::set_interval */
typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,
      unsigned interval_distance);

/** @copydoc retro_location_callback::start */
typedef bool (RETRO_CALLCONV *retro_location_start_t)(void);

/** @copydoc retro_location_callback::stop */
typedef void (RETRO_CALLCONV *retro_location_stop_t)(void);

/** @copydoc retro_location_callback::get_position */
typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,
      double *horiz_accuracy, double *vert_accuracy);

/** Function type that reports the status of the location service. */
typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);

/**
 * An interface that the core can use to access a device's location.
 *
 * @note It is the frontend's responsibility to request the necessary permissions
 * from the operating system.
 * @see RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE
 */
struct retro_location_callback
{
   /**
    * Starts listening the device's location service.
    *
    * The frontend will report changes to the device's location
    * at the interval defined by \c set_interval.
    * Set by the frontend.
    *
    * @return true if location services were successfully started, false otherwise.
    * Note that this will return \c false if location services are disabled
    * or the frontend doesn't have permission to use them.
    * @note The device's location service may or may not have been enabled
    * before the core calls this function.
    */
   retro_location_start_t         start;

   /**
    * Stop listening to the device's location service.
    *
    * Set by the frontend.
    *
    * @note The location service itself may or may not
    * be turned off by this function,
    * depending on the platform and the frontend.
    * @post The core will stop receiving location service updates.
    */
   retro_location_stop_t          stop;

   /**
    * Returns the device's current coordinates.
    *
    * Set by the frontend.
    *
    * @param[out] lat Pointer to latitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] lon Pointer to longitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] horiz_accuracy Pointer to horizontal accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] vert_accuracy Pointer to vertical accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    */
   retro_location_get_position_t  get_position;

   /**
    * Sets the rate at which the location service should report updates.
    *
    * This is only a hint; the actual rate may differ.
    * Sets the interval of time and/or distance at which to update/poll
    * location-based data.
    *
    * Some platforms may only support one of the two parameters;
    * cores should provide both to ensure compatibility.
    *
    * Set by the frontend.
    *
    * @param interval_ms The desired period of time between location updates, in milliseconds.
    * @param interval_distance The desired distance between location updates, in meters.
    */
   retro_location_set_interval_t  set_interval;

   /** Called when the location service is initialized. Set by the core. Optional. */
   retro_location_lifetime_status_t initialized;

   /** Called when the location service is deinitialized. Set by the core. Optional. */
   retro_location_lifetime_status_t deinitialized;
};

/** @} */

/** @addtogroup GET_RUMBLE_INTERFACE
 * @{ */

/**
 * The type of rumble motor in a controller.
 *
 * Both motors can be controlled independently,
 * and the strong motor does not override the weak motor.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
enum retro_rumble_effect
{
   RETRO_RUMBLE_STRONG = 0,
   RETRO_RUMBLE_WEAK = 1,

   /** @private Defined to ensure &lt;tt&gt;sizeof(enum retro_rumble_effect) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_RUMBLE_DUMMY = INT_MAX
};

/**
 * Requests a rumble state change for a controller.
 * Set by the frontend.
 *
 * @param port The controller port to set the rumble state for.
 * @param effect The rumble motor to set the strength of.
 * @param strength The desired intensity of the rumble motor, ranging from \c 0 to \c 0xffff (inclusive).
 * @return \c true if the requested rumble state was honored.
 * If the controller doesn't support rumble, will return \c false.
 * @note Calling this before the first \c retro_run() may return \c false.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,
      enum retro_rumble_effect effect, uint16_t strength);

/**
 * An interface that the core can use to set the rumble state of a controller.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
struct retro_rumble_interface
{
   /** @copydoc retro_set_rumble_state_t */
   retro_set_rumble_state_t set_rumble_state;
};

/** @} */

/**
 * Called by the frontend to request audio samples.
 * The core should render audio within this function
 * using the callback provided by \c retro_set_audio_sample or \c retro_set_audio_sample_batch.
 *
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_sample_batch_t
 * @see retro_audio_sample_t
 */
typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);

/**
 * Called by the frontend to notify the core that it should pause or resume audio rendering.
 * The initial state of the audio driver after registering this callback is \c false (inactive).
 *
 * @param enabled \c true if the frontend's audio driver is active.
 * If so, the registered audio callback will be called regularly.
 * If not, the audio callback will not be invoked until the next time
 * the frontend calls this function with \c true.
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @note Even if no audio samples are rendered,
 * the core should continue to update its emulated platform's audio engine if necessary.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_callback_t
 */
typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);

/**
 * An interface that the frontend uses to request audio samples from the core.
 * @note To unregister a callback, pass a \c retro_audio_callback_t
 * with both fields set to &lt;tt&gt;NULL&lt;/tt&gt;.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 */
struct retro_audio_callback
{
   /** @see retro_audio_callback_t */
   retro_audio_callback_t callback;

   /** @see retro_audio_set_state_callback_t */
   retro_audio_set_state_callback_t set_state;
};

typedef int64_t retro_usec_t;

/**
 * Called right before each iteration of \c retro_run
 * if registered via &lt;tt&gt;RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK&lt;/tt&gt;.
 *
 * @param usec Time since the last call to &lt;tt&gt;retro_run&lt;/tt&gt;, in microseconds.
 * If the frontend is manipulating the frame time
 * (e.g. via fast-forward or slow motion),
 * this value will be the reference value initially provided to the environment call.
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 * @see retro_frame_time_callback
 */
typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);

/**
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
struct retro_frame_time_callback
{
   /**
    * Called to notify the core of the current frame time.
    * If &lt;tt&gt;NULL&lt;/tt&gt;, the frontend will clear its registered callback.
    */
   retro_frame_time_callback_t callback;

   /**
    * The ideal duration of one frame, in microseconds.
    * Compute it as &lt;tt&gt;1000000 / fps&lt;/tt&gt;.
    * The frontend will resolve rounding to ensure that framestepping, etc is exact.
    */
   retro_usec_t reference;
};

/** @defgroup SET_AUDIO_BUFFER_STATUS_CALLBACK Audio Buffer Occupancy
 * @{
 */

/**
 * Notifies a libretro core of how full the frontend's audio buffer is.
 * Set by the core, called by the frontend.
 * It will be called right before \c retro_run() every frame.
 *
 * @param active \c true if the frontend's audio buffer is currently in use,
 * \c false if audio is disabled in the frontend.
 * @param occupancy A value between 0 and 100 (inclusive),
 * corresponding to the frontend's audio buffer occupancy percentage.
 * @param underrun_likely \c true if the frontend expects an audio buffer underrun
 * during the next frame, which indicates that a core should attempt frame-skipping.
 */
typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
      bool active, unsigned occupancy, bool underrun_likely);

/**
 * A callback to register with the frontend to receive audio buffer occupancy information.
 */
struct retro_audio_buffer_status_callback
{
   /** @copydoc retro_audio_buffer_status_callback_t */
   retro_audio_buffer_status_callback_t callback;
};

/** @} */

/* Pass this to retro_video_refresh_t if rendering to hardware.
 * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
 * */
#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)

/* Invalidates the current HW context.
 * Any GL state is lost, and must not be deinitialized explicitly.
 * If explicit deinitialization is desired by the libretro core,
 * it should implement context_destroy callback.
 * If called, all GPU resources must be reinitialized.
 * Usually called when frontend reinits video driver.
 * Also called first time video driver is initialized,
 * allowing libretro core to initialize resources.
 */
typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);

/* Gets current framebuffer which is to be rendered to.
 * Could change every frame potentially.
 */
typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);

/* Get a symbol from HW context. */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);

enum retro_hw_context_type
{
   RETRO_HW_CONTEXT_NONE             = 0,
   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
   RETRO_HW_CONTEXT_OPENGL           = 1,
   /* OpenGL ES 2.0. */
   RETRO_HW_CONTEXT_OPENGLES2        = 2,
   /* Modern desktop core GL context. Use version_major/
    * version_minor fields to set GL version. */
   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,
   /* OpenGL ES 3.0 */
   RETRO_HW_CONTEXT_OPENGLES3        = 4,
   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
    * use the corresponding enums directly. */
   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,

   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
   RETRO_HW_CONTEXT_VULKAN           = 6,

   /* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D11            = 7,

   /* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D10            = 8,

   /* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D12            = 9,

   /* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D9             = 10,

   /** Dummy value to ensure sizeof(enum retro_hw_context_type) == sizeof(int). Do not use. */
   RETRO_HW_CONTEXT_DUMMY = INT_MAX
};

struct retro_hw_render_callback
{
   /* Which API to use. Set by libretro core. */
   enum retro_hw_context_type context_type;

   /* Called when a context has been created or when it has been reset.
    * An OpenGL context is only valid after context_reset() has been called.
    *
    * When context_reset is called, OpenGL resources in the libretro
    * implementation are guaranteed to be invalid.
    *
    * It is possible that context_reset is called multiple times during an
    * application lifecycle.
    * If context_reset is called without any notification (context_destroy),
    * the OpenGL context was lost and resources should just be recreated
    * without any attempt to "free" old resources.
    */
   retro_hw_context_reset_t context_reset;

   /* Set by frontend.
    * TODO: This is rather obsolete. The frontend should not
    * be providing preallocated framebuffers. */
   retro_hw_get_current_framebuffer_t get_current_framebuffer;

   /* Set by frontend.
    * Can return all relevant functions, including glClear on Windows. */
   retro_hw_get_proc_address_t get_proc_address;

   /* Set if render buffers should have depth component attached.
    * TODO: Obsolete. */
   bool depth;

   /* Set if stencil buffers should be attached.
    * TODO: Obsolete. */
   bool stencil;

   /* If depth and stencil are true, a packed 24/8 buffer will be added.
    * Only attaching stencil is invalid and will be ignored. */

   /* Use conventional bottom-left origin convention. If false,
    * standard libretro top-left origin semantics are used.
    * TODO: Move to GL specific interface. */
   bool bottom_left_origin;

   /* Major version number for core GL context or GLES 3.1+. */
   unsigned version_major;

   /* Minor version number for core GL context or GLES 3.1+. */
   unsigned version_minor;

   /* If this is true, the frontend will go very far to avoid
    * resetting context in scenarios like toggling fullscreen, etc.
    * TODO: Obsolete? Maybe frontend should just always assume this ...
    */
   bool cache_context;

   /* The reset callback might still be called in extreme situations
    * such as if the context is lost beyond recovery.
    *
    * For optimal stability, set this to false, and allow context to be
    * reset at any time.
    */

   /* A callback to be called before the context is destroyed in a
    * controlled way by the frontend. */
   retro_hw_context_reset_t context_destroy;

   /* OpenGL resources can be deinitialized cleanly at this step.
    * context_destroy can be set to NULL, in which resources will
    * just be destroyed without any notification.
    *
    * Even when context_destroy is non-NULL, it is possible that
    * context_reset is called without any destroy notification.
    * This happens if context is lost by external factors (such as
    * notified by GL_ARB_robustness).
    *
    * In this case, the context is assumed to be already dead,
    * and the libretro implementation must not try to free any OpenGL
    * resources in the subsequent context_reset.
    */

   /* Creates a debug context. */
   bool debug_context;
};

/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
 * Called by the frontend in response to keyboard events.
 * down is set if the key is being pressed, or false if it is being released.
 * keycode is the RETROK value of the char.
 * character is the text character of the pressed key. (UTF-32).
 * key_modifiers is a set of RETROKMOD values or'ed together.
 *
 * The pressed/keycode state can be independent of the character.
 * It is also possible that multiple characters are generated from a
 * single keypress.
 * Keycode events should be treated separately from character events.
 * However, when possible, the frontend should try to synchronize these.
 * If only a character is posted, keycode should be RETROK_UNKNOWN.
 *
 * Similarly if only a keycode event is generated with no corresponding
 * character, character should be 0.
 */
typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,
      uint32_t character, uint16_t key_modifiers);

struct retro_keyboard_callback
{
   retro_keyboard_event_t callback;
};

/** @defgroup SET_DISK_CONTROL_INTERFACE Disk Control
 *
 * Callbacks for inserting and removing disks from the emulated console at runtime.
 * Should be provided by cores that support doing so.
 * Cores should automate this process if possible,
 * but some cases require the player's manual input.
 *
 * The steps for swapping disk images are generally as follows:
 *
 * \li Eject the emulated console's disk drive with \c set_eject_state(true).
 * \li Insert the new disk image with \c set_image_index(index).
 * \li Close the virtual disk tray with \c set_eject_state(false).
 *
 * @{
 */

/**
 * Called by the frontend to open or close the emulated console's virtual disk tray.
 *
 * The frontend may only set the disk image index
 * while the emulated tray is opened.
 *
 * If the emulated console's disk tray is already in the state given by \c ejected,
 * then this function should return \c true without doing anything.
 * The core should return \c false if it couldn't change the disk tray's state;
 * this may happen if the console itself limits when the disk tray can be open or closed
 * (e.g. to wait for the disc to stop spinning).
 *
 * @param ejected \c true if the virtual disk tray should be "ejected",
 * \c false if it should be "closed".
 * @return \c true if the virtual disk tray's state has been set to the given state,
 * false if there was an error.
 * @see retro_get_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);

/**
 * Gets the current ejected state of the disk drive.
 * The initial state is closed, i.e. \c false.
 *
 * @return \c true if the virtual disk tray is "ejected",
 * i.e. it's open and a disk can be inserted.
 * @see retro_set_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);

/**
 * Gets the index of the current disk image,
 * as determined by however the frontend orders disk images
 * (such as m3u-formatted playlists or special directories).
 *
 * @return The index of the current disk image
 * (starting with 0 for the first disk),
 * or a value greater than or equal to \c get_num_images() if no disk is inserted.
 * @see retro_get_num_images_t
 */
typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);

/**
 * Inserts the disk image at the given index into the emulated console's drive.
 * Can only be called while the disk tray is ejected
 * (i.e. \c retro_get_eject_state_t returns \c true).
 *
 * If the emulated disk tray is ejected
 * and already contains the disk image named by \c index,
 * then this function should do nothing and return \c true.
 *
 * @param index The index of the disk image to insert,
 * starting from 0 for the first disk.
 * A value greater than or equal to \c get_num_images()
 * represents the frontend removing the disk without inserting a new one.
 * @return \c true if the disk image was successfully set.
 * \c false if the disk tray isn't ejected or there was another error
 * inserting a new disk image.
 */
typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);

/**
 * @return The number of disk images which are available to use.
 * These are most likely defined in a playlist file.
 */
typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);

struct retro_game_info;

/**
 * Replaces the disk image at the given index with a new disk.
 *
 * Replaces the disk image associated with index.
 * Arguments to pass in info have same requirements as retro_load_game().
 * Virtual disk tray must be ejected when calling this.
 *
 * Passing \c NULL to this function indicates
 * that the frontend has removed this disk image from its internal list.
 * As a result, calls to this function can change the number of available disk indexes.
 *
 * For example, calling &lt;tt&gt;replace_image_index(1, NULL)&lt;/tt&gt;
 * will remove the disk image at index 1,
 * and the disk image at index 2 (if any)
 * will be moved to the newly-available index 1.
 *
 * @param index The index of the disk image to replace.
 * @param info Details about the new disk image,
 * or \c NULL if the disk image at the given index should be discarded.
 * The semantics of each field are the same as in \c retro_load_game.
 * @return \c true if the disk image was successfully replaced
 * or removed from the playlist,
 * \c false if the tray is not ejected
 * or if there was an error.
 */
typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
      const struct retro_game_info *info);

/**
 * Adds a new index to the core's internal disk list.
 * This will increment the return value from \c get_num_images() by 1.
 * This image index cannot be used until a disk image has been set
 * with \c replace_image_index.
 *
 * @return \c true if the core has added space for a new disk image
 * and is ready to receive one.
 */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);

/**
 * Sets the disk image that will be inserted into the emulated disk drive
 * before \c retro_load_game is called.
 *
 * \c retro_load_game does not provide a way to ensure
 * that a particular disk image in a playlist is inserted into the console;
 * this function makes up for that.
 * Frontends should call it immediately before \c retro_load_game,
 * and the core should use the arguments
 * to validate the disk image in \c retro_load_game.
 *
 * When content is loaded, the core should verify that the
 * disk specified by \c index can be found at \c path.
 * This is to guard against auto-selecting the wrong image
 * if (for example) the user should modify an existing M3U playlist.
 * We have to let the core handle this because
 * \c set_initial_image() must be called before loading content,
 * i.e. the frontend cannot access image paths in advance
 * and thus cannot perform the error check itself.
 * If \c index is invalid (i.e. &lt;tt&gt;index &gt;= get_num_images()&lt;/tt&gt;)
 * or the disk image doesn't match the value given in \c path,
 * the core should ignore the arguments
 * and insert the disk at index 0 into the virtual disk tray.
 *
 * @warning If \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE is called within \c retro_load_game,
 * then this function may not be executed.
 * Set the disk control interface in \c retro_init if possible.
 *
 * @param index The index of the disk image within the playlist to set.
 * @param path The path of the disk image to set as the first.
 * The core should not load this path immediately;
 * instead, it should use it within \c retro_load_game
 * to verify that the correct disk image was loaded.
 * @return \c true if the initial disk index was set,
 * \c false if the arguments are invalid
 * or the core doesn't support this function.
 */
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);

/**
 * Returns the path of the disk image at the given index
 * on the host's file system.
 *
 * @param index The index of the disk image to get the path of.
 * @param s A buffer to store the path in.
 * @param len The size of \c s, in bytes.
 * @return \c true if the disk image's location was successfully
 * queried and copied into \c s,
 * \c false if the index is invalid
 * or the core couldn't locate the disk image.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *s, size_t len);

/**
 * Returns a friendly label for the given disk image.
 *
 * In the simplest case, this may be the disk image's file name
 * with the extension omitted.
 * For cores or games with more complex content requirements,
 * the label can be used to provide information to help the player
 * select a disk image to insert;
 * for example, a core may label different kinds of disks
 * (save data, level disk, installation disk, bonus content, etc.).
 * with names that correspond to in-game prompts,
 * so that the frontend can provide better guidance to the player.
 *
 * @param index The index of the disk image to return a label for.
 * @param s A buffer to store the resulting label in.
 * @param len The length of \c s, in bytes.
 * @return \c true if the disk image at \c index is valid
 * and a label was copied into \c s.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *s, size_t len);

/**
 * An interface that the frontend can use to exchange disks
 * within the emulated console's disk drive.
 *
 * All function pointers are required.
 *
 * @deprecated This struct is superseded by \ref retro_disk_control_ext_callback.
 * Only use this one to maintain compatibility
 * with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * @see retro_disk_control_ext_callback
 */
struct retro_disk_control_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;
};

/**
 * @copybrief retro_disk_control_callback
 *
 * All function pointers are required unless otherwise noted.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
struct retro_disk_control_ext_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;

   /** @copydoc retro_set_initial_image_t
    *
    * Optional; not called if \c NULL.
    *
    * @note The frontend will only try to record/restore the last-used disk index
    * if both \c set_initial_image and \c get_image_path are implemented.
    */
   retro_set_initial_image_t set_initial_image;

   /**
    * @copydoc retro_get_image_path_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_path_t get_image_path;

   /**
    * @copydoc retro_get_image_label_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_label_t get_image_label;
};

/** @} */

/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
 * A core can set it if sending and receiving custom network packets
 * during a multiplayer session is desired.
 */

/* Netpacket flags for retro_netpacket_send_t */
#define RETRO_NETPACKET_UNRELIABLE  0        /* Packet to be sent unreliable, depending on network quality it might not arrive. */
#define RETRO_NETPACKET_RELIABLE    (1 &lt;&lt; 0) /* Reliable packets are guaranteed to arrive at the target in the order they were sent. */
#define RETRO_NETPACKET_UNSEQUENCED (1 &lt;&lt; 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */
#define RETRO_NETPACKET_FLUSH_HINT  (1 &lt;&lt; 2) /* Request the packet and any previously buffered ones to be sent immediately */

/* Broadcast client_id for retro_netpacket_send_t */
#define RETRO_NETPACKET_BROADCAST 0xFFFF

/* Used by the core to send a packet to one or all connected players.
 * A single packet sent via this interface can contain up to 64 KB of data.
 *
 * The client_id RETRO_NETPACKET_BROADCAST sends the packet as a broadcast to
 * all connected players. This is supported from the host as well as clients.
*  Otherwise, the argument indicates the player to send the packet to.
 *
 * A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).
 * Unreliable packets might not be supported by the frontend, but the flags can
 * still be specified. Reliable transmission will be used instead.
 *
 * Calling this with the flag RETRO_NETPACKET_FLUSH_HINT will send off the
 * packet and any previously buffered ones immediately and without blocking.
 * To only flush previously queued packets, buf or len can be passed as NULL/0.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id);

/* Optionally read any incoming packets without waiting for the end of the
 * frame. While polling, retro_netpacket_receive_t and retro_netpacket_stop_t
 * can be called. The core can perform this in a loop to do a blocking read,
 * i.e., wait for incoming data, but needs to handle stop getting called and
 * also give up after a short while to avoid freezing on a connection problem.
 * It is a good idea to manually flush outgoing packets before calling this.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_receive_t)(void);

/* Called by the frontend to signify that a multiplayer session has started.
 * If client_id is 0 the local player is the host of the session and at this
 * point no other player has connected yet.
 *
 * If client_id is &gt; 0 the local player is a client connected to a host and
 * at this point is already fully connected to the host.
 *
 * The core must store the function pointer send_fn and use it whenever it
 * wants to send a packet. Optionally poll_receive_fn can be stored and used
 * when regular receiving between frames is not enough. These function pointers
 * remain valid until the frontend calls retro_netpacket_stop_t.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn, retro_netpacket_poll_receive_t poll_receive_fn);

/* Called by the frontend when a new packet arrives which has been sent from
 * another player with retro_netpacket_send_t. The client_id argument indicates
 * who has sent the packet.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);

/* Called by the frontend when the multiplayer session has ended.
 * Once this gets called the function pointers passed to
 * retro_netpacket_start_t will not be valid anymore.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);

/* Called by the frontend every frame (between calls to retro_run while
 * updating the state of the multiplayer session.
 * This is a good place for the core to call retro_netpacket_send_t from.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);

/* Called by the frontend when a new player connects to the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 * If this function returns false, the newly connected player gets dropped.
 * This can be used for example to limit the number of players.
 */
typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);

/* Called by the frontend when a player leaves or disconnects from the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);

/**
 * A callback interface for giving a core the ability to send and receive custom
 * network packets during a multiplayer session between two or more instances
 * of a libretro frontend.
 *
 * Normally during connection handshake the frontend will compare library_version
 * used by both parties and show a warning if there is a difference. When the core
 * supplies protocol_version, the frontend will check against this instead.
 *
 * @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE
 */
struct retro_netpacket_callback
{
   retro_netpacket_start_t        start;
   retro_netpacket_receive_t      receive;
   retro_netpacket_stop_t         stop;         /* Optional - may be NULL */
   retro_netpacket_poll_t         poll;         /* Optional - may be NULL */
   retro_netpacket_connected_t    connected;    /* Optional - may be NULL */
   retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */
   const char* protocol_version; /* Optional - if not NULL will be used instead of core version to decide if communication is compatible */
};

/**
 * The pixel format used for rendering.
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 */
enum retro_pixel_format
{
   /**
    * 0RGB1555, native endian.
    * Used as the default if \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT is not called.
    * The most significant bit must be set to 0.
    * @deprecated This format remains supported to maintain compatibility.
    * New code should use &lt;tt&gt;RETRO_PIXEL_FORMAT_RGB565&lt;/tt&gt; instead.
    * @see RETRO_PIXEL_FORMAT_RGB565
    */
   RETRO_PIXEL_FORMAT_0RGB1555 = 0,

   /**
    * XRGB8888, native endian.
    * The most significant byte (the &lt;tt&gt;X&lt;/tt&gt;) is ignored.
    */
   RETRO_PIXEL_FORMAT_XRGB8888 = 1,

   /**
    * RGB565, native endian.
    * This format is recommended if 16-bit pixels are desired,
    * as it is available on a variety of devices and APIs.
    */
   RETRO_PIXEL_FORMAT_RGB565   = 2,

   /** Defined to ensure that &lt;tt&gt;sizeof(retro_pixel_format) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX
};

/** @defgroup GET_SAVESTATE_CONTEXT Savestate Context
 * @{
 */

/**
 * Details about how the frontend will use savestates.
 *
 * @see RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT
 * @see retro_serialize
 */
enum retro_savestate_context
{
   /**
    * Standard savestate written to disk.
    * May be loaded at any time,
    * even in a separate session or on another device.
    *
    * Should not contain any pointers to code or data.
    */
   RETRO_SAVESTATE_CONTEXT_NORMAL                 = 0,

   /**
    * The savestate is guaranteed to be loaded
    * within the same session, address space, and binary.
    * Will not be written to disk or sent over the network;
    * therefore, internal pointers to code or data are acceptable.
    * May still be loaded or saved at any time.
    *
    * @note This context generally implies the use of runahead or rewinding,
    * which may work by taking savestates multiple times per second.
    * Savestate code that runs in this context should be fast.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,

   /**
    * The savestate is guaranteed to be loaded
    * in the same session and by the same binary,
    * but possibly by a different address space
    * (e.g. for "second instance" runahead)
    *
    * Will not be written to disk or sent over the network,
    * but may be loaded in a different address space.
    * Therefore, the savestate &lt;em&gt;must not&lt;/em&gt; contain pointers.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY   = 2,

   /**
    * The savestate will not be written to disk,
    * but no other guarantees are made.
    * The savestate will almost certainly be loaded
    * by a separate binary, device, and address space.
    *
    * This context is intended for use with frontends that support rollback netplay.
    * Serialized state should omit any data that would unnecessarily increase bandwidth usage.
    * Must not contain pointers, and integers must be saved in big-endian format.
    * @see retro_endianness.h
    * @see network_stream
    */
   RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY       = 3,

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(retro_savestate_context) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_SAVESTATE_CONTEXT_UNKNOWN                = INT_MAX
};

/** @} */

/** @defgroup SET_MESSAGE User-Visible Messages
 *
 * @{
 */

/**
 * Defines a message that the frontend will display to the user,
 * as determined by &lt;tt&gt;RETRO_ENVIRONMENT_SET_MESSAGE&lt;/tt&gt;.
 *
 * @deprecated This struct is superseded by \ref retro_message_ext,
 * which provides more control over how a message is presented.
 * Only use it for compatibility with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see retro_message_ext
 */
struct retro_message
{
   /**
    * Null-terminated message to be displayed.
    * If \c NULL or empty, the message will be ignored.
    */
   const char *msg;

   /** Duration to display \c msg in frames. */
   unsigned    frames;
};

/**
 * The method that the frontend will use to display a message to the player.
 * @see retro_message_ext
 */
enum retro_message_target
{
   /**
    * Indicates that the frontend should display the given message
    * using all other targets defined by \c retro_message_target at once.
    */
   RETRO_MESSAGE_TARGET_ALL = 0,

   /**
    * Indicates that the frontend should display the given message
    * using the frontend's on-screen display, if available.
    *
    * @attention If the frontend allows players to customize or disable notifications,
    * then they may not see messages sent to this target.
    */
   RETRO_MESSAGE_TARGET_OSD,

   /**
    * Indicates that the frontend should log the message
    * via its usual logging mechanism, if available.
    *
    * This is not intended to be a substitute for \c RETRO_ENVIRONMENT_SET_LOG_INTERFACE.
    * It is intended for the common use case of
    * logging a player-facing message.
    *
    * This target should not be used for messages
    * of type \c RETRO_MESSAGE_TYPE_STATUS or \c RETRO_MESSAGE_TYPE_PROGRESS,
    * as it may add unnecessary noise to a log file.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   RETRO_MESSAGE_TARGET_LOG
};

/**
 * A broad category for the type of message that the frontend will display.
 *
 * Each message type has its own use case,
 * therefore the frontend should present each one differently.
 *
 * @note This is a hint that the frontend may ignore.
 * The frontend should fall back to \c RETRO_MESSAGE_TYPE_NOTIFICATION
 * for message types that it doesn't support.
 */
enum retro_message_type
{
   /**
    * A standard on-screen message.
    *
    * Suitable for a variety of use cases,
    * such as messages about errors
    * or other important events.
    *
    * Frontends that display their own messages
    * should display this type of core-generated message the same way.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION = 0,

   /**
    * An on-screen message that should be visually distinct
    * from \c RETRO_MESSAGE_TYPE_NOTIFICATION messages.
    *
    * The exact meaning of "visually distinct" is left to the frontend,
    * but this usually implies that the frontend shows the message
    * in a way that it doesn't typically use for its own notices.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,

   /**
    * Indicates a frequently-updated status display,
    * rather than a standard notification.
    * Status messages are intended to be displayed permanently while a core is running
    * in a way that doesn't suggest user action is required.
    *
    * Here are some possible use cases for status messages:
    *
    * @li An internal framerate counter.
    * @li Debugging information.
    *     Remember to let the player disable it in the core options.
    * @li Core-specific state, such as when a microphone is active.
    *
    * The status message is displayed for the given duration,
    * unless another status message of equal or greater priority is shown.
    */
   RETRO_MESSAGE_TYPE_STATUS,

   /**
    * Denotes a message that reports the progress
    * of a long-running asynchronous task,
    * such as when a core loads large files from disk or the network.
    *
    * The frontend should display messages of this type as a progress bar
    * (or a progress spinner for indefinite tasks),
    * where \c retro_message_ext::msg is the progress bar's title
    * and \c retro_message_ext::progress sets the progress bar's length.
    *
    * This message type shouldn't be used for tasks that are expected to complete quickly.
    */
   RETRO_MESSAGE_TYPE_PROGRESS
};

/**
 * A core-provided message that the frontend will display to the player.
 *
 * @note The frontend is encouraged store these messages in a queue.
 * However, it should not empty the queue of core-submitted messages upon exit;
 * if a core exits with an error, it may want to use this API
 * to show an error message to the player.
 *
 * The frontend should maintain its own copy of the submitted message
 * and all subobjects, including strings.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 */
struct retro_message_ext
{
   /**
    * The \c NULL-terminated text of a message to show to the player.
    * Must not be \c NULL.
    *
    * @note The frontend must honor newlines in this string
    * when rendering text to \c RETRO_MESSAGE_TARGET_OSD.
    */
   const char *msg;

   /**
    * The duration that \c msg will be displayed on-screen, in milliseconds.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned duration;

   /**
    * The relative importance of this message
    * when targeting \c RETRO_MESSAGE_TARGET_OSD.
    * Higher values indicate higher priority.
    *
    * The frontend should use this to prioritize messages
    * when it can't show all active messages at once,
    * or to remove messages from its queue if it's full.
    *
    * The relative display order of messages with the same priority
    * is left to the frontend's discretion,
    * although we suggest breaking ties
    * in favor of the most recently-submitted message.
    *
    * Frontends may handle deprioritized messages at their discretion;
    * such messages may have their \c duration altered,
    * be hidden without being delayed,
    * or even be discarded entirely.
    *
    * @note In the reference frontend (RetroArch),
    * the same priority values are used for frontend-generated notifications,
    * which are typically between 0 and 3 depending upon importance.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned priority;

   /**
    * The severity level of this message.
    *
    * The frontend may use this to filter or customize messages
    * depending on the player's preferences.
    * Here are some ideas:
    *
    * @li Use this to prioritize errors and warnings
    *     over higher-ranking info and debug messages.
    * @li Render warnings or errors with extra visual feedback,
    *     e.g. with brighter colors or accompanying sound effects.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   enum retro_log_level level;

   /**
    * The intended destination of this message.
    *
    * @see retro_message_target
    */
   enum retro_message_target target;

   /**
    * The intended semantics of this message.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    *
    * @see retro_message_type
    */
   enum retro_message_type type;

   /**
    * The progress of an asynchronous task.
    *
    * A value between 0 and 100 (inclusive) indicates the task's percentage,
    * and a value of -1 indicates a task of unknown completion.
    *
    * @note Since message type is a hint, a frontend may ignore progress values.
    * Where relevant, a core should include progress percentage within the message string,
    * such that the message intent remains clear when displayed
    * as a standard frontend-generated notification.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG and for
    * message types other than \c RETRO_MESSAGE_TYPE_PROGRESS.
    */
   int8_t progress;
};

/** @} */

/* Describes how the libretro implementation maps a libretro input bind
 * to its internal input system through a human readable string.
 * This string can be used to better let a user configure input. */
struct retro_input_descriptor
{
   /* Associates given parameters with a description. */
   unsigned port;
   unsigned device;
   unsigned index;
   unsigned id;

   /* Human readable description for parameters.
    * The pointer must remain valid until
    * retro_unload_game() is called. */
   const char *description;
};

/**
 * Contains basic information about the core.
 *
 * @see retro_get_system_info
 * @warning All pointers are owned by the core
 * and must remain valid throughout its lifetime.
 */
struct retro_system_info
{
   /**
    * Descriptive name of the library.
    *
    * @note Should not contain any version numbers, etc.
    */
   const char *library_name;

   /**
    * Descriptive version of the core.
    */
   const char *library_version;

   /**
    * A pipe-delimited string list of file extensions that this core can load, e.g. "bin|rom|iso".
    * Typically used by a frontend for filtering or core selection.
    */
   const char *valid_extensions;

   /* Libretro cores that need to have direct access to their content
    * files, including cores which use the path of the content files to
    * determine the paths of other files, should set need_fullpath to true.
    *
    * Cores should strive for setting need_fullpath to false,
    * as it allows the frontend to perform patching, etc.
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to have a valid path
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * See also:
    *    - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
    *    - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
    */
   bool        need_fullpath;

   /* If true, the frontend is not allowed to extract any archives before
    * loading the real content.
    * Necessary for certain libretro implementations that load games
    * from zipped archives. */
   bool        block_extract;
};

/* Defines overrides which modify frontend handling of
 * specific content file types.
 * An array of retro_system_content_info_override is
 * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_system_content_info_override
{
   /* A list of file extensions for which the override
    * should apply, delimited by a 'pipe' character
    * (e.g. "md|sms|gg")
    * Permitted file extensions are limited to those
    * included in retro_system_info::valid_extensions
    * and/or retro_subsystem_rom_info::valid_extensions */
   const char *extensions;

   /* Overrides the need_fullpath value set in
    * retro_system_info and/or retro_subsystem_rom_info.
    * To reiterate:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * In addition:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info_ext::full_path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info_ext::archive_path may be NULL
    *    - retro_game_info_ext::archive_file may be NULL
    *    - retro_game_info_ext::dir is guaranteed to contain a valid path
    *      to the directory in which the content file exists
    *    - retro_game_info_ext::name is guaranteed to contain the
    *      basename of the content file, without extension
    *    - retro_game_info_ext::ext is guaranteed to contain the
    *      extension of the content file in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - If retro_game_info_ext::file_in_archive is false:
    *       - retro_game_info_ext::full_path is guaranteed to contain
    *         a valid path to an existent file
    *       - retro_game_info_ext::archive_path may be NULL
    *       - retro_game_info_ext::archive_file may be NULL
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the content file exists
    *       - retro_game_info_ext::name is guaranteed to contain the
    *         basename of the content file, without extension
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file in lower case format
    *    - If retro_game_info_ext::file_in_archive is true:
    *       - retro_game_info_ext::full_path may be NULL
    *       - retro_game_info_ext::archive_path is guaranteed to
    *         contain a valid path to an existent compressed file
    *         inside which the content file is located
    *       - retro_game_info_ext::archive_file is guaranteed to
    *         contain a valid path to an existent content file
    *         inside the compressed file referred to by
    *         retro_game_info_ext::archive_path
    *            e.g. for a compressed file '/path/to/foo.zip'
    *            containing 'bar.sfc'
    *             &gt; retro_game_info_ext::archive_path will be '/path/to/foo.zip'
    *             &gt; retro_game_info_ext::archive_file will be 'bar.sfc'
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the compressed file
    *         (containing the content file) exists
    *       - retro_game_info_ext::name is guaranteed to contain
    *         EITHER
    *         1) the basename of the compressed file (containing
    *            the content file), without extension
    *         OR
    *         2) the basename of the content file inside the
    *            compressed file, without extension
    *         In either case, a core should consider 'name' to
    *         be the canonical name/ID of the the content file
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file inside the compressed file,
    *         in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size are
    *      guaranteed to be valid */
   bool need_fullpath;

   /* If need_fullpath is false, specifies whether the content
    * data buffer available in retro_load_game() is 'persistent'
    *
    * If persistent_data is false and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid only until retro_load_game() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid only until retro_load_game() returns
    *
    * If persistent_data is true and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid until retro_deinit() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid until retro_deinit() returns */
   bool persistent_data;
};

/* Similar to retro_game_info, but provides extended
 * information about the source content file and
 * game memory buffer status.
 * And array of retro_game_info_ext is returned by
 * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_game_info_ext
{
   /* - If file_in_archive is false, contains a valid
    *   path to an existent content file (UTF-8 encoded)
    * - If file_in_archive is true, may be NULL */
   const char *full_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contains a valid path
    *   to an existent compressed file inside which the
    *   content file is located (UTF-8 encoded) */
   const char *archive_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contain a valid path
    *   to an existent content file inside the compressed
    *   file referred to by archive_path (UTF-8 encoded)
    *      e.g. for a compressed file '/path/to/foo.zip'
    *      containing 'bar.sfc'
    *      &gt; archive_path will be '/path/to/foo.zip'
    *      &gt; archive_file will be 'bar.sfc' */
   const char *archive_file;

   /* - If file_in_archive is false, contains a valid path
    *   to the directory in which the content file exists
    *   (UTF-8 encoded)
    * - If file_in_archive is true, contains a valid path
    *   to the directory in which the compressed file
    *   (containing the content file) exists (UTF-8 encoded) */
   const char *dir;

   /* Contains the canonical name/ID of the content file
    * (UTF-8 encoded). Intended for use when identifying
    * 'complementary' content named after the loaded file -
    * i.e. companion data of a different format (a CD image
    * required by a ROM), texture packs, internally handled
    * save files, etc.
    * - If file_in_archive is false, contains the basename
    *   of the content file, without extension
    * - If file_in_archive is true, then string is
    *   implementation specific. A frontend may choose to
    *   set a name value of:
    *   EITHER
    *   1) the basename of the compressed file (containing
    *      the content file), without extension
    *   OR
    *   2) the basename of the content file inside the
    *      compressed file, without extension
    *   RetroArch sets the 'name' value according to (1).
    *   A frontend that supports routine loading of
    *   content from archives containing multiple unrelated
    *   content files may set the 'name' value according
    *   to (2). */
   const char *name;

   /* - If file_in_archive is false, contains the extension
    *   of the content file in lower case format
    * - If file_in_archive is true, contains the extension
    *   of the content file inside the compressed file,
    *   in lower case format */
   const char *ext;

   /* String of implementation specific meta-data. */
   const char *meta;

   /* Memory buffer of loaded game content. Will be NULL:
    * IF
    * - retro_system_info::need_fullpath is true and
    *   retro_system_content_info_override::need_fullpath
    *   is unset
    * OR
    * - retro_system_content_info_override::need_fullpath
    *   is true */
   const void *data;

   /* Size of game content memory buffer, in bytes */
   size_t size;

   /* True if loaded content file is inside a compressed
    * archive */
   bool file_in_archive;

   /* - If data is NULL, value is unset/ignored
    * - If data is non-NULL:
    *   - If persistent_data is false, data and size are
    *     valid only until retro_load_game() returns
    *   - If persistent_data is true, data and size are
    *     are valid until retro_deinit() returns */
   bool persistent_data;
};

/**
 * Parameters describing the size and shape of the video frame.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 * @see retro_get_system_av_info
 */
struct retro_game_geometry
{
   /**
    * Nominal video width of game, in pixels.
    * This will typically be the emulated platform's native video width
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_width;

   /**
    * Nominal video height of game, in pixels.
    * This will typically be the emulated platform's native video height
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_height;

   /**
    * Maximum possible width of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video width.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's widest possible screen layout (e.g. side-by-side).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_width;

   /**
    * Maximum possible height of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video height.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's tallest possible screen layout (e.g. vertical).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_height;    /* Maximum possible height of game. */

   /**
    * Nominal aspect ratio of game.
    * If zero or less,
    * an aspect ratio of &lt;tt&gt;base_width / base_height&lt;/tt&gt; is assumed.
    *
    * @note A frontend may ignore this setting.
    */
   float    aspect_ratio;
};

/**
 * Parameters describing the timing of the video and audio.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_timing
{
   /** Video output refresh rate, in frames per second. */
   double fps;

   /** The audio output sample rate, in Hz. */
   double sample_rate;
};

/**
 * Configures how the core's audio and video should be updated.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_av_info
{
   /** Parameters describing the size and shape of the video frame. */
   struct retro_game_geometry geometry;

   /** Parameters describing the timing of the video and audio. */
   struct retro_system_timing timing;
};

/** @defgroup SET_CORE_OPTIONS Core Options
 *  @{
 */

/**
 * Represents \ref RETRO_ENVIRONMENT_GET_VARIABLE "a core option query".
 *
 * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
 * (which is a deprecated API),
 * this \c struct serves as an option definition.
 *
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 */
struct retro_variable
{
   /**
    * A unique key identifying this option.
    *
    * Should be a key for an option that was previously defined
    * with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 or similar.
    *
    * Should be prefixed with the core's name
    * to minimize the risk of collisions with another core's options,
    * as frontends are not required to use a namespacing scheme for storing options.
    * For example, a core named "foo" might define an option named "foo_option".
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is used to define an option
    * named by this key.
    */
   const char *key;

   /**
    * Value to be obtained.
    *
    * Set by the frontend to \c NULL if
    * the option named by \ref key does not exist.
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is set by the core to define the possible values
    * for an option named by \ref key.
    * When used this way, it must be formatted as follows:
    * @li The text before the first ';' is the option's human-readable title.
    * @li A single space follows the ';'.
    * @li The rest of the string is a '|'-delimited list of possible values,
    * with the first one being the default.
    */
   const char *value;
};

/**
 * An argument that's used to show or hide a core option in the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 */
struct retro_core_option_display
{
   /**
    * The key for a core option that was defined with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
    * \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
    * or their legacy equivalents.
    */
   const char *key;

   /**
    * Whether the option named by \c key
    * should be displayed to the player in the frontend's core options menu.
    *
    * @note This value is a hint, \em not a requirement;
    * the frontend is free to ignore this field.
    */
   bool visible;
};

/**
 * The maximum number of choices that can be defined for a given core option.
 *
 * This limit was chosen as a compromise between
 * a core's flexibility and a streamlined user experience.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 *
 * If you need more than 128 choices for a core option,
 * consider simplifying your option structure.
 * Here are some ideas:
 *
 * \li If a core option represents a numeric value,
 *     consider reducing the option's granularity
 *     (e.g. define time limits in increments of 5 seconds instead of 1 second).
 *     Providing a fixed set of values based on experimentation
 *     is also a good idea.
 * \li If a core option represents a dynamically-built list of files,
 *     consider leaving out files that won't be useful.
 *     For example, if a core allows the player to choose a specific BIOS file,
 *     it can omit files of the wrong length or without a valid header.
 *
 * @see retro_core_option_definition
 * @see retro_core_option_v2_definition
 */
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128

/**
 * A descriptor for a particular choice within a core option.
 *
 * @note All option values are represented as strings.
 * If you need to represent any other type,
 * parse the string in \ref value.
 *
 * @see retro_core_option_v2_category
 */
struct retro_core_option_value
{
   /**
    * The option value that the frontend will serialize.
    *
    * Must not be \c NULL or empty.
    * No other hard limits are placed on this value's contents,
    * but here are some suggestions:
    *
    * \li If the value represents a number,
    *     don't include any non-digit characters (units, separators, etc.).
    *     Instead, include that information in \c label.
    *     This will simplify parsing.
    * \li If the value represents a file path,
    *     store it as a relative path with respect to one of the common libretro directories
    *     (e.g. \ref RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY "the system directory"
    *     or \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "the save directory"),
    *     and use forward slashes (\c "/") as directory separators.
    *     This will simplify cloud storage if supported by the frontend,
    *     as the same file may be used on multiple devices.
    */
   const char *value;

   /**
    * Human-readable name for \c value that the frontend should show to players.
    *
    * May be \c NULL, in which case the frontend
    * should display \c value itself.
    *
    * Here are some guidelines for writing a good label:
    *
    * \li Make the option labels obvious
    *     so that they don't need to be explained in the description.
    * \li Keep labels short, and don't use unnecessary words.
    *     For example, "OpenGL" is a better label than "OpenGL Mode".
    * \li If the option represents a number,
    *     consider adding units, separators, or other punctuation
    *     into the label itself.
    *     For example, "5 seconds" is a better label than "5".
    * \li If the option represents a number, use intuitive units
    *     that don't take a lot of digits to express.
    *     For example, prefer "1 minute" over "60 seconds" or "60,000 milliseconds".
    */
   const char *label;
};

/**
 * @copybrief retro_core_option_v2_definition
 *
 * @deprecated Use \ref retro_core_option_v2_definition instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
struct retro_core_option_definition
{
   /** @copydoc retro_core_option_v2_definition::key */
   const char *key;

   /** @copydoc retro_core_option_v2_definition::desc */
   const char *desc;

   /** @copydoc retro_core_option_v2_definition::info */
   const char *info;

   /** @copydoc retro_core_option_v2_definition::values */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /** @copydoc retro_core_option_v2_definition::default_value */
   const char *default_value;
};

#ifdef __PS3__
#undef local
#endif

/**
 * A variant of \ref retro_core_options that supports internationalization.
 *
 * @deprecated Use \ref retro_core_options_v2_intl instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see retro_core_options
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_intl
{
   /** @copydoc retro_core_options_v2_intl::us */
   struct retro_core_option_definition *us;

   /** @copydoc retro_core_options_v2_intl::local */
   struct retro_core_option_definition *local;
};

/**
 * A descriptor for a group of related core options.
 *
 * Here's an example category:
 *
 * @code
 * {
 *     "cpu",
 *     "CPU Emulation",
 *     "Settings for CPU quirks."
 * }
 * @endcode
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_category
{
   /**
    * A string that uniquely identifies this category within the core's options.
    * Any \c retro_core_option_v2_definition whose \c category_key matches this
    * is considered to be within this category.
    * Different cores may use the same category keys,
    * so namespacing them is not necessary.
    * Valid characters are &lt;tt&gt;[a-zA-Z0-9_-]&lt;/tt&gt;.
    *
    * Frontends should use this category to organize core options,
    * but may customize this category's presentation in other ways.
    * For example, a frontend may use common keys like "audio" or "gfx"
    * to select an appropriate icon in its UI.
    *
    * Required; must not be \c NULL.
    */
   const char *key;

   /**
    * A brief human-readable name for this category,
    * intended for the frontend to display to the player.
    * This should be a name that's concise and descriptive, such as "Audio" or "Video".
    *
    * Required; must not be \c NULL.
    */
   const char *desc;

   /**
    * A human-readable description for this category,
    * intended for the frontend to display to the player
    * as secondary help text (e.g. a sublabel or a tooltip).
    * Optional; may be \c NULL or an empty string.
    */
   const char *info;
};

/**
 * A descriptor for a particular core option and the values it may take.
 *
 * Supports categorizing options into groups,
 * so as not to overwhelm the player.
 *
 * @see retro_core_option_v2_category
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_definition
{
   /**
    * A unique identifier for this option that cores may use
    * \ref RETRO_ENVIRONMENT_GET_VARIABLE "to query its value from the frontend".
    * Must be unique within this core.
    *
    * Should be unique globally;
    * the recommended method for doing so
    * is to prefix each option with the core's name.
    * For example, an option that controls the resolution for a core named "foo"
    * should be named \c "foo_resolution".
    *
    * Valid key characters are in the set &lt;tt&gt;[a-zA-Z0-9_-]&lt;/tt&gt;.
    */
   const char *key;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * Required; must not be \c NULL or empty.
    */
   const char *desc;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version may be slightly more concise than \ref desc,
    * as it can rely on the structure of the options menu.
    * For example, "Interface" is a good \c desc_categorized,
    * as it can be displayed as a sublabel for a "Network" category.
    * For \c desc, "Network Interface" would be more suitable.
    *
    * Optional; if this field or \c category_key is empty or \c NULL,
    * \c desc will be used instead.
    */
   const char *desc_categorized;

   /**
    * A human-readable description of this option and its effects,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * @details Intended to be displayed as secondary help text,
    * such as a tooltip or a sublabel.
    *
    * Here are some suggestions for writing a good description:
    *
    * \li Avoid technical jargon unless this option is meant for advanced users.
    *     If unavoidable, suggest one of the default options for those unsure.
    * \li Don't repeat the option name in the description;
    *     instead, describe what the option name means.
    * \li If an option requires a core restart or game reset to take effect,
    *     be sure to say so.
    * \li Try to make the option labels obvious
    *     so that they don't need to be explained in the description.
    *
    * Optional; may be \c NULL.
    */
   const char *info;

   /**
    * @brief A human-readable description of this option and its effects,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version is provided to accommodate descriptions
    * that reference other options by name,
    * as options may have different user-facing names
    * depending on whether the frontend supports categorization.
    *
    * @copydetails info
    *
    * If empty or \c NULL, \c info will be used instead.
    * Will be ignored if \c category_key is empty or \c NULL.
    */
   const char *info_categorized;

   /**
    * The key of the category that this option belongs to.
    *
    * Optional; if equal to \ref retro_core_option_v2_category::key "a defined category",
    * then this option shall be displayed by the frontend
    * next to other options in this same category,
    * assuming it supports doing so.
    * Option categories are intended to be displayed in a submenu,
    * but this isn't a hard requirement.
    *
    * If \c NULL, empty, or not equal to a defined category,
    * then this option is considered uncategorized
    * and the frontend shall display it outside of any category
    * (most likely at a top-level menu).
    *
    * @see retro_core_option_v2_category
    */
   const char *category_key;

   /**
    * One or more possible values for this option,
    * up to the limit of \ref RETRO_NUM_CORE_OPTION_VALUES_MAX.
    *
    * Terminated by a \c { NULL, NULL } element,
    * although frontends should work even if all elements are used.
    */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /**
    * The default value for this core option.
    * Used if it hasn't been set, e.g. for new cores.
    * Must equal one of the \ref value members in the \c values array,
    * or else this option will be ignored.
    */
   const char *default_value;
};

/**
 * A set of core option descriptors and the categories that group them,
 * suitable for enabling a core to be customized.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
struct retro_core_options_v2
{
   /**
    * An array of \ref retro_core_option_v2_category "option categories",
    * terminated by a zeroed-out category \c struct.
    *
    * Will be ignored if the frontend doesn't support core option categories.
    *
    * If \c NULL or ignored, all options will be treated as uncategorized.
    * This most likely means that a frontend will display them at a top-level menu
    * without any kind of hierarchy or grouping.
    */
   struct retro_core_option_v2_category *categories;

   /**
    * An array of \ref retro_core_option_v2_definition "core option descriptors",
    * terminated by a zeroed-out definition \c struct.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_option_v2_definition *definitions;
};

/**
 * A variant of \ref retro_core_options_v2 that supports internationalization.
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_v2_intl
{
   /**
    * Pointer to a core options set
    * whose text is written in American English.
    *
    * This may be passed to \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 as-is
    * if not using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_options_v2 *us;

   /**
    * Pointer to a core options set
    * whose text is written in one of libretro's \ref retro_language "supported languages",
    * most likely the one returned by \ref RETRO_ENVIRONMENT_GET_LANGUAGE.
    *
    * Structure is the same, but usage is slightly different:
    *
    * \li All text (except for keys and option values)
    *     should be written in whichever language
    *     is returned by \c RETRO_ENVIRONMENT_GET_LANGUAGE.
    * \li All fields besides keys and option values may be \c NULL,
    *     in which case the corresponding string in \c us
    *     is used instead.
    * \li All \ref retro_core_option_v2_definition::default_value "default option values"
    *     are taken from \c us.
    *     The defaults in this field are ignored.
    *
    * May be \c NULL, in which case \c us is used instead.
    */
   struct retro_core_options_v2 *local;
};

/**
 * Called by the frontend to determine if any core option's visibility has changed.
 *
 * Each time a frontend sets a core option,
 * it should call this function to see if
 * any core option should be made visible or invisible.
 *
 * May also be called after \ref retro_load_game "loading a game",
 * to determine what the initial visibility of each option should be.
 *
 * Within this function, the core must update the visibility
 * of any dynamically-hidden options
 * using \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.
 *
 * @note All core options are visible by default,
 * even during this function's first call.
 *
 * @return \c true if any core option's visibility was adjusted
 * since the last call to this function.
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
typedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void);

/**
 * Callback registered by the core for the frontend to use
 * when setting the visibility of each core option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
struct retro_core_options_update_display_callback
{
   /**
    * @copydoc retro_core_options_update_display_callback_t
    *
    * Set by the core.
    */
   retro_core_options_update_display_callback_t callback;
};

/** @} */

struct retro_game_info
{
   const char *path;       /* Path to game, UTF-8 encoded.
                            * Sometimes used as a reference for building other paths.
                            * May be NULL if game was loaded from stdin or similar,
                            * but in this case some cores will be unable to load `data`.
                            * So, it is preferable to fabricate something here instead
                            * of passing NULL, which will help more cores to succeed.
                            * retro_system_info::need_fullpath requires
                            * that this path is valid. */
   const void *data;       /* Memory buffer of loaded game. Will be NULL
                            * if need_fullpath was set. */
   size_t      size;       /* Size of memory buffer. */
   const char *meta;       /* String of implementation specific meta-data. */
};

/** @defgroup GET_CURRENT_SOFTWARE_FRAMEBUFFER Frontend-Owned Framebuffers
 * @{
 */

/** @defgroup RETRO_MEMORY_ACCESS Framebuffer Memory Access Types
 * @{
 */

/** Indicates that core will write to the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_WRITE (1 &lt;&lt; 0)

/** Indicates that the core will read from the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_READ (1 &lt;&lt; 1)

/** @} */

/** @defgroup RETRO_MEMORY_TYPE Framebuffer Memory Types
 * @{
 */

/**
 * Indicates that the returned framebuffer's memory is cached.
 * If not set, random access to the buffer may be very slow.
 */
#define RETRO_MEMORY_TYPE_CACHED (1 &lt;&lt; 0)

/** @} */

/**
 * A frame buffer owned by the frontend that a core may use for rendering.
 *
 * @see GET_CURRENT_SOFTWARE_FRAMEBUFFER
 * @see retro_video_refresh_t
 */
struct retro_framebuffer
{
   /**
    * Pointer to the beginning of the framebuffer provided by the frontend.
    * The initial contents of this buffer are unspecified,
    * as is the means used to map the memory;
    * this may be defined in software,
    * or it may be GPU memory mapped to RAM.
    *
    * If the framebuffer is used,
    * this pointer must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to pass an offset to this pointer.
    *
    * @warning This pointer is only guaranteed to be valid
    * for the duration of the same \c retro_run iteration
    * \ref GET_CURRENT_SOFTWARE_FRAMEBUFFER "that requested the framebuffer".
    * Reuse of this pointer is undefined.
    */
   void *data;

   /**
    * The width of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other width.
    */
   unsigned width;

   /**
    * The height of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other height.
    */
   unsigned height;

   /**
    * The distance between the start of one scanline and the beginning of the next, in bytes.
    * In practice this is usually equal to \c width times the pixel size,
    * but that's not guaranteed.
    * Sometimes called the "stride".
    *
    * @setby{frontend}
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined to try to render \c data with any other pitch.
    */
   size_t pitch;

   /**
    * The pixel format of the returned framebuffer.
    * May be different than the format specified by the core in \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT,
    * e.g. due to conversions.
    * Set by the frontend.
    *
    * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
    */
   enum retro_pixel_format format;

   /**
    * One or more \ref RETRO_MEMORY_ACCESS "memory access flags"
    * that specify how the core will access the memory in \c data.
    *
    * @setby{core}
    */
   unsigned access_flags;

   /**
    * Zero or more \ref RETRO_MEMORY_TYPE "memory type flags"
    * that describe how the framebuffer's memory has been mapped.
    *
    * @setby{frontend}
    */
   unsigned memory_flags;
};

/** @} */

/** @defgroup SET_FASTFORWARDING_OVERRIDE Fast-Forward Override
 * @{
 */

/**
 * Parameters that govern when and how the core takes control
 * of fast-forwarding mode.
 */
struct retro_fastforwarding_override
{
   /**
    * The factor by which the core will be sped up
    * when \c fastforward is \c true.
    * This value is used as follows:
    *
    * @li A value greater than 1.0 will run the core at
    *     the specified multiple of normal speed.
    *     For example, a value of 5.0
    *     combined with a normal target rate of 60 FPS
    *     will result in a target rate of 300 FPS.
    *     The actual rate may be lower if the host's hardware can't keep up.
    * @li A value of 1.0 will run the core at normal speed.
    * @li A value between 0.0 (inclusive) and 1.0 (exclusive)
    *     will run the core as fast as the host system can manage.
    * @li A negative value will let the frontend choose a factor.
    * @li An infinite value or \c NaN results in undefined behavior.
    *
    * @attention Setting this value to less than 1.0 will \em not
    * slow down the core.
    */
   float ratio;

   /**
    * If \c true, the frontend should activate fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool fastforward;

   /**
    * If \c true, the frontend should display an on-screen notification or icon
    * while \c fastforward is \c true (where supported).
    * Otherwise, the frontend should not display any such notification.
    */
   bool notification;

   /**
    * If \c true, the core has exclusive control
    * over enabling and disabling fast-forwarding
    * via the \c fastforward field.
    * The frontend will not be able to start or stop fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool inhibit_toggle;
};

/** @} */

/**
 * During normal operation.
 *
 * @note Rate will be equal to the core's internal FPS.
 */
#define RETRO_THROTTLE_NONE              0

/**
 * While paused or stepping single frames.
 *
 * @note Rate will be 0.
 */
#define RETRO_THROTTLE_FRAME_STEPPING    1

/**
 * During fast forwarding.
 *
 * @note Rate will be 0 if not specifically limited to a maximum speed.
 */
#define RETRO_THROTTLE_FAST_FORWARD      2

/**
 * During slow motion.
 *
 * @note Rate will be less than the core's internal FPS.
 */
#define RETRO_THROTTLE_SLOW_MOTION       3

/**
 * While rewinding recorded save states.
 *
 * @note Rate can vary depending on the rewind speed or be 0 if the frontend
 * is not aiming for a specific rate.
 */
#define RETRO_THROTTLE_REWINDING         4

/**
 * While vsync is active in the video driver, and the target refresh rate is lower than the core's internal FPS.
 *
 * @note Rate is the target refresh rate.
 */
#define RETRO_THROTTLE_VSYNC             5

/**
 * When the frontend does not throttle in any way.
 *
 * @note Rate will be 0. An example could be if no vsync or audio output is active.
 */
#define RETRO_THROTTLE_UNBLOCKED         6

/**
 * Details about the actual rate an implementation is calling \c retro_run() at.
 *
 * @see RETRO_ENVIRONMENT_GET_THROTTLE_STATE
 */
struct retro_throttle_state
{
   /**
    * The current throttling mode.
    *
    * @note Should be one of the \c RETRO_THROTTLE_* values.
    * @see RETRO_THROTTLE_NONE
    * @see RETRO_THROTTLE_FRAME_STEPPING
    * @see RETRO_THROTTLE_FAST_FORWARD
    * @see RETRO_THROTTLE_SLOW_MOTION
    * @see RETRO_THROTTLE_REWINDING
    * @see RETRO_THROTTLE_VSYNC
    * @see RETRO_THROTTLE_UNBLOCKED
    */
   unsigned mode;

   /**
    * How many times per second the frontend aims to call retro_run.
    *
    * @note Depending on the mode, it can be 0 if there is no known fixed rate.
    * This won't be accurate if the total processing time of the core and
    * the frontend is longer than what is available for one frame.
    */
   float rate;
};

/** @defgroup GET_MICROPHONE_INTERFACE Microphone Interface
 * @{
 */

/**
 * Opaque handle to a microphone that's been opened for use.
 * The underlying object is accessed or created with \c retro_microphone_interface_t.
 */
typedef struct retro_microphone retro_microphone_t;

/**
 * Parameters for configuring a microphone.
 * Some of these might not be honored,
 * depending on the available hardware and driver configuration.
 */
typedef struct retro_microphone_params
{
   /**
    * The desired sample rate of the microphone's input, in Hz.
    * The microphone's input will be resampled,
    * so cores can ask for whichever frequency they need.
    *
    * If zero, some reasonable default will be provided by the frontend
    * (usually from its config file).
    *
    * @see retro_get_mic_rate_t
    */
   unsigned rate;
} retro_microphone_params_t;

/**
 * @copydoc retro_microphone_interface::open_mic
 */
typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::close_mic
 */
typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::get_params
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::set_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);

/**
 * @copydoc retro_microphone_interface::get_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::read_mic
 */
typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);

/**
 * The current version of the microphone interface.
 * Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t
 * receive new fields.
 *
 * Frontends using cores built against older mic interface versions
 * should not access fields introduced in newer versions.
 */
#define RETRO_MICROPHONE_INTERFACE_VERSION 1

/**
 * An interface for querying the microphone and accessing data read from it.
 *
 * @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE
 */
struct retro_microphone_interface
{
   /**
    * The version of this microphone interface.
    * Set by the core to request a particular version,
    * and set by the frontend to indicate the returned version.
    * 0 indicates that the interface is invalid or uninitialized.
    */
   unsigned interface_version;

   /**
    * Initializes a new microphone.
    * Assuming that microphone support is enabled and provided by the frontend,
    * cores may call this function whenever necessary.
    * A microphone could be opened throughout a core's lifetime,
    * or it could wait until a microphone is plugged in to the emulated device.
    *
    * The returned handle will be valid until it's freed,
    * even if the audio driver is reinitialized.
    *
    * This function is not guaranteed to be thread-safe.
    *
    * @param[in] args Parameters used to create the microphone.
    * May be \c NULL, in which case the default value of each parameter will be used.
    *
    * @returns Pointer to the newly-opened microphone,
    * or \c NULL if one couldn't be opened.
    * This likely means that no microphone is plugged in and recognized,
    * or the maximum number of supported microphones has been reached.
    *
    * @note Microphones are \em inactive by default;
    * to begin capturing audio, call \c set_mic_state.
    * @see retro_microphone_params_t
    */
   retro_open_mic_t open_mic;

   /**
    * Closes a microphone that was initialized with \c open_mic.
    * Calling this function will stop all microphone activity
    * and free up the resources that it allocated.
    * Afterwards, the handle is invalid and must not be used.
    *
    * A frontend may close opened microphones when unloading content,
    * but this behavior is not guaranteed.
    * Cores should close their microphones when exiting, just to be safe.
    *
    * @param microphone Pointer to the microphone that was allocated by \c open_mic.
    * If \c NULL, this function does nothing.
    *
    * @note The handle might be reused if another microphone is opened later.
    */
   retro_close_mic_t close_mic;

   /**
    * Returns the configured parameters of this microphone.
    * These may differ from what was requested depending on
    * the driver and device configuration.
    *
    * Cores should check these values before they start fetching samples.
    *
    * Will not change after the mic was opened.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose parameters will be retrieved.
    * @param[out] params The parameters object that the
    * microphone's parameters will be copied to.
    *
    * @return \c true if the parameters were retrieved,
    * \c false if there was an error.
    */
   retro_get_mic_params_t get_params;

   /**
    * Enables or disables the given microphone.
    * Microphones are disabled by default
    * and must be explicitly enabled before they can be used.
    * Disabled microphones will not process incoming audio samples,
    * and will therefore have minimal impact on overall performance.
    * Cores may enable microphones throughout their lifetime,
    * or only for periods where they're needed.
    *
    * Cores that accept microphone input should be able to operate without it;
    * we suggest substituting silence in this case.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be adjusted.
    * This will have been provided by \c open_mic.
    * @param state \c true if the microphone should receive audio input,
    * \c false if it should be idle.
    * @returns \c true if the microphone's state was successfully set,
    * \c false if \c microphone is invalid
    * or if there was an error.
    */
   retro_set_mic_state_t set_mic_state;

   /**
    * Queries the active state of a microphone at the given index.
    * Will return whether the microphone is enabled,
    * even if the driver is paused.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be queried.
    * @return \c true if the provided \c microphone is valid and active,
    * \c false if not or if there was an error.
    */
   retro_get_mic_state_t get_mic_state;

   /**
    * Retrieves the input processed by the microphone since the last call.
    * \em Must be called every frame unless \c microphone is disabled,
    * similar to how \c retro_audio_sample_batch_t works.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose recent input will be retrieved.
    * @param[out] samples The buffer that will be used to store the microphone's data.
    * Microphone input is in mono (i.e. one number per sample).
    * Should be large enough to accommodate the expected number of samples per frame;
    * for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.
    * @param[in] num_samples The size of the data buffer in samples (\em not bytes).
    * Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here.
    *
    * @return The number of samples that were copied into \c samples.
    * If \c microphone is pending driver initialization,
    * this function will copy silence of the requested length into \c samples.
    *
    * Will return -1 if the microphone is disabled,
    * the audio driver is paused,
    * or there was an error.
    */
   retro_read_mic_t read_mic;
};

/** @} */

/** @defgroup GET_DEVICE_POWER Device Power
 * @{
 */

/**
 * Describes how a device is being powered.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
enum retro_power_state
{
   /**
    * Indicates that the frontend cannot report its power state at this time,
    * most likely due to a lack of support.
    *
    * \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value;
    * instead, the environment callback will return \c false.
    */
   RETRO_POWERSTATE_UNKNOWN = 0,

   /**
    * Indicates that the device is running on its battery.
    * Usually applies to portable devices such as handhelds, laptops, and smartphones.
    */
   RETRO_POWERSTATE_DISCHARGING,

   /**
    * Indicates that the device's battery is currently charging.
    */
   RETRO_POWERSTATE_CHARGING,

   /**
    * Indicates that the device is connected to a power source
    * and that its battery has finished charging.
    */
   RETRO_POWERSTATE_CHARGED,

   /**
    * Indicates that the device is connected to a power source
    * and that it does not have a battery.
    * This usually suggests a desktop computer or a non-portable game console.
    */
   RETRO_POWERSTATE_PLUGGED_IN
};

/**
 * Indicates that an estimate is not available for the battery level or time remaining,
 * even if the actual power state is known.
 */
#define RETRO_POWERSTATE_NO_ESTIMATE (-1)

/**
 * Describes the power state of the device running the frontend.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
struct retro_device_power
{
   /**
    * The current state of the frontend's power usage.
    */
   enum retro_power_state state;

   /**
    * A rough estimate of the amount of time remaining (in seconds)
    * before the device powers off.
    * This value depends on a variety of factors,
    * so it is not guaranteed to be accurate.
    *
    * Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING.
    * May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate.
    */
   int seconds;

   /**
    * The approximate percentage of battery charge,
    * ranging from 0 to 100 (inclusive).
    * The device may power off before this reaches 0.
    *
    * The user might have configured their device
    * to stop charging before the battery is full,
    * so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state.
    */
   int8_t percent;
};

/** @} */

/**
 * @defgroup Callbacks
 * @{
 */

/**
 * Environment callback to give implementations a way of performing uncommon tasks.
 *
 * @note Extensible.
 *
 * @param cmd The command to run.
 * @param data A pointer to the data associated with the command.
 *
 * @return Varies by callback,
 * but will always return \c false if the command is not recognized.
 *
 * @see RETRO_ENVIRONMENT_SET_ROTATION
 * @see retro_set_environment()
 */
typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);

/**
 * Render a frame.
 *
 * @note For performance reasons, it is highly recommended to have a frame
 * that is packed in memory, i.e. pitch == width * byte_per_pixel.
 * Certain graphic APIs, such as OpenGL ES, do not like textures
 * that are not packed in memory.
 *
 * @param data A pointer to the frame buffer data with a pixel format of 15-bit \c 0RGB1555 native endian, unless changed with \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT.
 * @param width The width of the frame buffer, in pixels.
 * @param height The height frame buffer, in pixels.
 * @param pitch The width of the frame buffer, in bytes.
 *
 * @see retro_set_video_refresh()
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 * @see retro_pixel_format
 */
typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,
      unsigned height, size_t pitch);

/**
 * Renders a single audio frame. Should only be used if implementation generates a single sample at a time.
 *
 * @param left The left audio sample represented as a signed 16-bit native endian.
 * @param right The right audio sample represented as a signed 16-bit native endian.
 *
 * @see retro_set_audio_sample()
 * @see retro_set_audio_sample_batch()
 */
typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);

/**
 * Renders multiple audio frames in one go.
 *
 * @note Only one of the audio callbacks must ever be used.
 *
 * @param data A pointer to the audio sample data pairs to render.
 * @param frames The number of frames that are represented in the data. One frame
 *     is defined as a sample of left and right channels, interleaved.
 *     For example: &lt;tt&gt;int16_t buf[4] = { l, r, l, r };&lt;/tt&gt; would be 2 frames.
 *
 * @return The number of frames that were processed.
 *
 * @see retro_set_audio_sample_batch()
 * @see retro_set_audio_sample()
 */
typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,
      size_t frames);

/**
 * Polls input.
 *
 * @see retro_set_input_poll()
 */
typedef void (RETRO_CALLCONV *retro_input_poll_t)(void);

/**
 * Queries for input for player 'port'.
 *
 * @param port Which player 'port' to query.
 * @param device Which device to query for. Will be masked with \c RETRO_DEVICE_MASK.
 * @param index The input index to retrieve.
 * The exact semantics depend on the device type given in \c device.
 * @param id The ID of which value to query, like \c RETRO_DEVICE_ID_JOYPAD_B.
 * @returns Depends on the provided arguments,
 * but will return 0 if their values are unsupported
 * by the frontend or the backing physical device.
 * @note Specialization of devices such as \c RETRO_DEVICE_JOYPAD_MULTITAP that
 * have been set with \c retro_set_controller_port_device() will still use the
 * higher level \c RETRO_DEVICE_JOYPAD to request input.
 *
 * @see retro_set_input_state()
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 */
typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,
      unsigned index, unsigned id);

/**
 * Sets the environment callback.
 *
 * @param cb The function which is used when making environment calls.
 *
 * @note Guaranteed to be called before \c retro_init().
 *
 * @see RETRO_ENVIRONMENT
 */
RETRO_API void retro_set_environment(retro_environment_t cb);

/**
 * Sets the video refresh callback.
 *
 * @param cb The function which is used when rendering a frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_video_refresh(retro_video_refresh_t cb);

/**
 * Sets the audio sample callback.
 *
 * @param cb The function which is used when rendering a single audio frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample(retro_audio_sample_t cb);

/**
 * Sets the audio sample batch callback.
 *
 * @param cb The function which is used when rendering multiple audio frames in one go.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);

/**
 * Sets the input poll callback.
 *
 * @param cb The function which is used to poll the active input.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_poll(retro_input_poll_t cb);

/**
 * Sets the input state callback.
 *
 * @param cb The function which is used to query the input state.
 *
 *@note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_state(retro_input_state_t cb);

/**
 * @}
 */

/**
 * Called by the frontend when initializing a libretro core.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * &lt;ul&gt;
 * &lt;li&gt;Do not assume that the core was loaded by the operating system
 * for the first time within this call.
 * It may have been statically linked or retained from a previous session.
 * Consequently, cores must not rely on global variables being initialized
 * to their default values before this function is called;
 * this also goes for object constructors in C++.
 * &lt;li&gt;Although C++ requires that constructors be called for global variables,
 * it does not require that their destructors be called
 * if stored within a dynamic library's global scope.
 * &lt;li&gt;If the core is statically linked to the frontend,
 * global variables may be initialized when the frontend itself is initially executed.
 * &lt;/ul&gt;
 * @see retro_deinit
 */
RETRO_API void retro_init(void);

/**
 * Called by the frontend when deinitializing a libretro core.
 * The core must release all of its allocated resources before this function returns.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * &lt;ul&gt;
 * &lt;li&gt;Do not assume that the operating system will unload the core after this function returns,
 * as the core may be linked statically or retained in memory.
 * Cores should use this function to clean up all allocated resources
 * and reset all global variables to their default states.
 * &lt;li&gt;Do not assume that this core won't be loaded again after this function returns.
 * It may be kept in memory by the frontend for later use,
 * or it may be statically linked.
 * Therefore, all global variables should be reset to their default states within this function.
 * &lt;li&gt;C++ does not require that destructors be called
 * for variables within a dynamic library's global scope.
 * Therefore, global objects that own dynamically-managed resources
 * (such as \c std::string or &lt;tt&gt;std::vector&lt;/tt&gt;)
 * should be kept behind pointers that are explicitly deallocated within this function.
 * &lt;/ul&gt;
 * @see retro_init
 */
RETRO_API void retro_deinit(void);

/**
 * Retrieves which version of the libretro API is being used.
 *
 * @note This is used to validate ABI compatibility when the API is revised.
 *
 * @return Must return \c RETRO_API_VERSION.
 *
 * @see RETRO_API_VERSION
 */
RETRO_API unsigned retro_api_version(void);

/**
 * Gets statically known system info.
 *
 * @note Can be called at any time, even before retro_init().
 *
 * @param info A pointer to a \c retro_system_info where the info is to be loaded into. This must be statically allocated.
 */
RETRO_API void retro_get_system_info(struct retro_system_info *info);

/**
 * Gets information about system audio/video timings and geometry.
 *
 * @note Can be called only after \c retro_load_game() has successfully completed.
 *
 * @note The implementation of this function might not initialize every variable
 * if needed. For example, \c geom.aspect_ratio might not be initialized if
 * the core doesn't desire a particular aspect ratio.
 *
 * @param info A pointer to a \c retro_system_av_info where the audio/video information should be loaded into.
 *
 * @see retro_system_av_info
 */
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);

/**
 * Sets device to be used for player 'port'.
 *
 * By default, \c RETRO_DEVICE_JOYPAD is assumed to be plugged into all
 * available ports.
 *
 * @note Setting a particular device type is not a guarantee that libretro cores
 * will only poll input based on that particular device type. It is only a
 * hint to the libretro core when a core cannot automatically detect the
 * appropriate input device type on its own. It is also relevant when a
 * core can change its behavior depending on device type.
 *
 * @note As part of the core's implementation of retro_set_controller_port_device,
 * the core should call \c RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
 * frontend if the descriptions for any controls have changed as a
 * result of changing the device type.
 *
 * @param port Which port to set the device for, usually indicates the player number.
 * @param device Which device the given port is using. By default, \c RETRO_DEVICE_JOYPAD is assumed for all ports.
 *
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);

/**
 * Resets the currently-loaded game.
 * Cores should treat this as a soft reset (i.e. an emulated reset button) if possible,
 * but hard resets are acceptable.
 */
RETRO_API void retro_reset(void);

/**
 * Runs the game for one video frame.
 *
 * During \c retro_run(), the \c retro_input_poll_t callback must be called at least once.
 *
 * @note If a frame is not rendered for reasons where a game "dropped" a frame,
 * this still counts as a frame, and \c retro_run() should explicitly dupe
 * a frame if \c RETRO_ENVIRONMENT_GET_CAN_DUPE returns true. In this case,
 * the video callback can take a NULL argument for data.
 *
 * @see retro_input_poll_t
 */
RETRO_API void retro_run(void);

/**
 * Returns the amount of data the implementation requires to serialize internal state (save states).
 *
 * @note Between calls to \c retro_load_game() and \c retro_unload_game(), the
 * returned size is never allowed to be larger than a previous returned
 * value, to ensure that the frontend can allocate a save state buffer once.
 *
 * @return The amount of data the implementation requires to serialize the internal state.
 *
 * @see retro_serialize()
 */
RETRO_API size_t retro_serialize_size(void);

/**
 * Serializes the internal state.
 *
 * @param data A pointer to where the serialized data should be saved to.
 * @param size The size of the memory.
 *
 * @return If failed, or size is lower than \c retro_serialize_size(), it
 * should return false. On success, it will return true.
 *
 * @see retro_serialize_size()
 * @see retro_unserialize()
 */
RETRO_API bool retro_serialize(void *data, size_t len);

/**
 * Unserialize the given state data, and load it into the internal state.
 *
 * @return Returns true if loading the state was successful, false otherwise.
 *
 * @see retro_serialize()
 */
RETRO_API bool retro_unserialize(const void *data, size_t len);

/**
 * Reset all the active cheats to their default disabled state.
 *
 * @see retro_cheat_set()
 */
RETRO_API void retro_cheat_reset(void);

/**
 * Enable or disable a cheat.
 *
 * @param index The index of the cheat to act upon.
 * @param enabled Whether to enable or disable the cheat.
 * @param code A string of the code used for the cheat.
 *
 * @see retro_cheat_reset()
 */
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);

/**
 * Loads a game.
 *
 * @param game A pointer to a \c retro_game_info detailing information about the game to load.
 * May be \c NULL if the core is loaded without content.
 *
 * @return Will return true when the game was loaded successfully, or false otherwise.
 *
 * @see retro_game_info
 * @see RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME
 */
RETRO_API bool retro_load_game(const struct retro_game_info *game);

/**
 * Called when the frontend has loaded one or more "special" content files,
 * typically through subsystems.
 *
 * @note Only necessary for cores that support subsystems.
 * Others may return \c false or delegate to &lt;tt&gt;retro_load_game&lt;/tt&gt;.
 *
 * @param game_type The type of game to load,
 * as determined by \c retro_subsystem_info.
 * @param info A pointer to an array of \c retro_game_info objects
 * providing information about the loaded content.
 * @param num_info The number of \c retro_game_info objects passed into the info parameter.
 * @return \c true if loading is successful, false otherwise.
 * If the core returns \c false,
 * the frontend should abort the core
 * and return to its main menu (if applicable).
 *
 * @see RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_load_game()
 * @see retro_subsystem_info
 */
RETRO_API bool retro_load_game_special(
  unsigned game_type,
  const struct retro_game_info *info, size_t num_info
);

/**
 * Unloads the currently loaded game.
 *
 * @note This is called before \c retro_deinit(void).
 *
 * @see retro_load_game()
 * @see retro_deinit()
 */
RETRO_API void retro_unload_game(void);

/**
 * Gets the region of the actively loaded content as either \c RETRO_REGION_NTSC or \c RETRO_REGION_PAL.
 * @note This refers to the region of the content's intended television standard,
 * not necessarily the region of the content's origin.
 * For emulated consoles that don't use either standard
 * (e.g. handhelds or post-HD platforms),
 * the core should return \c RETRO_REGION_NTSC.
 * @return The region of the actively loaded content.
 *
 * @see RETRO_REGION_NTSC
 * @see RETRO_REGION_PAL
 */
RETRO_API unsigned retro_get_region(void);

/**
 * Get a region of memory.
 *
 * @param id The ID for the memory block that's desired to retrieve. Can be \c RETRO_MEMORY_SAVE_RAM, \c RETRO_MEMORY_RTC, \c RETRO_MEMORY_SYSTEM_RAM, or \c RETRO_MEMORY_VIDEO_RAM.
 *
 * @return A pointer to the desired region of memory, or NULL when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API void *retro_get_memory_data(unsigned id);

/**
 * Gets the size of the given region of memory.
 *
 * @param id The ID for the memory block to check the size of. Can be RETRO_MEMORY_SAVE_RAM, RETRO_MEMORY_RTC, RETRO_MEMORY_SYSTEM_RAM, or RETRO_MEMORY_VIDEO_RAM.
 *
 * @return The size of the region in memory, or 0 when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API size_t retro_get_memory_size(unsigned id);

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/include/libretro_vulkan.h</h2>
<pre>/* Copyright (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------------
 * The following license statement only applies to this libretro API header (libretro_vulkan.h)
 * ---------------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_VULKAN_H__
#define LIBRETRO_VULKAN_H__

#include &lt;libretro.h&gt;
#include &lt;vulkan/vulkan.h&gt;

#define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 5
#define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 2

struct retro_vulkan_image
{
   VkImageView image_view;
   VkImageLayout image_layout;
   VkImageViewCreateInfo create_info;
};

typedef void (*retro_vulkan_set_image_t)(void *handle,
      const struct retro_vulkan_image *image,
      uint32_t num_semaphores,
      const VkSemaphore *semaphores,
      uint32_t src_queue_family);

typedef uint32_t (*retro_vulkan_get_sync_index_t)(void *handle);
typedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void *handle);
typedef void (*retro_vulkan_set_command_buffers_t)(void *handle,
      uint32_t num_cmd,
      const VkCommandBuffer *cmd);
typedef void (*retro_vulkan_wait_sync_index_t)(void *handle);
typedef void (*retro_vulkan_lock_queue_t)(void *handle);
typedef void (*retro_vulkan_unlock_queue_t)(void *handle);
typedef void (*retro_vulkan_set_signal_semaphore_t)(void *handle, VkSemaphore semaphore);

typedef const VkApplicationInfo *(*retro_vulkan_get_application_info_t)(void);

struct retro_vulkan_context
{
   VkPhysicalDevice gpu;
   VkDevice device;
   VkQueue queue;
   uint32_t queue_family_index;
   VkQueue presentation_queue;
   uint32_t presentation_queue_family_index;
};

/* This is only used in v1 of the negotiation interface.
 * It is deprecated since it cannot express PDF2 features or optional extensions. */
typedef bool (*retro_vulkan_create_device_t)(
      struct retro_vulkan_context *context,
      VkInstance instance,
      VkPhysicalDevice gpu,
      VkSurfaceKHR surface,
      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
      const char **required_device_extensions,
      unsigned num_required_device_extensions,
      const char **required_device_layers,
      unsigned num_required_device_layers,
      const VkPhysicalDeviceFeatures *required_features);

typedef void (*retro_vulkan_destroy_device_t)(void);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef VkInstance (*retro_vulkan_create_instance_wrapper_t)(
      void *opaque, const VkInstanceCreateInfo *create_info);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef VkInstance (*retro_vulkan_create_instance_t)(
      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
      const VkApplicationInfo *app,
      retro_vulkan_create_instance_wrapper_t create_instance_wrapper,
      void *opaque);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef VkDevice (*retro_vulkan_create_device_wrapper_t)(
      VkPhysicalDevice gpu, void *opaque,
      const VkDeviceCreateInfo *create_info);

/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
typedef bool (*retro_vulkan_create_device2_t)(
      struct retro_vulkan_context *context,
      VkInstance instance,
      VkPhysicalDevice gpu,
      VkSurfaceKHR surface,
      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
      retro_vulkan_create_device_wrapper_t create_device_wrapper,
      void *opaque);

/* Note on thread safety:
 * The Vulkan API is heavily designed around multi-threading, and
 * the libretro interface for it should also be threading friendly.
 * A core should be able to build command buffers and submit
 * command buffers to the GPU from any thread.
 */

struct retro_hw_render_context_negotiation_interface_vulkan
{
   /* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN. */
   enum retro_hw_render_context_negotiation_interface_type interface_type;
   /* Usually set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION,
    * but can be lower depending on GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT. */
   unsigned interface_version;

   /* If non-NULL, returns a VkApplicationInfo struct that the frontend can use instead of
    * its "default" application info.
    * VkApplicationInfo::apiVersion also controls the target core Vulkan version for instance level functionality.
    * Lifetime of the returned pointer must remain until the retro_vulkan_context is initialized.
    *
    * NOTE: For optimal compatibility with e.g. Android which is very slow to update its loader,
    * a core version of 1.1 should be requested. Features beyond that can be requested with extensions.
    * Vulkan 1.0 is only appropriate for legacy cores, but is still supported.
    * A frontend is free to bump the instance creation apiVersion as necessary if the frontend requires more advanced core features.
    *
    * v2: This function must not be NULL, and must not return NULL.
    * v1: It was not clearly defined if this function could return NULL.
    *     Frontends should be defensive and provide a default VkApplicationInfo
    *     if this function returns NULL or if this function is NULL.
    */
   retro_vulkan_get_application_info_t get_application_info;

   /* If non-NULL, the libretro core will choose one or more physical devices,
    * create one or more logical devices and create one or more queues.
    * The core must prepare a designated PhysicalDevice, Device, Queue and queue family index
    * which the frontend will use for its internal operation.
    *
    * If gpu is not VK_NULL_HANDLE, the physical device provided to the frontend must be this PhysicalDevice if the call succeeds.
    * The core is still free to use other physical devices for other purposes that are private to the core.
    *
    * The frontend will request certain extensions and layers for a device which is created.
    * The core must ensure that the queue and queue_family_index support GRAPHICS and COMPUTE.
    *
    * If surface is not VK_NULL_HANDLE, the core must consider presentation when creating the queues.
    * If presentation to "surface" is supported on the queue, presentation_queue must be equal to queue.
    * If not, a second queue must be provided in presentation_queue and presentation_queue_index.
    * If surface is not VK_NULL_HANDLE, the instance from frontend will have been created with supported for
    * VK_KHR_surface extension.
    *
    * The core is free to set its own queue priorities.
    * Device provided to frontend is owned by the frontend, but any additional device resources must be freed by core
    * in destroy_device callback.
    *
    * If this function returns true, a PhysicalDevice, Device and Queues are initialized.
    * If false, none of the above have been initialized and the frontend will attempt
    * to fallback to "default" device creation, as if this function was never called.
    */
   retro_vulkan_create_device_t create_device;

   /* If non-NULL, this callback is called similar to context_destroy for HW_RENDER_INTERFACE.
    * However, it will be called even if context_reset was not called.
    * This can happen if the context never succeeds in being created.
    * destroy_device will always be called before the VkInstance
    * of the frontend is destroyed if create_device was called successfully so that the core has a chance of
    * tearing down its own device resources.
    *
    * Only auxiliary resources should be freed here, i.e. resources which are not part of retro_vulkan_context.
    * v2: Auxiliary instance resources created during create_instance can also be freed here.
    */
   retro_vulkan_destroy_device_t destroy_device;

   /* v2 API: If interface_version is &lt; 2, fields below must be ignored.
    * If the frontend does not support interface version 2, the v1 entry points will be used instead. */

   /* If non-NULL, this is called to create an instance, otherwise a VkInstance is created by the frontend.
    * v1 interface bug: The only way to enable instance features is through core versions signalled in VkApplicationInfo.
    * The frontend may request that certain extensions and layers
    * are enabled on the VkInstance. Application may add additional features.
    * If app is non-NULL, apiVersion controls the minimum core version required by the application.
    * Return a VkInstance or VK_NULL_HANDLE. The VkInstance is owned by the frontend.
    *
    * Rather than call vkCreateInstance directly, a core must call the CreateInstance wrapper provided with:
    * VkInstance instance = create_instance_wrapper(opaque, &amp;create_info);
    * If the core wishes to create a private instance for whatever reason (relying on shared memory for example),
    * it may call vkCreateInstance directly. */
   retro_vulkan_create_instance_t create_instance;

   /* If non-NULL and frontend recognizes negotiation interface &gt;= 2, create_device2 takes precedence over create_device.
    * Similar to create_device, but is extended to better understand new core versions and PDF2 feature enablement.
    * Requirements for create_device2 are the same as create_device unless a difference is mentioned.
    *
    * v2 consideration:
    * If the chosen gpu by frontend cannot be supported, a core must return false.
    *
    * NOTE: "Cannot be supported" is intentionally vaguely defined.
    * Refusing to run on an iGPU for a very intensive core with desktop GPU as a minimum spec may be in the gray area.
    * Not supporting optional features is not a good reason to reject a physical device, however.
    *
    * On device creation feature with explicit gpu, a frontend should fall back create_device2 with gpu == VK_NULL_HANDLE and let core
    * decide on a supported device if possible.
    *
    * A core must assume that the explicitly provided GPU is the only guaranteed attempt it has to create a device.
    * A fallback may not be attempted if there are particular reasons why only a specific physical device can work,
    * but these situations should be esoteric and rare in nature, e.g. a libretro frontend is implemented with external memory
    * and only LUID matching would work.
    * Cores and frontends should ensure "best effort" when negotiating like this and appropriate logging is encouraged.
    *
    * v1 note: In the v1 version of create_device, it was never expected that create_device would fail like this,
    * and frontends are not expected to attempt fall backs.
    *
    * Rather than call vkCreateDevice directly, a core must call the CreateDevice wrapper provided with:
    * VkDevice device = create_device_wrapper(gpu, opaque, &amp;create_info);
    * If the core wishes to create a private device for whatever reason (relying on shared memory for example),
    * it may call vkCreateDevice directly.
    *
    * This allows the frontend to add additional extensions that it requires as well as adjust the PDF2 pNext as required.
    * It is also possible adjust the queue create infos in case the frontend desires to allocate some private queues.
    *
    * The get_instance_proc_addr provided in create_device2 must be the same as create_instance.
    *
    * NOTE: The frontend must not disable features requested by application.
    * NOTE: The frontend must not add any robustness features as some API behavior may change (VK_EXT_descriptor_buffer comes to mind).
    * I.e. robustBufferAccess and the like. (nullDescriptor from robustness2 is allowed to be enabled).
    */
   retro_vulkan_create_device2_t create_device2;
};

struct retro_hw_render_interface_vulkan
{
   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */
   enum retro_hw_render_interface_type interface_type;
   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */
   unsigned interface_version;

   /* Opaque handle to the Vulkan backend in the frontend
    * which must be passed along to all function pointers
    * in this interface.
    *
    * The rationale for including a handle here (which libretro v1
    * doesn't currently do in general) is:
    *
    * - Vulkan cores should be able to be freely threaded without lots of fuzz.
    *   This would break frontends which currently rely on TLS
    *   to deal with multiple cores loaded at the same time.
    * - Fixing this in general is TODO for an eventual libretro v2.
    */
   void *handle;

   /* The Vulkan instance the context is using. */
   VkInstance instance;
   /* The physical device used. */
   VkPhysicalDevice gpu;
   /* The logical device used. */
   VkDevice device;

   /* Allows a core to fetch all its needed symbols without having to link
    * against the loader itself. */
   PFN_vkGetDeviceProcAddr get_device_proc_addr;
   PFN_vkGetInstanceProcAddr get_instance_proc_addr;

   /* The queue the core must use to submit data.
    * This queue and index must remain constant throughout the lifetime
    * of the context.
    *
    * This queue will be the queue that supports graphics and compute
    * if the device supports compute.
    */
   VkQueue queue;
   unsigned queue_index;

   /* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID,
    * set which image to use for this frame.
    *
    * If num_semaphores is non-zero, the frontend will wait for the
    * semaphores provided to be signaled before using the results further
    * in the pipeline.
    *
    * Semaphores provided by a single call to set_image will only be
    * waited for once (waiting for a semaphore resets it).
    * E.g. set_image, video_refresh, and then another
    * video_refresh without set_image,
    * but same image will only wait for semaphores once.
    *
    * For this reason, ownership transfer will only occur if semaphores
    * are waited on for a particular frame in the frontend.
    *
    * Using semaphores is optional for synchronization purposes,
    * but if not using
    * semaphores, an image memory barrier in vkCmdPipelineBarrier
    * should be used in the graphics_queue.
    * Example:
    *
    * vkCmdPipelineBarrier(cmd,
    *    srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
    *    dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
    *    image_memory_barrier = {
    *       srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    *       dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
    *    });
    *
    * The use of pipeline barriers instead of semaphores is encouraged
    * as it is simpler and more fine-grained. A layout transition
    * must generally happen anyways which requires a
    * pipeline barrier.
    *
    * The image passed to set_image must have imageUsage flags set to at least
    * VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT.
    * The core will naturally want to use flags such as
    * VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or
    * VK_IMAGE_USAGE_TRANSFER_DST_BIT depending
    * on how the final image is created.
    *
    * The image must also have been created with MUTABLE_FORMAT bit set if
    * 8-bit formats are used, so that the frontend can reinterpret sRGB
    * formats as it sees fit.
    *
    * Images passed to set_image should be created with TILING_OPTIMAL.
    * The image layout should be transitioned to either
    * VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
    * The actual image layout used must be set in image_layout.
    *
    * The image must be a 2D texture which may or not be layered
    * and/or mipmapped.
    *
    * The image must be suitable for linear sampling.
    * While the image_view is typically the only field used,
    * the frontend may want to reinterpret the texture as sRGB vs.
    * non-sRGB for example so the VkImageViewCreateInfo used to
    * create the image view must also be passed in.
    *
    * The data in the pointer to the image struct will not be copied
    * as the pNext field in create_info cannot be reliably deep-copied.
    * The image pointer passed to set_image must be valid until
    * retro_video_refresh_t has returned.
    *
    * If frame duping is used when passing NULL to retro_video_refresh_t,
    * the frontend is free to either use the latest image passed to
    * set_image or reuse the older pointer passed to set_image the
    * frame RETRO_HW_FRAME_BUFFER_VALID was last used.
    *
    * Essentially, the lifetime of the pointer passed to
    * retro_video_refresh_t should be extended if frame duping is used
    * so that the frontend can reuse the older pointer.
    *
    * The image itself however, must not be touched by the core until
    * wait_sync_index has been completed later. The frontend may perform
    * layout transitions on the image, so even read-only access is not defined.
    * The exception to read-only rule is if GENERAL layout is used for the image.
    * In this case, the frontend is not allowed to perform any layout transitions,
    * so concurrent reads from core and frontend are allowed.
    *
    * If frame duping is used, or if set_command_buffers is used,
    * the frontend will not wait for any semaphores.
    *
    * The src_queue_family is used to specify which queue family
    * the image is currently owned by. If using multiple queue families
    * (e.g. async compute), the frontend will need to acquire ownership of the
    * image before rendering with it and release the image afterwards.
    *
    * If src_queue_family is equal to the queue family (queue_index),
    * no ownership transfer will occur.
    * Similarly, if src_queue_family is VK_QUEUE_FAMILY_IGNORED,
    * no ownership transfer will occur.
    *
    * The frontend will always release ownership back to src_queue_family.
    * Waiting for frontend to complete with wait_sync_index() ensures that
    * the frontend has released ownership back to the application.
    * Note that in Vulkan, transferring ownership is a two-part process.
    *
    * Example frame:
    *  - core releases ownership from src_queue_index to queue_index with VkImageMemoryBarrier.
    *  - core calls set_image with src_queue_index.
    *  - Frontend will acquire the image with src_queue_index -&gt; queue_index as well, completing the ownership transfer.
    *  - Frontend renders the frame.
    *  - Frontend releases ownership with queue_index -&gt; src_queue_index.
    *  - Next time image is used, core must acquire ownership from queue_index ...
    *
    * Since the frontend releases ownership, we cannot necessarily dupe the frame because
    * the core needs to make the roundtrip of ownership transfer.
    */
   retro_vulkan_set_image_t set_image;

   /* Get the current sync index for this frame which is obtained in
    * frontend by calling e.g. vkAcquireNextImageKHR before calling
    * retro_run().
    *
    * This index will correspond to which swapchain buffer is currently
    * the active one.
    *
    * Knowing this index is very useful for maintaining safe asynchronous CPU
    * and GPU operation without stalling.
    *
    * The common pattern for synchronization is to receive fences when
    * submitting command buffers to Vulkan (vkQueueSubmit) and add this fence
    * to a list of fences for frame number get_sync_index().
    *
    * Next time we receive the same get_sync_index(), we can wait for the
    * fences from before, which will usually return immediately as the
    * frontend will generally also avoid letting the GPU run ahead too much.
    *
    * After the fence has signaled, we know that the GPU has completed all
    * GPU work related to work submitted in the frame we last saw get_sync_index().
    *
    * This means we can safely reuse or free resources allocated in this frame.
    *
    * In theory, even if we wait for the fences correctly, it is not technically
    * safe to write to the image we earlier passed to the frontend since we're
    * not waiting for the frontend GPU jobs to complete.
    *
    * The frontend will guarantee that the appropriate pipeline barrier
    * in graphics_queue has been used such that
    * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot
    * start until the frontend is done with the image.
    */
   retro_vulkan_get_sync_index_t get_sync_index;

   /* Returns a bitmask of how many swapchain images we currently have
    * in the frontend.
    *
    * If bit #N is set in the return value, get_sync_index can return N.
    * Knowing this value is useful for preallocating per-frame management
    * structures ahead of time.
    *
    * While this value will typically remain constant throughout the
    * applications lifecycle, it may for example change if the frontend
    * suddenly changes fullscreen state and/or latency.
    *
    * If this value ever changes, it is safe to assume that the device
    * is completely idle and all synchronization objects can be deleted
    * right away as desired.
    */
   retro_vulkan_get_sync_index_mask_t get_sync_index_mask;

   /* Instead of submitting the command buffer to the queue first, the core
    * can pass along its command buffer to the frontend, and the frontend
    * will submit the command buffer together with the frontends command buffers.
    *
    * This has the advantage that the overhead of vkQueueSubmit can be
    * amortized into a single call. For this mode, semaphores in set_image
    * will be ignored, so vkCmdPipelineBarrier must be used to synchronize
    * the core and frontend.
    *
    * The command buffers in set_command_buffers are only executed once,
    * even if frame duping is used.
    *
    * If frame duping is used, set_image should be used for the frames
    * which should be duped instead.
    *
    * Command buffers passed to the frontend with set_command_buffers
    * must not actually be submitted to the GPU until retro_video_refresh_t
    * is called.
    *
    * The frontend must submit the command buffer before submitting any
    * other command buffers provided by set_command_buffers. */
   retro_vulkan_set_command_buffers_t set_command_buffers;

   /* Waits on CPU for device activity for the current sync index to complete.
    * This is useful since the core will not have a relevant fence to sync with
    * when the frontend is submitting the command buffers. */
   retro_vulkan_wait_sync_index_t wait_sync_index;

   /* If the core submits command buffers itself to any of the queues provided
    * in this interface, the core must lock and unlock the frontend from
    * racing on the VkQueue.
    *
    * Queue submission can happen on any thread.
    * Even if queue submission happens on the same thread as retro_run(),
    * the lock/unlock functions must still be called.
    *
    * NOTE: Queue submissions are heavy-weight. */
   retro_vulkan_lock_queue_t lock_queue;
   retro_vulkan_unlock_queue_t unlock_queue;

   /* Sets a semaphore which is signaled when the image in set_image can safely be reused.
    * The semaphore is consumed next call to retro_video_refresh_t.
    * The semaphore will be signalled even for duped frames.
    * The semaphore will be signalled only once, so set_signal_semaphore should be called every frame.
    * The semaphore may be VK_NULL_HANDLE, which disables semaphore signalling for next call to retro_video_refresh_t.
    *
    * This is mostly useful to support use cases where you're rendering to a single image that
    * is recycled in a ping-pong fashion with the frontend to save memory (but potentially less throughput).
    */
   retro_vulkan_set_signal_semaphore_t set_signal_semaphore;
};

#endif</pre>
<h2>./include/libretro-common/include/lists/dir_list.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dir_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_DIR_LIST_H
#define __LIBRETRO_SDK_DIR_LIST_H

#include &lt;retro_common_api.h&gt;
#include &lt;boolean.h&gt;

#include &lt;lists/string_list.h&gt;

RETRO_BEGIN_DECLS

/**
 * dir_list_append:
 * @list               : existing list to append to.
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing, appending to an existing list
 *
 * @return Returns true on success, otherwise false.
 **/
bool dir_list_append(struct string_list *list, const char *dir, const char *ext,
      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);

/**
 * dir_list_new:
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : include compressed files, even when not part of ext.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing.
 *
 * @return pointer to a directory listing of type 'struct string_list *' on success,
 * NULL in case of error. Has to be freed manually.
 **/
struct string_list *dir_list_new(const char *dir, const char *ext,
      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);

/**
 * dir_list_initialize:
 *
 * NOTE: @list must zero initialised before
 * calling this function, otherwise UB.
 **/
bool dir_list_initialize(struct string_list *list,
      const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive);

/**
 * dir_list_sort:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing.
 **/
void dir_list_sort(struct string_list *list, bool dir_first);

/**
 * dir_list_sort_ignore_ext:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing. File extensions are ignored.
 **/
void dir_list_sort_ignore_ext(struct string_list *list, bool dir_first);

/**
 * dir_list_free:
 * @list : pointer to the directory listing
 *
 * Frees a directory listing.
 **/
void dir_list_free(struct string_list *list);

bool dir_list_deinitialize(struct string_list *list);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/lists/file_list.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FILE_LIST_H__
#define __LIBRETRO_SDK_FILE_LIST_H__

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;boolean.h&gt;

struct item_file
{
   void *userdata;
   void *actiondata;
   char *path;
   char *label;
   char *alt;
   size_t directory_ptr;
   size_t entry_idx;
   unsigned type;
};

typedef struct file_list
{
   struct item_file *list;

   size_t capacity;
   size_t size;
} file_list_t;

void *file_list_get_userdata_at_offset(const file_list_t *list,
      size_t index);

void *file_list_get_actiondata_at_offset(const file_list_t *list,
      size_t index);

/**
 * @brief frees the list
 *
 * NOTE: This function will also free() the entries actiondata
 * and userdata fields if they are non-null. If you store complex
 * or non-contiguous data there, make sure you free it's fields
 * before calling this function or you might get a memory leak.
 *
 * @param list List to be freed
 */
void file_list_free(file_list_t *list);

bool file_list_deinitialize(file_list_t *list);

/**
 * @brief makes the list big enough to contain at least nitems
 *
 * This function will not change the capacity if nitems is smaller
 * than the current capacity.
 *
 * @param list The list to open for input
 * @param nitems Number of items to reserve space for
 * @return whether or not the operation succeeded
 */
bool file_list_reserve(file_list_t *list, size_t nitems);

bool file_list_append(file_list_t *userdata, const char *path,
      const char *label, unsigned type, size_t current_directory_ptr,
      size_t entry_index);

bool file_list_insert(file_list_t *list,
      const char *path, const char *label,
      unsigned type, size_t directory_ptr,
      size_t entry_idx,
      size_t idx);

void file_list_pop(file_list_t *list, size_t *directory_ptr);

void file_list_clear(file_list_t *list);

void file_list_free_userdata(const file_list_t *list, size_t index);

void file_list_free_actiondata(const file_list_t *list, size_t idx);

void file_list_set_alt_at_offset(file_list_t *list, size_t index,
      const char *alt);

void file_list_sort_on_alt(file_list_t *list);

void file_list_sort_on_type(file_list_t *list);

bool file_list_search(const file_list_t *list, const char *needle,
      size_t *index);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/lists/linked_list.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (linked_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_LINKED_LIST_H
#define __LIBRETRO_SDK_LINKED_LIST_H

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;
#include &lt;stddef.h&gt;

RETRO_BEGIN_DECLS

/**
 * Represents a linked list. Contains any number of elements.
 */
typedef struct linked_list linked_list_t;

/**
 * Represents an iterator for iterating over a linked list. The iterator can
 * go through the linked list forwards or backwards.
 */
typedef struct linked_list_iterator linked_list_iterator_t;

/**
 * Creates a new linked list with no elements.
 *
 * @return New linked list
 */
linked_list_t *linked_list_new(void);

/**
 * @brief frees the memory used by the linked list
 *
 * Frees all of the memory used by this linked list. The values of all
 * remaining elements are freed using the "free_value" function. Does
 * nothing if "list" is NULL.
 *
 * @param list linked list to free
 * @param free_value function to use to free remaining values
 */
void linked_list_free(linked_list_t *list, void (*free_value)(void *value));

/**
 * @brief adds an element to the linked list
 *
 * Add a new element to the end of this linked list. Does nothing if
 * "list" is NULL.
 *
 * @param list list to add the element to
 * @param value new value to add to the linked list
 */
void linked_list_add(linked_list_t *list, void *value);

/**
 * @brief inserts a value into the linked list
 *
 * Inserts a value into the linked list at the specified index. Does
 * nothing if "list" is NULL.
 *
 * @param list list to insert the value into
 * @param index index where the value should be inserted at (can be equal to list size)
 * @param value value to insert into the linked list
 */
void linked_list_insert(linked_list_t *list, size_t index, void *value);

/**
 * @brief Get the value in the linked list at the provided index.
 *
 * Return the value vstored in the linked list at the provided index. Does
 * nothing if "list" is NULL.
 *
 * @param list list to get the value from
 * @param index index of the value to return
 * @return value in the list at the provided index
 */
void *linked_list_get(linked_list_t *list, size_t index);

/**
 * @brief Get the first value that is matched by the provided function
 *
 * Return the first value that the function matches. The matches function
 * parameters are value from the linked list and the provided state.
 *
 * @param list list to get the value from
 * @param matches function to test the values with
 * @param usrptr user data to pass to the matches function
 * @return first value that matches otherwise NULL
 */
void *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);

/**
 * @brief Get the last value that is matched by the provided function
 *
 * Return the last value that the function matches. The matches function
 * parameters are value from the linked list and the provided state.
 *
 * @param list list to get the value from
 * @param matches function to test the values with
 * @param usrptr user data to pass to the matches function
 * @return last value that matches otherwise NULL
 */
void *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);

/**
 * @brief Remove the element at the provided index
 *
 * Removes the element of the linked list at the provided index.
 *
 * @param list linked list to remove the element from
 * @param index index of the element to remove
 * @return value of the element that was removed, NULL if list is NULL or
 *         index is invalid
 */
void *linked_list_remove_at(linked_list_t *list, size_t index);

/**
 * @brief Remove the first element with the provided value
 *
 * Removes the first element with a value equal to the provided value.
 * Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the element from
 * @param value value of the element to remove
 * @return value if a matching element was removed
 */
void *linked_list_remove_first(linked_list_t *list, void *value);

/**
 * @brief Remove the last element with the provided value
 *
 * Removes the last element with a value equal to the provided value.
 * Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the element from
 * @param value value of the element to remove
 * @return value if a matching element was removed
 */
void *linked_list_remove_last(linked_list_t *list, void *value);

/**
 * @brief Remove all elements with the provided value
 *
 * Removes all elements with a value equal to the provided value.
 * Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the elements from
 * @param value value of the elements to remove
 * @return value if any matching element(s) where removed
 */
void *linked_list_remove_all(linked_list_t *list, void *value);

/**
 * @brief Remove the first matching element
 *
 * Removes the first matching element from the linked list. The "matches" function
 * is used to test for matching element values. Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the element from
 * @param matches function to use for testing element values for a match
 * @return value if a matching element was removed
 */
void *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value));

/**
 * @brief Remove the last matching element
 *
 * Removes the last matching element from the linked list. The "matches" function
 * is used to test for matching element values.
 *
 * @param list linked list to remove the element from
 * @param matches function to use for testing element value for a match
 * @return value if a matching element was removed
 */
void *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value));

/**
 * @brief Remove all matching elements
 *
 * Removes all matching elements from the linked list. The "matches" function
 * is used to test for matching element values. Does nothing if "list" is NULL.
 *
 * @param list linked list to remove the elements from
 * @param matches function to use for testing element values for a match
 */
void linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value));

/**
 * @brief Replace the value of the element at the provided index
 *
 * Replaces the value of the element at the provided index. The linked list must
 * contain an element at the index.
 *
 * @param list linked list to replace the value in
 * @param index index of the element to replace the value of
 * @param value new value for the selected element
 * @return whether an element was updated
 */
bool linked_list_set_at(linked_list_t *list, size_t index, void *value);

/**
 * @brief Get the size of the linked list
 *
 * Returns the number of elements in the linked list.
 *
 * @param linked list to get the size of
 * @return number of elements in the linked list, 0 if linked list is NULL
 */
size_t linked_list_size(linked_list_t *list);

/**
 * @brief Get an iterator for the linked list
 *
 * Returns a new iterator for the linked list. Can be either a forward or backward
 * iterator.
 *
 * @param list linked list to iterate over
 * @param forward true for a forward iterator, false for backwards
 * @return new iterator for the linked list in the specified direction, NULL if
 *         "list" is NULL
 */
linked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward);

/**
 * @brief Move to the next element in the linked list
 *
 * Moves the iterator to the next element in the linked list. The direction is
 * specified when retrieving a new iterator.
 *
 * @param iterator iterator for the current element
 * @return iterator for the next element, NULL if iterator is NULL or "iterator"
 *         is at the last element
 */
linked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator);

/**
 * @brief Get the value of the element for the iterator
 *
 * Returns the value of the element that the iterator is at.
 *
 * @param iterator iterator for the current element
 * @return value of the element for the iterator
 */
void *linked_list_iterator_value(linked_list_iterator_t *iterator);

/**
 * @brief Remove the element that the iterator is at
 *
 * Removes the element that the iterator is at. The iterator is updated to the
 * next element.
 *
 * @param iterator iterator for the current element
 * @return updated iterator or NULL if the last element was removed
 */
linked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator);

/**
 * @brief Release the memory for the iterator
 *
 * Frees the memory for the provided iterator. Does nothing if "iterator" is NULL.
 *
 * @param iterator iterator to free
 */
void linked_list_iterator_free(linked_list_iterator_t *iterator);

/**
 * @brief Apply the provided function to all values in the linked list
 *
 * Apply the provided function to all values in the linked list. The values are applied
 * in the forward direction. Does nothing if "list" is NULL.
 *
 * @param list linked list to apply the function to
 * @param fn function to apply to all elements
 */
void linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value));

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/lists/nested_list.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nested_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_NESTED_LIST_H__
#define __LIBRETRO_SDK_NESTED_LIST_H__

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;

RETRO_BEGIN_DECLS

/* Prevent direct access to nested_list_* members */
typedef struct nested_list_item nested_list_item_t;
typedef struct nested_list nested_list_t;

/**************************************/
/* Initialisation / De-Initialisation */
/**************************************/

/**
 * nested_list_init:
 *
 * Creates a new empty nested list. Returned pointer
 * must be freed using nested_list_free.
 *
 * Returns: Valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_init(void);

/**
 * nested_list_free:
 *
 * @list : pointer to nested_list_t object
 *
 * Frees specified nested list.
 */
void nested_list_free(nested_list_t *list);

/***********/
/* Setters */
/***********/

/**
 * nested_list_add_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 * @value   : optional value (user data) associated with
 *            new list item. This is added to the last
 *            item specified by @address
 *
 * Appends a new item to the specified nested list.
 * If @delim is NULL, item is added to the top level
 * list (@list itself) with id equal to @address.
 * Otherwise, @address is split by @delim and each
 * id is added as new 'layer'. For example:
 *
 * &gt; @address = "one:two:three", @delim = ":" will
 *   produce:
 *      top_level_list:one
 *                     `- "one" list:two
 *                                   `- "two" list:three
 *   where @value is assigned to the "two" list:three
 *   item.
 *
 * Returns: true if successful, otherwise false. Will
 * always return false if item specified by @address
 * already exists in the nested list.
 */
bool nested_list_add_item(nested_list_t *list,
      const char *address, const char *delim, const void *value);

/***********/
/* Getters */
/***********/

/**
 * nested_list_get_size:
 *
 * @list : pointer to nested_list_t object
 *
 * Fetches the current size (number of items) in
 * the specified list.
 *
 * Returns: list size.
 */
size_t nested_list_get_size(nested_list_t *list);

/**
 * nested_list_get_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 *
 * Searches for (and returns) the list item corresponding
 * to @address. If @delim is NULL, the top level list
 * (@list itself) is searched for an item with an id
 * equal to @address. Otherwise, @address is split by
 * @delim and each id is searched for in a subsequent
 * list level.
 *
 * Returns: valid nested_list_item_t pointer if item
 * is found, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item(nested_list_t *list,
      const char *address, const char *delim);

/**
 * nested_list_get_item_idx:
 *
 * @list : pointer to nested_list_t object
 * @idx  : item index
 *
 * Fetches the item corresponding to index @idx in
 * the top level list (@list itself) of the specified
 * nested list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * exists, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item_idx(nested_list_t *list,
      size_t idx);

/**
 * nested_list_item_get_parent:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the parent item of the specified nested
 * list item. If returned value is NULL, specified
 * nested list item belongs to a top level list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * has a parent, otherwise NULL.
 */
nested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item);

/**
 * nested_list_item_get_parent_list:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of which the
 * specified list item is a direct member.
 *
 * Returns: valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item);

/**
 * nested_list_item_get_children:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of child items
 * belonging to the specified list item.
 *
 * Returns: valid nested_list_t pointer if item has
 * children, otherwise NULL.
 */
nested_list_t *nested_list_item_get_children(nested_list_item_t *list_item);

/**
 * nested_list_item_get_id:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the id string of the specified list item,
 * as set by nested_list_add_item().
 *
 * Returns: item id if successful, otherwise NULL.
 */
const char *nested_list_item_get_id(nested_list_item_t *list_item);

/**
 * nested_list_item_get_address:
 *
 * @list_item : pointer to nested_list_item_t object
 * @delim     : delimiter to use when concatenating
 *              individual item ids into a an @address
 *              string
 * @address   : a delimited list of item identifiers,
 *              corresponding to item 'levels'
 * @len       : length of supplied @address char array
 
 * Fetches a compound @address string corresponding to
 * the specified item's 'position' in the top level
 * nested list of which it is a member. The resultant
 * @address may be used to find the item when calling
 * nested_list_get_item() on the top level nested list.
 *
 * Returns: true if successful, otherwise false.
 */
bool nested_list_item_get_address(nested_list_item_t *list_item,
      const char *delim, char *address, size_t len);

/**
 * nested_list_item_get_value:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the value (user data) associated with the
 * specified list item.
 *
 * Returns: pointer to user data if set, otherwise
 * NULL.
 */
const void *nested_list_item_get_value(nested_list_item_t *list_item);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/lists/string_list.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (string_list.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_STRING_LIST_H
#define __LIBRETRO_SDK_STRING_LIST_H

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;

RETRO_BEGIN_DECLS

union string_list_elem_attr
{
   bool  b;
   int   i;
   void *p;
};

struct string_list_elem
{
   char *data;
   void *userdata;
   union string_list_elem_attr attr;
};

struct string_list
{
   struct string_list_elem *elems;
   size_t size;
   size_t cap;
};

/**
 * string_list_find_elem:
 * @list             : pointer to string list
 * @elem             : element to find inside the string list.
 *
 * Searches for an element (@elem) inside the string list.
 *
 * @return Number of elements found, otherwise 0.
 */
int string_list_find_elem(const struct string_list *list, const char *elem);

/**
 * string_list_find_elem_prefix:
 * @list             : pointer to string list
 * @prefix           : prefix to append to @elem
 * @elem             : element to find inside the string list.
 *
 * Searches for an element (@elem) inside the string list. Will
 * also search for the same element prefixed by @prefix.
 *
 * Returns: true (1) if element could be found, otherwise false (0).
 */
bool string_list_find_elem_prefix(const struct string_list *list,
      const char *prefix, const char *elem);

/**
 * string_split:
 * @str              : string to turn into a string list
 * @delim            : delimiter character to use for splitting the string.
 *
 * Creates a new string list based on string @str, delimited by @delim.
 *
 * Returns: new string list if successful, otherwise NULL.
 */
struct string_list *string_split(const char *str, const char *delim);

bool string_split_noalloc(struct string_list *list,
      const char *str, const char *delim);

bool string_list_deinitialize(struct string_list *list);

bool string_list_initialize(struct string_list *list);

/**
 * string_list_new:
 *
 * Creates a new string list. Has to be freed manually.
 *
 * @return New string list if successful, otherwise NULL.
 **/
struct string_list *string_list_new(void);

/**
 * string_list_append:
 * @list             : pointer to string list
 * @elem             : element to add to the string list
 * @attr             : attributes of new element.
 *
 * Appends a new element to the string list.

 * Hidden non-leaf function cost:
 * - Calls string_list_capacity()
 * - Calls strdup
 *
 * @return true if successful, otherwise false.
 **/
bool string_list_append(struct string_list *list, const char *elem,
      union string_list_elem_attr attr);

/**
 * string_list_free
 * @list             : pointer to string list object
 *
 * Frees a string list.
 **/
void string_list_free(struct string_list *list);

/**
 * string_list_join_concat:
 * @s                : buffer that @list will be joined to.
 * @len              : length of @s.
 * @list             : pointer to string list.
 * @delim            : delimiter character for @list.
 *
 * A string list will be joined/concatenated as a
 * string to @s, delimited by @delim.
 *
 * NOTE: @s must be NULL-terminated.
 *
 * Hidden non-leaf function cost:
 * - Calls strlen()
 * - Calls strlcpy x times in a loop
 **/
void string_list_join_concat(char *s, size_t len,
      const struct string_list *list, const char *sep);

/**
 * string_list_join_concat_special:
 * @s                : buffer that @list will be joined to.
 * @len              : length of @s.
 * @list             : pointer to string list.
 * @delim            : delimiter character for @list.
 *
 * Specialized version of string_list_join_concat
 * without the bounds check.
 *
 * A string list will be joined/concatenated as a
 * string to @s, delimited by @delim.
 **/
void string_list_join_concat_special(char *s, size_t len,
      const struct string_list *list, const char *delim);

/**
 * string_list_capacity:
 * @list             : pointer to string list
 * @cap              : new capacity for string list.
 *
 * Change maximum capacity of string list's size.
 *
 * @return true if successful, otherwise false.
 **/
bool string_list_capacity(struct string_list *list, size_t cap);

struct string_list *string_list_clone(const struct string_list *src);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/lrc_hash.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (lrc_hash.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_HASH_H
#define __LIBRETRO_SDK_HASH_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;compat/msvc.h&gt;
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include &lt;retro_inline.h&gt;

#include &lt;retro_common_api.h&gt;

#ifdef __APPLE__
#include &lt;CommonCrypto/CommonDigest.h&gt;
#endif

RETRO_BEGIN_DECLS

/**
 * sha256_hash:
 * @s                 : Output.
 * @in                : Input.
 * @len               : Size of @out.
 *
 * Hashes SHA256 and outputs a human readable string.
 **/
void sha256_hash(char *s, const uint8_t *in, size_t len);

int sha1_calculate(const char *path, char *result);

uint32_t djb2_calculate(const char *str);

#ifdef __APPLE__
typedef CC_MD5_CTX MD5_CTX;
#define MD5_Init CC_MD5_Init
#define MD5_Update CC_MD5_Update
#define MD5_Final CC_MD5_Final
#else

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;

typedef struct {
	MD5_u32plus lo, hi;
	MD5_u32plus a, b, c, d;
	unsigned char buffer[64];
	MD5_u32plus block[16];
} MD5_CTX;

/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer &lt;solar at openwall.com&gt;
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * See md5.c for more information.
 */

void MD5_Init(MD5_CTX *ctx);
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
void MD5_Final(unsigned char *result, MD5_CTX *ctx);

#endif

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/math/complex.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (complex.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_MATH_COMPLEX_H__
#define __LIBRETRO_SDK_MATH_COMPLEX_H__

#include &lt;stdint.h&gt;

#include &lt;retro_inline.h&gt;

typedef struct
{
   float real;
   float imag;
} fft_complex_t;

static INLINE fft_complex_t fft_complex_mul(fft_complex_t a,
      fft_complex_t b)
{
   fft_complex_t out;
   out.real = a.real * b.real - a.imag * b.imag;
   out.imag = a.imag * b.real + a.real * b.imag;

   return out;

}

static INLINE fft_complex_t fft_complex_add(fft_complex_t a,
      fft_complex_t b)
{
   fft_complex_t out;
   out.real = a.real + b.real;
   out.imag = a.imag + b.imag;

   return out;

}

static INLINE fft_complex_t fft_complex_sub(fft_complex_t a,
      fft_complex_t b)
{
   fft_complex_t out;
   out.real = a.real - b.real;
   out.imag = a.imag - b.imag;

   return out;

}

static INLINE fft_complex_t fft_complex_conj(fft_complex_t a)
{
   fft_complex_t out;
   out.real = a.real;
   out.imag = -a.imag;

   return out;
}

#endif</pre>
<h2>./include/libretro-common/include/math/float_minmax.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (float_minmax.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__
#define __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__

#include &lt;stdint.h&gt;
#include &lt;math.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;retro_environment.h&gt;

#ifdef __SSE2__
#include &lt;emmintrin.h&gt;
#include &lt;mmintrin.h&gt;
#endif

static INLINE float float_min(float a, float b)
{
#ifdef __SSE2__
   _mm_store_ss( &amp;a, _mm_min_ss(_mm_set_ss(a),_mm_set_ss(b)) );
   return a;
#elif !defined(DJGPP) &amp;&amp; (defined(__STDC_C99__) || defined(__STDC_C11__))
   return fminf(a, b);
#else
   return MIN(a, b);
#endif
}

static INLINE float float_max(float a, float b)
{
#ifdef __SSE2__
   _mm_store_ss( &amp;a, _mm_max_ss(_mm_set_ss(a),_mm_set_ss(b)) );
   return a;
#elif !defined(DJGPP) &amp;&amp; (defined(__STDC_C99__) || defined(__STDC_C11__))
   return fmaxf(a, b);
#else
   return MAX(a, b);
#endif
}

#endif</pre>
<h2>./include/libretro-common/include/math/fxp.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fxp.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_MATH_FXP_H__
#define __LIBRETRO_SDK_MATH_FXP_H__

#include &lt;stdint.h&gt;

#ifdef _MSC_VER
#include &lt;intrin.h&gt;
#endif

#include &lt;retro_inline.h&gt;

static INLINE int64_t fx32_mul(const int32_t a, const int32_t b)
{
#ifdef _MSC_VER
   return __emul(a, b);
#else
   return ((int64_t)a) * ((int64_t)b);
#endif
}

static INLINE int32_t fx32_shiftdown(const int64_t a)
{
#ifdef _MSC_VER
	return (int32_t)__ll_rshift(a, 12);
#else
	return (int32_t)(a &gt;&gt; 12);
#endif
}

static INLINE int64_t fx32_shiftup(const int32_t a)
{
#ifdef _MSC_VER
	return __ll_lshift(a, 12);
#else
	return ((int64_t)a) &lt;&lt; 12;
#endif
}

#endif</pre>
<h2>./include/libretro-common/include/media/media_detect_cd.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (media_detect_cd.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_MEDIA_DETECT_CD_H
#define __LIBRETRO_SDK_MEDIA_DETECT_CD_H

#include &lt;retro_common_api.h&gt;
#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

enum media_detect_cd_system
{
   MEDIA_CD_SYSTEM_MEGA_CD,
   MEDIA_CD_SYSTEM_SATURN,
   MEDIA_CD_SYSTEM_DREAMCAST,
   MEDIA_CD_SYSTEM_PSX,
   MEDIA_CD_SYSTEM_3DO,
   MEDIA_CD_SYSTEM_PC_ENGINE_CD
};

typedef struct
{
   char title[256];
   char system[128];
   char region[128];
   char serial[64];
   char maker[64];
   char version[32];
   char release_date[32];
   enum media_detect_cd_system system_id;
} media_detect_cd_info_t;

/* Fill in "info" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */
bool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info);

/* Fill in "info" with detected CD info. Use this when you have a cue file and want it parsed to find the first data track and any pregap info. */
bool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/memalign.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memalign.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_MEMALIGN_H
#define _LIBRETRO_MEMALIGN_H

#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

void *memalign_alloc(size_t boundary, size_t len);

void *memalign_alloc_aligned(size_t len);

void memalign_free(void *ptr);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/memmap.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memmap.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_MEMMAP_H
#define _LIBRETRO_MEMMAP_H

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;

#if defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX) || defined(__PS3__) || defined(__PSL1GHT__)
/* No mman available */
#elif defined(_WIN32) &amp;&amp; !defined(_XBOX)
#include &lt;windows.h&gt;
#include &lt;errno.h&gt;
#include &lt;io.h&gt;
#else
#define HAVE_MMAN
#include &lt;sys/mman.h&gt;
#endif

#if !defined(HAVE_MMAN) || defined(_WIN32)
void* mmap(void *addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off);

int munmap(void *addr, size_t len);

int mprotect(void *addr, size_t len, int prot);
#endif

int memsync(void *start, void *end);

int memprotect(void *addr, size_t len);

#endif</pre>
<h2>./include/libretro-common/include/net/net_compat.h</h2>
<pre>/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_compat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_COMPAT_H
#define _LIBRETRO_SDK_NET_COMPAT_H

#include &lt;stdint.h&gt;
#include &lt;boolean.h&gt;
#include &lt;retro_inline.h&gt;

#include &lt;errno.h&gt;

#ifndef _WIN32
#include &lt;sys/time.h&gt;
#include &lt;unistd.h&gt;
#endif

#include &lt;retro_common_api.h&gt;

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN

#include &lt;winsock2.h&gt;
#include &lt;windows.h&gt;
#include &lt;ws2tcpip.h&gt;

#if _MSC_VER &amp;&amp; _MSC_VER &lt;= 1600
/* If we are using MSVC2010 or lower, disable WSAPoll support 
 * to ensure Windows XP and earlier backwards compatibility */
#else
#ifndef WIN32_SUPPORTS_POLL
#define WIN32_SUPPORTS_POLL 1
#endif
#endif

#if defined(WIN32_SUPPORTS_POLL) &amp;&amp; defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &gt;= 0x0600
#define NETWORK_HAVE_POLL 1
#endif

#elif defined(_XBOX)
#define NOD3D

#include &lt;xtl.h&gt;
#include &lt;io.h&gt;

#ifndef SO_KEEPALIVE
#define SO_KEEPALIVE 0 /* verify if correct */
#endif

#define socklen_t unsigned int

#elif defined(VITA)
#include &lt;psp2/net/net.h&gt;
#include &lt;psp2/net/netctl.h&gt;

#define NETWORK_HAVE_POLL 1

#define AF_UNSPEC 0
#define AF_INET SCE_NET_AF_INET

#define SOCK_STREAM SCE_NET_SOCK_STREAM
#define SOCK_DGRAM SCE_NET_SOCK_DGRAM

#define INADDR_ANY SCE_NET_INADDR_ANY
#define INADDR_NONE 0xFFFFFFFF

#define SOL_SOCKET SCE_NET_SOL_SOCKET
#define SO_REUSEADDR SCE_NET_SO_REUSEADDR
#define SO_KEEPALIVE SCE_NET_SO_KEEPALIVE
#define SO_BROADCAST SCE_NET_SO_BROADCAST
#define SO_SNDBUF SCE_NET_SO_SNDBUF
#define SO_RCVBUF SCE_NET_SO_RCVBUF
#define SO_SNDTIMEO SCE_NET_SO_SNDTIMEO
#define SO_RCVTIMEO SCE_NET_SO_RCVTIMEO
#define SO_ERROR SCE_NET_SO_ERROR
#define SO_NBIO SCE_NET_SO_NBIO

#define IPPROTO_IP SCE_NET_IPPROTO_IP
#define IP_MULTICAST_TTL SCE_NET_IP_MULTICAST_TTL

#define IPPROTO_TCP SCE_NET_IPPROTO_TCP
#define TCP_NODELAY SCE_NET_TCP_NODELAY

#define IPPROTO_UDP SCE_NET_IPPROTO_UDP

#define MSG_DONTWAIT SCE_NET_MSG_DONTWAIT

#define POLLIN   SCE_NET_EPOLLIN
#define POLLOUT  SCE_NET_EPOLLOUT
#define POLLERR  SCE_NET_EPOLLERR
#define POLLHUP  SCE_NET_EPOLLHUP
#define POLLNVAL 0

#define sockaddr SceNetSockaddr
#define sockaddr_in SceNetSockaddrIn
#define in_addr SceNetInAddr
#define socklen_t unsigned int

#define socket(a,b,c) sceNetSocket("unknown",a,b,c)
#define getsockname sceNetGetsockname
#define getsockopt sceNetGetsockopt
#define setsockopt sceNetSetsockopt
#define bind sceNetBind
#define listen sceNetListen
#define accept sceNetAccept
#define connect sceNetConnect
#define send sceNetSend
#define sendto sceNetSendto
#define recv sceNetRecv
#define recvfrom sceNetRecvfrom
#define htonl sceNetHtonl
#define ntohl sceNetNtohl
#define htons sceNetHtons
#define ntohs sceNetNtohs
#define inet_ntop sceNetInetNtop
#define inet_pton sceNetInetPton

#elif defined(GEKKO)
#include &lt;network.h&gt;

#define NETWORK_HAVE_POLL 1

#define pollfd pollsd

#define socket(a,b,c) net_socket(a,b,c)
#define getsockopt(a,b,c,d,e) net_getsockopt(a,b,c,d,e)
#define setsockopt(a,b,c,d,e) net_setsockopt(a,b,c,d,e)
#define bind(a,b,c) net_bind(a,b,c)
#define listen(a,b) net_listen(a,b)
#define accept(a,b,c) net_accept(a,b,c)
#define connect(a,b,c) net_connect(a,b,c)
#define send(a,b,c,d) net_send(a,b,c,d)
#define sendto(a,b,c,d,e,f) net_sendto(a,b,c,d,e,f)
#define recv(a,b,c,d) net_recv(a,b,c,d)
#define recvfrom(a,b,c,d,e,f) net_recvfrom(a,b,c,d,e,f)
#define select(a,b,c,d,e) net_select(a,b,c,d,e)
#define gethostbyname(a) net_gethostbyname(a)

#else
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;sys/select.h&gt;

#include &lt;netinet/in.h&gt;
#ifndef __PSL1GHT__
#include &lt;netinet/tcp.h&gt;
#endif

#include &lt;arpa/inet.h&gt;
#include &lt;netdb.h&gt;
#include &lt;fcntl.h&gt;

#if !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
#include &lt;netex/libnetctl.h&gt;
#include &lt;netex/errno.h&gt;
#else
#include &lt;signal.h&gt;
#endif

#if defined(__PSL1GHT__)
#include &lt;net/poll.h&gt;

#define NETWORK_HAVE_POLL 1

#elif defined(WIIU)
#define WIIU_RCVBUF 0x40000
#define WIIU_SNDBUF 0x40000

#elif !defined(__PS3__)
#include &lt;poll.h&gt;

#define NETWORK_HAVE_POLL 1

#endif
#endif

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

#if defined(AF_INET6) &amp;&amp; !defined(HAVE_SOCKET_LEGACY) &amp;&amp; !defined(_3DS)
#define HAVE_INET6 1
#endif

#ifdef NETWORK_HAVE_POLL
#ifdef GEKKO
#define NET_POLL_FD(sockfd, sockfds)    (sockfds)-&gt;socket  = (sockfd)
#else
#define NET_POLL_FD(sockfd, sockfds)    (sockfds)-&gt;fd      = (sockfd)
#endif
#define NET_POLL_EVENT(sockev, sockfds) (sockfds)-&gt;events |= (sockev)
#define NET_POLL_HAS_EVENT(sockev, sockfds) ((sockfds)-&gt;revents &amp; (sockev))
#endif

RETRO_BEGIN_DECLS

/* Compatibility layer for legacy or incomplete BSD socket implementations.
 * Only for IPv4. Mostly useful for the consoles which do not support
 * anything reasonably modern on the socket API side of things. */
#ifdef HAVE_SOCKET_LEGACY
#define sockaddr_storage sockaddr_in

#ifdef AI_PASSIVE
#undef AI_PASSIVE
#endif
#ifdef AI_CANONNAME
#undef AI_CANONNAME
#endif
#ifdef AI_NUMERICHOST
#undef AI_NUMERICHOST
#endif
#ifdef AI_NUMERICSERV
#undef AI_NUMERICSERV
#endif

#ifdef NI_NUMERICHOST
#undef NI_NUMERICHOST
#endif
#ifdef NI_NUMERICSERV
#undef NI_NUMERICSERV
#endif
#ifdef NI_NOFQDN
#undef NI_NOFQDN
#endif
#ifdef NI_NAMEREQD
#undef NI_NAMEREQD
#endif
#ifdef NI_DGRAM
#undef NI_DGRAM
#endif

#define AI_PASSIVE     1
#define AI_CANONNAME   2
#define AI_NUMERICHOST 4
#define AI_NUMERICSERV 8

#define NI_NUMERICHOST 1
#define NI_NUMERICSERV 2
#define NI_NOFQDN      4
#define NI_NAMEREQD    8
#define NI_DGRAM       16

#ifndef __PS3__
struct addrinfo
{
   int ai_flags;
   int ai_family;
   int ai_socktype;
   int ai_protocol;
   socklen_t ai_addrlen;
   struct sockaddr *ai_addr;
   char *ai_canonname;
   struct addrinfo *ai_next;
};
#endif

/* gai_strerror() not used, so we skip that. */

#else
/* Ensure that getaddrinfo and getnameinfo flags are always defined. */
#ifndef AI_PASSIVE
#define AI_PASSIVE 0
#endif
#ifndef AI_CANONNAME
#define AI_CANONNAME 0
#endif
#ifndef AI_NUMERICHOST
#define AI_NUMERICHOST 0
#endif
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV 0
#endif

#ifndef NI_NUMERICHOST
#define NI_NUMERICHOST 0
#endif
#ifndef NI_NUMERICSERV
#define NI_NUMERICSERV 0
#endif
#ifndef NI_NOFQDN
#define NI_NOFQDN 0
#endif
#ifndef NI_NAMEREQD
#define NI_NAMEREQD 0
#endif
#ifndef NI_DGRAM
#define NI_DGRAM 0
#endif

#endif

#if defined(_XBOX)
struct hostent
{
   char *h_name;
   char **h_aliases;
   int  h_addrtype;
   int  h_length;
   char **h_addr_list;
   char *h_addr;
   char *h_end;
};

#elif defined(VITA)
struct pollfd
{
   int fd;
   unsigned events;
   unsigned revents;
   unsigned __pad; /* Align to 64-bits boundary */
};

struct hostent
{
   char *h_name;
   char **h_aliases;
   int  h_addrtype;
   int  h_length;
   char **h_addr_list;
   char *h_addr;
   char *h_end;
};

#endif

static INLINE bool isagain(int val)
{
#if defined(_WIN32)
   return (val == SOCKET_ERROR) &amp;&amp; (WSAGetLastError() == WSAEWOULDBLOCK);
#elif !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
   return (sys_net_errno == SYS_NET_EAGAIN) || (sys_net_errno == SYS_NET_EWOULDBLOCK);
#elif defined(VITA)
   return (val == SCE_NET_ERROR_EAGAIN) || (val == SCE_NET_ERROR_EWOULDBLOCK);
#elif defined(WIIU)
   return (val == -1) &amp;&amp; (socketlasterr() == SO_SUCCESS || socketlasterr() == SO_EWOULDBLOCK);
#elif defined(GEKKO)
   return (-val == EAGAIN);
#else
   return (val &lt; 0) &amp;&amp; (errno == EAGAIN || errno == EWOULDBLOCK);
#endif
}

static INLINE bool isinprogress(int val)
{
#if defined(_WIN32)
   return (val == SOCKET_ERROR) &amp;&amp; (WSAGetLastError() == WSAEWOULDBLOCK);
#elif !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
   return (sys_net_errno == SYS_NET_EINPROGRESS);
#elif defined(VITA)
   return (val == SCE_NET_ERROR_EINPROGRESS);
#elif defined(WIIU)
   return (val == -1) &amp;&amp; (socketlasterr() == SO_EINPROGRESS);
#elif defined(GEKKO)
   return (-val == EINPROGRESS);
#else
   return (val &lt; 0) &amp;&amp; (errno == EINPROGRESS);
#endif
}

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#if !defined(_WIN32_WINNT) || _WIN32_WINNT &lt; 0x0600
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
int inet_pton(int af, const char *src, void *dst);
#endif

#elif defined(_XBOX)
struct hostent *gethostbyname(const char *name);

#elif defined(VITA)
char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
uint32_t inet_addr(const char *cp);

struct hostent *gethostbyname(const char *name);

#elif defined(GEKKO)
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
int inet_pton(int af, const char *src, void *dst);

#endif

int getaddrinfo_retro(const char *node, const char *service,
      struct addrinfo *hints, struct addrinfo **res);

void freeaddrinfo_retro(struct addrinfo *res);

int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);

bool addr_6to4(struct sockaddr_storage *addr);

bool ipv4_is_lan_address(const struct sockaddr_in *addr);
bool ipv4_is_cgnat_address(const struct sockaddr_in *addr);

/**
 * network_init:
 *
 * Platform specific socket library initialization.
 *
 * @return true if successful, otherwise false.
 **/
bool network_init(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/net/net_http.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_HTTP_H
#define _LIBRETRO_SDK_NET_HTTP_H

#include &lt;stdint.h&gt;
#include &lt;boolean.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

struct http_t;
struct http_connection_t;

struct http_connection_t *net_http_connection_new(const char *url, const char *method, const char *data);

/**
 * net_http_connection_iterate:
 *
 * Leaf function.
 **/
bool net_http_connection_iterate(struct http_connection_t *conn);

bool net_http_connection_done(struct http_connection_t *conn);

void net_http_connection_free(struct http_connection_t *conn);

void net_http_connection_set_user_agent(struct http_connection_t *conn, const char *user_agent);

void net_http_connection_set_headers(struct http_connection_t *conn, const char *headers);

void net_http_connection_set_content(struct http_connection_t *conn, const char *content_type,
      size_t content_length, const void *content);

const char *net_http_connection_url(struct http_connection_t *conn);

const char* net_http_connection_method(struct http_connection_t* conn);

struct http_t *net_http_new(struct http_connection_t *conn);

/**
 * net_http_fd:
 *
 * Leaf function.
 *
 * You can use this to call net_http_update
 * only when something will happen; select() it for reading.
 **/
int net_http_fd(struct http_t *state);

/**
 * net_http_update:
 *
 * @return true if it's done, or if something broke.
 * @total will be 0 if it's not known.
 **/
bool net_http_update(struct http_t *state, size_t* progress, size_t* total);

/**
 * net_http_status:
 *
 * Report HTTP status. 200, 404, or whatever.
 *
 * Leaf function.
 *
 * @return HTTP status code.
 **/
int net_http_status(struct http_t *state);

/**
 * net_http_error:
 *
 * Leaf function
 **/
bool net_http_error(struct http_t *state);

/**
 * net_http_headers:
 *
 * Leaf function.
 *
 * @return the response headers. The returned buffer is owned by the
 * caller of net_http_new; it is not freed by net_http_delete.
 * If the status is not 20x and accept_error is false, it returns NULL.
 **/
struct string_list *net_http_headers(struct http_t *state);

/**
 * net_http_data:
 *
 * Leaf function.
 *
 * @return the downloaded data. The returned buffer is owned by the
 * HTTP handler; it's freed by net_http_delete.
 * If the status is not 20x and accept_error is false, it returns NULL.
 **/
uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_error);

/**
 * net_http_delete:
 *
 * Cleans up all memory.
 **/
void net_http_delete(struct http_t *state);

/**
 * net_http_urlencode:
 *
 * URL Encode a string
 * caller is responsible for deleting the destination buffer
 **/
void net_http_urlencode(char **dest, const char *source);

/**
 * net_http_urlencode_full:
 *
 * Re-encode a full URL
 **/
void net_http_urlencode_full(char *s, const char *source, size_t len);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/net/net_http_parse.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_HTTP_PARSE_H
#define _LIBRETRO_SDK_NET_HTTP_PARSE_H

#include &lt;stdint.h&gt;
#include &lt;boolean.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/**
 * string_parse_html_anchor:
 * @line               : Buffer where the &lt;a&gt; tag is stored
 * @link               : Buffer to store the link URL in
 * @name               : Buffer to store the link URL in
 * @link_size          : Size of the link buffer including the NUL-terminator
 * @name_size          : Size of the name buffer including the NUL-terminator
 *
 * Parses an HTML anchor link stored in @line in the form of: &lt;a href="/path/to/url"&gt;Title&lt;/a&gt;
 * The buffer pointed to by @link is filled with the URL path the link points to,
 * and @name is filled with the title portion of the link.
 *
 * @return 0 if URL was parsed completely, otherwise 1.
 **/
int string_parse_html_anchor(const char *line, char *link, char *name,
      size_t link_size, size_t name_size);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/net/net_ifinfo.h</h2>
<pre>/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_ifinfo.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_IFINFO_H
#define _LIBRETRO_SDK_NET_IFINFO_H

#include &lt;stddef.h&gt;

#include &lt;boolean.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

struct net_ifinfo_entry
{
   char name[256];
   char host[256];
};

typedef struct net_ifinfo
{
   struct net_ifinfo_entry *entries;
   size_t size;
} net_ifinfo_t;

bool net_ifinfo_new(net_ifinfo_t *list);

void net_ifinfo_free(net_ifinfo_t *list);

bool net_ifinfo_best(const char *dst, void *src, bool ipv6);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/net/net_socket.h</h2>
<pre>/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_SOCKET_H
#define _LIBRETRO_SDK_NET_SOCKET_H

#include &lt;stddef.h&gt;
#include &lt;stdint.h&gt;
#include &lt;boolean.h&gt;

#include &lt;net/net_compat.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

enum socket_domain
{
   SOCKET_DOMAIN_INET = 0
};

enum socket_type
{
   SOCKET_TYPE_DATAGRAM = 0,
   SOCKET_TYPE_STREAM,
   SOCKET_TYPE_SEQPACKET
};

enum socket_protocol
{
   SOCKET_PROTOCOL_NONE = 0,
   SOCKET_PROTOCOL_TCP,
   SOCKET_PROTOCOL_UDP
};

typedef struct socket_target
{
   unsigned port;
   const char *server;
   enum socket_domain domain;
   enum socket_protocol prot;
} socket_target_t;

int socket_init(void **address, uint16_t port, const char *server,
      enum socket_type type, int family);

int socket_next(void **address);

int socket_close(int fd);

bool socket_set_block(int fd, bool block);

/* TODO: all callers should be converted to socket_set_block() */
bool socket_nonblock(int fd);

int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
      fd_set *errorfds, struct timeval *timeout);

#ifdef NETWORK_HAVE_POLL
int socket_poll(struct pollfd *fds, unsigned nfds, int timeout);
#endif

bool socket_wait(int fd, bool *rd, bool *wr, int timeout);

bool socket_send_all_blocking(int fd, const void *data_, size_t len, bool no_signal);

bool socket_send_all_blocking_with_timeout(int fd,
      const void *data_, size_t len, int timeout, bool no_signal);

ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t len,
      bool no_signal);

bool socket_receive_all_blocking(int fd, void *data_, size_t len);

bool socket_receive_all_blocking_with_timeout(int fd,
      void *data_, size_t len, int timeout);

ssize_t socket_receive_all_nonblocking(int fd, bool *error,
      void *data_, size_t len);

bool socket_bind(int fd, void *data);

int socket_connect(int fd, void *data);

bool socket_connect_with_timeout(int fd, void *data, int timeout);

int socket_create(
      const char *name,
      enum socket_domain domain_type,
      enum socket_type socket_type,
      enum socket_protocol protocol_type);

void socket_set_target(void *data, socket_target_t *in_addr);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/net/net_socket_ssl.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NET_SOCKET_SSL_H
#define _LIBRETRO_SDK_NET_SOCKET_SSL_H

#include &lt;stdlib.h&gt;
#include &lt;boolean.h&gt;
#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

void* ssl_socket_init(int fd, const char *domain);

int ssl_socket_connect(void *state_data, void *data, bool timeout_enable, bool nonblock);

int ssl_socket_send_all_blocking(void *state_data, const void *data_, size_t len, bool no_signal);

ssize_t ssl_socket_send_all_nonblocking(void *state_data, const void *data_, size_t len, bool no_signal);

int ssl_socket_receive_all_blocking(void *state_data, void *data_, size_t len);

ssize_t ssl_socket_receive_all_nonblocking(void *state_data, bool *error, void *data_, size_t len);

void ssl_socket_close(void *state_data);

void ssl_socket_free(void *state_data);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/playlists/label_sanitization.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (label_sanitization.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include &lt;stddef.h&gt;
#include &lt;boolean.h&gt;

/**
 * label_sanitize:
 *
 * NOTE: Does not work with nested blocks.
 **/
void label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*));

void label_remove_parens(char *label);

void label_remove_brackets(char *label);

void label_remove_parens_and_brackets(char *label);

void label_keep_region(char *label);

void label_keep_disc(char *label);

void label_keep_region_and_disc(char *label);</pre>
<h2>./include/libretro-common/include/queues/fifo_queue.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fifo_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FIFO_BUFFER_H
#define __LIBRETRO_SDK_FIFO_BUFFER_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

/**
 * Returns the available data in \c buffer for reading.
 *
 * @param buffer &lt;tt&gt;fifo_buffer_t *&lt;/tt&gt;. The FIFO queue to check.
 * @return The number of bytes available for reading from \c buffer.
 */
#define FIFO_READ_AVAIL(buffer) (((buffer)-&gt;end + (((buffer)-&gt;end &lt; (buffer)-&gt;first) ? (buffer)-&gt;size : 0)) - (buffer)-&gt;first)

/**
 * Returns the available space in \c buffer for writing.
 *
 * @param buffer &lt;tt&gt;fifo_buffer_t *&lt;/tt&gt;. The FIFO queue to check.
 * @return The number of bytes that \c buffer can accept.
 */
#define FIFO_WRITE_AVAIL(buffer) (((buffer)-&gt;size - 1) - (((buffer)-&gt;end + (((buffer)-&gt;end &lt; (buffer)-&gt;first) ? (buffer)-&gt;size : 0)) - (buffer)-&gt;first))

/**
 * Returns the available data in \c buffer for reading.
 *
 * @param buffer \c fifo_buffer_t. The FIFO queue to check.
 * @return The number of bytes available for reading from \c buffer.
 */
#define FIFO_READ_AVAIL_NONPTR(buffer) (((buffer).end + (((buffer).end &lt; (buffer).first) ? (buffer).size : 0)) - (buffer).first)

/**
 * Returns the available space in \c buffer for writing.
 *
 * @param buffer \c fifo_buffer_t. The FIFO queue to check.
 * @return The number of bytes that \c buffer can accept.
 */
#define FIFO_WRITE_AVAIL_NONPTR(buffer) (((buffer).size - 1) - (((buffer).end + (((buffer).end &lt; (buffer).first) ? (buffer).size : 0)) - (buffer).first))

/** @copydoc fifo_buffer_t */
struct fifo_buffer
{
   uint8_t *buffer;
   size_t size;
   size_t first;
   size_t end;
};

/**
 * A bounded FIFO byte queue implemented as a ring buffer.
 *
 * Useful for communication between threads,
 * although the caller is responsible for synchronization.
 */
typedef struct fifo_buffer fifo_buffer_t;

/**
 * Creates a new FIFO queue with \c size bytes of memory.
 * Must be freed with \c fifo_free.
 *
 * @param size The size of the FIFO queue, in bytes.
 * @return The new queue if successful, \c NULL otherwise.
 * @see fifo_initialize
 */
fifo_buffer_t *fifo_new(size_t len);

/**
 * Initializes an existing FIFO queue with \c size bytes of memory.
 *
 * Suitable for use with \c fifo_buffer_t instances
 * of static or automatic lifetime.
 * Must be freed with \c fifo_deinitialize.
 *
 * @param buf Pointer to the FIFO queue to initialize.
 * May be static or automatic.
 * @param size The size of the FIFO queue, in bytes.
 * @return \c true if \c buf was initialized with the requested memory,
 * \c false if \c buf is \c NULL or there was an error.
 */
bool fifo_initialize(fifo_buffer_t *buf, size_t len);

/**
 * Resets the bounds of \c buffer,
 * effectively clearing it.
 *
 * No memory will actually be freed,
 * but the contents of \c buffer will be overwritten
 * with the next call to \c fifo_write.
 * @param buffer The FIFO queue to clear.
 * Behavior is undefined if \c NULL.
 */
static INLINE void fifo_clear(fifo_buffer_t *buffer)
{
   buffer-&gt;first = 0;
   buffer-&gt;end   = 0;
}

/**
 * Writes \c size bytes to the given queue.
 *
 * @param buffer The FIFO queue to write to.
 * @param in_buf The buffer to read bytes from.
 * @param size The length of \c in_buf, in bytes.
 */
void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len);

/**
 * Reads \c size bytes from the given queue.
 *
 * @param buffer The FIFO queue to read from.
 * @param in_buf The buffer to store the read bytes in.
 * @param size The length of \c in_buf, in bytes.
 * @post Upon return, \c buffer will have up to \c size more bytes of space available for writing.
 */
void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t len);

/**
 * Releases \c buffer and its contents.
 *
 * @param buffer The FIFO queue to free.
 * If \c NULL, this function will do nothing.
 * Behavior is undefined if \c buffer was previously freed.
 * @see fifo_deinitialize
 */
void fifo_free(fifo_buffer_t *buffer);

/**
 * Deallocates the contents of \c buffer,
 * but not \c buffer itself.
 *
 * Suitable for use with static or automatic \c fifo_buffer_t instances.
 *
 * @param buffer The buffer to deinitialize.
 * @return \c false if \c buffer is \c NULL, \c true otherwise.
 * @see fifo_free
 */
bool fifo_deinitialize(fifo_buffer_t *buffer);


RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/queues/generic_queue.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (generic_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_GENERIC_QUEUE_H
#define __LIBRETRO_SDK_GENERIC_QUEUE_H

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;
#include &lt;stddef.h&gt;

RETRO_BEGIN_DECLS

/**
 * Represents a generic queue. Can contain any number of elements. Each element contains
 * a value of type "void *". Can be used as a FIFO or LIFO queue.
 */
typedef struct generic_queue generic_queue_t;

/**
 * Represents an iterator for iterating over a queue.
 */
typedef struct generic_queue_iterator generic_queue_iterator_t;

/**
 * Creates a new queue with no elements.
 *
 * @return New queue
 */
generic_queue_t *generic_queue_new(void);

/**
 * @brief frees the memory used by the queue
 * 
 * Frees all of the memory used by this queue. The values of all
 * remaining elements are freed using the "free_value" function. Does
 * nothing if "queue" is NULL.
 *
 * @param queue queue to free
 * @param free_value function to use to free remaining values
 */
void generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value));

/**
 * @brief Push a new value onto the queue
 *
 * Pushes a new value onto the end of the queue. Does nothing if "queue"
 * is NULL.
 *
 * @param queue queue to the push the value onto
 * @param value value to push onto the queue
 */
void generic_queue_push(generic_queue_t *queue, void *value);

/**
 * @brief Remove the last value from the queue
 *
 * Removes the last element from the queue. Does nothing if the queue is
 * NULL.
 *
 * @param queue queue to get the value from
 * @return value of the last element, NULL if queue is empty or NULL
 */
void *generic_queue_pop(generic_queue_t *queue);

/**
 * @brief Get the last value from the queue
 *
 * Returns the value of the last element in the queue. Returns NULL if the
 * queue is NULL or empty.
 *
 * @param queue queue to get the last value from
 * @return value of the last element or NULL
 */
void *generic_queue_peek(generic_queue_t *queue);

/**
 * @brief Get the first value from the queue
 *
 * Returns the value of the first element in the queue. Returns NULL if the
 * queue is NULL or empty.
 *
 * @param queue queue to get the first value from
 * @return value of the first element or NULL
 */
void *generic_queue_peek_first(generic_queue_t *queue);

/**
 * @brief Push a new value onto the front of the queue
 *
 * Pushes a new value onto the front of the queue. Does nothing if "queue"
 * is NULL.
 *
 * @param queue queue to the push the value onto
 * @param value value to push onto the queue
 */
void generic_queue_shift(generic_queue_t *queue, void *value);

/**
 * @brief Remove the first value from the queue
 *
 * Removes the first element from the queue. Does nothing if the queue is
 * NULL.
 *
 * @param queue queue to get the value from
 * @return value of the last element, NULL if queue is empty or NULL
 */
void *generic_queue_unshift(generic_queue_t *queue);

/**
 * @brief Get the size of the queue
 *
 * Returns the number of elements in the queue.
 *
 * @param queue queue to get the size of
 * @return number of elements in the queue, 0 if queue is NULL
 */
size_t generic_queue_length(generic_queue_t *queue);

/**
 * @brief Remove the first element in the queue with the provided value
 *
 * Removes the first element with a value matching the provided value. Does
 * nothing if queue is NULL.
 *
 * @param queue queue to remove the element from
 * @param value value to look for in the queue
 * @return the value of the element removed, NULL if no element was removed
 */
void *generic_queue_remove(generic_queue_t *queue, void *value);

/**
 * @brief Get an iterator for the queue
 *
 * Returns a new iterator for the queue. Can be either a forward or backward
 * iterator.
 *
 * @param queue queue to iterate over
 * @param forward true for a forward iterator, false for backwards
 * @return new iterator for the queue in the specified direction, NULL if
 *         "queue" is NULL
 */
generic_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward);

/**
 * @brief Move to the next element in the queue
 *
 * Moves the iterator to the next element in the queue. The direction is
 * specified when retrieving a new iterator.
 *
 * @param iterator iterator for the current element
 * @return iterator for the next element, NULL if iterator is NULL or "iterator"
 *         is at the last element
 */
generic_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator);

/**
 * @brief Get the value of the element for the iterator
 *
 * Returns the value of the element that the iterator is at.
 *
 * @param iterator iterator for the current element
 * @return value of the element for the iterator
 */
void *generic_queue_iterator_value(generic_queue_iterator_t *iterator);

/**
 * @brief Remove the element that the iterator is at
 *
 * Removes the element that the iterator is at. The iterator is updated to the
 * next element.
 *
 * @param iterator iterator for the current element
 * @return updated iterator or NULL if the last element was removed
 */
generic_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator);

/**
 * @brief Release the memory for the iterator
 *
 * Frees the memory for the provided iterator. Does nothing if "iterator" is NULL.
 *
 * @param iterator iterator to free
 */
void generic_queue_iterator_free(generic_queue_iterator_t *iterator);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/queues/message_queue.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (message_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_MSG_QUEUE_H
#define __LIBRETRO_SDK_MSG_QUEUE_H

#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

enum message_queue_icon
{
   MESSAGE_QUEUE_ICON_DEFAULT = 0 /* default icon is tied to category */
};

enum message_queue_category
{
   MESSAGE_QUEUE_CATEGORY_INFO = 0,
   MESSAGE_QUEUE_CATEGORY_ERROR,
   MESSAGE_QUEUE_CATEGORY_WARNING,
   MESSAGE_QUEUE_CATEGORY_SUCCESS
};

typedef struct queue_elem
{
   char *msg;
   char *title;
   unsigned duration;
   unsigned prio;
   enum message_queue_icon icon;
   enum message_queue_category category;
} queue_elem_t;

typedef struct msg_queue
{
   char *tmp_msg;
   queue_elem_t **elems;
   size_t ptr;
   size_t size;
} msg_queue_t;

typedef struct
{
   unsigned duration;
   unsigned prio;
   enum message_queue_icon icon;
   enum message_queue_category category;
   char msg[1024];
   char title[1024];
} msg_queue_entry_t;

/**
 * msg_queue_new:
 * @len               : maximum size of message
 *
 * Creates a message queue with maximum size different messages.
 *
 * Returns: NULL if allocation error, pointer to a message queue
 * if successful. Has to be freed manually.
 **/
msg_queue_t *msg_queue_new(size_t len);

bool msg_queue_initialize(msg_queue_t *queue, size_t len);

/**
 * msg_queue_push:
 * @queue             : pointer to queue object
 * @msg               : message to add to the queue
 * @prio              : priority level of the message
 * @duration          : how many times the message can be pulled
 *                      before it vanishes (E.g. show a message for
 *                      3 seconds @ 60fps = 180 duration).
 *
 * Push a new message onto the queue.
 **/
void msg_queue_push(msg_queue_t *queue, const char *msg,
      unsigned prio, unsigned duration,
      char *title,
      enum message_queue_icon icon, enum message_queue_category category);

/**
 * msg_queue_pull:
 * @queue             : pointer to queue object
 *
 * Pulls highest priority message in queue.
 *
 * Returns: NULL if no message in queue, otherwise a string
 * containing the message.
 **/
const char *msg_queue_pull(msg_queue_t *queue);

/**
 * msg_queue_extract:
 * @queue             : pointer to queue object
 * @queue_entry       : pointer to external queue entry struct
 *
 * Removes highest priority message from queue, copying
 * contents into queue_entry struct.
 *
 * Returns: false if no messages in queue, otherwise true
 **/
bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry);

/**
 * msg_queue_size:
 * @queue             : pointer to queue object
 *
 * Fetches number of messages in queue.
 *
 * Returns: Number of messages in queue.
 **/
size_t msg_queue_size(msg_queue_t *queue);

/**
 * msg_queue_clear:
 * @queue             : pointer to queue object
 *
 * Clears out everything in the queue.
 **/
void msg_queue_clear(msg_queue_t *queue);

/**
 * msg_queue_free:
 * @queue             : pointer to queue object
 *
 * Frees message queue..
 **/
void msg_queue_free(msg_queue_t *queue);

bool msg_queue_deinitialize(msg_queue_t *queue);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/queues/task_queue.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (task_queue.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_TASK_QUEUE_H__
#define __LIBRETRO_SDK_TASK_QUEUE_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;boolean.h&gt;

#include &lt;retro_common.h&gt;
#include &lt;retro_common_api.h&gt;

#include &lt;libretro.h&gt;

RETRO_BEGIN_DECLS

enum task_type
{
   /** A regular task. The vast majority of tasks will use this type. */
   TASK_TYPE_NONE,

   /**
    * Only one blocking task can exist in the queue at a time.
    * Attempts to add a new one while another is running will fail.
    */
   TASK_TYPE_BLOCKING
};

enum task_style
{
   TASK_STYLE_NONE,
   TASK_STYLE_POSITIVE,
   TASK_STYLE_NEGATIVE
};

typedef struct retro_task retro_task_t;

/** @copydoc retro_task::callback */
typedef void (*retro_task_callback_t)(retro_task_t *task,
      void *task_data,
      void *user_data, const char *error);

/** @copydoc retro_task::handler */
typedef void (*retro_task_handler_t)(retro_task_t *task);

/** @copydoc task_finder_data::func */
typedef bool (*retro_task_finder_t)(retro_task_t *task,
      void *userdata);

/**
 * Displays a message output by a task.
 */
typedef void (*retro_task_queue_msg_t)(retro_task_t *task,
      const char *msg,
      unsigned prio, unsigned duration, bool flush);

/** @copydoc task_retriever_data::func */
typedef bool (*retro_task_retriever_t)(retro_task_t *task, void *data);

/**
 * Called by \c task_queue_wait after each task executes
 * (i.e. once per pass over the queue).
 * @param data Arbitrary data.
 * The function should cast this to a known type.
 * @return \c true if \c task_queue_wait should continue waiting,
 * \c false if it should return early.
 * @see task_queue_wait
 */
typedef bool (*retro_task_condition_fn_t)(void *data);

typedef struct
{
   char *source_file;
} decompress_task_data_t;

enum retro_task_flags
{
   /**
    * If \c true, the frontend should use some alternative means
    * of displaying this task's progress or messages.
    * Not used within cores.
    */
   RETRO_TASK_FLG_ALTERNATIVE_LOOK = (1 &lt;&lt; 0),
   /**
    * Set to \c true by \c handler to indicate that this task has finished.
    * At this point the task queue will call \c callback and \c cleanup,
    * then deallocate the task.
    */
   RETRO_TASK_FLG_FINISHED         = (1 &lt;&lt; 1),
   /**
    * Set to true by the task queue to signal that this task \em must end.
    * \c handler should check to see if this is set,
    * aborting or completing its work as soon as possible afterward.
    * \c callback and \c cleanup will still be called as normal.
    *
    * @see task_queue_reset
    */
   RETRO_TASK_FLG_CANCELLED        = (1 &lt;&lt; 2),
   /**
    * If set, the task queue will not call \c progress_cb
    * and will not display any messages from this task.
    */
   RETRO_TASK_FLG_MUTE             = (1 &lt;&lt; 3)
};

/**
 * A unit of work executed by the task system,
 * spread across one or more frames.
 *
 * Some fields are set by the caller,
 * others are set by the task system.
 */
struct retro_task
{
   /**
    * The time (in microseconds) when the task should start running,
    * or 0 if it should start as soon as possible.
    * The exact time this task starts will depend on when the queue is next updated.
    * Set by the caller.
    * @note This is a point in time, not a duration.
    * It is not affected by a frontend's time manipulation (pausing, fast-forward, etc.).
    * @see cpu_features_get_time_usec
    */
   retro_time_t when;

   /**
    * The main body of work for a task.
    * Should be as fast as possible,
    * as it will be called with each task queue update
    * (usually once per frame).
    * Must not be \c NULL.
    *
    * @param task The task that this handler is associated with.
    * Can be used to configure or query the task.
    * Will never be \c NULL.
    * @see task_queue_check
    */
   retro_task_handler_t  handler;

   /**
    * Called when this task finishes;
    * executed during the next task queue update
    * after \c finished is set to \c true.
    * May be \c NULL, in which case this function is skipped.
    *
    * @param task The task that is being cleaned up.
    * Will never be \c NULL.
    * @param task_data \c task's \c task_data field.
    * @param user_data \c task's \c user_data field.
    * @param error \c task's \c error field.
    * @see task_queue_check
    * @see retro_task_callback_t
    */
   retro_task_callback_t callback;

   /**
    * Called when this task finishes immediately after \c callback is run.
    * Used to clean up any resources or state owned by the task.
    * May be \c NULL, in which case this function is skipped.
    *
    * @param task The task that is being cleaned up.
    * Will never be \c NULL.
    */
   retro_task_handler_t cleanup;

   /**
    * Pointer to arbitrary data, intended for "returning" an object from the task
    * (although it can be used for any purpose).
    * If owned by the task, it should be cleaned up within \c cleanup.
    * Not modified or freed by the task queue.
    */
   void *task_data;

   /**
    * Pointer to arbitrary data, intended for passing parameters to the task.
    * If owned by the task, it should be cleaned up within \c cleanup.
    * Not modified or freed by the task queue.
    */
   void *user_data;

   /**
    * Pointer to arbitrary data, intended for state that exists for the task's lifetime.
    * If owned by the task, it should be cleaned up within \c cleanup.
    * Not modified or freed by the task queue.
    */
   void *state;

   /**
    * Human-readable details about an error that occurred while running the task.
    * Should be created and assigned within \c handler if there was an error.
    * Will be cleaned up by the task queue with \c free() upon this task's completion.
    * @see task_set_error
    */
   char *error;

   /**
    * Called to update a task's \c progress,
    * or to update some view layer (e.g. an on-screen display)
    * about the task's progress.
    *
    * Skipped if \c NULL or if \c mute is set.
    *
    * @param task The task whose progress is being updated or reported.
    * @see progress
    */
   void (*progress_cb)(retro_task_t*);

   /**
    * Human-readable description of this task.
    * May be \c NULL,
    * but if not then it will be disposed of by the task system with \c free()
    * upon this task's completion.
    * Can be modified or replaced at any time.
    * @see strdup
    */
   char *title;

   /**
    * Pointer to arbitrary data, intended for use by a frontend
    * (for example, to associate a sticky notification with a task).
    *
    * This should be cleaned up within \c cleanup if necessary.
    * Cores may use this for any purpose.
    */
   void *frontend_userdata;

   /**
    * @private Pointer to the next task in the queue.
    * Do not touch this; it is managed by the task system.
    */
   retro_task_t *next;

   /**
    * Indicates the current progress of the task.
    *
    * -1 means the task is indefinite or not measured,
    * 0-100 is a percentage of the task's completion.
    *
    * Set by the caller.
    *
    * @see progress_cb
    */
   int8_t progress;

   /**
    * A unique identifier assigned to a task when it's created.
    * Set by the task system.
    */
   uint32_t ident;

   /**
    * The type of task this is.
    * Set by the caller.
    */
   enum task_type type;
   enum task_style style;

   uint8_t flags;
};

/**
 * Parameters for \c task_queue_find.
 *
 * @see task_queue_find
 */
typedef struct task_finder_data
{
   /**
    * Predicate to call for each task.
    * Must not be \c NULL.
    *
    * @param task The task to query.
    * @param userdata \c userdata from this struct.
    * @return \c true if this task matches the search criteria,
    * at which point \c task_queue_find will stop searching and return \c true.
    */
   retro_task_finder_t func;

   /**
    * Pointer to arbitrary data.
    * Passed directly to \c func.
    * May be \c NULL.
    */
   void *userdata;
} task_finder_data_t;

/**
 * Contains the result of a call to \c task_retriever_data::func.
 * Implemented as an intrusive singly-linked list.
 */
typedef struct task_retriever_info
{
   /**
    * The next item in the result list,
    * or \c NULL if this is the last one.
    */
   struct task_retriever_info *next;

   /**
    * Arbitrary data returned by \c func.
    * Can be anything, but should be a simple \c struct
    * so that it can be freed by \c task_queue_retriever_info_free.
    */
   void *data;
} task_retriever_info_t;

/**
 * Parameters for \c task_queue_retrieve.
 *
 * @see task_queue_retrieve
 */
typedef struct task_retriever_data
{
   /**
    * Contains the result of each call to \c func that returned \c true.
    * Should be initialized to \c NULL.
    * Will remain \c NULL after \c task_queue_retrieve if no tasks matched.
    * Must be freed by \c task_queue_retriever_info_free.
    * @see task_queue_retriever_info_free
    */
   task_retriever_info_t *list;

   /**
    * The handler to compare against.
    * Only tasks with this handler will be considered for retrieval.
    * Must not be \c NULL.
    */
   retro_task_handler_t handler;

   /**
    * The predicate that determines if the given task will be retrieved.
    * Must not be \c NULL.
    *
    * @param task[in] The task to query.
    * @param data[out] Arbitrary data that the retriever should return.
    * Allocated by the task queue based on \c element_size.
    * @return \c true if \c data should be appended to \c list.
    */
   retro_task_retriever_t func;

   /**
    * The size of the output that \c func may write to.
    * Must not be zero.
    */
   size_t element_size;
} task_retriever_data_t;

/**
 * Returns the next item in the result list.
 * Here's a usage example, assuming that \c results is used to store strings:
 *
 * @code{.c}
 * void print_results(task_retriever_info_t *results)
 * {
 *    char* text = NULL;
 *    task_retriever_info_t *current = results;
 *    while (text = task_queue_retriever_info_next(&amp;current))
 *    {
 *       printf("%s\n", text);
 *    }
 * }
 * @endcode
 *
 * @param link Pointer to the first element in the result list.
 * Must not be \c NULL.
 * @return The next item in the result list.
 */
void *task_queue_retriever_info_next(task_retriever_info_t **link);

/**
 * Frees the result of a call to \c task_queue_retrieve.
 * @param list The result list to free.
 * May be \c NULL, in which case this function does nothing.
 * The list, its nodes, and its elements will all be freed.
 *
 * If the list's elements must be cleaned up with anything besides \c free,
 * then the caller must do that itself before invoking this function.
 */
void task_queue_retriever_info_free(task_retriever_info_t *list);

/**
 * Cancels the provided task.
 * The task should finish its work as soon as possible afterward.
 *
 * @param task The task to cancel.
 * @see task_set_cancelled
 */
void task_queue_cancel_task(void *task);

void task_set_flags(retro_task_t *task, uint8_t flags, bool set);

/**
 * Sets \c task::error to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param error The error message to set.
 * @see retro_task::error
 * @warning This does not free the existing error message.
 * The caller must do that itself.
 */
void task_set_error(retro_task_t *task, char *error);

/**
 * Sets \c task::progress to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param progress The progress value to set.
 * @see retro_task::progress
 */
void task_set_progress(retro_task_t *task, int8_t progress);

/**
 * Sets \c task::title to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param title The title to set.
 * @see retro_task::title
 * @see task_free_title
 * @warning This does not free the existing title.
 * The caller must do that itself.
 */
void task_set_title(retro_task_t *task, char *title);

/**
 * Sets \c task::data to the given value.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * Behavior is undefined if \c NULL.
 * @param data The data to set.
 * @see retro_task::data
 */
void task_set_data(retro_task_t *task, void *data);

/**
 * Frees the \c task's title, if any.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to modify.
 * @see task_set_title
 */
void task_free_title(retro_task_t *task);

/**
 * Returns \c task::error.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::error.
 * @see retro_task::error
 */
char* task_get_error(retro_task_t *task);

/**
 * Returns \c task::progress.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::progress.
 * @see retro_task::progress
 */
int8_t task_get_progress(retro_task_t *task);

/**
 * Returns \c task::title.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::title.
 * @see retro_task::title
 */
char* task_get_title(retro_task_t *task);

/**
 * Returns \c task::data.
 * Thread-safe if the task queue is threaded.
 *
 * @param task The task to query.
 * Behavior is undefined if \c NULL.
 * @return The value of \c task::data.
 * @see retro_task::data
 */
void* task_get_data(retro_task_t *task);

/**
 * Returns whether the task queue is running
 * on the same thread that called \c task_queue_init.
 *
 * @return \c true if the caller is running
 * on the same thread that called \c task_queue_init.
 */
bool task_is_on_main_thread(void);

/**
 * Ensures that the task queue is in threaded mode.
 *
 * Next time \c retro_task_queue_check is called,
 * the task queue will be recreated with threading enabled.
 * Existing tasks will continue to run on the new thread.
 */
void task_queue_set_threaded(void);

/**
 * Ensures that the task queue is not in threaded mode.
 *
 * Next time \c retro_task_queue_check is called,
 * the task queue will be recreated with threading disabled.
 * Existing tasks will continue to run on whichever thread updates the queue.
 *
 * @see task_queue_set_threaded
 * @see task_queue_is_threaded
 */
void task_queue_unset_threaded(void);

/**
 * Returns whether the task queue is running in threaded mode.
 *
 * @return \c true if the task queue is running its tasks on a separate thread.
 */
bool task_queue_is_threaded(void);

/**
 * Calls the function given in \c find_data for each task
 * until it returns \c true for one of them,
 * or until all tasks have been searched.
 *
 * @param find_data Parameters for the search.
 * Behavior is undefined if \c NULL.
 * @return \c true if \c find_data::func returned \c true for any task.
 * @see task_finder_data_t
 */
bool task_queue_find(task_finder_data_t *find_data);

/**
 * Retrieves arbitrary data from every task
 * whose handler matches \c data::handler.
 *
 * @param data[in, out] Parameters for retrieving data from the task queue,
 * including the results themselves.
 * Behavior is undefined if \c NULL.
 * @see task_retriever_data_t
 */
void task_queue_retrieve(task_retriever_data_t *data);

 /**
  * Runs each task.
  * If a task is finished or cancelled,
  * its callback and cleanup handler will be called.
  * Afterwards, the task will be deallocated.
  * If used in a core, generally called in \c retro_run
  * and just before \c task_queue_deinit.
  * @warning This must only be called from the main thread.
  */
void task_queue_check(void);

uint8_t task_get_flags(retro_task_t *task);

/**
 * Schedules a task to start running.
 * If \c task::when is 0, it will start as soon as possible.
 *
 * Tasks with the same \c task::when value
 * will be executed in the order they were scheduled.
 *
 * @param task The task to schedule.
 * @return \c true unless \c task's type is \c TASK_TYPE_BLOCKING
 * and there's already a blocking task in the queue.
 */
bool task_queue_push(retro_task_t *task);

/**
 * Block until all active (i.e. current time &gt; \c task::when) tasks have finished,
 * or until the given function returns \c false.
 * If a scheduled task's \c when is passed while within this function,
 * it will start executing.
 *
 * Must only be called from the main thread.
 *
 * @param cond Function to call after all tasks in the queue have executed
 * (i.e. once per pass over the task queue).
 * May be \c NULL, in which case the task queue will wait unconditionally.
 * @param data Pointer to arbitrary data, passed directly into \c cond.
 * May be \c NULL.
 * @see retro_task_condition_fn_t
 * @see task_queue_deinit
 * @see task_queue_reset
 * @warning Passing \c NULL to \c cond is strongly discouraged.
 * If you use tasks that run indefinitely
 * (e.g. for the lifetime of the core),
 * you will need a way to stop these tasks externally;
 * otherwise, you risk the frontend and core freezing.
 */
void task_queue_wait(retro_task_condition_fn_t cond, void* data);

/**
 * Marks all tasks in the queue as cancelled.
 *
 * The tasks won't immediately be terminated;
 * each task may finish its work,
 * but must do so as quickly as possible.
 *
 * Must only be called from the main thread.
 *
 * @see task_queue_wait
 * @see task_queue_deinit
 * @see task_set_finished
 * @see task_get_cancelled
 */
void task_queue_reset(void);

/**
 * Deinitializes the task system.
 *
 * Outstanding tasks will not be cleaned up;
 * if the intent is to finish the core or frontend's work,
 * then all tasks must be finished before calling this function.
 * May be safely called multiple times in a row,
 * but only from the main thread.
 * @see task_queue_wait
 * @see task_queue_reset
 */
void task_queue_deinit(void);

/**
 * Initializes the task system with the provided parameters.
 * Must be called before any other task_queue_* function,
 * and must only be called from the main thread.
 *
 * @param threaded \c true if tasks should run on a separate thread,
 * \c false if they should remain on the calling thread.
 * All tasks run in sequence on a single thread.
 * If you want to scale a task to multiple threads,
 * you must do so within the task itself.
 * @param msg_push The task system will call this function to output messages.
 * If \c NULL, no messages will be output.
 * @note Calling this function while the task system is already initialized
 * will reinitialize it with the new parameters,
 * but it will not reset the task queue;
 * all existing tasks will continue to run
 * when the queue is updated.
 * @see task_queue_deinit
 * @see retro_task_queue_msg_t
 */
void task_queue_init(bool threaded, retro_task_queue_msg_t msg_push);

/**
 * Allocates and initializes a new task.
 * Deallocated by the task queue after it finishes executing.
 *
 * @returns Pointer to a newly allocated task,
 * or \c NULL if allocation fails.
 */
retro_task_t *task_init(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/retro_assert.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_assert.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RETRO_ASSERT_H
#define __RETRO_ASSERT_H

#include &lt;assert.h&gt;

#ifdef RARCH_INTERNAL
#include &lt;stdio.h&gt;
#define retro_assert(cond) ((void)( (cond) || (printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__), abort(), 0) ))
#else
#define retro_assert(cond) assert(cond)
#endif

#endif</pre>
<h2>./include/libretro-common/include/retro_common_api.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_common_api.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H

/*
This file is designed to normalize the libretro-common compiling environment
for public API headers. This should be leaner than a normal compiling environment,
since it gets #included into other project's sources.
*/

/* ------------------------------------ */

/*
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
headers to enable them to get used by c++ sources.
However, we want to support building this library as C++ as well, so a
special technique is called for.
*/

#define RETRO_BEGIN_DECLS
#define RETRO_END_DECLS

#ifdef __cplusplus

#ifdef CXX_BUILD
/* build wants everything to be built as c++, so no extern "C" */
#else
#undef RETRO_BEGIN_DECLS
#undef RETRO_END_DECLS
#define RETRO_BEGIN_DECLS extern "C" {
#define RETRO_END_DECLS }
#endif

#else

/* header is included by a C source file, so no extern "C" */

#endif

/*
IMO, this non-standard ssize_t should not be used.
However, it's a good example of how to handle something like this.
*/
#ifdef _MSC_VER
#ifndef HAVE_SSIZE_T
#define HAVE_SSIZE_T
#if defined(_WIN64)
typedef __int64 ssize_t;
#elif defined(_WIN32)
typedef int ssize_t;
#endif
#endif
#elif defined(__MACH__)
#include &lt;sys/types.h&gt;
#endif

#ifdef _MSC_VER
#if _MSC_VER &gt;= 1800
#include &lt;inttypes.h&gt;
#else
#ifndef PRId64
#define PRId64 "I64d"
#define PRIu64 "I64u"
#define PRIuPTR "Iu"
#endif
#endif
#else
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
/* https://github.com/libretro/RetroArch/issues/6009 */
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS 1
#endif
#include &lt;inttypes.h&gt;
#endif
#ifndef PRId64
#error "inttypes.h is being screwy"
#endif
#define STRING_REP_INT64 "%" PRId64
#define STRING_REP_UINT64 "%" PRIu64
#define STRING_REP_USIZE "%" PRIuPTR

/* Wrap a declaration in RETRO_DEPRECATED() to produce a compiler warning when
it's used. This is intended for developer machines, so it won't work on ancient
or obscure compilers */
#if defined(_MSC_VER)
#if _MSC_VER &gt;= 1400 /* Visual C 2005 or later */
#define RETRO_DEPRECATED(decl) __declspec(deprecated) decl
#endif
#elif defined(__GNUC__)
#if __GNUC__ &gt;= 3 /* GCC 3 or later */
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
#endif
#elif defined(__clang__)
#if __clang_major__ &gt;= 3 /* clang 3 or later */
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
#endif
#endif
#ifndef RETRO_DEPRECATED /* Unsupported compilers */
#define RETRO_DEPRECATED(decl) decl
#endif

/*
I would like to see retro_inline.h moved in here; possibly boolean too.

rationale: these are used in public APIs, and it is easier to find problems
and write code that works the first time portably when they are included uniformly
than to do the analysis from scratch each time you think you need it, for each feature.

Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
then you should pay the price everywhere, so you can see how much grief it will cause.

Of course, another school of thought is that you should do as little damage as possible
in as few places as possible...
*/

/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
#endif</pre>
<h2>./include/libretro-common/include/retro_common.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_common.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_COMMON_RETRO_COMMON_H
#define _LIBRETRO_COMMON_RETRO_COMMON_H

/*!
 * @internal This file is designed to normalize the libretro-common compiling environment.
 * It is not to be used in public API headers, as they should be designed as leanly as possible.
 * Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable,
 * in a public API, you may need this.
 */

/* conditional compilation is handled inside here */
#include &lt;compat/msvc.h&gt;

#endif</pre>
<h2>./include/libretro-common/include/retro_dirent.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_dirent.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RETRO_DIRENT_H
#define __RETRO_DIRENT_H

#include &lt;libretro.h&gt;
#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

/** @defgroup dirent Directory Entries
 * @{
 */

RETRO_BEGIN_DECLS

/**
 * The minimum VFS version (as defined in \c retro_vfs_interface_info::required_interface_version)
 * required by the \c dirent functions.
 * If no acceptable VFS interface is provided,
 * all dirent functions will fall back to libretro-common's implementations.
 * @see retro_vfs_interface_info
 */
#define DIRENT_REQUIRED_VFS_VERSION 3

/**
 * Installs a frontend-provided VFS interface for the dirent functions to use
 * instead of libretro-common's built-in implementations.
 *
 * @param vfs_info The VFS interface returned by the frontend.
 * The dirent functions will fall back to libretro-common's implementations
 * if \c vfs_info::required_interface_version is too low.
 * @see retro_vfs_interface_info
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info);

/**
 * Opaque handle to a directory entry (aka "dirent").
 * It may name a file, directory, or other filesystem object.
 * @see retro_opendir
 */
typedef struct RDIR RDIR;

/**
 * Opens a directory for reading.
 *
 * @param name Path to a directory to open.
 * @return An \c RDIR representing the given directory if successful.
 * Returns \c NULL if \c name is \c NULL, the empty string, or does not name a directory.
 * @note The returned \c RDIR must be closed with \c retro_closedir.
 * @see retro_opendir_include_hidden
 * @see retro_closedir
 */
struct RDIR *retro_opendir(const char *name);

/**
 * @copybrief retro_opendir
 *
 * @param name Path to the directory to open.
 * @param include_hidden Whether to include hidden files and directories
 * when iterating over this directory with \c retro_readdir.
 * Platforms and filesystems have different notions of "hidden" files.
 * Setting this to \c false will not prevent this function from opening \c name.
 * @return An \c RDIR representing the given directory if successful.
 * Returns \c NULL if \c name is \c NULL, the empty string, or does not name a directory.
 * @note The returned \c RDIR must be closed with \c retro_closedir.
 * @see retro_opendir
 * @see retro_closedir
 */
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden);

/**
 * Reads the next entry in the given directory.
 *
 * Here's a usage example that prints the names of all files in the current directory:
 * @code
 * struct RDIR *rdir = retro_opendir(".");
 * if (rdir)
 * {
 *    while (retro_readdir(rdir))
 *    {
 *       const char *name = retro_dirent_get_name(rdir);
 *       printf("%s\n", name);
 *    }
 *    retro_closedir(rdir);
 *    rdir = NULL;
 * }
 * @endcode
 *
 * @param rdir The directory to iterate over.
 * Behavior is undefined if \c NULL.
 * @return \c true if the next entry was read successfully,
 * \c false if there are no more entries to read or if there was an error.
 * @note This may include "." and ".." on Unix-like platforms.
 * @see retro_dirent_get_name
 * @see retro_dirent_is_dir
 */
int retro_readdir(struct RDIR *rdir);

/**
 * @deprecated Left for compatibility.
 * @param rdir Ignored.
 * @return \c false.
 */
bool retro_dirent_error(struct RDIR *rdir);

/**
 * Gets the name of the dirent's current file or directory.
 *
 * @param rdir The dirent to get the name of.
 * Behavior is undefined if \c NULL.
 * @return The name of the directory entry (file, directory, etc.) that the dirent points to.
 * Will return \c NULL if there was an error,
 * \c retro_readdir has not been called on \c rdir,
 * or if there are no more entries to read.
 * @note This returns only a name, not a full path.
 * @warning The returned string is managed by the VFS implementation
 * and must not be modified or freed by the caller.
 * @warning The returned string is only valid until the next call to \c retro_readdir.
 * @see retro_readdir
 */
const char *retro_dirent_get_name(struct RDIR *rdir);

/**
 * Checks if the given \c RDIR's current dirent names a directory.
 *
 * @param rdir The directory entry to check.
 * Behavior is undefined if \c NULL.
 * @param unused Ignored for compatibility reasons. Pass \c NULL.
 * @return \c true if \c rdir refers to a directory, otherwise \c false.
 * @see retro_readdir
 */
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused);

/**
 * Closes an opened \c RDIR that was returned by \c retro_opendir.
 *
 * @param rdir The directory entry to close.
 * If \c NULL, this function does nothing.
 * @see retro_vfs_closedir_t
 */
void retro_closedir(struct RDIR *rdir);

RETRO_END_DECLS

/** @} */

#endif</pre>
<h2>./include/libretro-common/include/retro_endianness.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_endianness.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ENDIANNESS_H
#define __LIBRETRO_SDK_ENDIANNESS_H

#include &lt;retro_inline.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;

#if defined(_MSC_VER) &amp;&amp; _MSC_VER &gt; 1200
#define SWAP16 _byteswap_ushort
#define SWAP32 _byteswap_ulong
#else
/**
 * Swaps the byte order of a 16-bit unsigned integer.
 * @param x The integer to byteswap.
 * @return \c with its two bytes swapped.
 */
static INLINE uint16_t SWAP16(uint16_t x)
{
  return ((x &amp; 0x00ff) &lt;&lt; 8) |
         ((x &amp; 0xff00) &gt;&gt; 8);
}

/**
 * Swaps the byte order of a 32-bit unsigned integer.
 * @param x The integer to byteswap.
 * @return \c with its bytes swapped.
 */
static INLINE uint32_t SWAP32(uint32_t x)
{
  return ((x &amp; 0x000000ff) &lt;&lt; 24) |
         ((x &amp; 0x0000ff00) &lt;&lt;  8) |
         ((x &amp; 0x00ff0000) &gt;&gt;  8) |
         ((x &amp; 0xff000000) &gt;&gt; 24);
}

#endif

#if defined(_MSC_VER) &amp;&amp; _MSC_VER &lt;= 1200
static INLINE uint64_t SWAP64(uint64_t val)
{
  return
      ((val &amp; 0x00000000000000ff) &lt;&lt; 56)
    | ((val &amp; 0x000000000000ff00) &lt;&lt; 40)
    | ((val &amp; 0x0000000000ff0000) &lt;&lt; 24)
    | ((val &amp; 0x00000000ff000000) &lt;&lt; 8)
    | ((val &amp; 0x000000ff00000000) &gt;&gt; 8)
    | ((val &amp; 0x0000ff0000000000) &gt;&gt; 24)
    | ((val &amp; 0x00ff000000000000) &gt;&gt; 40)
    | ((val &amp; 0xff00000000000000) &gt;&gt; 56);
}
#else
/**
 * Swaps the byte order of a 64-bit unsigned integer.
 * @param x The integer to byteswap.
 * @return \c with its bytes swapped.
 */
static INLINE uint64_t SWAP64(uint64_t val)
{
  return   ((val &amp; 0x00000000000000ffULL) &lt;&lt; 56)
	 | ((val &amp; 0x000000000000ff00ULL) &lt;&lt; 40)
	 | ((val &amp; 0x0000000000ff0000ULL) &lt;&lt; 24)
	 | ((val &amp; 0x00000000ff000000ULL) &lt;&lt; 8)
	 | ((val &amp; 0x000000ff00000000ULL) &gt;&gt; 8)
	 | ((val &amp; 0x0000ff0000000000ULL) &gt;&gt; 24)
	 | ((val &amp; 0x00ff000000000000ULL) &gt;&gt; 40)
         | ((val &amp; 0xff00000000000000ULL) &gt;&gt; 56);
}
#endif

#ifdef _MSC_VER
/* MSVC pre-defines macros depending on target arch */
#if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_M_ARM64)
#ifndef LSB_FIRST
#define LSB_FIRST 1
#endif
#elif _M_PPC
#ifndef MSB_FIRST
#define MSB_FIRST 1
#endif
#else
/* MSVC can run on _M_ALPHA and _M_IA64 too, but they're both bi-endian; need to find what mode MSVC runs them at */
#error "unknown platform, can't determine endianness"
#endif
#else
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#ifndef MSB_FIRST
#define MSB_FIRST 1
#endif
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#ifndef LSB_FIRST
#define LSB_FIRST 1
#endif
#else
#error "Invalid endianness macros"
#endif
#endif

#if defined(MSB_FIRST) &amp;&amp; defined(LSB_FIRST)
#  error "Bug in LSB_FIRST/MSB_FIRST definition"
#endif

#if !defined(MSB_FIRST) &amp;&amp; !defined(LSB_FIRST)
#  error "Bug in LSB_FIRST/MSB_FIRST definition"
#endif

#ifdef MSB_FIRST
#  define RETRO_IS_BIG_ENDIAN 1
#  define RETRO_IS_LITTLE_ENDIAN 0
/* For compatibility */
#  define WORDS_BIGENDIAN 1
#else
#  define RETRO_IS_BIG_ENDIAN 0
#  define RETRO_IS_LITTLE_ENDIAN 1
/* For compatibility */
#  undef WORDS_BIGENDIAN
#endif


/**
 * Checks if the current CPU is little-endian.
 *
 * @return \c true on little-endian CPUs,
 * \c false on big-endian CPUs.
 */
#define is_little_endian() RETRO_IS_LITTLE_ENDIAN

/**
 * Byte-swaps an unsigned 64-bit integer on big-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on big-endian CPUs,
 * \c val unchanged on little-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_big64(val) (SWAP64(val))
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big64(val) (val)
#endif

/**
 * Byte-swaps an unsigned 32-bit integer on big-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on big-endian CPUs,
 * \c val unchanged on little-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_big32(val) (SWAP32(val))
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big32(val) (val)
#endif

/**
 * Byte-swaps an unsigned 64-bit integer on little-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on little-endian CPUs,
 * \c val unchanged on big-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_little64(val) (val)
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little64(val) (SWAP64(val))
#endif

/**
 * Byte-swaps an unsigned 32-bit integer on little-endian CPUs.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on little-endian CPUs,
 * \c val unchanged on big-endian CPUs.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_little32(val) (val)
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little32(val) (SWAP32(val))
#endif

/**
 * Byte-swaps an unsigned 16-bit integer on big-endian systems.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on big-endian systems,
 * \c val unchanged on little-endian systems.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_big16(val) (SWAP16(val))
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_big16(val) (val)
#endif

/**
 * Byte-swaps an unsigned 16-bit integer on little-endian systems.
 *
 * @param val The value to byteswap if necessary.
 * @return \c val byteswapped on little-endian systems,
 * \c val unchanged on big-endian systems.
 */
#if RETRO_IS_BIG_ENDIAN
#define swap_if_little16(val) (val)
#elif RETRO_IS_LITTLE_ENDIAN
#define swap_if_little16(val) (SWAP16(val))
#endif

/**
 * Stores a 32-bit integer in at the given address, in big-endian order.
 *
 * @param addr The address to store the value at.
 * Behavior is undefined if \c NULL or not aligned to a 32-bit boundary.
 * @param data The value to store in \c addr.
 * Will be byteswapped if on a little-endian CPU.
 */
static INLINE void store32be(uint32_t *addr, uint32_t data)
{
   *addr = swap_if_little32(data);
}

/**
 * Loads a 32-bit integer order from the given address, in big-endian order.
 *
 * @param addr The address to load the value from.
 * Behavior is undefined if \c NULL or not aligned to a 32-bit boundary.
 * @return The value at \c addr, byteswapped if on a little-endian CPU.
 */
static INLINE uint32_t load32be(const uint32_t *addr)
{
   return swap_if_little32(*addr);
}

/**
 * Converts the given unsigned 16-bit integer to little-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_le16(val) swap_if_big16(val)

/**
 * Converts the given unsigned 32-bit integer to little-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_le32(val) swap_if_big32(val)

/**
 * Converts the given unsigned 64-bit integer to little-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_le64(val) swap_if_big64(val)

/**
 * Converts the given unsigned 16-bit integer to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_le_to_cpu16(val) swap_if_big16(val)

/**
 * Converts the given unsigned 32-bit integer to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_le_to_cpu32(val) swap_if_big32(val)

/**
 * Converts the given unsigned 64-bit integer to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a big-endian CPU,
 * unchanged otherwise.
 */
#define retro_le_to_cpu64(val) swap_if_big64(val)

/**
 * Converts the given unsigned 16-bit integer to big-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_be16(val) swap_if_little16(val)

/**
 * Converts the given unsigned 32-bit integer to big-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_be32(val) swap_if_little32(val)

/**
 * Converts the given unsigned 64-bit integer to big-endian order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_cpu_to_be64(val) swap_if_little64(val)

/**
 * Converts the given unsigned 16-bit integer from big-endian to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_be_to_cpu16(val) swap_if_little16(val)

/**
 * Converts the given unsigned 32-bit integer from big-endian to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_be_to_cpu32(val) swap_if_little32(val)

/**
 * Converts the given unsigned 64-bit integer from big-endian to host-native order if necessary.
 *
 * @param val The value to convert if necessary.
 * @return \c val byteswapped if on a little-endian CPU,
 * unchanged otherwise.
 */
#define retro_be_to_cpu64(val) swap_if_little64(val)

#ifdef  __GNUC__
/**
 * This attribute indicates that pointers to this type may alias
 * to pointers of any other type, similar to \c void* or \c char*.
 */
#define MAY_ALIAS  __attribute__((__may_alias__))
#else
#define MAY_ALIAS
#endif

#pragma pack(push, 1)
struct retro_unaligned_uint16_s
{
  uint16_t val;
} MAY_ALIAS;
struct retro_unaligned_uint32_s
{
  uint32_t val;
} MAY_ALIAS;
struct retro_unaligned_uint64_s
{
  uint64_t val;
} MAY_ALIAS;
#pragma pack(pop)

/**
 * A wrapper around a \c uint16_t that allows unaligned access
 * where supported by the compiler.
 */
typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;

/**
 * A wrapper around a \c uint32_t that allows unaligned access
 * where supported by the compiler.
 */
typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;

/**
 * A wrapper around a \c uint64_t that allows unaligned access
 * where supported by the compiler.
 */
typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;

/* L-value references to unaligned pointers.  */
#define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)-&gt;val)
#define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)-&gt;val)
#define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)-&gt;val)

/**
 * Reads a 16-bit unsigned integer from the given address
 * and converts it from big-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @return The first two bytes of \c addr as a 16-bit unsigned integer,
 * byteswapped from big-endian to host-native order if necessary.
 */
static INLINE uint16_t retro_get_unaligned_16be(void *addr)
{
   return retro_be_to_cpu16(retro_unaligned16(addr));
}

/**
 * Reads a 32-bit unsigned integer from the given address
 * and converts it from big-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @return The first four bytes of \c addr as a 32-bit unsigned integer,
 * byteswapped from big-endian to host-native order if necessary.
 */
static INLINE uint32_t retro_get_unaligned_32be(void *addr)
{
   return retro_be_to_cpu32(retro_unaligned32(addr));
}

/**
 * Reads a 64-bit unsigned integer from the given address
 * and converts it from big-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @return The first eight bytes of \c addr as a 64-bit unsigned integer,
 * byteswapped from big-endian to host-native order if necessary.
 */
static INLINE uint64_t retro_get_unaligned_64be(void *addr)
{
   return retro_be_to_cpu64(retro_unaligned64(addr));
}

/**
 * Reads a 16-bit unsigned integer from the given address
 * and converts it from little-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @return The first two bytes of \c addr as a 16-bit unsigned integer,
 * byteswapped from little-endian to host-native order if necessary.
 */
static INLINE uint16_t retro_get_unaligned_16le(void *addr)
{
   return retro_le_to_cpu16(retro_unaligned16(addr));
}

/**
 * Reads a 32-bit unsigned integer from the given address
 * and converts it from little-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @return The first four bytes of \c addr as a 32-bit unsigned integer,
 * byteswapped from little-endian to host-native order if necessary.
 */
static INLINE uint32_t retro_get_unaligned_32le(void *addr)
{
   return retro_le_to_cpu32(retro_unaligned32(addr));
}

/**
 * Reads a 64-bit unsigned integer from the given address
 * and converts it from little-endian to host-native order (if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address of the integer to read.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @return The first eight bytes of \c addr as a 64-bit unsigned integer,
 * byteswapped from little-endian to host-native order if necessary.
 */
static INLINE uint64_t retro_get_unaligned_64le(void *addr)
{
   return retro_le_to_cpu64(retro_unaligned64(addr));
}

/**
 * Writes a 16-bit unsigned integer to the given address
 * (converted to little-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v)
{
   retro_unaligned16(addr) = retro_cpu_to_le16(v);
}

/**
 * Writes a 32-bit unsigned integer to the given address
 * (converted to little-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v)
{
   retro_unaligned32(addr) = retro_cpu_to_le32(v);
}

/**
 * Writes a 64-bit unsigned integer to the given address
 * (converted to little-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v)
{
   retro_unaligned64(addr) = retro_cpu_to_le64(v);
}

/**
 * Writes a 16-bit unsigned integer to the given address
 * (converted to big-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 2
 * the way a \c uint16_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v)
{
   retro_unaligned16(addr) = retro_cpu_to_be16(v);
}

/**
 * Writes a 32-bit unsigned integer to the given address
 * (converted to big-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 4
 * the way a \c uint32_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v)
{
   retro_unaligned32(addr) = retro_cpu_to_be32(v);
}

/**
 * Writes a 64-bit unsigned integer to the given address
 * (converted to big-endian order if necessary),
 * regardless of the CPU's alignment requirements.
 *
 * @param addr The address to write the integer to.
 * Does not need to be divisible by 8
 * the way a \c uint64_t* usually would be.
 * @param v The value to write.
 */
static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v)
{
   retro_unaligned64(addr) = retro_cpu_to_be64(v);
}


#endif</pre>
<h2>./include/libretro-common/include/retro_environment.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_environment.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ENVIRONMENT_H
#define __LIBRETRO_SDK_ENVIRONMENT_H

/*
This file is designed to create a normalized environment for compiling
libretro-common's private implementations, or any other sources which might
enjoy use of it's environment (RetroArch for instance).
This should be an elaborately crafted environment so that sources don't
need to be full of platform-specific workarounds.
*/

#if defined (__cplusplus)
#if 0
printf("This is C++, version %d.\n", __cplusplus);
#endif
/* The expected values would be
 *   199711L, for ISO/IEC 14882:1998 or 14882:2003
 */

#elif defined(__STDC__)
/* This is standard C. */

#if (__STDC__ == 1)
/* The implementation is ISO-conforming. */
#define __STDC_ISO__
#else
/* The implementation is not ISO-conforming. */
#endif

#if defined(__STDC_VERSION__)
#if (__STDC_VERSION__ &gt;= 201112L)
/* This is C11. */
#define __STDC_C11__
#elif (__STDC_VERSION__ &gt;= 199901L)
/* This is C99. */
#define __STDC_C99__
#elif (__STDC_VERSION__ &gt;= 199409L)
/* This is C89 with amendment 1. */
#define __STDC_C89__
#define __STDC_C89_AMENDMENT_1__
#else
/* This is C89 without amendment 1. */
#define __STDC_C89__
#endif
#else /* !defined(__STDC_VERSION__) */
/* This is C89. __STDC_VERSION__ is not defined. */
#define __STDC_C89__
#endif

#else   /* !defined(__STDC__) */
/* This is not standard C. __STDC__ is not defined. */
#endif

#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
/* Try to find out if we're compiling for WinRT or non-WinRT */
#if defined(_MSC_VER) &amp;&amp; defined(__has_include)
#if __has_include(&lt;winapifamily.h&gt;)
#define HAVE_WINAPIFAMILY_H 1
#else
#define HAVE_WINAPIFAMILY_H 0
#endif

/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
#elif defined(_MSC_VER) &amp;&amp; (_MSC_VER &gt;= 1700 &amp;&amp; !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */
#define HAVE_WINAPIFAMILY_H 1
#else
#define HAVE_WINAPIFAMILY_H 0
#endif

#if HAVE_WINAPIFAMILY_H
#include &lt;winapifamily.h&gt;
#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) &amp;&amp; WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
#else
#define WINAPI_FAMILY_WINRT 0
#endif /* HAVE_WINAPIFAMILY_H */

#if WINAPI_FAMILY_WINRT
#undef __WINRT__
#define __WINRT__ 1
#endif

/* MSVC obviously has to have some non-standard constants... */
#if _M_IX86_FP == 1
#define __SSE__ 1
#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))
#define __SSE__ 1
#define __SSE2__ 1
#endif

#endif

#endif</pre>
<h2>./include/libretro-common/include/retro_inline.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_inline.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_INLINE_H
#define __LIBRETRO_SDK_INLINE_H

#ifndef INLINE

/**
 * Cross-platform inline specifier.
 *
 * Expands to something like \c __inline or \c inline,
 * depending on the compiler.
 */
#if defined(_WIN32) || defined(__INTEL_COMPILER)
#define INLINE __inline
#elif defined(__STDC_VERSION__) &amp;&amp; __STDC_VERSION__&gt;=199901L
#define INLINE inline
#elif defined(__GNUC__)
#define INLINE __inline__
#else
#define INLINE
#endif

#endif
#endif</pre>
<h2>./include/libretro-common/include/retro_math.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_math.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_COMMON_MATH_H
#define _LIBRETRO_COMMON_MATH_H

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include &lt;windows.h&gt;
#elif defined(_WIN32) &amp;&amp; defined(_XBOX)
#include &lt;Xtl.h&gt;
#endif

#include &lt;limits.h&gt;

#ifdef _MSC_VER
#include &lt;compat/msvc.h&gt;
#endif
#include &lt;retro_inline.h&gt;

#ifndef M_PI
#if !defined(USE_MATH_DEFINES)
#define M_PI 3.14159265358979323846264338327
#endif
#endif

#ifndef MAX
#define MAX(a, b) ((a) &gt; (b) ? (a) : (b))
#endif

#ifndef MIN
#define MIN(a, b) ((a) &lt; (b) ? (a) : (b))
#endif

/**
 * next_pow2:
 * @v         : initial value
 *
 * Get next power of 2 value based on  initial value.
 *
 * Returns: next power of 2 value (derived from @v).
 **/
static INLINE uint32_t next_pow2(uint32_t v)
{
   v--;
   v |= v &gt;&gt; 1;
   v |= v &gt;&gt; 2;
   v |= v &gt;&gt; 4;
   v |= v &gt;&gt; 8;
   v |= v &gt;&gt; 16;
   v++;
   return v;
}

/**
 * prev_pow2:
 * @v         : initial value
 *
 * Get previous power of 2 value based on initial value.
 *
 * Returns: previous power of 2 value (derived from @v).
 **/
static INLINE uint32_t prev_pow2(uint32_t v)
{
   v |= v &gt;&gt; 1;
   v |= v &gt;&gt; 2;
   v |= v &gt;&gt; 4;
   v |= v &gt;&gt; 8;
   v |= v &gt;&gt; 16;
   return v - (v &gt;&gt; 1);
}

/**
 * clamp:
 * @v         : initial value
 *
 * Get the clamped value based on initial value.
 *
 * Returns: clamped value (derived from @v).
 **/
static INLINE float clamp_value(float v, float min, float max)
{
   return v &lt;= min ? min : v &gt;= max ? max : v;
}

/**
 * saturate_value:
 * @v         : initial value
 *
 * Get the clamped 0.0-1.0 value based on initial value.
 *
 * Returns: clamped 0.0-1.0 value (derived from @v).
 **/
static INLINE float saturate_value(float v)
{
   return clamp_value(v, 0.0f, 1.0f);
}

/**
 * dot_product:
 * @a         : left hand vector value
 * @b         : right hand vector value
 *
 * Get the dot product of the two passed in vectors.
 *
 * Returns: dot product value (derived from @a and @b).
 **/
static INLINE float dot_product(const float* a, const float* b)
{
   return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
}

/**
 * convert_rgb_to_yxy:
 * @rgb         : in RGB colour space value
 * @Yxy         : out Yxy colour space value
 *
 * Convert from RGB colour space to Yxy colour space.
 *
 * Returns: Yxy colour space value (derived from @rgb).
 **/
static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)
{
   float inv;
   float xyz[3];
   float one[3]        = {1.0, 1.0, 1.0};
   float rgb_xyz[3][3] = {
      {0.4124564, 0.3575761, 0.1804375},
      {0.2126729, 0.7151522, 0.0721750},
      {0.0193339, 0.1191920, 0.9503041}
   };

   xyz[0]              = dot_product(rgb_xyz[0], rgb);
   xyz[1]              = dot_product(rgb_xyz[1], rgb);
   xyz[2]              = dot_product(rgb_xyz[2], rgb);

   inv                 = 1.0f / dot_product(xyz, one);
   Yxy[0]              = xyz[1];
   Yxy[1]              = xyz[0] * inv;
   Yxy[2]              = xyz[1] * inv;
}

/**
 * convert_yxy_to_rgb:
 * @rgb         : in Yxy colour space value
 * @Yxy         : out rgb colour space value
 *
 * Convert from Yxy colour space to rgb colour space.
 *
 * Returns: rgb colour space value (derived from @Yxy).
 **/
static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
{
   float xyz[3];
   float xyz_rgb[3][3] = {
      {3.2404542, -1.5371385, -0.4985314},
      {-0.9692660, 1.8760108,  0.0415560},
      {0.0556434, -0.2040259, 1.0572252}
   };
   xyz[0]              = Yxy[0] * Yxy[1] / Yxy[2];
   xyz[1]              = Yxy[0];
   xyz[2]              = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];

   rgb[0]              = dot_product(xyz_rgb[0], xyz);
   rgb[1]              = dot_product(xyz_rgb[1], xyz);
   rgb[2]              = dot_product(xyz_rgb[2], xyz);
}

/**
 * Picks a random value between a specified range.
 *
 * @param \c min unsigned minimum possible value.
 * @param \c max unsigned maximum possible value.
 *
 * @return unsigned random value between \c min and \c max (inclusive).
 */
static INLINE size_t random_range(unsigned min, unsigned max)
{
   return (min == max) ? min : (size_t)((float)rand() / (float)RAND_MAX * (max + 1 - min) + min);
}

#endif</pre>
<h2>./include/libretro-common/include/retro_miscellaneous.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_miscellaneous.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RARCH_MISCELLANEOUS_H
#define __RARCH_MISCELLANEOUS_H

#define RARCH_MAX_SUBSYSTEMS 10
#define RARCH_MAX_SUBSYSTEM_ROMS 10

#include &lt;stdint.h&gt;
#include &lt;boolean.h&gt;
#include &lt;retro_inline.h&gt;

#if defined(_WIN32)

#if defined(_XBOX)
#include &lt;Xtl.h&gt;
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include &lt;windows.h&gt;
#endif

#endif

#include &lt;limits.h&gt;

#ifdef _MSC_VER
#include &lt;compat/msvc.h&gt;
#endif

#ifdef IOS
#include &lt;sys/param.h&gt;
#endif

/**
 * Computes the bitwise OR of two bit arrays.
 *
 * @param a[in,out] The first bit array, and the location of the result.
 * @param b[in] The second bit array.
 * @param count The length of each bit array, in 32-bit words.
 */
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
{
   uint32_t i;
   for (i = 0; i &lt; count;i++)
      a[i] |= b[i];
}

/**
 * Clears every bit in \c a that is set in \c b.
 *
 * @param a[in,out] The bit array to modify.
 * @param b[in] The bit array to use for reference.
 * @param count The length of each bit array, in 32-bit words
 * (\em not bits or bytes).
 */
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
{
   uint32_t i;
   for (i = 0; i &lt; count;i++)
      a[i] &amp;= ~b[i];
}

/**
 * Checks if any bits in \c ptr are set.
 *
 * @param ptr The bit array to check.
 * @param count The length of the buffer pointed to by \c ptr, in 32-bit words
 * (\em not bits or bytes).
 * @return \c true if any bit in \c ptr is set,
 * \c false if all bits are clear (zero).
 */
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
{
   uint32_t i;
   for (i = 0; i &lt; count; i++)
   {
      if (ptr[i] != 0)
         return true;
   }
   return false;
}

/**
 * Checks if any bits in \c a are different from those in \c b.
 *
 * @param a The first bit array to compare.
 * @param b The second bit array to compare.
 * @param count The length of each bit array, in 32-bit words
 * (\em not bits or bytes).
 * @return \c true if \c and \c differ by at least one bit,
 * \c false if they're both identical.
 */
static INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count)
{
   uint32_t i;
   for (i = 0; i &lt; count; i++)
   {
      if (a[i] != b[i])
         return true;
   }
   return false;
}

/**
 * An upper limit for the length of a path (including the filename).
 * If a path is longer than this, it may not work properly.
 * This value may vary by platform.
 */

#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__) || defined(HAVE_EMSCRIPTEN)

#ifndef PATH_MAX_LENGTH
#define PATH_MAX_LENGTH 512
#endif

#ifndef DIR_MAX_LENGTH
#define DIR_MAX_LENGTH 256
#endif

/**
 * An upper limit for the length of a file or directory (excluding parent directories).
 * If a path has a component longer than this, it may not work properly.
 */
#ifndef NAME_MAX_LENGTH
#define NAME_MAX_LENGTH 128
#endif

#else

#ifndef PATH_MAX_LENGTH
#define PATH_MAX_LENGTH 2048
#endif

#ifndef DIR_MAX_LENGTH
#define DIR_MAX_LENGTH 1024
#endif

/**
 * An upper limit for the length of a file or directory (excluding parent directories).
 * If a path has a component longer than this, it may not work properly.
 */
#ifndef NAME_MAX_LENGTH
#define NAME_MAX_LENGTH 256
#endif

#endif


#ifndef MAX
/**
 * @return \c a or \c b, whichever is larger.
 */
#define MAX(a, b) ((a) &gt; (b) ? (a) : (b))
#endif

#ifndef MIN
/**
 * @return \c a or \c b, whichever is smaller.
 */
#define MIN(a, b) ((a) &lt; (b) ? (a) : (b))
#endif

/**
 * Gets the number of elements in an array whose size is known at compile time.
 * @param a An array of fixed length.
 * @return The number of elements in \c a.
 */
#define ARRAY_SIZE(a)              (sizeof(a) / sizeof((a)[0]))

/** @defgroup BITS Bit Arrays
 *
 * @{
 */

#define BITS_GET_ELEM(a, i)        ((a).data[i])
#define BITS_GET_ELEM_PTR(a, i)    ((a)-&gt;data[i])

/** @defgroup BIT_ Arbitrary-length Bit Arrays
 *
 * @{
 */

/**
 * Sets a particular bit within a bit array to 1.
 *
 * @param a A \c uint8_t array,
 * treated here as a bit vector.
 * @param bit Index of the bit to set, where 0 is the least significant.
 */
#define BIT_SET(a, bit)   ((a)[(bit) &gt;&gt; 3] |=  (1 &lt;&lt; ((bit) &amp; 7)))

/**
 * Clears a particular bit within a bit array.
 *
 * @param a A \c uint8_t array,
 * treated here as a bit vector.
 * @param bit Index of the bit to clear, where 0 is the least significant.
 */
#define BIT_CLEAR(a, bit) ((a)[(bit) &gt;&gt; 3] &amp;= ~(1 &lt;&lt; ((bit) &amp; 7)))

/**
 * Gets the value of a particular bit within a bit array.
 *
 * @param a A \c uint8_t array,
 * treated here as a bit vector.
 * @param bit Index of the bit to get, where 0 is the least significant.
 * @return The value of the bit at the specified index.
 */
#define BIT_GET(a, bit)   (((a)[(bit) &gt;&gt; 3] &gt;&gt; ((bit) &amp; 7)) &amp; 1)

/** @} */

/** @defgroup BIT16 16-bit Bit Arrays
 *
 * @{
 */

/**
 * Sets a particular bit within a 16-bit integer to 1.
 * @param a An unsigned 16-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to set, where 0 is the least significant and 15 is the most.
 */
#define BIT16_SET(a, bit)    ((a) |=  (1 &lt;&lt; ((bit) &amp; 15)))

/**
 * Clears a particular bit within a 16-bit integer.
 *
 * @param a An unsigned 16-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to clear, where 0 is the least significant and 15 is the most.
 */
#define BIT16_CLEAR(a, bit)  ((a) &amp;= ~(1 &lt;&lt; ((bit) &amp; 15)))

/**
 * Gets the value of a particular bit within a 16-bit integer.
 *
 * @param a An unsigned 16-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to get, where 0 is the least significant and 15 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT16_GET(a, bit)    (((a) &gt;&gt; ((bit) &amp; 15)) &amp; 1)

/**
 * Clears all bits in a 16-bit bitmask.
 */
#define BIT16_CLEAR_ALL(a)   ((a) = 0)

/** @} */

/** @defgroup BIT32 32-bit Bit Arrays
 *
 * @{
 */

/**
 * Sets a particular bit within a 32-bit integer to 1.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to set, where 0 is the least significant and 31 is the most.
 */
#define BIT32_SET(a, bit)    ((a) |=  (UINT32_C(1) &lt;&lt; ((bit) &amp; 31)))

/**
 * Clears a particular bit within a 32-bit integer.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to clear, where 0 is the least significant and 31 is the most.
 */
#define BIT32_CLEAR(a, bit)  ((a) &amp;= ~(UINT32_C(1) &lt;&lt; ((bit) &amp; 31)))

/**
 * Gets the value of a particular bit within a 32-bit integer.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to get, where 0 is the least significant and 31 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT32_GET(a, bit)    (((a) &gt;&gt; ((bit) &amp; 31)) &amp; 1)

/**
 * Clears all bits in a 32-bit bitmask.
 *
 * @param a An unsigned 32-bit integer,
 * treated as a bit array.
 */
#define BIT32_CLEAR_ALL(a)   ((a) = 0)

/** @} */

/**
 * @defgroup BIT64 64-bit Bit Arrays
 * @{
 */

/**
 * Sets a particular bit within a 64-bit integer to 1.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to set, where 0 is the least significant and 63 is the most.
 */
#define BIT64_SET(a, bit)    ((a) |=  (UINT64_C(1) &lt;&lt; ((bit) &amp; 63)))

/**
 * Clears a particular bit within a 64-bit integer.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to clear, where 0 is the least significant and 63 is the most.
 */
#define BIT64_CLEAR(a, bit)  ((a) &amp;= ~(UINT64_C(1) &lt;&lt; ((bit) &amp; 63)))

/**
 * Gets the value of a particular bit within a 64-bit integer.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 * @param bit Index of the bit to get, where 0 is the least significant and 63 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT64_GET(a, bit)    (((a) &gt;&gt; ((bit) &amp; 63)) &amp; 1)

/**
 * Clears all bits in a 64-bit bitmask.
 *
 * @param a An unsigned 64-bit integer,
 * treated as a bit array.
 */
#define BIT64_CLEAR_ALL(a)   ((a) = 0)

/** @} */

#define BIT128_SET(a, bit)   ((a).data[(bit) &gt;&gt; 5] |=  (UINT32_C(1) &lt;&lt; ((bit) &amp; 31)))
#define BIT128_CLEAR(a, bit) ((a).data[(bit) &gt;&gt; 5] &amp;= ~(UINT32_C(1) &lt;&lt; ((bit) &amp; 31)))
#define BIT128_GET(a, bit)   (((a).data[(bit) &gt;&gt; 5] &gt;&gt; ((bit) &amp; 31)) &amp; 1)
#define BIT128_CLEAR_ALL(a)  memset(&amp;(a), 0, sizeof(a))

#define BIT128_SET_PTR(a, bit)   BIT128_SET(*a, bit)
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
#define BIT128_GET_PTR(a, bit)   BIT128_GET(*a, bit)
#define BIT128_CLEAR_ALL_PTR(a)  BIT128_CLEAR_ALL(*a)

/**
 * Sets a single bit from a 256-bit \c retro_bits_t to 1.
 *
 * @param a A 256-bit \c retro_bits_t.
 * @param bit Index of the bit to set,
 * where 0 is the least significant and 255 is the most.
 */
#define BIT256_SET(a, bit)       BIT128_SET(a, bit)

/**
 * Clears a single bit from a 256-bit \c retro_bits_t.
 *
 * @param a A 256-bit \c retro_bits_t.
 * @param bit Index of the bit to clear,
 * where 0 is the least significant and 255 is the most.
 */
#define BIT256_CLEAR(a, bit)     BIT128_CLEAR(a, bit)

/**
 * Gets the value of a single bit from a 256-bit \c retro_bits_t.
 *
 * @param a A 256-bit \c retro_bits_t.
 * @param bit Index of the bit to get,
 * where 0 is the least significant and 255 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT256_GET(a, bit)       BIT128_GET(a, bit)

/**
 * Clears all bits in a 256-bit \c retro_bits_t.
 *
 * @param a A 256-bit \c retro_bits_t.
 */
#define BIT256_CLEAR_ALL(a)      BIT128_CLEAR_ALL(a)

/** Variant of BIT256_SET() that takes a pointer to a \c retro_bits_t. */
#define BIT256_SET_PTR(a, bit)   BIT256_SET(*a, bit)

/** Variant of BIT256_CLEAR() that takes a pointer to a \c retro_bits_t. */
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)

/** Variant of BIT256_GET() that takes a pointer to a \c retro_bits_t. */
#define BIT256_GET_PTR(a, bit)   BIT256_GET(*a, bit)

/** Variant of BIT256_CLEAR_ALL() that takes a pointer to a \c retro_bits_t. */
#define BIT256_CLEAR_ALL_PTR(a)  BIT256_CLEAR_ALL(*a)

/**
 * Sets a single bit from a 512-bit \c retro_bits_512_t to 1.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 * @param bit Index of the bit to set,
 * where 0 is the least significant and 511 is the most.
 */
#define BIT512_SET(a, bit)       BIT256_SET(a, bit)

/**
 * Clears a single bit from a 512-bit \c retro_bits_512_t.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 * @param bit Index of the bit to clear,
 * where 0 is the least significant and 511 is the most.
 */
#define BIT512_CLEAR(a, bit)     BIT256_CLEAR(a, bit)

/**
 * Gets the value of a single bit from a 512-bit \c retro_bits_512_t.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 * @param bit Index of the bit to get,
 * where 0 is the least significant and 511 is the most.
 * @return The value of the bit at the specified index.
 */
#define BIT512_GET(a, bit)       BIT256_GET(a, bit)

/**
 * Clears all bits in a 512-bit \c retro_bits_512_t.
 *
 * @param a A 512-bit \c retro_bits_512_t.
 */
#define BIT512_CLEAR_ALL(a)      BIT256_CLEAR_ALL(a)

/** Variant of BIT512_SET() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_SET_PTR(a, bit)   BIT512_SET(*a, bit)

/** Variant of BIT512_CLEAR() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)

/** Variant of BIT512_GET() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_GET_PTR(a, bit)   BIT512_GET(*a, bit)

/** Variant of BIT512_CLEAR_ALL() that takes a pointer to a \c retro_bits_512_t. */
#define BIT512_CLEAR_ALL_PTR(a)  BIT512_CLEAR_ALL(*a)

#define BITS_COPY16_PTR(a,bits) \
{ \
   BIT128_CLEAR_ALL_PTR(a); \
   BITS_GET_ELEM_PTR(a, 0) = (bits) &amp; 0xffff; \
}

#define BITS_COPY32_PTR(a,bits) \
{ \
   BIT128_CLEAR_ALL_PTR(a); \
   BITS_GET_ELEM_PTR(a, 0) = (bits); \
}

#define BITS_COPY64_PTR(a,bits) \
{ \
   BIT128_CLEAR_ALL_PTR(a); \
   BITS_GET_ELEM_PTR(a, 0) = (bits); \
   BITS_GET_ELEM_PTR(a, 1) = (bits &gt;&gt; 32); \
}

/* Helper macros and struct to keep track of many booleans. */

/** A 256-bit boolean array. */
typedef struct
{
   /** @private 256 bits. Not intended for direct use. */
   uint32_t data[8];
} retro_bits_t;

/** A 512-bit boolean array. */
typedef struct
{
   /** @private 512 bits. Not intended for direct use. */
   uint32_t data[16];
} retro_bits_512_t;

/** @} */

#ifdef _WIN32
#  ifdef _WIN64
#    define PRI_SIZET PRIu64
#  else
#    if _MSC_VER == 1800
#      define PRI_SIZET PRIu32
#    else
#      define PRI_SIZET "u"
#    endif
#  endif
#elif defined(PS2)
#  define PRI_SIZET "u"
#else
#  if (SIZE_MAX == 0xFFFF)
#    define PRI_SIZET "hu"
#  elif (SIZE_MAX == 0xFFFFFFFF)
#    define PRI_SIZET "u"
#  elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
#    define PRI_SIZET "lu"
#  else
#    error PRI_SIZET: unknown SIZE_MAX
#  endif
#endif

#endif</pre>
<h2>./include/libretro-common/include/retro_stat.h</h2>
<pre>/* Copyright  (C) 2010-2016 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_stat.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __RETRO_STAT_H
#define __RETRO_STAT_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

/**
 * path_is_directory:
 * @path               : path
 *
 * Checks if path is a directory.
 *
 * Returns: true (1) if path is a directory, otherwise false (0).
 */
bool path_is_directory(const char *path);

bool path_is_character_special(const char *path);

bool path_is_valid(const char *path);

int32_t path_get_size(const char *path);

/**
 * path_mkdir_norecurse:
 * @dir                : directory
 *
 * Create directory on filesystem.
 *
 * Returns: true (1) if directory could be created, otherwise false (0).
 **/
bool mkdir_norecurse(const char *dir);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/retro_timers.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (retro_timers.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_COMMON_TIMERS_H
#define __LIBRETRO_COMMON_TIMERS_H

#include &lt;stdint.h&gt;

#if defined(XENON)
#include &lt;time/time.h&gt;
#elif !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
#include &lt;sys/timer.h&gt;
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
#include &lt;unistd.h&gt;
#elif defined(WIIU)
#include &lt;wiiu/os/thread.h&gt;
#elif defined(PSP)
#include &lt;pspthreadman.h&gt;
#elif defined(VITA)
#include &lt;psp2/kernel/threadmgr.h&gt;
#elif defined(_3DS)
#include &lt;3ds.h&gt;
#else
#include &lt;time.h&gt;
#endif

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include &lt;windows.h&gt;
#elif defined(_WIN32) &amp;&amp; defined(_XBOX)
#include &lt;Xtl.h&gt;
#endif

#include &lt;limits.h&gt;

#ifdef _MSC_VER
#include &lt;compat/msvc.h&gt;
#endif
#include &lt;retro_inline.h&gt;

#ifdef DJGPP
#define timespec timeval
#define tv_nsec tv_usec
#include &lt;unistd.h&gt;

extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
{
   usleep(1000000L * rqtp-&gt;tv_sec + rqtp-&gt;tv_nsec / 1000);

   if (rmtp)
      rmtp-&gt;tv_sec = rmtp-&gt;tv_nsec=0;

   return 0;
}

#define nanosleep nanosleepDOS
#endif

/**
 * Briefly suspends the running thread.
 *
 * @param msec The time to sleep for, in milliseconds.
 **/
#if defined(VITA)
#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))
#elif defined(_3DS)
#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) &amp;&amp; WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
#define retro_sleep(msec) (SleepEx((msec), FALSE))
#elif defined(_WIN32)
#define retro_sleep(msec) (Sleep((msec)))
#elif defined(XENON)
#define retro_sleep(msec) (udelay(1000 * (msec)))
#elif !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
#define retro_sleep(msec) (sys_timer_usleep(1000 * (msec)))
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
#define retro_sleep(msec) (usleep(1000 * (msec)))
#elif defined(WIIU)
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
#elif defined(__EMSCRIPTEN__)
/* defined in frontend */
#ifdef __cplusplus
extern "C" {
#endif
void retro_sleep(unsigned msec);
#ifdef __cplusplus
}
#endif
#else
static INLINE void retro_sleep(unsigned msec)
{
   struct timespec tv;
   tv.tv_sec          = msec / 1000;
   tv.tv_nsec         = (msec % 1000) * 1000000;
   nanosleep(&amp;tv, NULL);
}
#endif

#endif</pre>
<h2>./include/libretro-common/include/rthreads/async_job.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (async_job.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_ASYNC_JOB_H
#define __LIBRETRO_SDK_ASYNC_JOB_H

typedef struct async_job async_job_t;
typedef void (*async_task_t)(void *payload);

async_job_t *async_job_new(void);

void async_job_free(async_job_t *ajob);

int async_job_add(async_job_t *ajob, async_task_t task, void *payload);

#endif /* __LIBRETRO_SDK_ASYNC_JOB_H */</pre>
<h2>./include/libretro-common/include/rthreads/rthreads.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rthreads.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_RTHREADS_H__
#define __LIBRETRO_SDK_RTHREADS_H__

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;
#include &lt;stdint.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;retro_miscellaneous.h&gt;

RETRO_BEGIN_DECLS

/** Platform-agnostic handle to a thread. */
typedef struct sthread sthread_t;

/** Platform-agnostic handle to a mutex. */
typedef struct slock slock_t;

/** Platform-agnostic handle to a condition variable. */
typedef struct scond scond_t;

#ifdef HAVE_THREAD_STORAGE
/** Platform-agnostic handle to thread-local storage. */
typedef unsigned sthread_tls_t;
#endif

/**
 * Creates a new thread and starts running it.
 *
 * @param thread_func Function to run in the new thread.
 * Called with the value given in \c userdata as an argument.
 * @param userdata Pointer to anything (even \c NULL), passed directly to \c thread_func.
 * Must be cleaned up by the caller or the thread.
 * @return Pointer to the new thread,
 * or \c NULL if there was an error.
 * @warn Make sure that the thread can respond to cancellation requests,
 * especially if used in a core.
 * If a core-created thread isn't terminated by the time the core is unloaded,
 * it may leak into the frontend and cause undefined behavior
 * (especially if another session with the core is started).
 */
sthread_t *sthread_create(void (*thread_func)(void*), void *userdata);

/**
 * Creates a new thread with a specific priority hint and starts running it.
 *
 * @param thread_func Function to run in the new thread.
 * Called with the value given in \c userdata as an argument.
 * @param userdata Pointer to anything (even \c NULL), passed directly to \c thread_func.
 * Must be cleaned up by the caller or the thread.
 * @param thread_priority Priority hint for the new thread.
 * Threads with a higher number are more likely to be scheduled first.
 * Should be between 1 and 100, inclusive;
 * if not, the operating system will assign a default priority.
 * May be ignored.
 * @return Pointer to the new thread,
 * or \c NULL if there was an error.
 */
sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority);

/**
 * Detaches the given thread.
 *
 * When a detached thread terminates,
 * its resources are automatically released back to the operating system
 * without needing another thread to join with it.
 *
 * @param thread Thread to detach.
 * @return 0 on success, a non-zero error code on failure.
 * @warn Once a thread is detached, it cannot be joined.
 * @see sthread_join
 */
int sthread_detach(sthread_t *thread);

/**
 * Waits for the given thread to terminate.
 *
 * @param thread The thread to wait for.
 * Must be joinable.
 * Returns immediately if it's already terminated
 * or if it's \c NULL.
 */
void sthread_join(sthread_t *thread);

/**
 * Returns whether the given thread is the same as the calling thread.
 *
 * @param thread Thread to check.
 * @return \c true if \c thread is the same as the calling thread,
 * \c false if not or if it's \c NULL.
 * @note libretro does not have a notion of a "main" thread,
 * since the core may not be running on the same thread
 * that called \c main (or local equivalent).
 * @see sthread_get_thread_id
 */
bool sthread_isself(sthread_t *thread);

/**
 * Creates a new mutex (a.k.a. lock) that can be used to synchronize shared data.
 *
 * Must be manually freed with \c slock_free.
 *
 * @return Pointer to the new mutex,
 * or \c NULL if there was an error.
 */
slock_t *slock_new(void);

/**
 * Frees a mutex.
 *
 * Behavior is undefined if \c lock was previously freed.
 *
 * @param lock Pointer to the mutex to free.
 * May be \c NULL, in which this function does nothing.
 */
void slock_free(slock_t *lock);

/**
 * Locks a mutex, preventing other threads from claiming it until it's unlocked.
 *
 * If the mutex is already locked by another thread,
 * the calling thread will block until the mutex is unlocked.
 *
 * @param lock Pointer to the mutex to lock.
 * If \c NULL, will return without further action.
 * @see slock_try_lock
 */
void slock_lock(slock_t *lock);

/**
 * Tries to lock a mutex if it's not already locked by another thread.
 *
 * If the mutex is already in use by another thread,
 * returns immediately without waiting for it.
 *
 * @param lock The mutex to try to lock.
 * @return \c true if the mutex was successfully locked,
 * \c false if it was already locked by another thread or if \c lock is \c NULL.
 * @see slock_lock
 */
bool slock_try_lock(slock_t *lock);

/**
 * Unlocks a mutex, allowing other threads to claim it.
 *
 * @post The mutex is unlocked,
 * and another thread may lock it.
 * @param lock The mutex to unlock.
 * If \c NULL, this function is a no-op.
 */
void slock_unlock(slock_t *lock);

/**
 * Creates and initializes a condition variable.
 *
 * Must be manually freed with \c scond_free.
 *
 * @return Pointer to the new condition variable,
 * or \c NULL if there was an error.
 */
scond_t *scond_new(void);

/**
 * Frees a condition variable.
 *
 * @param cond Pointer to the condition variable to free.
 * If \c NULL, this function is a no-op.
 * Behavior is undefined if \c cond was previously freed.
 */
void scond_free(scond_t *cond);

/**
 * Blocks until the given condition variable is signaled or broadcast.
 *
 * @param cond Condition variable to wait on.
 * This function blocks until another thread
 * calls \c scond_signal or \c scond_broadcast with this condition variable.
 * @param lock Mutex to lock while waiting.
 *
 * @see scond_signal
 * @see scond_broadcast
 * @see scond_wait_timeout
 */
void scond_wait(scond_t *cond, slock_t *lock);

/**
 * Blocks until the given condition variable is signaled or broadcast,
 * or until the specified time has passed.
 *
 * @param cond Condition variable to wait on.
 * This function blocks until another thread
 * calls \c scond_signal or \c scond_broadcast with this condition variable.
 * @param lock Mutex to lock while waiting.
 * @param timeout_us Time to wait for a signal, in microseconds.
 *
 * @return \c false if \c timeout_us elapses
 * before \c cond is signaled or broadcast, otherwise \c true.
 */
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);

/**
 * Unblocks all threads waiting on the specified condition variable.
 *
 * @param cond Condition variable to broadcast.
 * @return 0 on success, non-zero on failure.
 */
int scond_broadcast(scond_t *cond);

/**
 * Unblocks at least one thread waiting on the specified condition variable.
 *
 * @param cond Condition variable to signal.
 */
void scond_signal(scond_t *cond);

#ifdef HAVE_THREAD_STORAGE
/**
 * Creates a thread-local storage key.
 *
 * Thread-local storage keys have a single value associated with them
 * that is unique to the thread that uses them.
 *
 * New thread-local storage keys have a value of \c NULL for all threads,
 * and new threads initialize all existing thread-local storage to \c NULL.
 *
 * @param tls[in,out] Pointer to the thread local storage key that will be initialized.
 * Must be cleaned up with \c sthread_tls_delete.
 * Behavior is undefined if \c NULL.
 * @return \c true if the operation succeeded, \c false otherwise.
 * @see sthread_tls_delete
 */
bool sthread_tls_create(sthread_tls_t *tls);

/**
 * Deletes a thread local storage key.
 *
 * The value must be cleaned up separately \em before calling this function,
 * if necessary.
 *
 * @param tls The thread local storage key to delete.
 * Behavior is undefined if \c NULL.
 * @return \c true if the operation succeeded, \c false otherwise.
 */
bool sthread_tls_delete(sthread_tls_t *tls);

/**
 * Gets the calling thread's local data for the given key.
 *
 * @param tls The thread-local storage key to get the data for.
 * @return The calling thread's local data associated with \c tls,
 * which should previously have been set with \c sthread_tls_set.
 * Will be \c NULL if this thread has not set a value or if there was an error.
 */
void *sthread_tls_get(sthread_tls_t *tls);

/**
 * Sets the calling thread's local data for the given key.
 *
 * @param tls The thread-local storage key to set the data for.
 * @param data Pointer to the data that will be associated with \c tls.
 * May be \c NULL.
 * @return \c true if \c data was successfully assigned to \c tls,
 * \c false if there was an error.
 */
bool sthread_tls_set(sthread_tls_t *tls, const void *data);
#endif

/**
 * Gets a thread's unique ID.
 *
 * @param thread The thread to get the ID of.
 * @return The provided thread's ID,
 * or 0 if it's \c NULL.
 */
uintptr_t sthread_get_thread_id(sthread_t *thread);

/**
 * Get the calling thread's unique ID.
 * @return The calling thread's ID.
 * @see sthread_get_thread_id
 */
uintptr_t sthread_get_current_thread_id(void);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/rthreads/tpool.h</h2>
<pre>/*
 * Copyright (c) 2010-2020 The RetroArch team
 * Copyright (c) 2017 John Schember &lt;john@nachtimwald.com&gt;
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (tpool.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE
 */

#ifndef __LIBRETRO_SDK_TPOOL_H__
#define __LIBRETRO_SDK_TPOOL_H__

#include &lt;retro_common_api.h&gt;

#include &lt;boolean.h&gt;

#include &lt;retro_inline.h&gt;
#include &lt;retro_miscellaneous.h&gt;

RETRO_BEGIN_DECLS

struct tpool;
typedef struct tpool tpool_t;

/**
 * (*thread_func_t):
 * @arg           : Argument.
 *
 * Callback function that the pool will call to do work.
 **/
typedef void (*thread_func_t)(void *arg);

/**
 * tpool_create:
 * @num           : Number of threads the pool should have.
 *                  If 0 defaults to 2.
 *
 * Create a thread pool.
 *
 * Returns: pool.
 */
tpool_t *tpool_create(size_t num);

/**
 * tpool_destroy:
 * @tp            : Thread pool.
 *
 * Destroy a thread pool
 * The pool can be destroyed while there is outstanding work to process. All
 * outstanding unprocessed work will be discarded. There may be a delay before
 * this function returns because it will block for work that is processing to
 * complete.
 **/
void tpool_destroy(tpool_t *tp);

/**
 * tpool_add_work:
 * @tp         : Thread pool.
 * @func       : Function the pool should call.
 * @arg        : Argument to pass to func.
 *
 * Add work to a thread pool.
 *
 * Returns: true if work was added, otherwise false.
 **/
bool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg);

/**
 * tpool_wait:
 * @tp Thread pool.
 *
 * Wait for all work in the pool to be completed.
 */
void tpool_wait(tpool_t *tp);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/chd_stream.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (chd_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILE_CHD_STREAM_H
#define _LIBRETRO_SDK_FILE_CHD_STREAM_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

typedef struct chdstream chdstream_t;

/* First data track */
#define CHDSTREAM_TRACK_FIRST_DATA (-1)
/* Last track */
#define CHDSTREAM_TRACK_LAST (-2)
/* Primary (largest) data track, used for CRC identification purposes */
#define CHDSTREAM_TRACK_PRIMARY (-3)

chdstream_t *chdstream_open(const char *path, int32_t track);

void chdstream_close(chdstream_t *stream);

ssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes);

int chdstream_getc(chdstream_t *stream);

char *chdstream_gets(chdstream_t *stream, char *buffer, size_t len);

uint64_t chdstream_tell(chdstream_t *stream);

void chdstream_rewind(chdstream_t *stream);

int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence);

ssize_t chdstream_get_size(chdstream_t *stream);

uint32_t chdstream_get_track_start(chdstream_t* stream);

uint32_t chdstream_get_frame_size(chdstream_t* stream);

uint32_t chdstream_get_first_track_sector(chdstream_t* stream);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/file_stream.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_FILE_STREAM_H
#define __LIBRETRO_SDK_FILE_STREAM_H

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;

#include &lt;sys/types.h&gt;

#include &lt;libretro.h&gt;
#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;boolean.h&gt;

#include &lt;stdarg.h&gt;
#include &lt;vfs/vfs_implementation.h&gt;

/** @defgroup file_stream File Streams
 *
 * All functions in this header will use the VFS interface set in \ref filestream_vfs_init if possible,
 * or else they will fall back to built-in equivalents.
 *
 * @note These functions are modeled after those in the C standard library
 * (and may even use them internally),
 * but identical behavior is not guaranteed.
 *
 * @{
 */

/**
 * The minimum version of the VFS interface required by the \c filestream functions.
 */
#define FILESTREAM_REQUIRED_VFS_VERSION 2

RETRO_BEGIN_DECLS

/**
 * Opaque handle to a file stream.
 * @warning This is not interchangeable with \c FILE* or \c retro_vfs_file_handle.
 */
typedef struct RFILE RFILE;

#define FILESTREAM_REQUIRED_VFS_VERSION 2

/**
 * Initializes the \c filestream functions to use the VFS interface provided by the frontend.
 * Optional; if not called, all \c filestream functions
 * will use libretro-common's built-in implementations.
 *
 * @param vfs_info The VFS interface returned by the frontend.
 * If \c vfs_info::iface (but \em not \c vfs_info itself) is \c NULL,
 * then libretro-common's built-in VFS implementation will be used.
 */
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);

/**
 * Returns the size of the given file, in bytes.
 *
 * @param stream The open file to query.
 * @return The size of \c stream in bytes,
 * or -1 if there was an error.
 * @see retro_vfs_size_t
 */
int64_t filestream_get_size(RFILE *stream);

/**
 * Sets the size of the given file,
 * truncating or extending it as necessary.
 *
 * @param stream The file to resize.
 * @param length The new size of \c stream, in bytes.
 * @return 0 if the resize was successful,
 * or -1 if there was an error.
 * @see retro_vfs_truncate_t
 */
int64_t filestream_truncate(RFILE *stream, int64_t length);

/**
 * Opens a file for reading or writing.
 *
 * @param path Path to the file to open.
 * Should be in the format described in \ref GET_VFS_INTERFACE.
 * @param mode The mode to open the file in.
 * Should be one or more of the flags in \refitem RETRO_VFS_FILE_ACCESS OR'd together,
 * and \c RETRO_VFS_FILE_ACCESS_READ or \c RETRO_VFS_FILE_ACCESS_WRITE
 * (or both) must be included.
 * @param hints Optional hints to pass to the frontend.
 *
 * @return The opened file, or \c NULL if there was an error.
 * Must be cleaned up with \c filestream_close when no longer needed.
 * @see retro_vfs_open_t
 */
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);

/**
 * Sets the current position of the file stream.
 * Use this to read specific sections of a file.
 *
 * @param stream The file to set the stream position of.
 * @param offset The new stream position, in bytes.
 * @param seek_position The position to seek from.
 * Should be one of the values in \refitem RETRO_VFS_SEEK_POSITION.
 * @return The new stream position in bytes relative to the beginning,
 * or -1 if there was an error.
 * @see RETRO_VFS_SEEK_POSITION
 * @see retro_vfs_seek_t
 */
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);

/**
 * Reads data from the given file into a buffer.
 * If the read is successful,
 * the file's stream position will advance by the number of bytes read.
 *
 * @param stream The file to read from.
 * @param data The buffer in which to store the read data.
 * @param len The size of \c data, in bytes.
 * @return The number of bytes read,
 * or -1 if there was an error.
 * May be less than \c len, but never more.
 * @see retro_vfs_read_t
 */
int64_t filestream_read(RFILE *stream, void *data, int64_t len);

/**
 * Writes data from a buffer to the given file.
 * If the write is successful,
 * the file's stream position will advance by the number of bytes written.
 *
 * @param stream The file to write to.
 * @param data The buffer containing the data to write.
 * @param len The size of \c data, in bytes.
 * @return The number of bytes written,
 * or -1 if there was an error.
 * May be less than \c len, but never more.
 * @see retro_vfs_write_t
 */
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);

/**
 * Returns the current position of the given file in bytes.
 *
 * @param stream The file to return the stream position for.
 * @return The current stream position in bytes relative to the beginning,
 * or -1 if there was an error.
 * @see retro_vfs_tell_t
 */
int64_t filestream_tell(RFILE *stream);

/**
 * Rewinds the given file to the beginning.
 * Equivalent to &lt;tt&gt;filestream_seek(stream, 0, RETRO_VFS_SEEK_POSITION_START)&lt;/tt&gt;.

 * @param stream The file to rewind.
 * May be \c NULL, in which case this function does nothing.
 */
void filestream_rewind(RFILE *stream);

/**
 * Closes the given file.
 *
 * @param stream The file to close.
 * This should have been created with \c filestream_open.
 * Behavior is undefined if \c NULL.
 * @return 0 if the file was closed successfully,
 * or -1 if there was an error.
 * @post \c stream is no longer valid and should not be used,
 * even if this function fails.
 * @see retro_vfs_close_t
 */
int filestream_close(RFILE *stream);

/**
 * Opens a file, reads its contents into a newly-allocated buffer,
 * then closes it.
 *
 * @param path[in] Path to the file to read.
 * Should be in the format described in \ref GET_VFS_INTERFACE.
 * @param buf[out] A pointer to the address of the newly-allocated buffer.
 * The buffer will contain the entirety of the file at \c path.
 * Will be allocated with \c malloc and must be freed with \c free.
 * @param len[out] Pointer to the size of the buffer in bytes.
 * May be \c NULL, in which case the length is not written.
 * Value is unspecified if this function fails.
 * @return 1 if the file was read successfully,
 * 0 if there was an error.
 * @see filestream_write_file
 */
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);

/**
 * Reads a line of text from the given file,
 * up to a given length.
 *
 * Will read to the next newline or until the buffer is full,
 * whichever comes first.
 *
 * @param stream The file to read from.
 * @param s The buffer to write the retrieved line to.
 * Will contain at most \c len - 1 characters
 * plus a null terminator.
 * The newline character (if any) will not be included.
 * The line delimiter must be Unix-style (\c '\n').
 * Carriage returns (\c '\r') will not be treated specially.
 * @param len The length of the buffer \c s, in bytes.
 * @return \s if successful, \c NULL if there was an error.
 */
char* filestream_gets(RFILE *stream, char *s, size_t len);

/**
 * Reads a single character from the given file.
 *
 * @param stream The file to read from.
 * @return The character read, or -1 upon reaching the end of the file.
 */
int filestream_getc(RFILE *stream);

/**
 * Reads formatted text from the given file,
 * with arguments provided as a standard \c va_list.
 *
 * @param stream The file to read from.
 * @param format The string to write, possibly including scanf-compatible format specifiers.
 * @param args Argument list with zero or more elements
 * whose values will be updated according to the semantics of \c format.
 * @return The number of arguments in \c args that were successfully assigned,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/fscanf
 * @see https://en.cppreference.com/w/c/variadic
 */
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);

/**
 * Reads formatted text from the given file.
 *
 * @param stream The file to read from.
 * @param format The string to write, possibly including scanf-compatible format specifiers.
 * @param ... Zero or more arguments that will be updated according to the semantics of \c format.
 * @return The number of arguments in \c ... that were successfully assigned,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/fscanf
 */
int filestream_scanf(RFILE *stream, const char* format, ...);

/**
 * Determines if there's any more data left to read from this file.
 *
 * @param stream The file to check the position of.
 * @return -1 if this stream has reached the end of the file,
 * 0 if not.
 */
int filestream_eof(RFILE *stream);

/**
 * Writes the entirety of a given buffer to a file at a given path.
 * Any file that already exists will be overwritten.
 *
 * @param path Path to the file that will be written to.
 * @param data The buffer to write to \c path.
 * @param size The size of \c data, in bytes.
 * @return \c true if the file was written successfully,
 * \c false if there was an error.
 */
bool filestream_write_file(const char *path, const void *data, int64_t size);

/**
 * Writes a single character to the given file.
 *
 * @param stream The file to write to.
 * @param c The character to write.
 * @return The character written,
 * or -1 if there was an error.
 * Will return -1 if \c stream is \c NULL.
 */
int filestream_putc(RFILE *stream, int c);

/**
 * Writes formatted text to the given file,
 * with arguments provided as a standard \c va_list.
 *
 * @param stream The file to write to.
 * @param format The string to write, possibly including printf-compatible format specifiers.
 * @param args A list of arguments to be formatted and inserted in the resulting string.
 * @return The number of characters written,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/vfprintf
 * @see https://en.cppreference.com/w/c/variadic
 */
int filestream_vprintf(RFILE *stream, const char* format, va_list args);

/**
 * Writes formatted text to the given file.
 *
 * @param stream The file to write to.
 * @param format The string to write, possibly including printf-compatible format specifiers.
 * @param ... Zero or more arguments to be formatted and inserted into the resulting string.
 * @return The number of characters written,
 * or -1 if there was an error.
 * @see https://en.cppreference.com/w/c/io/printf
 */
int filestream_printf(RFILE *stream, const char* format, ...);

/**
 * Checks if there was an error in using the given file stream.
 *
 * @param stream The file stream to check for errors.
 * @return \c true if there was an error in using this stream,
 * \c false if not or if \c stream is \c NULL.
 */
int filestream_error(RFILE *stream);

/**
 * Flushes pending writes to the operating system's file layer.
 * There is no guarantee that pending writes will be written to disk immediately.
 *
 * @param stream The file to flush.
 * @return 0 if the flush was successful,
 * or -1 if there was an error.
 * @see retro_vfs_flush_t
 */
int filestream_flush(RFILE *stream);

/**
 * Deletes the file at the given path.
 * If the file is open by any process,
 * the behavior is platform-specific.
 *
 * @note This function might or might not delete directories recursively,
 * depending on the platform and the underlying VFS implementation.
 *
 * @param path The file to delete.
 * @return 0 if the file was deleted successfully,
 * or -1 if there was an error.
 * @see retro_vfs_remove_t
 */
int filestream_delete(const char *path);

/**
 * Moves a file to a new location, with a new name.
 *
 * @param old_path Path to the file to rename.
 * @param new_path The target name and location of the file.
 * @return 0 if the file was renamed successfully,
 * or -1 if there was an error.
 * @see retro_vfs_rename_t
 */
int filestream_rename(const char *old_path, const char *new_path);

/**
 * Copies a file to a new location.
 *
 * @param src_path Path to the file to rename.
 * @param dst_path The target name and location of the file.
 * @return 0 if the file was copied successfully,
 * or -1 if there was an error.
 */
int filestream_copy(const char *src_path, const char *dst_path);

/**
 * Compares and verifies files.
 *
 * @param src_path Path to the file.
 * @param dst_path Path to the other file.
 * @return 0 if the files are equal,
 * or -1 if there was an error.
 */
int filestream_cmp(const char *src_path, const char *dst_path);

/**
 * Get the path that was used to open a file.
 *
 * @param stream The file to get the path of.
 * @return The path that was used to open \c stream,
 * or \c NULL if there was an error.
 * The string is owned by \c stream and must not be modified or freed by the caller.
 */
const char* filestream_get_path(RFILE *stream);

/**
 * Determines if a file exists at the given path.
 *
 * @param path The path to check for existence.
 * @return \c true if a file exists at \c path,
 * \c false if not or if \c path is \c NULL or empty.
 */
bool filestream_exists(const char *path);

/**
 * Reads a line from the given file into a newly-allocated buffer.
 *
 * @param stream The file to read from.
 * @return Pointer to the line read from \c stream,
 * or \c NULL if there was an error.
 * Must be freed with \c free when no longer needed.
 */
char* filestream_getline(RFILE *stream);

/**
 * Returns the open file handle
 * that was originally returned by the VFS interface.
 *
 * @param stream File handle returned by \c filestream_open.
 * @return The file handle returned by the underlying VFS implementation.
 */
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);

RETRO_END_DECLS

/** @} */

#endif</pre>
<h2>./include/libretro-common/include/streams/file_stream_transforms.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream_transforms.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H

#include &lt;stdint.h&gt;
#include &lt;string.h&gt;
#include &lt;retro_common_api.h&gt;
#include &lt;streams/file_stream.h&gt;

/**
 * @file file_stream_transforms.h
 *
 * Contains macros that redirect standard C I/O functions
 * to libretro's own file stream API.
 * Useful when porting an existing emulator to a core.
 * To use these functions without overriding the standard I/O functions,
 * define \c SKIP_STDIO_REDEFINES before including this header.
 *
 * @see https://man7.org/linux/man-pages/man3/stdio.3.html
 */

RETRO_BEGIN_DECLS

#ifndef SKIP_STDIO_REDEFINES

/** @see https://en.cppreference.com/w/c/io/FILE */
#define FILE RFILE

#undef fopen
#undef fclose
#undef ftell
#undef fseek
#undef fread
#undef fgets
#undef fgetc
#undef fwrite
#undef fputc
#undef fflush
#undef fprintf
#undef ferror
#undef feof
#undef fscanf

#define fopen rfopen
#define fclose rfclose
#define ftell rftell
#define fseek rfseek
#define fread rfread
#define fgets rfgets
#define fgetc rfgetc
#define fwrite rfwrite
#define fputc rfputc
#define fflush rfflush
#define fprintf rfprintf
#define ferror rferror
#define feof rfeof
#define fscanf rfscanf

#endif

/** @see https://en.cppreference.com/w/c/io/fopen */
RFILE* rfopen(const char *path, const char *mode);

/** @see https://en.cppreference.com/w/c/io/fclose */
int rfclose(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/ftell */
int64_t rftell(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fseek */
int64_t rfseek(RFILE* stream, int64_t offset, int origin);

/** @see https://en.cppreference.com/w/c/io/fread */
int64_t rfread(void* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fgets */
char *rfgets(char *s, int maxCount, RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fgetc */
int rfgetc(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fwrite */
int64_t rfwrite(void const* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fputc */
int rfputc(int character, RFILE * stream);

/** @see https://en.cppreference.com/w/c/io/fflush */
int64_t rfflush(RFILE * stream);

/** @see https://en.cppreference.com/w/c/io/fprintf */
int rfprintf(RFILE * stream, const char * format, ...);

/** @see https://en.cppreference.com/w/c/io/ferror */
int rferror(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/feof */
int rfeof(RFILE* stream);

/** @see https://en.cppreference.com/w/c/io/fscanf */
int rfscanf(RFILE * stream, const char * format, ...);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/interface_stream.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (interface_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_INTERFACE_STREAM_H
#define _LIBRETRO_SDK_INTERFACE_STREAM_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;sys/types.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;boolean.h&gt;

RETRO_BEGIN_DECLS

enum intfstream_type
{
   INTFSTREAM_FILE = 0,
   INTFSTREAM_MEMORY,
   INTFSTREAM_CHD,
   INTFSTREAM_RZIP
};

typedef struct intfstream_internal intfstream_internal_t, intfstream_t;

typedef struct intfstream_info
{
   struct
   {
      struct
      {
         uint8_t *data;
         uint64_t size;
      } buf;
      bool writable;
   } memory;
   struct
   {
      void *handle;
      int32_t track;
   } chd;
   enum intfstream_type type;
} intfstream_info_t;

void *intfstream_init(intfstream_info_t *info);

bool intfstream_resize(intfstream_internal_t *intf,
      intfstream_info_t *info);

bool intfstream_open(intfstream_internal_t *intf,
      const char *path, unsigned mode, unsigned hints);

int64_t intfstream_read(intfstream_internal_t *intf,
      void *s, uint64_t len);

int64_t intfstream_write(intfstream_internal_t *intf,
      const void *s, uint64_t len);

int intfstream_printf(intfstream_internal_t *intf,
      const char* format, ...);

int64_t intfstream_get_ptr(intfstream_internal_t *intf);

char *intfstream_gets(intfstream_internal_t *intf,
      char *buffer, uint64_t len);

int intfstream_getc(intfstream_internal_t *intf);

int64_t intfstream_seek(intfstream_internal_t *intf,
      int64_t offset, int whence);

int64_t intfstream_truncate(intfstream_internal_t *intf,
      uint64_t len);

void intfstream_rewind(intfstream_internal_t *intf);

int64_t intfstream_tell(intfstream_internal_t *intf);

int intfstream_eof(intfstream_internal_t *intf);

void intfstream_putc(intfstream_internal_t *intf, int c);

int intfstream_close(intfstream_internal_t *intf);

int64_t intfstream_get_size(intfstream_internal_t *intf);

int intfstream_flush(intfstream_internal_t *intf);

uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf);

uint32_t intfstream_get_frame_size(intfstream_internal_t *intf);

uint32_t intfstream_get_first_sector(intfstream_internal_t* intf);

bool intfstream_is_compressed(intfstream_internal_t *intf);

bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc);

intfstream_t *intfstream_open_file(const char *path,
      unsigned mode, unsigned hints);

intfstream_t *intfstream_open_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size);

/* Deprecated.  Has the same effect as `intfstream_open_memory` with
   a mode including `RETRO_VFS_FILE_ACCESS_WRITE`. */
intfstream_t *intfstream_open_writable_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size);

intfstream_t *intfstream_open_chd_track(const char *path,
      unsigned mode, unsigned hints, int32_t track);

intfstream_t *intfstream_open_rzip_file(const char *path,
      unsigned mode);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/memory_stream.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memory_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILE_MEMORY_STREAM_H
#define _LIBRETRO_SDK_FILE_MEMORY_STREAM_H

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

typedef struct memstream memstream_t;

memstream_t *memstream_open(unsigned writing);

void memstream_close(memstream_t *stream);

uint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes);

uint64_t memstream_write(memstream_t *stream, const void *data, uint64_t bytes);

int memstream_getc(memstream_t *stream);

void memstream_putc(memstream_t *stream, int c);

char *memstream_gets(memstream_t *stream, char *s, size_t len);

uint64_t memstream_pos(memstream_t *stream);

void memstream_rewind(memstream_t *stream);

int64_t memstream_seek(memstream_t *stream, int64_t offset, int whence);

void memstream_set_buffer(uint8_t *buffer, uint64_t size);

uint64_t memstream_get_last_size(void);

uint64_t memstream_get_ptr(memstream_t *stream);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/network_stream.h</h2>
<pre>/* Copyright  (C) 2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (network_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_NETWORK_STREAM_H
#define _LIBRETRO_SDK_NETWORK_STREAM_H

#include &lt;stddef.h&gt;
#include &lt;stdint.h&gt;

#include &lt;boolean.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

enum
{
   /**
    * Indicates that \c netstream_seek should seek
    * relative to the beginning of the stream.
    */
   NETSTREAM_SEEK_SET = 0,

   /**
    * Indicates that \c netstream_seek should seek
    * relative to its current position.
    */
   NETSTREAM_SEEK_CUR,

   /**
    * Indicates that \c netstream_seek should seek
    * relative to the end of the stream.
    */
   NETSTREAM_SEEK_END
};

/**
 * A stream that ensures data is read/written in network byte order (big endian).
 *
 * @note Despite what the name may suggests,
 * this object does \em not actually perform any network operations.
 * It is intended to be used as input/output for functions that do.
 */
typedef struct netstream
{
   /** The buffer used by the stream for reading or writing. */
   void   *buf;

   /** The size of \c buf in bytes. */
   size_t size;

   /** The number of bytes that have been written to \c buf. */
   size_t used;

   /**
    * The current position of the stream, in bytes.
    * @see netstream_seek
    */
   size_t pos;
} netstream_t;

/**
 * Opens a network-order stream.
 *
 * @param stream Pointer to the network-order stream to initialize.
 * Behavior is undefined if \c NULL.
 * @param buf Pre-allocated buffer.
 * May be \c NULL, in which case a new buffer will be created with \c malloc.
 * @param size Buffer size in bytes.
 * If \c buf is \c NULL, then this will be the size of the newly-allocated buffer.
 * If not, then this is the size of the existing buffer.
 * If zero, then a buffer will not be allocated.
 * @param used The number of bytes in use.
 * Ignored for non pre-allocated buffers.
 * @return \c true if the stream was opened.
 * For new buffers, \c false if allocation failed.
 * For existing buffers, \c false if \c size is zero
 * or less than \c used.
 * @see netstream_close
 */
bool netstream_open(netstream_t *stream, void *buf, size_t len, size_t used);

/**
 * Closes a network-order stream.
 *
 * @param stream Pointer to the network-order stream to close.
 * The stream itself is not deallocated,
 * but its fields will be reset.
 * Behavior is undefined if \c NULL.
 * @param dealloc Whether to release the underlying buffer with \c free.
 * Set to \c true if the creating \c netstream_open call allocated a buffer,
 * or else its memory will be leaked.
 * @note \c stream itself is not deallocated.
 * This function can be used on static or local variables.
 * @see netstream_open
 */
void netstream_close(netstream_t *stream, bool dealloc);

/**
 * Resets the stream to the beginning and discards any used bytes.
 *
 * @param stream The network-order stream to reset.
 * Behavior is undefined if \c NULL.
 *
 * @note This does not deallocate the underlying buffer,
 * nor does it wipe its memory.
 */
void netstream_reset(netstream_t *stream);

/**
 * Resizes the "used" portion of the stream.
 *
 * @param stream The network-order stream to resize.
 * Behavior is undefined if \c NULL.
 * @param used The number of bytes in the stream that are considered written.
 * @return \c true if the stream's "used" region was resized,
 * \c false if it would've been extended past the buffer's capacity.
 * @note This function does not reallocate or clear the underlying buffer.
 * It only sets the boundaries of the "used" portion of the stream.
 */
bool netstream_truncate(netstream_t *stream, size_t used);

/**
 * Retrieves the network-order stream's data.
 *
 * @param stream Pointer to the network-order stream.
 * Behavior is undefined if \c NULL.
 * @param data[out] Pointer to a variable to store the stream's data.
 * The data itself is not copied,
 * so the pointer will be invalidated
 * if the stream is closed or reallocated.
 * @param len[out] Set to the length of the stream's data in bytes.
 */
void netstream_data(netstream_t *stream, void **data, size_t *len);

/**
 * Checks whether the network-order stream has any more data to read,
 * or any more room to write data.
 *
 * @param stream The network-order stream to check.
 * @return \c true if the stream is at EOF, \c false otherwise.
 */
bool netstream_eof(netstream_t *stream);

/**
 * Gets the network-order stream's current position.
 *
 * @param stream Pointer to a network-order stream.
 * @return The stream's position indicator.
 */
size_t netstream_tell(netstream_t *stream);

/**
 * Sets the network-order stream's current position.
 *
 * @param stream Pointer to a network-order stream.
 * @param offset The new position of the stream, in bytes.
 * @param origin The position used as reference for the offset.
 * Must be one of \c NETSTREAM_SEEK_SET, \c NETSTREAM_SEEK_CUR or \c NETSTREAM_SEEK_END.
 * @return \c true on success, \c false on failure.
 */
bool netstream_seek(netstream_t *stream, long offset, int origin);

/**
 * Reads data from the network-order stream.
 * Does not byte-swap any data;
 * this is useful for reading strings or unspecified binary data.
 *
 * @param stream The network-order stream to read from.
 * @param data The buffer that will receive data from the stream.
 * @param len The number of bytes to read.
 * If 0, will read all remaining bytes.
 * @return \c true on success, \c false on failure.
 */
bool netstream_read(netstream_t *stream, void *data, size_t len);

/**
 * Reads a single byte from the network-order stream.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the byte that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_byte(netstream_t   *stream, uint8_t  *data);

/**
 * Reads an unsigned 16-bit integer from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_word(netstream_t   *stream, uint16_t *data);

/**
 * Reads an unsigned 32-bit integer from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_dword(netstream_t  *stream, uint32_t *data);

/**
 * Reads an unsigned 64-bit integer from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_qword(netstream_t  *stream, uint64_t *data);
#ifdef __STDC_IEC_559__
/**
 * Reads a 32-bit floating-point number from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_float(netstream_t  *stream, float    *data);

/**
 * Reads a 64-bit floating-point number from the network-order stream,
 * byte-swapping it from big endian to host-native byte order if necessary.
 *
 * @param stream[in] The network-order stream to read from.
 * @param data[out] Pointer to the value that will receive the read value.
 * @return \c true on success, \c false if there was an error.
 */
bool netstream_read_double(netstream_t *stream, double   *data);
#endif

/**
 * Reads a null-terminated string from the network-order stream,
 * up to the given length.
 *
 * @param stream Pointer to a network stream object.
 * @param s[out] The buffer that will receive the string.
 * Will be \c NULL-terminated.
 * @param len The length of \c s, in bytes.
 * @return The length of the read string in bytes,
 * or -1 if there was an error.
 */
int netstream_read_string(netstream_t *stream, char *s, size_t len);

/**
 * Reads a string of fixed length from a network-order stream.
 * Will fail if there isn't enough data to read.
 *
 * @param stream Pointer to a network stream object.
 * @param s The buffer that will receive the string.
 * Will be \c NULL-terminated.
 * @param len The length of \c s in bytes,
 * including the \c NULL terminator.
 *
 * @return \c true if a string of the exact length was read,
 * \c false if there was an error.
 */
bool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len);

/**
 * Writes arbitrary data to a network-order stream.
 * Does not byte-swap any data;
 * this is useful for writing strings or unspecified binary data.
 *
 * @param stream Pointer to a network stream object.
 * @param data The data to write into the network stream.
 * @param len The length of \c data, in bytes.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write(netstream_t *stream, const void *data, size_t len);

/**
 * Writes a single byte to a network-order stream.
 *
 * @param stream Pointer to a network stream object.
 * @param data The byte to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_byte(netstream_t   *stream, uint8_t  data);

/**
 * Writes an unsigned 16-bit integer to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_word(netstream_t   *stream, uint16_t data);

/**
 * Writes an unsigned 32-bit integer to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_dword(netstream_t  *stream, uint32_t data);

/**
 * Writes an unsigned 64-bit integer to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_qword(netstream_t  *stream, uint64_t data);
#ifdef __STDC_IEC_559__

/**
 * Writes a 32-bit floating-point number to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_float(netstream_t  *stream, float    data);

/**
 * Writes a 64-bit floating-point number to a network-order stream,
 * byte-swapping it from host-native byte order to big-endian if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param data The value to write to the stream.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_double(netstream_t *stream, double   data);
#endif

/**
 * Writes a null-terminated string to a network-order stream.
 * Does not byte-swap any data.
 *
 * @param stream Pointer to a network stream object.
 * @param s A \c NULL-terminated string.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_string(netstream_t *stream, const char *s);

/**
 * Writes a string of fixed length to a network-order stream,
 * \c NULL-terminating it if necessary.
 *
 * @param stream Pointer to a network stream object.
 * @param s Pointer to a string.
 * Does not need to be \c NULL-terminated,
 * but \c NULL values will not stop processing.
 * Will be \c NULL
 * @param len Length of \c s in bytes,
 * including the \c NULL terminator.
 * Exactly this many bytes will be written to the stream;
 * the last character will be set to \c NULL.
 * @return \c true on success,
 * \c false if there was an error.
 */
bool netstream_write_fixed_string(netstream_t *stream, const char *s,
      size_t len);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/rzip_stream.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rzip_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _LIBRETRO_SDK_FILE_RZIP_STREAM_H
#define _LIBRETRO_SDK_FILE_RZIP_STREAM_H

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;stdarg.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/* Rudimentary interface for streaming data to/from a
 * zlib-compressed chunk-based RZIP archive file.
 * 
 * This is somewhat less efficient than using regular
 * gzip code, but this is by design - the intention here
 * is to create an interface that integrates seamlessly
 * with normal RetroArch functionality, using only
 * standard/existing libretro-common routines.
 * (Actual efficiency is pretty good, regardless:
 * archived file size is almost identical to a solid
 * zip file, and compression/decompression speed is
 * not substantially worse than external archiving tools;
 * it is certainly acceptable for use in real-time
 * frontend applications)
 * 
 * When reading existing files, uncompressed content
 * is handled automatically. File type (compressed/
 * uncompressed) is detected via the RZIP header.
 * 
 * ## RZIP file format:
 * 
 * &lt;file id header&gt;:                8 bytes
 *                                  - [#][R][Z][I][P][v][file format version][#]
 * &lt;uncompressed chunk size&gt;:       4 bytes, little endian order
 *                                  - nominal (maximum) size of each uncompressed
 *                                    chunk, in bytes
 * &lt;total uncompressed data size&gt;:  8 bytes, little endian order
 * &lt;size of next compressed chunk&gt;: 4 bytes, little endian order
 *                                  - size on-disk of next compressed data
 *                                    chunk, in bytes
 * &lt;next compressed chunk&gt;:         n bytes of zlib compressed data
 * ...
 * &lt;size of next compressed chunk&gt; : repeated until end of file
 * &lt;next compressed chunk&gt;         :
 * 
 */

/* Prevent direct access to rzipstream_t members */
typedef struct rzipstream rzipstream_t;

/* File Open */

/* Opens a new or existing RZIP file
 * &gt; Supported 'mode' values are:
 *   - RETRO_VFS_FILE_ACCESS_READ
 *   - RETRO_VFS_FILE_ACCESS_WRITE
 * &gt; When reading, 'path' may reference compressed
 *   or uncompressed data
 * Returns NULL if arguments are invalid, file
 * is invalid or an IO error occurs */
rzipstream_t* rzipstream_open(const char *path, unsigned mode);

/* File Read */

/* Reads (a maximum of) 'len' bytes from an RZIP file.
 * Returns actual number of bytes read, or -1 in
 * the event of an error */
int64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len);

/* Reads next character from an RZIP file.
 * Returns character value, or EOF if no data
 * remains.
 * Note: Always returns EOF if file is open
 * for writing. */
int rzipstream_getc(rzipstream_t *stream);

/* Reads one line from an RZIP file and stores it
 * in the character array pointed to by 's'.
 * It stops reading when either (len-1) characters
 * are read, the newline character is read, or the
 * end-of-file is reached, whichever comes first.
 * On success, returns 's'. In the event of an error,
 * or if end-of-file is reached and no characters
 * have been read, returns NULL. */
char* rzipstream_gets(rzipstream_t *stream, char *s, size_t len);

/* Reads all data from file specified by 'path' and
 * copies it to 'buf'.
 * - 'buf' will be allocated and must be free()'d manually.
 * - Allocated 'buf' size is equal to 'len'.
 * Returns false in the event of an error */
bool rzipstream_read_file(const char *path, void **buf, int64_t *len);

/* File Write */

/* Writes 'len' bytes to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len);

/* Writes a single character to an RZIP file.
 * Returns character written, or EOF in the event
 * of an error */
int rzipstream_putc(rzipstream_t *stream, int c);

/* Writes a variable argument list to an RZIP file.
 * Ugly 'internal' function, required to enable
 * 'printf' support in the higher level 'interface_stream'.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args);

/* Writes formatted output to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_printf(rzipstream_t *stream, const char* format, ...);

/* Writes contents of 'data' buffer to file
 * specified by 'path'.
 * Returns false in the event of an error */
bool rzipstream_write_file(const char *path, const void *data, int64_t len);

/* File Control */

/* Sets file position to the beginning of the
 * specified RZIP file.
 * Note: It is not recommended to rewind a file
 * that is open for writing, since the caller
 * may end up with a file containing junk data
 * at the end (harmless, but a waste of space). */
void rzipstream_rewind(rzipstream_t *stream);

/* File Status */

/* Returns total size (in bytes) of the *uncompressed*
 * data in an RZIP file.
 * (If reading an uncompressed file, this corresponds
 * to the 'physical' file size in bytes)
 * Returns -1 in the event of a error. */
int64_t rzipstream_get_size(rzipstream_t *stream);

/* Returns EOF when no further *uncompressed* data
 * can be read from an RZIP file. */
int rzipstream_eof(rzipstream_t *stream);

/* Returns the offset of the current byte of *uncompressed*
 * data relative to the beginning of an RZIP file.
 * Returns -1 in the event of a error. */
int64_t rzipstream_tell(rzipstream_t *stream);

/* Returns true if specified RZIP file contains
 * compressed content */
bool rzipstream_is_compressed(rzipstream_t *stream);

/* File Close */

/* Closes RZIP file. If file is open for writing,
 * flushes any remaining buffered data to disk.
 * Returns -1 in the event of a error. */
int rzipstream_close(rzipstream_t *stream);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/stdin_stream.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdin_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_STDIN_STREAM_H__
#define LIBRETRO_SDK_STDIN_STREAM_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;

#include &lt;retro_miscellaneous.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/**
 * Reads data from \c stdin if supported by the current platform.
 * @param buf[out] The buffer to read data into.
 * @param size The length of \c buf in bytes.
 * @return The number of bytes that were read,
 * or 0 if there was an error
 * (including a lack of platform support).
 * @note \c stdin is commonly used for text,
 * but this function can read binary data as well.
 * @see https://man7.org/linux/man-pages/man3/stdout.3.html
 */
size_t read_stdin(char *s, size_t len);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/streams/trans_stream.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_SDK_TRANS_STREAM_H__
#define LIBRETRO_SDK_TRANS_STREAM_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;boolean.h&gt;

#ifdef _WIN32
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt;
#endif

#include &lt;retro_miscellaneous.h&gt;

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

enum trans_stream_error
{
    TRANS_STREAM_ERROR_NONE = 0,
    TRANS_STREAM_ERROR_AGAIN, /* more work to do */
    TRANS_STREAM_ERROR_ALLOCATION_FAILURE, /* malloc failure */
    TRANS_STREAM_ERROR_INVALID, /* invalid state */
    TRANS_STREAM_ERROR_BUFFER_FULL, /* output buffer full */
    TRANS_STREAM_ERROR_OTHER
};

struct trans_stream_backend
{
   const char *ident;
   const struct trans_stream_backend *reverse;

   /* Create a stream data structure */
   void *(*stream_new)(void);

   /* Free it */
   void  (*stream_free)(void *);

   /* (Optional) Set extra properties, defined per transcoder */
   bool  (*define)(void *, const char *, uint32_t);

   /* Set our input source */
   void  (*set_in)(void *, const uint8_t *, uint32_t);

   /* Set our output target */
   void  (*set_out)(void *, uint8_t *, uint32_t);

   /* Perform a transcoding, flushing/finalizing if asked to. Writes out how
    * many bytes were read and written. Error target optional. */
   bool  (*trans)(void *, bool, uint32_t *, uint32_t *, enum trans_stream_error *);
};

/**
 * trans_stream_trans_full:
 * @backend                     : transcoding backend
 * @data                        : (optional) existing stream data, or a target
 *                                for the new stream data to be saved
 * @in                          : input data
 * @in_size                     : input size
 * @out                         : output data
 * @out_size                    : output size
 * @error                       : (optional) output for error code
 *
 * Perform a full transcoding from a source to a destination.
 */
bool trans_stream_trans_full(
    struct trans_stream_backend *backend, void **data,
    const uint8_t *in, uint32_t in_size,
    uint8_t *out, uint32_t out_size,
    enum trans_stream_error *error);

const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void);
const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void);
const struct trans_stream_backend* trans_stream_get_pipe_backend(void);

extern const struct trans_stream_backend zlib_deflate_backend;
extern const struct trans_stream_backend zlib_inflate_backend;
extern const struct trans_stream_backend pipe_backend;

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/string/stdstring.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdstring.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_STDSTRING_H
#define __LIBRETRO_SDK_STDSTRING_H

#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;boolean.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;compat/strl.h&gt;

RETRO_BEGIN_DECLS

#define STRLEN_CONST(x)                   ((sizeof((x))-1))

#define string_is_not_equal(a, b)         !string_is_equal((a), (b))

#define TOLOWER(c)   ((c) |  (lr_char_props[(unsigned char)(c)] &amp; 0x20))
#define TOUPPER(c)   ((c) &amp; ~(lr_char_props[(unsigned char)(c)] &amp; 0x20))

/* C standard says \f \v are space, but this one disagrees */
#define ISSPACE(c)   (lr_char_props[(unsigned char)(c)] &amp; 0x80)

#define ISDIGIT(c)   (lr_char_props[(unsigned char)(c)] &amp; 0x40)
#define ISALPHA(c)   (lr_char_props[(unsigned char)(c)] &amp; 0x20)
#define ISLOWER(c)   (lr_char_props[(unsigned char)(c)] &amp; 0x04)
#define ISUPPER(c)   (lr_char_props[(unsigned char)(c)] &amp; 0x02)
#define ISALNUM(c)   (lr_char_props[(unsigned char)(c)] &amp; 0x60)
#define ISUALPHA(c)  (lr_char_props[(unsigned char)(c)] &amp; 0x28)
#define ISUALNUM(c)  (lr_char_props[(unsigned char)(c)] &amp; 0x68)
#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] &amp; 0x01)

/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
#define string_is_equal_noncase string_is_equal_case_insensitive

static INLINE bool string_is_empty(const char *data)
{
   return !data || (*data == '\0');
}

static INLINE bool string_is_equal(const char *a, const char *b)
{
   return (a &amp;&amp; b) ? !strcmp(a, b) : false;
}

static INLINE bool string_starts_with_size(const char *str, const char *prefix,
      size_t len)
{
   return (str &amp;&amp; prefix) ? !strncmp(prefix, str, len) : false;
}

static INLINE bool string_starts_with(const char *str, const char *prefix)
{
   return (str &amp;&amp; prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
}

static INLINE bool string_ends_with_size(const char *s, const char *suffix,
      size_t len, size_t suffix_len)
{
   return (len &lt; suffix_len) ? false :
         !memcmp(suffix, s + (len - suffix_len), suffix_len);
}

static INLINE bool string_ends_with(const char *s, const char *suffix)
{
   return s &amp;&amp; suffix &amp;&amp; string_ends_with_size(s, suffix, strlen(s), strlen(suffix));
}

/**
 * strlen_size:
 *
 * Leaf function.
 *
 * @return the length of 'str' (c.f. strlen()), but only
 * checks the first 'size' characters
 * - If 'str' is NULL, returns 0
 * - If 'str' is not NULL and no '\0' character is found
 *   in the first 'size' characters, returns 'size'
 **/
static INLINE size_t strlen_size(const char *str, size_t len)
{
   size_t i = 0;
   if (str)
      while (i &lt; len &amp;&amp; str[i]) i++;
   return i;
}


static INLINE bool string_is_equal_case_insensitive(const char *a,
      const char *b)
{
   int result              = 0;
   const unsigned char *p1 = (const unsigned char*)a;
   const unsigned char *p2 = (const unsigned char*)b;

   if (!a || !b)
      return false;
   if (p1 == p2)
      return true;

   while ((result = tolower (*p1) - tolower (*p2++)) == 0)
      if (*p1++ == '\0')
         break;

   return (result == 0);
}

static INLINE bool string_starts_with_case_insensitive(const char *str,
      const char *prefix)
{
   int result              = 0;
   const unsigned char *p1 = (const unsigned char*)str;
   const unsigned char *p2 = (const unsigned char*)prefix;

   if (!str || !prefix)
      return false;
   if (p1 == p2)
      return true;

   while ((result = tolower (*p1++) - tolower (*p2)) == 0)
      if (*p2++ == '\0')
         break;

   return (result == 0 || *p2 == '\0');
}

char *string_to_upper(char *s);

char *string_to_lower(char *s);

char *string_ucwords(char *s);

char *string_replace_substring(
      const char *in,          size_t in_len,
      const char *pattern,     size_t pattern_len,
      const char *replacement, size_t replacement_len);

/**
 * string_trim_whitespace_left:
 *
 * Remove leading whitespaces
 **/
char *string_trim_whitespace_left(char *const s);

/**
 * string_trim_whitespace_right:
 *
 * Remove trailing whitespaces
 **/
char *string_trim_whitespace_right(char *const s);

/**
 * string_trim_whitespace:
 *
 * Remove leading and trailing whitespaces
 **/
char *string_trim_whitespace(char *const s);

/**
 * word_wrap:
 * @dst                : pointer to destination buffer.
 * @dst_size           : size of destination buffer.
 * @src                : pointer to input string.
 * @src_len            : length of @src
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : not used, but is necessary to keep
 *                       compatibility with word_wrap_wideglyph().
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by 'src' to destination buffer
 * specified by 'dst' and 'dst_size'.
 * This function assumes that all glyphs in the string
 * have an on-screen pixel width similar to that of
 * regular Latin characters - i.e. it will not wrap
 * correctly any text containing so-called 'wide' Unicode
 * characters (e.g. CJK languages, emojis, etc.).
 **/
size_t word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,
      int line_width, int wideglyph_width, unsigned max_lines);

/**
 * word_wrap_wideglyph:
 * @dst                : pointer to destination buffer.
 * @dst_size           : size of destination buffer.
 * @src                : pointer to input string.
 * @src_len            : length of @src
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : effective width of 'wide' Unicode glyphs.
 *                       the value here is normalised relative to the
 *                       typical on-screen pixel width of a regular
 *                       Latin character:
 *                       - a regular Latin character is defined to
 *                         have an effective width of 100
 *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
 *                       - e.g. if 'wide' Unicode characters in 'src'
 *                         have an on-screen pixel width twice that of
 *                         regular Latin characters, wideglyph_width
 *                         would be 200
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by @src to destination buffer
 * specified by @dst and @dst_size.
 * This function assumes that all glyphs in the string
 * are:
 * - EITHER 'non-wide' Unicode glyphs, with an on-screen
 *   pixel width similar to that of regular Latin characters
 * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
 *   with an on-screen pixel width defined by @wideglyph_width
 * Note that wrapping may occur in inappropriate locations
 * if @src string contains 'wide' Unicode characters whose
 * on-screen pixel width deviates greatly from the set
 * @wideglyph_width value.
 **/
size_t word_wrap_wideglyph(
      char *dst, size_t dst_size,
      const char *src, size_t src_len,
      int line_width, int wideglyph_width,
      unsigned max_lines);

/**
 * string_tokenize:
 *
 * Splits string into tokens separated by @delim
 * &gt; Returned token string must be free()'d
 * &gt; Returns NULL if token is not found
 * &gt; After each call, @str is set to the position after the
 *   last found token
 * &gt; Tokens *include* empty strings
 * Usage example:
 *    char *str      = "1,2,3,4,5,6,7,,,10,";
 *    char **str_ptr = &amp;str;
 *    char *token    = NULL;
 *    while ((token = string_tokenize(str_ptr, ",")))
 *    {
 *        printf("%s\n", token);
 *        free(token);
 *        token = NULL;
 *    }
 **/
char* string_tokenize(char **str, const char *delim);

/**
 * string_remove_all_chars:
 * @str                : input string (must be non-NULL, otherwise UB)
 *
 * Leaf function.
 *
 * Removes every instance of character @c from @str
 **/
void string_remove_all_chars(char *str, char c);

/**
 * string_replace_all_chars:
 * @str                : input string (must be non-NULL, otherwise UB)
 * @find               : character to find
 * @replace            : character to replace @find with
 *
 * Hidden non-leaf function cost:
 * - Calls strchr (in a loop)
 *
 * Replaces every instance of character @find in @str
 * with character @replace
 **/
void string_replace_all_chars(char *str, char find, char replace);

/**
 * string_to_unsigned:
 * @str                : input string
 *
 * Converts string to unsigned integer.
 *
 * @return 0 if string is invalid, otherwise &gt; 0
 **/
unsigned string_to_unsigned(const char *str);

/**
 * string_hex_to_unsigned:
 * @str                : input string (must be non-NULL, otherwise UB)
 *
 * Converts hexadecimal string to unsigned integer.
 * Handles optional leading '0x'.
 *
 * @return 0 if string is invalid, otherwise &gt; 0
 **/
unsigned string_hex_to_unsigned(const char *str);

/**
 * string_count_occurrences_single_character:
 *
 * Leaf function.
 *
 * Get the total number of occurrences of character @c in @str.
 *
 * @return Total number of occurrences of character @c
 */
int string_count_occurrences_single_character(const char *str, char c);

/**
 * string_replace_whitespace_with_single_character:
 *
 * Leaf function.
 *
 * Replaces all spaces with given character @c.
 **/
void string_replace_whitespace_with_single_character(char *str, char c);

/**
 * string_replace_multi_space_with_single_space:
 *
 * Leaf function.
 *
 * Replaces multiple spaces with a single space in a string.
 **/
void string_replace_multi_space_with_single_space(char *str);

/**
 * string_remove_all_whitespace:
 *
 * Leaf function.
 *
 * Remove all spaces from the given string.
 **/
void string_remove_all_whitespace(char *str_trimmed, const char *str);

/* Retrieve the last occurance of the given character in a string. */
int string_index_last_occurance(const char *str, char c);

/**
 * string_find_index_substring_string:
 * @str                : input string (must be non-NULL, otherwise UB)
 * @substr             : substring to find in @str
 *
 * Hidden non-leaf function cost:
 * - Calls strstr
 *
 * Find the position of substring @substr in string @str.
 **/
int string_find_index_substring_string(const char *str, const char *substr);

/**
 * string_copy_only_ascii:
 *
 * Leaf function.
 *
 * Strips non-ASCII characters from a string.
 **/
void string_copy_only_ascii(char *str_stripped, const char *str);

extern const unsigned char lr_char_props[256];

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/time/rtime.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtime.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_RTIME_H__
#define __LIBRETRO_SDK_RTIME_H__

#include &lt;retro_common_api.h&gt;

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;time.h&gt;

RETRO_BEGIN_DECLS

/* TODO/FIXME: Move all generic time handling functions
 * to this file */

/**
 * Must be called before using \c rtime_localtime().
 * May be called multiple times without ill effects,
 * but must only be called from the main thread.
 */
void rtime_init(void);

/**
 * Must be called upon program or core termination.
 * May be called multiple times without ill effects,
 * but must only be called from the main thread.
 */
void rtime_deinit(void);

/**
 * Thread-safe wrapper around standard \c localtime(),
 * which by itself is not guaranteed to be thread-safe.
 * @param timep Pointer to a time_t object to convert.
 * @param result Pointer to a tm object to store the result in.
 * @return \c result.
 * @see https://en.cppreference.com/w/c/chrono/localtime
 */
struct tm *rtime_localtime(const time_t *timep, struct tm *result);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/utils/md5.h</h2>
<pre>/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer &lt;solar at openwall.com&gt;
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * See md5.c for more information.
 */

#ifdef HAVE_OPENSSL
#include &lt;openssl/md5.h&gt;
#elif !defined(_MD5_H)
#define _MD5_H

#include &lt;retro_common_api.h&gt;

RETRO_BEGIN_DECLS

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;

typedef struct {
	MD5_u32plus lo, hi;
	MD5_u32plus a, b, c, d;
	unsigned char buffer[64];
	MD5_u32plus block[16];
} MD5_CTX;

extern void MD5_Init(MD5_CTX *ctx);
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/vfs/vfs.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef __LIBRETRO_SDK_VFS_H
#define __LIBRETRO_SDK_VFS_H

#include &lt;retro_common_api.h&gt;
#include &lt;boolean.h&gt;

#ifdef RARCH_INTERNAL
#ifndef VFS_FRONTEND
#define VFS_FRONTEND
#endif
#endif

RETRO_BEGIN_DECLS

#ifdef _WIN32
typedef void* HANDLE;
#endif

#ifdef HAVE_CDROM
typedef struct
{
   int64_t byte_pos;
   char *cue_buf;
   size_t cue_len;
   unsigned cur_lba;
   unsigned last_frame_lba;
   unsigned char cur_min;
   unsigned char cur_sec;
   unsigned char cur_frame;
   unsigned char cur_track;
   unsigned char last_frame[2352];
   char drive;
   bool last_frame_valid;
} vfs_cdrom_t;
#endif

enum vfs_scheme
{
   VFS_SCHEME_NONE = 0,
   VFS_SCHEME_CDROM
};

#if !(defined(__WINRT__) &amp;&amp; defined(__cplusplus_winrt))
#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else
struct libretro_vfs_implementation_file
#endif
{
#ifdef HAVE_CDROM
   vfs_cdrom_t cdrom; /* int64_t alignment */
#endif
   int64_t size;
   uint64_t mappos;
   uint64_t mapsize;
   FILE *fp;
#ifdef _WIN32
   HANDLE fh;
#endif
   char *buf;
   char* orig_path;
   uint8_t *mapped;
   int fd;
   unsigned hints;
   enum vfs_scheme scheme;
};
#endif

/* Replace the following symbol with something appropriate
 * to signify the file is being compiled for a front end instead of a core.
 * This allows the same code to act as reference implementation
 * for VFS and as fallbacks for when the front end does not provide VFS functionality.
 */

#ifdef VFS_FRONTEND
typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
#else
typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;
#endif

#ifdef VFS_FRONTEND
typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
#else
typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
#endif

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/vfs/vfs_implementation_cdrom.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vfs_implementation_cdrom.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H

#include &lt;vfs/vfs.h&gt;
#include &lt;cdrom/cdrom.h&gt;

RETRO_BEGIN_DECLS

int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence);

void retro_vfs_file_open_cdrom(
      libretro_vfs_implementation_file *stream,
      const char *path, unsigned mode, unsigned hints);

int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
      void *s, uint64_t len);

int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream);

const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void);

const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream);

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/vfs/vfs_implementation.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;libretro.h&gt;
#include &lt;retro_environment.h&gt;
#include &lt;vfs/vfs.h&gt;

RETRO_BEGIN_DECLS

libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);

int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);

int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);

int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);

int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);

int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len);

int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len);

int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream);

int retro_vfs_file_remove_impl(const char *path);

int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);

const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);

int retro_vfs_stat_impl(const char *path, int32_t *size);

int retro_vfs_mkdir_impl(const char *dir);

libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);

bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);

const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);

bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);

int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);

#ifdef __WINRT__

void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);

#endif

RETRO_END_DECLS

#endif</pre>
<h2>./include/libretro-common/include/vulkan/vulkan_symbol_wrapper.h</h2>
<pre>
/* This header is autogenerated by vulkan_loader_generator.py */
#ifndef VULKAN_SYMBOL_WRAPPER_H
#define VULKAN_SYMBOL_WRAPPER_H
#define VK_NO_PROTOTYPES
#include &lt;vulkan/vulkan.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

extern PFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;
#define vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance
extern PFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;
#define vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion
extern PFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;
#define vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties
extern PFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;
#define vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties
extern PFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;
#define vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance
extern PFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;
#define vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices
extern PFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;
#define vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures
extern PFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;
#define vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties
extern PFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;
#define vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties
extern PFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;
#define vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;
#define vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties
extern PFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;
#define vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties
extern PFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;
#define vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr
extern PFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;
#define vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice
extern PFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;
#define vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice
extern PFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;
#define vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties
extern PFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;
#define vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties
extern PFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;
#define vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue
extern PFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;
#define vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit
extern PFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;
#define vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle
extern PFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;
#define vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle
extern PFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;
#define vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory
extern PFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;
#define vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory
extern PFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;
#define vkMapMemory vulkan_symbol_wrapper_vkMapMemory
extern PFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;
#define vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory
extern PFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;
#define vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges
extern PFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;
#define vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges
extern PFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;
#define vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment
extern PFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;
#define vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory
extern PFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;
#define vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory
extern PFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;
#define vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements
extern PFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;
#define vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements
extern PFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;
#define vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements
extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;
#define vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties
extern PFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;
#define vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse
extern PFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;
#define vkCreateFence vulkan_symbol_wrapper_vkCreateFence
extern PFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;
#define vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence
extern PFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;
#define vkResetFences vulkan_symbol_wrapper_vkResetFences
extern PFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;
#define vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus
extern PFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;
#define vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences
extern PFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;
#define vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore
extern PFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;
#define vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore
extern PFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;
#define vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent
extern PFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;
#define vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent
extern PFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;
#define vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus
extern PFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;
#define vkSetEvent vulkan_symbol_wrapper_vkSetEvent
extern PFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;
#define vkResetEvent vulkan_symbol_wrapper_vkResetEvent
extern PFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;
#define vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool
extern PFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;
#define vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool
extern PFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;
#define vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults
extern PFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;
#define vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer
extern PFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;
#define vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer
extern PFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;
#define vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView
extern PFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;
#define vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView
extern PFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;
#define vkCreateImage vulkan_symbol_wrapper_vkCreateImage
extern PFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;
#define vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage
extern PFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;
#define vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout
extern PFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;
#define vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView
extern PFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;
#define vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView
extern PFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;
#define vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule
extern PFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;
#define vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule
extern PFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;
#define vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache
extern PFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;
#define vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache
extern PFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;
#define vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData
extern PFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;
#define vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches
extern PFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;
#define vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines
extern PFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;
#define vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines
extern PFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;
#define vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline
extern PFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;
#define vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout
extern PFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;
#define vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout
extern PFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;
#define vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler
extern PFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;
#define vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler
extern PFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;
#define vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout
extern PFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;
#define vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout
extern PFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;
#define vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool
extern PFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;
#define vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool
extern PFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;
#define vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool
extern PFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;
#define vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets
extern PFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;
#define vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets
extern PFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;
#define vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets
extern PFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;
#define vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer
extern PFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;
#define vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer
extern PFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;
#define vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass
extern PFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;
#define vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass
extern PFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;
#define vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity
extern PFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;
#define vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool
extern PFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;
#define vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool
extern PFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;
#define vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool
extern PFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;
#define vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers
extern PFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;
#define vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers
extern PFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;
#define vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer
extern PFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;
#define vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer
extern PFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;
#define vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer
extern PFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;
#define vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline
extern PFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;
#define vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport
extern PFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;
#define vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor
extern PFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;
#define vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth
extern PFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;
#define vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias
extern PFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;
#define vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants
extern PFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;
#define vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds
extern PFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;
#define vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask
extern PFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;
#define vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask
extern PFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;
#define vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference
extern PFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;
#define vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets
extern PFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;
#define vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer
extern PFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;
#define vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers
extern PFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;
#define vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw
extern PFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;
#define vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed
extern PFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;
#define vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect
extern PFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;
#define vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect
extern PFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;
#define vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch
extern PFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;
#define vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect
extern PFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;
#define vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer
extern PFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;
#define vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage
extern PFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;
#define vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage
extern PFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;
#define vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage
extern PFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;
#define vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer
extern PFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;
#define vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer
extern PFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;
#define vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer
extern PFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;
#define vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage
extern PFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;
#define vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage
extern PFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;
#define vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments
extern PFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;
#define vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage
extern PFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;
#define vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent
extern PFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;
#define vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent
extern PFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;
#define vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents
extern PFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;
#define vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier
extern PFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;
#define vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery
extern PFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;
#define vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery
extern PFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;
#define vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool
extern PFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;
#define vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp
extern PFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;
#define vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults
extern PFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;
#define vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants
extern PFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;
#define vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass
extern PFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;
#define vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass
extern PFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;
#define vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass
extern PFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;
#define vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands
extern PFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;
#define vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;
#define vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;
#define vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR
extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;
#define vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR
extern PFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;
#define vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR
extern PFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;
#define vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR
extern PFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;
#define vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR
extern PFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;
#define vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR
extern PFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;
#define vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR
extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;
#define vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR
extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
#define vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR
extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;
#define vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR
extern PFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;
#define vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR
extern PFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;
#define vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR
extern PFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;
#define vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR
extern PFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;
#define vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR
extern PFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;
#define vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR

extern PFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;
#define vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT
extern PFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;
#define vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT
extern PFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;
#define vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT

void vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr);
PFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void);
VkBool32 vulkan_symbol_wrapper_load_global_symbols(void);
VkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance);
VkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance);
VkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device);
VkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol);
VkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol);

#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, name, pfn) vulkan_symbol_wrapper_load_instance_symbol(instance, name, (PFN_vkVoidFunction*) &amp;(pfn))
#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, name) vulkan_symbol_wrapper_load_instance_symbol(instance, #name, (PFN_vkVoidFunction*) &amp; name)
#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, name, pfn) vulkan_symbol_wrapper_load_device_symbol(device, name, (PFN_vkVoidFunction*) &amp;(pfn))
#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, name) vulkan_symbol_wrapper_load_device_symbol(device, #name, (PFN_vkVoidFunction*) &amp; name)

#ifdef __cplusplus
}
#endif
#endif</pre>
<h2>./include/libretro-common/libco/aarch64.c</h2>
<pre>/*
  libco.aarch64 (2017-06-26)
  author: webgeek1234
  license: public domain
*/

#define LIBCO_C
#include "libco.h"
#include &lt;assert.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdint.h&gt;

#ifndef __APPLE__
#include &lt;malloc.h&gt;
#endif

#ifdef __cplusplus
extern "C" {
#endif

static thread_local uint64_t co_active_buffer[64];
static thread_local cothread_t co_active_handle;

asm (
      ".globl co_switch_aarch64\n"
      ".globl _co_switch_aarch64\n"
      "co_switch_aarch64:\n"
      "_co_switch_aarch64:\n"
      "  stp x8,  x9,  [x1]\n"
      "  stp x10, x11, [x1, #16]\n"
      "  stp x12, x13, [x1, #32]\n"
      "  stp x14, x15, [x1, #48]\n"
      "  str x19, [x1, #72]\n"
      "  stp x20, x21, [x1, #80]\n"
      "  stp x22, x23, [x1, #96]\n"
      "  stp x24, x25, [x1, #112]\n"
      "  stp x26, x27, [x1, #128]\n"
      "  stp x28, x29, [x1, #144]\n"
      "  mov x16, sp\n"
      "  stp x16, x30, [x1, #160]\n"

      "  ldp x8,  x9,  [x0]\n"
      "  ldp x10, x11, [x0, #16]\n"
      "  ldp x12, x13, [x0, #32]\n"
      "  ldp x14, x15, [x0, #48]\n"
      "  ldr x19, [x0, #72]\n"
      "  ldp x20, x21, [x0, #80]\n"
      "  ldp x22, x23, [x0, #96]\n"
      "  ldp x24, x25, [x0, #112]\n"
      "  ldp x26, x27, [x0, #128]\n"
      "  ldp x28, x29, [x0, #144]\n"
      "  ldp x16, x17, [x0, #160]\n"
      "  mov sp, x16\n"
      "  br x17\n"
    );

/* ASM */
void co_switch_aarch64(cothread_t handle, cothread_t current);

static void crash(void)
{
   /* Called only if cothread_t entrypoint returns. */
   assert(0);
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
	uint64_t *ptr     = NULL;
   cothread_t handle = 0;
   size              = (size + 1023) &amp; ~1023;
#if HAVE_POSIX_MEMALIGN &gt;= 1
   if (posix_memalign(&amp;handle, 1024, size + 512) &lt; 0)
      return 0;
#else
   handle            = memalign(1024, size + 512);
#endif

   if (!handle)
      return handle;

   ptr     = (uint64_t*)handle;
   /* Non-volatiles.  */
   ptr[0]  = 0; /* x8  */
   ptr[1]  = 0; /* x9  */
   ptr[2]  = 0; /* x10 */
   ptr[3]  = 0; /* x11 */
   ptr[4]  = 0; /* x12 */
   ptr[5]  = 0; /* x13 */
   ptr[6]  = 0; /* x14 */
   ptr[7]  = 0; /* x15 */
   ptr[8]  = 0; /* padding */
   ptr[9]  = 0; /* x19 */
   ptr[10] = 0; /* x20 */
   ptr[11] = 0; /* x21 */
   ptr[12] = 0; /* x22 */
   ptr[13] = 0; /* x23 */
   ptr[14] = 0; /* x24 */
   ptr[15] = 0; /* x25 */
   ptr[16] = 0; /* x26 */
   ptr[17] = 0; /* x27 */
   ptr[18] = 0; /* x28 */
   ptr[20] = (uintptr_t)ptr + size + 512 - 16; /* x30, stack pointer */
   ptr[19] = ptr[20]; /* x29, frame pointer */
   ptr[21] = (uintptr_t)entrypoint; /* PC (link register x31 gets saved here). */
   return handle;
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_active_handle = co_active_buffer;
   return co_active_handle;
}

void co_delete(cothread_t handle)
{
   free(handle);
}

void co_switch(cothread_t handle)
{
   cothread_t co_previous_handle = co_active();
   co_switch_aarch64(co_active_handle = handle, co_previous_handle);
}

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/amd64.c</h2>
<pre>/*
  libco.amd64 (2009-10-12)
  author: byuu
  license: public domain
*/

#define LIBCO_C
#include &lt;libco.h&gt;
#include &lt;assert.h&gt;
#include &lt;stdlib.h&gt;

#if defined(__GNUC__) &amp;&amp; !defined(_WIN32) &amp;&amp; !defined(__cplusplus)
#define CO_USE_INLINE_ASM
#endif

#ifdef __cplusplus
extern "C" {
#endif

static thread_local long long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
#ifndef CO_USE_INLINE_ASM
static void (*co_swap)(cothread_t, cothread_t)  = 0;
#endif

#ifdef _WIN32
/* ABI: Win64 */
  /* On windows handle is allocated by malloc and there it's guaranteed to
     have at least 16-byte alignment. Hence we don't need to align
     it in order to use movaps.  */
static unsigned char co_swap_function[] = {
    0x48, 0x89, 0x22,              /* mov [rdx],rsp          */
    0x48, 0x8b, 0x21,              /* mov rsp,[rcx]          */
    0x58,                          /* pop rax                */
    0x48, 0x89, 0x6a, 0x08,        /* mov [rdx+ 8],rbp       */
    0x48, 0x89, 0x72, 0x10,        /* mov [rdx+16],rsi       */
    0x48, 0x89, 0x7a, 0x18,        /* mov [rdx+24],rdi       */
    0x48, 0x89, 0x5a, 0x20,        /* mov [rdx+32],rbx       */
    0x4c, 0x89, 0x62, 0x28,        /* mov [rdx+40],r12       */
    0x4c, 0x89, 0x6a, 0x30,        /* mov [rdx+48],r13       */
    0x4c, 0x89, 0x72, 0x38,        /* mov [rdx+56],r14       */
    0x4c, 0x89, 0x7a, 0x40,        /* mov [rdx+64],r15       */
  #if !defined(LIBCO_NO_SSE)
    0x0f, 0x29, 0x72, 0x50,        /* movaps [rdx+ 80],xmm6  */
    0x0f, 0x29, 0x7a, 0x60,        /* movaps [rdx+ 96],xmm7  */
    0x44, 0x0f, 0x29, 0x42, 0x70,  /* movaps [rdx+112],xmm8  */
    0x48, 0x83, 0xc2, 0x70,        /* add rdx,112            */
    0x44, 0x0f, 0x29, 0x4a, 0x10,  /* movaps [rdx+ 16],xmm9  */
    0x44, 0x0f, 0x29, 0x52, 0x20,  /* movaps [rdx+ 32],xmm10 */
    0x44, 0x0f, 0x29, 0x5a, 0x30,  /* movaps [rdx+ 48],xmm11 */
    0x44, 0x0f, 0x29, 0x62, 0x40,  /* movaps [rdx+ 64],xmm12 */
    0x44, 0x0f, 0x29, 0x6a, 0x50,  /* movaps [rdx+ 80],xmm13 */
    0x44, 0x0f, 0x29, 0x72, 0x60,  /* movaps [rdx+ 96],xmm14 */
    0x44, 0x0f, 0x29, 0x7a, 0x70,  /* movaps [rdx+112],xmm15 */
  #endif
    0x48, 0x8b, 0x69, 0x08,        /* mov rbp,[rcx+ 8]       */
    0x48, 0x8b, 0x71, 0x10,        /* mov rsi,[rcx+16]       */
    0x48, 0x8b, 0x79, 0x18,        /* mov rdi,[rcx+24]       */
    0x48, 0x8b, 0x59, 0x20,        /* mov rbx,[rcx+32]       */
    0x4c, 0x8b, 0x61, 0x28,        /* mov r12,[rcx+40]       */
    0x4c, 0x8b, 0x69, 0x30,        /* mov r13,[rcx+48]       */
    0x4c, 0x8b, 0x71, 0x38,        /* mov r14,[rcx+56]       */
    0x4c, 0x8b, 0x79, 0x40,        /* mov r15,[rcx+64]       */
  #if !defined(LIBCO_NO_SSE)
    0x0f, 0x28, 0x71, 0x50,        /* movaps xmm6, [rcx+ 80] */
    0x0f, 0x28, 0x79, 0x60,        /* movaps xmm7, [rcx+ 96] */
    0x44, 0x0f, 0x28, 0x41, 0x70,  /* movaps xmm8, [rcx+112] */
    0x48, 0x83, 0xc1, 0x70,        /* add rcx,112            */
    0x44, 0x0f, 0x28, 0x49, 0x10,  /* movaps xmm9, [rcx+ 16] */
    0x44, 0x0f, 0x28, 0x51, 0x20,  /* movaps xmm10,[rcx+ 32] */
    0x44, 0x0f, 0x28, 0x59, 0x30,  /* movaps xmm11,[rcx+ 48] */
    0x44, 0x0f, 0x28, 0x61, 0x40,  /* movaps xmm12,[rcx+ 64] */
    0x44, 0x0f, 0x28, 0x69, 0x50,  /* movaps xmm13,[rcx+ 80] */
    0x44, 0x0f, 0x28, 0x71, 0x60,  /* movaps xmm14,[rcx+ 96] */
    0x44, 0x0f, 0x28, 0x79, 0x70,  /* movaps xmm15,[rcx+112] */
  #endif
    0xff, 0xe0,                    /* jmp rax                */
};

#include &lt;windows.h&gt;

static void co_init(void)
{
   DWORD old_privileges;
   VirtualProtect(co_swap_function,
         sizeof(co_swap_function), PAGE_EXECUTE_READWRITE, &amp;old_privileges);
}
#else
/* ABI: SystemV */
#ifndef CO_USE_INLINE_ASM
static unsigned char co_swap_function[] = {
  0x48, 0x89, 0x26,                                 /* mov    [rsi],rsp      */
  0x48, 0x8b, 0x27,                                 /* mov    rsp,[rdi]      */
  0x58,                                             /* pop    rax            */
  0x48, 0x89, 0x6e, 0x08,                           /* mov    [rsi+0x08],rbp */
  0x48, 0x89, 0x5e, 0x10,                           /* mov    [rsi+0x10],rbx */
  0x4c, 0x89, 0x66, 0x18,                           /* mov    [rsi+0x18],r12 */
  0x4c, 0x89, 0x6e, 0x20,                           /* mov    [rsi+0x20],r13 */
  0x4c, 0x89, 0x76, 0x28,                           /* mov    [rsi+0x28],r14 */
  0x4c, 0x89, 0x7e, 0x30,                           /* mov    [rsi+0x30],r15 */
  0x48, 0x8b, 0x6f, 0x08,                           /* mov    rbp,[rdi+0x08] */
  0x48, 0x8b, 0x5f, 0x10,                           /* mov    rbx,[rdi+0x10] */
  0x4c, 0x8b, 0x67, 0x18,                           /* mov    r12,[rdi+0x18] */
  0x4c, 0x8b, 0x6f, 0x20,                           /* mov    r13,[rdi+0x20] */
  0x4c, 0x8b, 0x77, 0x28,                           /* mov    r14,[rdi+0x28] */
  0x4c, 0x8b, 0x7f, 0x30,                           /* mov    r15,[rdi+0x30] */
  0xff, 0xe0,                                       /* jmp    rax            */
};

#include &lt;unistd.h&gt;
#include &lt;sys/mman.h&gt;

static void co_init(void)
{
   unsigned long long addr = (unsigned long long)co_swap_function;
   unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
   unsigned long long size = (addr - base) + sizeof(co_swap_function);
   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#else
static void co_init(void) {}
#endif
#endif

static void crash(void)
{
  assert(0); /* called only if cothread_t entrypoint returns */
}

cothread_t co_active(void)
{
  if (!co_active_handle)
     co_active_handle = &amp;co_active_buffer;
  return co_active_handle;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   cothread_t handle;
#ifndef CO_USE_INLINE_ASM
   if (!co_swap)
   {
      co_init();
      co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
   }
#endif

   if (!co_active_handle)
      co_active_handle = &amp;co_active_buffer;
   size += 512; /* allocate additional space for storage */
   size &amp;= ~15; /* align stack to 16-byte boundary */

#ifdef __GENODE__
   if ((handle = (cothread_t)genode_alloc_secondary_stack(size)))
   {
      long long *p        = (long long*)((char*)handle); /* OS returns top of stack */
      *--p                = (long long)crash;            /* crash if entrypoint returns */
      *--p                = (long long)entrypoint;       /* start of function */
      *(long long*)handle = (long long)p;                /* stack pointer */
   }
#else
   if ((handle = (cothread_t)malloc(size)))
   {
      long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
      *--p = (long long)crash;                           /* crash if entrypoint returns */
      *--p = (long long)entrypoint;                      /* start of function */
      *(long long*)handle = (long long)p;                /* stack pointer */
   }
#endif

   return handle;
}

void co_delete(cothread_t handle)
{
#ifdef __GENODE__
   genode_free_secondary_stack(handle);
#else
   free(handle);
#endif
}

#ifndef CO_USE_INLINE_ASM
void co_switch(cothread_t handle)
{
  register cothread_t co_previous_handle = co_active_handle;
  co_swap(co_active_handle = handle, co_previous_handle);
}
#else
#ifdef __APPLE__
#define ASM_PREFIX "_"
#else
#define ASM_PREFIX ""
#endif
__asm__(
".intel_syntax noprefix         \n"
".globl " ASM_PREFIX "co_switch              \n"
ASM_PREFIX "co_switch:                     \n"
"mov rsi, [rip+" ASM_PREFIX "co_active_handle]\n"
"mov [rsi],rsp                  \n"
"mov [rsi+0x08],rbp             \n"
"mov [rsi+0x10],rbx             \n"
"mov [rsi+0x18],r12             \n"
"mov [rsi+0x20],r13             \n"
"mov [rsi+0x28],r14             \n"
"mov [rsi+0x30],r15             \n"
"mov [rip+" ASM_PREFIX "co_active_handle], rdi\n"
"mov rsp,[rdi]                  \n"
"mov rbp,[rdi+0x08]             \n"
"mov rbx,[rdi+0x10]             \n"
"mov r12,[rdi+0x18]             \n"
"mov r13,[rdi+0x20]             \n"
"mov r14,[rdi+0x28]             \n"
"mov r15,[rdi+0x30]             \n"
"ret                            \n"
".att_syntax                    \n"
);
#endif

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/armeabi.c</h2>
<pre>/*
  libco.armeabi (2013-04-05)
  author: Themaister
  license: public domain
*/

#define LIBCO_C
#include &lt;libco.h&gt;
#include &lt;assert.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdint.h&gt;

#ifndef __APPLE__
#include &lt;malloc.h&gt;
#endif

#ifdef __cplusplus
extern "C" {
#endif

static thread_local uint32_t co_active_buffer[64];
static thread_local cothread_t co_active_handle;

__asm__ (
#if defined(__thumb2__)
      ".align 2\n"
      ".globl co_switch_arm\n"
      ".globl _co_switch_arm\n"
      ".thumb\n"
      ".thumb_func\n"
      ".type   co_switch_arm, %function\n"
      ".type   _co_switch_arm, %function\n"
      "co_switch_arm:\n"
      "_co_switch_arm:\n"
      " mov r3, sp\n"
      " stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
      " stmia r1!, {r3, lr}\n"
      " ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
      " ldmfd r0!, { r3 }\n"
      " mov sp, r3\n"
      " ldmfd r0!, { r3 }\n"
      " mov pc, r3\n"
#else
      ".arm\n"
      ".align 4\n"
      ".globl co_switch_arm\n"
      ".globl _co_switch_arm\n"
      "co_switch_arm:\n"
      "_co_switch_arm:\n"
      "  stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\n"
      "  ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\n"
#endif
    );

/* ASM */
void co_switch_arm(cothread_t handle, cothread_t current);

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   uint32_t *ptr     = NULL;
   cothread_t handle = 0;
   size              = (size + 1023) &amp; ~1023;
#if defined(__APPLE__) || HAVE_POSIX_MEMALIGN &gt;= 1
   if (posix_memalign(&amp;handle, 1024, size + 256) &lt; 0)
      return 0;
#else
   handle = memalign(1024, size + 256);
#endif

   if (!handle)
      return handle;

   ptr    = (uint32_t*)handle;
   /* Non-volatiles.  */
   ptr[0] = 0; /* r4  */
   ptr[1] = 0; /* r5  */
   ptr[2] = 0; /* r6  */
   ptr[3] = 0; /* r7  */
   ptr[4] = 0; /* r8  */
   ptr[5] = 0; /* r9  */
   ptr[6] = 0; /* r10 */
   ptr[7] = 0; /* r11 */
   /* Align stack to 64-bit */
   ptr[8] = (uintptr_t)ptr + size + 256 - 8; /* r13, stack pointer */
   ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */
   return handle;
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_active_handle = co_active_buffer;
   return co_active_handle;
}

void co_delete(cothread_t handle)
{
   free(handle);
}

void co_switch(cothread_t handle)
{
   cothread_t co_previous_handle = co_active();
   co_switch_arm(co_active_handle = handle, co_previous_handle);
}

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/fiber.c</h2>
<pre>/*
  libco.win (2008-01-28)
  authors: Nach, byuu
  license: public domain
*/

#define LIBCO_C
#include &lt;libco.h&gt;
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include &lt;windows.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

static thread_local cothread_t co_active_ = 0;

static void __stdcall co_thunk(void *coentry)
{
   ((void (*)(void))coentry)();
}

cothread_t co_active(void)
{
   if (!co_active_)
   {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
#else
      ConvertThreadToFiber(0);
#endif
      co_active_ = GetCurrentFiber();
   }
   return co_active_;
}

cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
{
   if (!co_active_)
   {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
#else
      ConvertThreadToFiber(0);
#endif
      co_active_ = GetCurrentFiber();
   }

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
   return (cothread_t)CreateFiberEx(heapsize, heapsize, FIBER_FLAG_FLOAT_SWITCH, co_thunk, (void*)coentry);
#else
   return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
#endif
}

void co_delete(cothread_t cothread)
{
   DeleteFiber(cothread);
}

void co_switch(cothread_t cothread)
{
   co_active_ = cothread;
   SwitchToFiber(cothread);
}

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/genode.cpp</h2>
<pre>/*
  libco.genode_secondary_stack (2018-09-15)
  author: Emery Hemingway
  license: public domain
*/

/* Genode include */
#include &lt;base/thread.h&gt;

/* Libco include */
#include &lt;libco.h&gt;

extern "C"
void *genode_alloc_secondary_stack(unsigned long stack_size)
{
	try
   {
		return Genode::Thread::myself()-&gt;alloc_secondary_stack("libco", stack_size);
   }
	catch (...)
   {
		Genode::error("libco: failed to allocate ", stack_size, " byte secondary stack");
		return nullptr;
	}
}

extern "C"
void genode_free_secondary_stack(void *stack)
{
	Genode::Thread::myself()-&gt;free_secondary_stack(stack);
}</pre>
<h2>./include/libretro-common/libco/libco.c</h2>
<pre>/*
  libco
  auto-selection module
  license: public domain
*/

#ifdef __GENODE__
void *genode_alloc_secondary_stack(unsigned long stack_size);
void genode_free_secondary_stack(void *stack);
#endif

#if defined _MSC_VER
  #include &lt;Windows.h&gt;
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
    #include "fiber.c"
  #elif defined _M_IX86
    #include "x86.c"
  #elif defined _M_AMD64
    #include "amd64.c"
  #else
    #include "fiber.c"
  #endif
#elif defined __GNUC__
  #if defined __i386__
    #include "x86.c"
  #elif defined __amd64__
    #include "amd64.c"
  #elif defined _ARCH_PPC
    #include "ppc.c"
  #elif defined(__aarch64__)
    #include "aarch64.c"
  #elif defined(PS2)
    #include "ps2.c"
  #elif defined(PSP)
    #include "psp1.c"
  #elif defined VITA
    #include "scefiber.c"
  #elif defined(__ARM_EABI__) || defined(__arm__)
    #include "armeabi.c"
  #else
    #include "sjlj.c"
  #endif
#else
  #error "libco: unsupported processor, compiler or operating system"
#endif</pre>
<h2>./include/libretro-common/libco/ppc.c</h2>
<pre>/*
  libco.ppc (2010-10-17)
  author: blargg
  license: public domain
*/

/* PowerPC 32/64 using embedded or external asm, with optional
floating-point and AltiVec save/restore */

#define LIBCO_C
#include &lt;libco.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;

#define LIBCO_MPROTECT (__unix__ &amp;&amp; !LIBCO_PPC_ASM)

#if LIBCO_MPROTECT
#include &lt;unistd.h&gt;
#include &lt;sys/mman.h&gt;
#endif

/* State format (offsets in 32-bit words)

+0	Pointer to swap code
	Rest of function descriptor for entry function
+8	PC
+10	SP
	Special regs
	GPRs
	FPRs
	VRs
	stack
*/

enum { state_size  = 1024 };
enum { above_stack = 2048 };
enum { stack_align = 256  };

static thread_local cothread_t co_active_handle = 0;

/**** Determine environment ****/

#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)

/* Whether function calls are indirect through a descriptor,
or are directly to function */
#ifndef LIBCO_PPCDESC
	#if !_CALL_SYSV &amp;&amp; (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
		#define LIBCO_PPCDESC 1
	#endif
#endif

/* Whether the code should be inline asm stored in .text, or the original
array buffer */
#ifndef LIBCO_STATIC_TEXT
   #if defined(WIIU)
      #define LIBCO_STATIC_TEXT 1
   #endif
#endif

#ifdef LIBCO_PPC_ASM

	#ifdef __cplusplus
		extern "C"
	#endif

	/* Swap code is in ppc.S */
	void co_swap_asm(cothread_t, cothread_t);
	#define CO_SWAP_ASM(x, y) co_swap_asm(x, y)

#elif LIBCO_STATIC_TEXT

asm(
	".globl libco_ppc_code\n"
	"libco_ppc_code:\n"
#if LIBCO_PPC64
	"mfcr    %r8\n"
	"std     %r1,40(%r4)\n"
	"mflr    %r9\n"
	"std     %r14,72(%r4)\n"
	"std     %r15,80(%r4)\n"
	"std     %r16,88(%r4)\n"
	"std     %r17,96(%r4)\n"
	"std     %r18,104(%r4)\n"
	"std     %r19,112(%r4)\n"
	"std     %r20,120(%r4)\n"
	"std     %r21,128(%r4)\n"
	"std     %r22,136(%r4)\n"
	"std     %r23,144(%r4)\n"
	"std     %r24,152(%r4)\n"
	"std     %r25,160(%r4)\n"
	"std     %r26,168(%r4)\n"
	"std     %r27,176(%r4)\n"
	"std     %r28,184(%r4)\n"
	"std     %r29,192(%r4)\n"
	"std     %r30,200(%r4)\n"
	"std     %r31,208(%r4)\n"
	"std     %r9,32(%r4)\n"
	"ld      %r7,32(%r3)\n"
	"ld      %r1,40(%r3)\n"
	"bl      1f\n"
	"trap\n"
	"1:stw     %r8,48(%r4)\n"
	"lwz     %r6,48(%r3)\n"
	"mtctr   %r7\n"
	"ld      %r14,72(%r3)\n"
	"ld      %r15,80(%r3)\n"
	"ld      %r16,88(%r3)\n"
	"ld      %r17,96(%r3)\n"
	"ld      %r18,104(%r3)\n"
	"ld      %r19,112(%r3)\n"
	"ld      %r20,120(%r3)\n"
	"ld      %r21,128(%r3)\n"
	"ld      %r22,136(%r3)\n"
	"ld      %r23,144(%r3)\n"
	"ld      %r24,152(%r3)\n"
	"ld      %r25,160(%r3)\n"
	"ld      %r26,168(%r3)\n"
	"ld      %r27,176(%r3)\n"
	"ld      %r28,184(%r3)\n"
	"ld      %r29,192(%r3)\n"
	"ld      %r30,200(%r3)\n"
	"ld      %r31,208(%r3)\n"
	"mtcr    %r6\n"
#else
	"mfcr    %r8\n"
	"stw     %r1,40(%r4)\n"
	"mflr    %r9\n"
	"stw     %r13,60(%r4)\n"
	"stw     %r14,64(%r4)\n"
	"stw     %r15,68(%r4)\n"
	"stw     %r16,72(%r4)\n"
	"stw     %r17,76(%r4)\n"
	"stw     %r18,80(%r4)\n"
	"stw     %r19,84(%r4)\n"
	"stw     %r20,88(%r4)\n"
	"stw     %r21,92(%r4)\n"
	"stw     %r22,96(%r4)\n"
	"stw     %r23,100(%r4)\n"
	"stw     %r24,104(%r4)\n"
	"stw     %r25,108(%r4)\n"
	"stw     %r26,112(%r4)\n"
	"stw     %r27,116(%r4)\n"
	"stw     %r28,120(%r4)\n"
	"stw     %r29,124(%r4)\n"
	"stw     %r30,128(%r4)\n"
	"stw     %r31,132(%r4)\n"
	"stw     %r9,32(%r4)\n"
	"lwz     %r7,32(%r3)\n"
	"lwz     %r1,40(%r3)\n"
	"bl      1f\n"
	"trap\n"
	"1:stw     %r8,48(%r4)\n"
	"lwz     %r6,48(%r3)\n"
	"mtctr   %r7\n"
	"lwz     %r13,60(%r3)\n"
	"lwz     %r14,64(%r3)\n"
	"lwz     %r15,68(%r3)\n"
	"lwz     %r16,72(%r3)\n"
	"lwz     %r17,76(%r3)\n"
	"lwz     %r18,80(%r3)\n"
	"lwz     %r19,84(%r3)\n"
	"lwz     %r20,88(%r3)\n"
	"lwz     %r21,92(%r3)\n"
	"lwz     %r22,96(%r3)\n"
	"lwz     %r23,100(%r3)\n"
	"lwz     %r24,104(%r3)\n"
	"lwz     %r25,108(%r3)\n"
	"lwz     %r26,112(%r3)\n"
	"lwz     %r27,116(%r3)\n"
	"lwz     %r28,120(%r3)\n"
	"lwz     %r29,124(%r3)\n"
	"lwz     %r30,128(%r3)\n"
	"lwz     %r31,132(%r3)\n"
	"mtcr    %r6\n"
#endif

#ifndef LIBCO_PPC_NOFP
	"stfd    %f14,224(%r4)\n"
	"stfd    %f15,232(%r4)\n"
	"stfd    %f16,240(%r4)\n"
	"stfd    %f17,248(%r4)\n"
	"stfd    %f18,256(%r4)\n"
	"stfd    %f19,264(%r4)\n"
	"stfd    %f20,272(%r4)\n"
	"stfd    %f21,280(%r4)\n"
	"stfd    %f22,288(%r4)\n"
	"stfd    %f23,296(%r4)\n"
	"stfd    %f24,304(%r4)\n"
	"stfd    %f25,312(%r4)\n"
	"stfd    %f26,320(%r4)\n"
	"stfd    %f27,328(%r4)\n"
	"stfd    %f28,336(%r4)\n"
	"stfd    %f29,344(%r4)\n"
	"stfd    %f30,352(%r4)\n"
	"stfd    %f31,360(%r4)\n"
	"lfd     %f14,224(%r3)\n"
	"lfd     %f15,232(%r3)\n"
	"lfd     %f16,240(%r3)\n"
	"lfd     %f17,248(%r3)\n"
	"lfd     %f18,256(%r3)\n"
	"lfd     %f19,264(%r3)\n"
	"lfd     %f20,272(%r3)\n"
	"lfd     %f21,280(%r3)\n"
	"lfd     %f22,288(%r3)\n"
	"lfd     %f23,296(%r3)\n"
	"lfd     %f24,304(%r3)\n"
	"lfd     %f25,312(%r3)\n"
	"lfd     %f26,320(%r3)\n"
	"lfd     %f27,328(%r3)\n"
	"lfd     %f28,336(%r3)\n"
	"lfd     %f29,344(%r3)\n"
	"lfd     %f30,352(%r3)\n"
	"lfd     %f31,360(%r3)\n"
#endif

#ifdef __ALTIVEC__
	"mfvrsave %r5\n"
	"addi    %r8,%r4,384\n"
	"addi    %r9,%r4,400\n"
	"andi.   %r0,%r5,4095\n"
	"stw     %r5,52(%r4)\n"
	"beq-    2\n"
	"stvx    %v20,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v21,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v22,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v23,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v24,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v25,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v26,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v27,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v28,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"stvx    %v29,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"stvx    %v30,%r0,%r8\n"
	"stvx    %v31,%r0,%r9\n"
	"2:lwz     %r5,52(%r3)\n"
	"addi    %r8,%r3,384\n"
	"addi    %r9,%r3,400\n"
	"andi.   %r0,%r5,4095\n"
	"mtvrsave %r5\n"
	"beqctr  \n"
	"lvx     %v20,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v21,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v22,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v23,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v24,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v25,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v26,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v27,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v28,%r0,%r8\n"
	"addi    %r8,%r8,32\n"
	"lvx     %v29,%r0,%r9\n"
	"addi    %r9,%r9,32\n"
	"lvx     %v30,%r0,%r8\n"
	"lvx     %v31,%r0,%r9\n"
#endif
	"bctr"
);

extern void libco_ppc_code(cothread_t, cothread_t);

#if LIBCO_PPCDESC
/* Function call goes through indirect descriptor */
#define CO_SWAP_ASM(x, y) \
			((void (*)(cothread_t, cothread_t)) (uintptr_t) x)(x, y)
#else
/* Function call goes directly to code */
#define CO_SWAP_ASM(x, y) \
			libco_ppc_code(x, y)
#endif

#else

/* Swap code is here in array. Please leave dieassembly comments,
as they make it easy to see what it does, and reorder instructions
if one wants to see whether that improves performance. */
static const uint32_t libco_ppc_code [] = {
#if LIBCO_PPC64
    0x7d000026, /* mfcr    r8 */
    0xf8240028, /* std     r1,40(r4) */
    0x7d2802a6, /* mflr    r9 */
    0xf9c40048, /* std     r14,72(r4) */
    0xf9e40050, /* std     r15,80(r4) */
    0xfa040058, /* std     r16,88(r4) */
    0xfa240060, /* std     r17,96(r4) */
    0xfa440068, /* std     r18,104(r4) */
    0xfa640070, /* std     r19,112(r4) */
    0xfa840078, /* std     r20,120(r4) */
    0xfaa40080, /* std     r21,128(r4) */
    0xfac40088, /* std     r22,136(r4) */
    0xfae40090, /* std     r23,144(r4) */
    0xfb040098, /* std     r24,152(r4) */
    0xfb2400a0, /* std     r25,160(r4) */
    0xfb4400a8, /* std     r26,168(r4) */
    0xfb6400b0, /* std     r27,176(r4) */
    0xfb8400b8, /* std     r28,184(r4) */
    0xfba400c0, /* std     r29,192(r4) */
    0xfbc400c8, /* std     r30,200(r4) */
    0xfbe400d0, /* std     r31,208(r4) */
    0xf9240020, /* std     r9,32(r4) */
    0xe8e30020, /* ld      r7,32(r3) */
    0xe8230028, /* ld      r1,40(r3) */
    0x48000009, /* bl      1 */
	0x7fe00008, /* trap */
    0x91040030,/*1:stw     r8,48(r4) */
    0x80c30030, /* lwz     r6,48(r3) */
    0x7ce903a6, /* mtctr   r7 */
    0xe9c30048, /* ld      r14,72(r3) */
    0xe9e30050, /* ld      r15,80(r3) */
    0xea030058, /* ld      r16,88(r3) */
    0xea230060, /* ld      r17,96(r3) */
    0xea430068, /* ld      r18,104(r3) */
    0xea630070, /* ld      r19,112(r3) */
    0xea830078, /* ld      r20,120(r3) */
    0xeaa30080, /* ld      r21,128(r3) */
    0xeac30088, /* ld      r22,136(r3) */
    0xeae30090, /* ld      r23,144(r3) */
    0xeb030098, /* ld      r24,152(r3) */
    0xeb2300a0, /* ld      r25,160(r3) */
    0xeb4300a8, /* ld      r26,168(r3) */
    0xeb6300b0, /* ld      r27,176(r3) */
    0xeb8300b8, /* ld      r28,184(r3) */
    0xeba300c0, /* ld      r29,192(r3) */
    0xebc300c8, /* ld      r30,200(r3) */
    0xebe300d0, /* ld      r31,208(r3) */
    0x7ccff120, /* mtcr    r6 */
#else
	0x7d000026, /* mfcr    r8 */
	0x90240028, /* stw     r1,40(r4) */
	0x7d2802a6, /* mflr    r9 */
	0x91a4003c, /* stw     r13,60(r4) */
	0x91c40040, /* stw     r14,64(r4) */
	0x91e40044, /* stw     r15,68(r4) */
	0x92040048, /* stw     r16,72(r4) */
	0x9224004c, /* stw     r17,76(r4) */
	0x92440050, /* stw     r18,80(r4) */
	0x92640054, /* stw     r19,84(r4) */
	0x92840058, /* stw     r20,88(r4) */
	0x92a4005c, /* stw     r21,92(r4) */
	0x92c40060, /* stw     r22,96(r4) */
	0x92e40064, /* stw     r23,100(r4) */
	0x93040068, /* stw     r24,104(r4) */
	0x9324006c, /* stw     r25,108(r4) */
	0x93440070, /* stw     r26,112(r4) */
	0x93640074, /* stw     r27,116(r4) */
	0x93840078, /* stw     r28,120(r4) */
	0x93a4007c, /* stw     r29,124(r4) */
	0x93c40080, /* stw     r30,128(r4) */
	0x93e40084, /* stw     r31,132(r4) */
	0x91240020, /* stw     r9,32(r4) */
	0x80e30020, /* lwz     r7,32(r3) */
	0x80230028, /* lwz     r1,40(r3) */
	0x48000009, /* bl      1 */
	0x7fe00008, /* trap */
	0x91040030,/*1:stw     r8,48(r4) */
	0x80c30030, /* lwz     r6,48(r3) */
	0x7ce903a6, /* mtctr   r7 */
	0x81a3003c, /* lwz     r13,60(r3) */
	0x81c30040, /* lwz     r14,64(r3) */
	0x81e30044, /* lwz     r15,68(r3) */
	0x82030048, /* lwz     r16,72(r3) */
	0x8223004c, /* lwz     r17,76(r3) */
	0x82430050, /* lwz     r18,80(r3) */
	0x82630054, /* lwz     r19,84(r3) */
	0x82830058, /* lwz     r20,88(r3) */
	0x82a3005c, /* lwz     r21,92(r3) */
	0x82c30060, /* lwz     r22,96(r3) */
	0x82e30064, /* lwz     r23,100(r3) */
	0x83030068, /* lwz     r24,104(r3) */
	0x8323006c, /* lwz     r25,108(r3) */
	0x83430070, /* lwz     r26,112(r3) */
	0x83630074, /* lwz     r27,116(r3) */
	0x83830078, /* lwz     r28,120(r3) */
	0x83a3007c, /* lwz     r29,124(r3) */
	0x83c30080, /* lwz     r30,128(r3) */
	0x83e30084, /* lwz     r31,132(r3) */
	0x7ccff120, /* mtcr    r6 */
#endif

#ifndef LIBCO_PPC_NOFP
	0xd9c400e0, /* stfd    f14,224(r4) */
	0xd9e400e8, /* stfd    f15,232(r4) */
	0xda0400f0, /* stfd    f16,240(r4) */
	0xda2400f8, /* stfd    f17,248(r4) */
	0xda440100, /* stfd    f18,256(r4) */
	0xda640108, /* stfd    f19,264(r4) */
	0xda840110, /* stfd    f20,272(r4) */
	0xdaa40118, /* stfd    f21,280(r4) */
	0xdac40120, /* stfd    f22,288(r4) */
	0xdae40128, /* stfd    f23,296(r4) */
	0xdb040130, /* stfd    f24,304(r4) */
	0xdb240138, /* stfd    f25,312(r4) */
	0xdb440140, /* stfd    f26,320(r4) */
	0xdb640148, /* stfd    f27,328(r4) */
	0xdb840150, /* stfd    f28,336(r4) */
	0xdba40158, /* stfd    f29,344(r4) */
	0xdbc40160, /* stfd    f30,352(r4) */
	0xdbe40168, /* stfd    f31,360(r4) */
	0xc9c300e0, /* lfd     f14,224(r3) */
	0xc9e300e8, /* lfd     f15,232(r3) */
	0xca0300f0, /* lfd     f16,240(r3) */
	0xca2300f8, /* lfd     f17,248(r3) */
	0xca430100, /* lfd     f18,256(r3) */
	0xca630108, /* lfd     f19,264(r3) */
	0xca830110, /* lfd     f20,272(r3) */
	0xcaa30118, /* lfd     f21,280(r3) */
	0xcac30120, /* lfd     f22,288(r3) */
	0xcae30128, /* lfd     f23,296(r3) */
	0xcb030130, /* lfd     f24,304(r3) */
	0xcb230138, /* lfd     f25,312(r3) */
	0xcb430140, /* lfd     f26,320(r3) */
	0xcb630148, /* lfd     f27,328(r3) */
	0xcb830150, /* lfd     f28,336(r3) */
	0xcba30158, /* lfd     f29,344(r3) */
	0xcbc30160, /* lfd     f30,352(r3) */
	0xcbe30168, /* lfd     f31,360(r3) */
#endif

#ifdef __ALTIVEC__
	0x7ca042a6, /* mfvrsave r5 */
	0x39040180, /* addi    r8,r4,384 */
	0x39240190, /* addi    r9,r4,400 */
	0x70a00fff, /* andi.   r0,r5,4095 */
	0x90a40034, /* stw     r5,52(r4) */
	0x4182005c, /* beq-    2 */
	0x7e8041ce, /* stvx    v20,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ea049ce, /* stvx    v21,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7ec041ce, /* stvx    v22,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ee049ce, /* stvx    v23,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f0041ce, /* stvx    v24,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f2049ce, /* stvx    v25,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f4041ce, /* stvx    v26,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f6049ce, /* stvx    v27,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f8041ce, /* stvx    v28,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7fa049ce, /* stvx    v29,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7fc041ce, /* stvx    v30,r0,r8 */
	0x7fe049ce, /* stvx    v31,r0,r9 */
	0x80a30034,/*2:lwz     r5,52(r3) */
	0x39030180, /* addi    r8,r3,384 */
	0x39230190, /* addi    r9,r3,400 */
	0x70a00fff, /* andi.   r0,r5,4095 */
	0x7ca043a6, /* mtvrsave r5 */
	0x4d820420, /* beqctr   */
	0x7e8040ce, /* lvx     v20,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ea048ce, /* lvx     v21,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7ec040ce, /* lvx     v22,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7ee048ce, /* lvx     v23,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f0040ce, /* lvx     v24,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f2048ce, /* lvx     v25,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f4040ce, /* lvx     v26,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7f6048ce, /* lvx     v27,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7f8040ce, /* lvx     v28,r0,r8 */
	0x39080020, /* addi    r8,r8,32 */
	0x7fa048ce, /* lvx     v29,r0,r9 */
	0x39290020, /* addi    r9,r9,32 */
	0x7fc040ce, /* lvx     v30,r0,r8 */
	0x7fe048ce, /* lvx     v31,r0,r9 */
#endif

	0x4e800420, /* bctr */
};

	#if LIBCO_PPCDESC
		/* Function call goes through indirect descriptor */
		#define CO_SWAP_ASM(x, y) \
			((void (*)(cothread_t, cothread_t)) (uintptr_t) x)(x, y)
	#else
		/* Function call goes directly to code */
		#define CO_SWAP_ASM(x, y) \
			((void (*)(cothread_t, cothread_t)) (uintptr_t) libco_ppc_code)(x, y)
	#endif

#endif

static uint32_t* co_create_( unsigned size, uintptr_t entry)
{
	uint32_t *t = (uint32_t*)malloc(size);

#if LIBCO_PPCDESC
   if (t)
   {
      /* Copy entry's descriptor */
      memcpy(t, (void*)entry, sizeof(void*) * 3);

      /* Set function pointer to swap routine */
#ifdef LIBCO_PPC_ASM
      *(const void**) t = *(void**) &amp;co_swap_asm;
#else
      *(const void**) t = libco_ppc_code;
#endif
   }
	#endif

	return t;
}

cothread_t co_create(unsigned int size, void (*entry_)(void))
{
	uintptr_t entry = (uintptr_t) entry_;
	uint32_t *t     = NULL;

	/* Be sure main thread was successfully allocated */
	if (co_active())
	{
		size += state_size + above_stack + stack_align;
		t     = co_create_(size, entry);
	}

	if (t)
   {
      uintptr_t sp;
#if LIBCO_PPC64
      int shift = 16;
#else
      int shift = 0;
#endif
      /* Save current registers into new thread, so that any special ones will
         have proper values when thread is begun */
      CO_SWAP_ASM(t, t);

#if LIBCO_PPCDESC
      /* Get real address */
      entry     = (uintptr_t) *(void**)entry;
#endif

      /* Put stack near end of block, and align */
      sp        = (uintptr_t) t + size - above_stack;
      sp       -= sp % stack_align;

      /* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
         save and restore them as 64 bits, regardless of the size the ABI
         uses. So, we manually write pointers at the proper size. We always
         save and restore at the same address, and since PPC is big-endian,
         we must put the low byte first on PPC32. */

      /* If uintptr_t is 32 bits, &gt;&gt;32 is undefined behavior, so we do two shifts
         and don't have to care how many bits uintptr_t is. */

      /* Set up so entry will be called on next swap */
      t [8]  = (uint32_t) (entry &gt;&gt; shift &gt;&gt; shift);
      t [9]  = (uint32_t) entry;

      t [10] = (uint32_t) (sp    &gt;&gt; shift &gt;&gt; shift);
      t [11] = (uint32_t) sp;
   }

	return t;
}

void co_delete(cothread_t t)
{
   free(t);
}

static void co_init_(void)
{
#if LIBCO_MPROTECT &amp;&amp; !LIBCO_STATIC_TEXT
   /* TODO: pre- and post-pad PPC code so that this doesn't make other
      data executable and writable */
   long page_size = sysconf(_SC_PAGESIZE);
   if (page_size &gt; 0)
   {
      uintptr_t align = page_size;
      uintptr_t begin = (uintptr_t) libco_ppc_code;
      uintptr_t end   = begin + sizeof libco_ppc_code;

      /* Align beginning and end */
      end            += align - 1;
      end            -= end   % align;
      begin          -= begin % align;

      mprotect((void*)begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC);
   }
#endif

   co_active_handle = co_create_(state_size, (uintptr_t) &amp;co_switch);
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_init_();

   return co_active_handle;
}

void co_switch(cothread_t t)
{
   cothread_t old   = co_active_handle;
   co_active_handle = t;
   CO_SWAP_ASM(t, old);
}</pre>
<h2>./include/libretro-common/libco/ps2.c</h2>
<pre>#define LIBCO_C
#include "libco.h"

#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;kernel.h&gt;

/* Since cothread_t is a void pointer it must contain an address. We can't return a reference to a local variable
 * because it would go out of scope, so we create a static variable instead so we can return a reference to it.
 */
static int32_t active_thread_id = -1;
extern void *_gp;

cothread_t co_active()
{
  active_thread_id = GetThreadId();
  return &amp;active_thread_id;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   /* Similar scenario as with active_thread_id except there will only be one active_thread_id while there could be many
    * new threads each with their own handle, so we create them on the heap instead and delete them manually when they're
    * no longer needed in co_delete().
    */
   ee_thread_t thread;
   int32_t new_thread_id;
   cothread_t handle       = malloc(sizeof(cothread_t));
   void *threadStack       = (void *)malloc(size);

   if (!threadStack)
      return -1;

   thread.stack_size		   = size;
   thread.gp_reg			   = &amp;_gp;
   thread.func				   = (void *)entrypoint;
   thread.stack			   = threadStack;
   thread.option			   = 0;
   thread.initial_priority = 1;

   new_thread_id           = CreateThread(&amp;thread);
   StartThread(new_thread_id, NULL);
   *(uint32_t *)handle     = new_thread_id;
   return handle;
}

void co_delete(cothread_t handle)
{
   TerminateThread(*(uint32_t *)handle);
   DeleteThread(*(uint32_t *)handle);
   free(handle);
}

void co_switch(cothread_t handle)
{
   WakeupThread(*(uint32_t *)handle);
   /* Sleep the currently active thread so the new thread can start */
   SleepThread();
}</pre>
<h2>./include/libretro-common/libco/ps3.S</h2>
<pre>.globl .co_swap_asm
.globl co_swap_asm
.type .co_swap_asm, @function
.type co_swap_asm, @function
.co_swap_asm:
co_swap_asm:
      mfcr    8
      std     1,40(4)
      mflr    9
      std     14,72(4)
      std     15,80(4)
      std     16,88(4)
      std     17,96(4)
      std     18,104(4)
      std     19,112(4)
      std     20,120(4)
      std     21,128(4)
      std     22,136(4)
      std     23,144(4)
      std     24,152(4)
      std     25,160(4)
      std     26,168(4)
      std     27,176(4)
      std     28,184(4)
      std     29,192(4)
      std     30,200(4)
      std     31,208(4)
      std     9,32(4)
      ld      7,32(3)
      ld      1,40(3)
      bl      swap
      trap
swap: stw     8,48(4)
      lwz     6,48(3)
      mtctr   7
      ld      14,72(3)
      ld      15,80(3)
      ld      16,88(3)
      ld      17,96(3)
      ld      18,104(3)
      ld      19,112(3)
      ld      20,120(3)
      ld      21,128(3)
      ld      22,136(3)
      ld      23,144(3)
      ld      24,152(3)
      ld      25,160(3)
      ld      26,168(3)
      ld      27,176(3)
      ld      28,184(3)
      ld      29,192(3)
      ld      30,200(3)
      ld      31,208(3)
      mtcr    6
      bctr</pre>
<h2>./include/libretro-common/libco/psp1.c</h2>
<pre>#define LIBCO_C
#include "libco.h"

#include &lt;stdlib.h&gt;
#include &lt;pspthreadman.h&gt;

typedef void (*entrypoint_t)(void);

cothread_t co_active(void)
{
  return (void *)sceKernelGetThreadId();
}

static int thread_wrap(unsigned int argc, void *argp)
{
  entrypoint_t entrypoint = *(entrypoint_t *) argp;
  sceKernelSleepThread();
  entrypoint();
  return 0;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
  SceUID new_thread_id = sceKernelCreateThread("cothread", thread_wrap, 0x12, size, 0, NULL);
  sceKernelStartThread(new_thread_id, sizeof (entrypoint), &amp;entrypoint);
  return (void *) new_thread_id;
}

void co_delete(cothread_t handle)
{
  SceUID id = (SceUID) handle;
  sceKernelTerminateDeleteThread(id);
}

void co_switch(cothread_t handle)
{
  SceUID id = (SceUID) handle;
  sceKernelWakeupThread(id);
  /* Sleep the currently active thread so the new thread can start */
  sceKernelSleepThread();
}</pre>
<h2>./include/libretro-common/libco/psp2.c</h2>
<pre>/*
libco.arm (2015-06-18)
license: public domain
*/

#define LIBCO_C
#include "libco.h"

#include &lt;assert.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;psp2/kernel/sysmem.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#define FOUR_KB_ALIGN(x) align(x, 12)
#define MB_ALIGN(x)      align(x, 20)

#ifdef __cplusplus
extern "C" {
#endif

   static inline int align(int x, int n)
   {
      return (((x &gt;&gt; n) + 1) &lt;&lt; n);
   }

   static thread_local unsigned long co_active_buffer[64];
   static thread_local cothread_t co_active_handle = 0;
   static void(*co_swap)(cothread_t, cothread_t) = 0;
   static int block;
   static uint32_t co_swap_function[] = {
      0xe8a16ff0,  /* stmia r1!, {r4-r11,sp,lr} */
      0xe8b0aff0,  /* ldmia r0!, {r4-r11,sp,pc} */
      0xe12fff1e,  /* bx lr                     */
   };

   static void co_init(void)
   {
      int ret;
      void *base;

      block = sceKernelAllocMemBlockForVM("libco",
            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
      if (block &lt; 0)
         return;

      /* Get base address */
      if ((ret = sceKernelGetMemBlockBase(block, &amp;base)) &lt; 0)
         return;

      /* Set domain to be writable by user */
      if ((ret = sceKernelOpenVMDomain()) &lt; 0)
         return;

      memcpy(base, co_swap_function, sizeof co_swap_function);

      /* Set domain back to read-only */
      if ((ret = sceKernelCloseVMDomain()) &lt; 0)
         return;

      /* Flush icache */
      ret = sceKernelSyncVMDomain(block, base,
            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
      if (ret &lt; 0)
         return;

      co_swap = (void(*)(cothread_t, cothread_t))base;
   }

   cothread_t co_active(void)
   {
      if (!co_active_handle)
         co_active_handle = &amp;co_active_buffer;
      return co_active_handle;
   }

   cothread_t co_create(unsigned int size, void(*entrypoint)(void))
   {
      unsigned long* handle = 0;
      if (!co_swap)
         co_init();
      if (!co_active_handle)
         co_active_handle   = &amp;co_active_buffer;
      size                 += 256;
      size                 &amp;= ~15;

      if ((handle = (unsigned long*)malloc(size)))
      {
         unsigned long *p   = (unsigned long*)((unsigned char*)handle + size);
         handle[8]          = (unsigned long)p;
         handle[9]          = (unsigned long)entrypoint;
      }

      return handle;
   }

   void co_delete(cothread_t handle)
   {
      free(handle);
      sceKernelFreeMemBlock(block);
   }

   void co_switch(cothread_t handle)
   {
      cothread_t co_previous_handle = co_active_handle;
      co_swap(co_active_handle = handle, co_previous_handle);
   }

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/scefiber.c</h2>
<pre>/*
  libco.win (2016-09-06)
  authors: frangarcj
  license: public domain
*/

#define LIBCO_C
#include &lt;libco.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;psp2/sysmodule.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

static thread_local cothread_t co_active_ = 0;

typedef struct SceFiber
{
	char reserved[128];
} SceFiber __attribute__( ( aligned ( 8 ) ) ) ;

/* Forward declarations */
int32_t _sceFiberInitializeImpl(SceFiber *fiber, char *name, void *entry, uint32_t argOnInitialize,
      void* addrContext, int32_t sizeContext, void* params);
int32_t sceFiberFinalize(SceFiber* fiber);
int32_t sceFiberRun(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
int32_t sceFiberSwitch(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
int32_t sceFiberReturnToThread(uint32_t argOnReturn, uint32_t* argOnRun);

static void co_thunk(uint32_t argOnInitialize, uint32_t argOnRun)
{
   ((void (*)(void))argOnInitialize)();
}

cothread_t co_active(void)
{
   if (!co_active_)
   {
      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
      co_active_ = (cothread_t)1;
   }
   return co_active_;
}

cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
{
   int ret;
   SceFiber* tail_fiber   = malloc(sizeof(SceFiber));
   char * m_ctxbuf        = malloc(sizeof(char)*heapsize);
   if (!co_active_)
   {
      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
      co_active_          = (cothread_t)1;
   }

   /* _sceFiberInitializeImpl */
   if ((ret = _sceFiberInitializeImpl(
               tail_fiber, "tailFiber", co_thunk,
               (uint32_t)coentry, (void*)m_ctxbuf, heapsize, NULL)) == 0)
      return (cothread_t)tail_fiber;
   return (cothread_t)ret;
}

void co_delete(cothread_t cothread)
{
   if (cothread != (cothread_t)1)
      sceFiberFinalize((SceFiber*)cothread);
}

void co_switch(cothread_t cothread)
{
   uint32_t argOnReturn  = 0;
   if (cothread == (cothread_t)1)
   {
      co_active_         = cothread;
      sceFiberReturnToThread(0, NULL);
   }
   else
   {
      SceFiber* theFiber = (SceFiber*)cothread;
      co_active_         = cothread;
      if (co_active_ == (cothread_t)1)
         sceFiberRun(theFiber, 0, &amp;argOnReturn);
      else
         sceFiberSwitch(theFiber, 0, &amp;argOnReturn);
   }
}

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/sjlj.c</h2>
<pre>/*
  libco.sjlj (2008-01-28)
  author: Nach
  license: public domain
*/

/*
 * Note this was designed for UNIX systems. Based on ideas expressed in a paper
 * by Ralf Engelschall.
 * For SJLJ on other systems, one would want to rewrite springboard() and
 * co_create() and hack the jmb_buf stack pointer.
 */

#define LIBCO_C
#include &lt;libco.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;signal.h&gt;
#include &lt;setjmp.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
   sigjmp_buf context;
   void (*coentry)(void);
   void *stack;
} cothread_struct;

static thread_local cothread_struct co_primary;
static thread_local cothread_struct *creating, *co_running = 0;

static void springboard(int ignored)
{
   if (sigsetjmp(creating-&gt;context, 0))
      co_running-&gt;coentry();
}

cothread_t co_active(void)
{
  if (!co_running)
     co_running = &amp;co_primary;
  return (cothread_t)co_running;
}

cothread_t co_create(unsigned int size, void (*coentry)(void))
{
   cothread_struct *thread;
   if (!co_running)
      co_running = &amp;co_primary;

   if ((thread = (cothread_struct*)malloc(sizeof(cothread_struct))))
   {
      stack_t stack;
      stack_t old_stack;

      thread-&gt;coentry = thread-&gt;stack = 0;

      stack.ss_flags  = 0;
      stack.ss_size   = size;
      thread-&gt;stack   = stack.ss_sp = malloc(size);

      if (stack.ss_sp &amp;&amp; !sigaltstack(&amp;stack, &amp;old_stack))
      {
         struct sigaction old_handler = {{0}};
         struct sigaction handler     = {{0}};
         handler.sa_handler           = springboard;
         handler.sa_flags             = SA_ONSTACK;
         sigemptyset(&amp;handler.sa_mask);
         creating                     = thread;

         if (!sigaction(SIGUSR1, &amp;handler, &amp;old_handler))
         {
            if (!raise(SIGUSR1))
               thread-&gt;coentry        = coentry;
            sigaltstack(&amp;old_stack, 0);
            sigaction(SIGUSR1, &amp;old_handler, 0);
         }
      }

      if (thread-&gt;coentry != coentry)
      {
         co_delete(thread);
         thread = 0;
      }
   }

   return (cothread_t)thread;
}

void co_delete(cothread_t cothread)
{
   if (cothread)
   {
      if (((cothread_struct*)cothread)-&gt;stack)
         free(((cothread_struct*)cothread)-&gt;stack);
      free(cothread);
   }
}

void co_switch(cothread_t cothread)
{
   if (!sigsetjmp(co_running-&gt;context, 0))
   {
      co_running = (cothread_struct*)cothread;
      siglongjmp(co_running-&gt;context, 1);
   }
}

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/ucontext.c</h2>
<pre>/*
  libco.ucontext (2008-01-28)
  author: Nach
  license: public domain
*/

/*
 * WARNING: the overhead of POSIX ucontext is very high,
 * assembly versions of libco or libco_sjlj should be much faster
 *
 * This library only exists for two reasons:
 * 1 - as an initial test for the viability of a ucontext implementation
 * 2 - to demonstrate the power and speed of libco over existing implementations,
 *     such as pth (which defaults to wrapping ucontext on unix targets)
 *
 * Use this library only as a *last resort*
 */

#define LIBCO_C
#include &lt;libco.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ucontext.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

static thread_local ucontext_t co_primary;
static thread_local ucontext_t *co_running = 0;

cothread_t co_active(void)
{
   if (!co_running)
      co_running = &amp;co_primary;
   return (cothread_t)co_running;
}

cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
{
   ucontext_t *thread;
   if (!co_running)
      co_running = &amp;co_primary;

   if ((thread = (ucontext_t*)malloc(sizeof(ucontext_t))))
   {
      if ((!getcontext(thread) &amp;&amp; !(thread-&gt;uc_stack.ss_sp = 0)) &amp;&amp; (thread-&gt;uc_stack.ss_sp = malloc(heapsize)))
      {
         thread-&gt;uc_link = co_running;
         thread-&gt;uc_stack.ss_size = heapsize;
         makecontext(thread, coentry, 0);
      }
      else
      {
         co_delete((cothread_t)thread);
         thread = 0;
      }
   }
   return (cothread_t)thread;
}

void co_delete(cothread_t cothread)
{
   if (!cothread)
      return;

   if (((ucontext_t*)cothread)-&gt;uc_stack.ss_sp)
      free(((ucontext_t*)cothread)-&gt;uc_stack.ss_sp);
   free(cothread);
}

void co_switch(cothread_t cothread)
{
   ucontext_t *old_thread = co_running;
   co_running             = (ucontext_t*)cothread;
   swapcontext(old_thread, co_running);
}

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libco/x86.c</h2>
<pre>/*
  libco.x86 (2009-10-12)
  author: byuu
  license: public domain
*/

#define LIBCO_C
#include &lt;libco.h&gt;
#include &lt;assert.h&gt;
#include &lt;stdlib.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

#if defined(_MSC_VER)
  #define fastcall __fastcall
#elif defined(__GNUC__)
  #define fastcall __attribute__((fastcall))
#else
  #error "libco: please define fastcall macro"
#endif

static thread_local long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;

/* ABI: fastcall */
static unsigned char co_swap_function[] = {
  0x89, 0x22,         /* mov [edx],esp      */
  0x8b, 0x21,         /* mov esp,[ecx]      */
  0x58,               /* pop eax            */
  0x89, 0x6a, 0x04,   /* mov [edx+0x04],ebp */
  0x89, 0x72, 0x08,   /* mov [edx+0x08],esi */
  0x89, 0x7a, 0x0c,   /* mov [edx+0x0c],edi */
  0x89, 0x5a, 0x10,   /* mov [edx+0x10],ebx */
  0x8b, 0x69, 0x04,   /* mov ebp,[ecx+0x04] */
  0x8b, 0x71, 0x08,   /* mov esi,[ecx+0x08] */
  0x8b, 0x79, 0x0c,   /* mov edi,[ecx+0x0c] */
  0x8b, 0x59, 0x10,   /* mov ebx,[ecx+0x10] */
  0xff, 0xe0,         /* jmp eax            */
};

#ifdef _WIN32
#include &lt;windows.h&gt;

static void co_init(void)
{
   DWORD old_privileges;
   VirtualProtect(co_swap_function,
         sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &amp;old_privileges);
}
#else
#include &lt;unistd.h&gt;
#include &lt;sys/mman.h&gt;

static void co_init(void)
{
   unsigned long addr = (unsigned long)co_swap_function;
   unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
   unsigned long size = (addr - base) + sizeof co_swap_function;
   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif

static void crash(void)
{
   assert(0); /* called only if cothread_t entrypoint returns */
}

cothread_t co_active(void)
{
   if (!co_active_handle)
      co_active_handle = &amp;co_active_buffer;
   return co_active_handle;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{
   cothread_t handle;
   if (!co_swap)
   {
      co_init();
      co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
   }

   if (!co_active_handle)
      co_active_handle = &amp;co_active_buffer;

   size += 256; /* allocate additional space for storage */
   size &amp;= ~15; /* align stack to 16-byte boundary */

   if ((handle = (cothread_t)malloc(size)))
   {
      long *p        = (long*)((char*)handle + size); /* seek to top of stack */
      *--p           = (long)crash;                   /* crash if entrypoint returns */
      *--p           = (long)entrypoint;              /* start of function */
      *(long*)handle = (long)p;                       /* stack pointer */
   }

   return handle;
}

void co_delete(cothread_t handle)
{
   free(handle);
}

void co_switch(cothread_t handle)
{
   register cothread_t co_previous_handle = co_active_handle;
   co_swap(co_active_handle = handle, co_previous_handle);
}

#ifdef __cplusplus
}
#endif</pre>
<h2>./include/libretro-common/libretro.h</h2>
<pre>/*!
 * libretro.h is a simple API that allows for the creation of games and emulators.
 *
 * @file libretro.h
 * @version 1
 * @author libretro
 * @copyright Copyright (C) 2010-2024 The RetroArch team
 *
 * @paragraph LICENSE
 * The following license statement only applies to this libretro API header (libretro.h).
 *
 * Copyright (C) 2010-2024 The RetroArch team
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef LIBRETRO_H__
#define LIBRETRO_H__

#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;limits.h&gt;

#ifdef __cplusplus
extern "C" {
#endif

#ifndef __cplusplus
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &lt; 1800 &amp;&amp; !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode
 * as it isn't C99-compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include &lt;stdbool.h&gt;
#endif
#endif

#ifndef RETRO_CALLCONV
#  if defined(__GNUC__) &amp;&amp; defined(__i386__) &amp;&amp; !defined(__x86_64__)
#    define RETRO_CALLCONV __attribute__((cdecl))
#  elif defined(_MSC_VER) &amp;&amp; defined(_M_X86) &amp;&amp; !defined(_M_X64)
#    define RETRO_CALLCONV __cdecl
#  else
#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */
#  endif
#endif

#ifndef RETRO_API
#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
#    ifdef RETRO_IMPORT_SYMBOLS
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)
#      endif
#    else
#      ifdef __GNUC__
#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))
#      else
#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)
#      endif
#    endif
#  else
#      if defined(__GNUC__) &amp;&amp; __GNUC__ &gt;= 4
#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
#      else
#        define RETRO_API RETRO_CALLCONV
#      endif
#  endif
#endif

/**
 * The major version of the libretro API and ABI.
 * Cores may support multiple versions,
 * or they may reject cores with unsupported versions.
 * It is only incremented for incompatible API/ABI changes;
 * this generally implies a function was removed or changed,
 * or that a \c struct had fields removed or changed.
 * @note A design goal of libretro is to avoid having to increase this value at all costs.
 * This is why there are APIs that are "extended" or "V2".
 */
#define RETRO_API_VERSION         1

/**
 * @defgroup RETRO_DEVICE Input Devices
 * @brief Libretro's fundamental device abstractions.
 *
 * Libretro's input system consists of abstractions over standard device types,
 * such as a joypad (with or without analog), mouse, keyboard, light gun, or an abstract pointer.
 * Instead of managing input devices themselves,
 * cores need only to map their own concept of a controller to libretro's abstractions.
 * This makes it possible for frontends to map the abstract types to a real input device
 * without having to worry about the correct use of arbitrary (real) controller layouts.
 * @{
 */

#define RETRO_DEVICE_TYPE_SHIFT         8
#define RETRO_DEVICE_MASK               ((1 &lt;&lt; RETRO_DEVICE_TYPE_SHIFT) - 1)

/**
 * Defines an ID for a subclass of a known device type.
 *
 * To define a subclass ID, use this macro like so:
 * @code{c}
 * #define RETRO_DEVICE_SUPER_SCOPE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)
 * #define RETRO_DEVICE_JUSTIFIER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)
 * @endcode
 *
 * Correct use of this macro allows a frontend to select a suitable physical device
 * to map to the emulated device.
 *
 * @note Cores must use the base ID when polling for input,
 * and frontends must only accept the base ID for this purpose.
 * Polling for input using subclass IDs is reserved for future definition.
 *
 * @param base One of the \ref RETRO_DEVICE "base device types".
 * @param id A unique ID, with respect to \c base.
 * Must be a non-negative integer.
 * @return A unique subclass ID.
 * @see retro_controller_description
 * @see retro_set_controller_port_device
 */
#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) &lt;&lt; RETRO_DEVICE_TYPE_SHIFT) | base)

/**
 * @defgroup RETRO_DEVICE Input Device Classes
 * @{
 */

/**
 * Indicates no input.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * all other arguments are ignored and zero is returned.
 *
 * @see retro_input_state_t
 */
#define RETRO_DEVICE_NONE         0

/**
 * An abstraction around a game controller, known as a "RetroPad".
 *
 * The RetroPad is modelled after a SNES controller,
 * but with additional L2/R2/L3/R3 buttons
 * (similar to a PlayStation controller).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button (including D-Pad directions) to query.
 * The result of said query will be 1 if the button is down, 0 if not.
 *
 * There is one exception; if \c RETRO_DEVICE_ID_JOYPAD_MASK is queried
 * (and the frontend supports this query),
 * the result will be a bitmask of all pressed buttons.
 *
 * @see retro_input_state_t
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_ID_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 */
#define RETRO_DEVICE_JOYPAD       1

/**
 * An abstraction around a mouse, similar to the SNES Mouse but with more buttons.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the button or axis to query.
 * For buttons, the result of said query
 * will be 1 if the button is down or 0 if not.
 * For mouse wheel axes, the result
 * will be 1 if the wheel was rotated in that direction and 0 if not.
 * For the mouse pointer axis, the result will be thee mouse's movement
 * relative to the last poll.
 * The core is responsible for tracking the mouse's position,
 * and the frontend is responsible for preventing interference
 * by the real hardware pointer (if applicable).
 *
 * @note This should only be used for cores that emulate mouse input,
 * such as for home computers
 * or consoles with mouse attachments.
 * Cores that emulate light guns should use \c RETRO_DEVICE_LIGHTGUN,
 * and cores that emulate touch screens should use \c RETRO_DEVICE_POINTER.
 *
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_DEVICE_LIGHTGUN
 */
#define RETRO_DEVICE_MOUSE        2

/**
 * An abstraction around a keyboard.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes the key to poll.
 *
 * @note This should only be used for cores that emulate keyboard input,
 * such as for home computers
 * or consoles with keyboard attachments.
 * Cores that emulate gamepads should use \c RETRO_DEVICE_JOYPAD or \c RETRO_DEVICE_ANALOG,
 * and leave keyboard compatibility to the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK
 * @see retro_key
 */
#define RETRO_DEVICE_KEYBOARD     3

/**
 * An abstraction around a light gun, similar to the PlayStation's Guncon.
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes one of several possible inputs.
 *
 * The gun's coordinates are reported in screen space (similar to the pointer)
 * in the range of [-0x8000, 0x7fff].
 * Zero is the center of the game's screen
 * and -0x8000 represents out-of-bounds.
 * The trigger and various auxiliary buttons are also reported.
 *
 * @note A forced off-screen shot can be requested for auto-reloading
 * function in some games.
 *
 * @see RETRO_DEVICE_POINTER
 */
#define RETRO_DEVICE_LIGHTGUN     4

/**
 * An extension of the RetroPad that supports analog input.
 *
 * The analog RetroPad provides two virtual analog sticks (similar to DualShock controllers)
 * and allows any button to be treated as analog (similar to Xbox shoulder triggers).
 *
 * When provided as the \c device argument to \c retro_input_state_t,
 * the \c id argument denotes an analog axis or an analog button.
 *
 * Analog axes are reported in the range of [-0x8000, 0x7fff],
 * with the X axis being positive towards the right
 * and the Y axis being positive towards the bottom.
 *
 * Analog buttons are reported in the range of [0, 0x7fff],
 * where 0 is unpressed and 0x7fff is fully pressed.
 *
 * @note Cores should only use this type if they need analog input.
 * Otherwise, \c RETRO_DEVICE_JOYPAD should be used.
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ANALOG       5

/**
 * Input Device: Pointer.
 *
 * Abstracts the concept of a pointing mechanism, e.g. touch.
 * This allows libretro to query in absolute coordinates where on the
 * screen a mouse (or something similar) is being placed.
 * For a touch centric device, coordinates reported are the coordinates
 * of the press.
 *
 * Coordinates in X and Y are reported as:
 * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
 * and 0x7fff corresponds to the far right/bottom of the screen.
 * The "screen" is here defined as area that is passed to the frontend and
 * later displayed on the monitor. If the pointer is outside this screen,
 * such as in the black surrounding areas when actual display is larger,
 * edge position is reported. An explicit edge detection is also provided,
 * that will return 1 if the pointer is near the screen edge or actually outside it.
 *
 * The frontend is free to scale/resize this screen as it sees fit, however,
 * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
 * game image, etc.
 *
 * To check if the pointer coordinates are valid (e.g. a touch display
 * actually being touched), \c RETRO_DEVICE_ID_POINTER_PRESSED returns 1 or 0.
 *
 * If using a mouse on a desktop, \c RETRO_DEVICE_ID_POINTER_PRESSED will
 * usually correspond to the left mouse button, but this is a frontend decision.
 * \c RETRO_DEVICE_ID_POINTER_PRESSED will only return 1 if the pointer is
 * inside the game screen.
 *
 * For multi-touch, the index variable can be used to successively query
 * more presses.
 * If index = 0 returns true for \c _PRESSED, coordinates can be extracted
 * with \c _X, \c _Y for index = 0. One can then query \c _PRESSED, \c _X, \c _Y with
 * index = 1, and so on.
 * Eventually \c _PRESSED will return false for an index. No further presses
 * are registered at this point.
 *
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_ID_POINTER_X
 * @see RETRO_DEVICE_ID_POINTER_Y
 * @see RETRO_DEVICE_ID_POINTER_PRESSED
 */
#define RETRO_DEVICE_POINTER      6

/** @} */

/** @defgroup RETRO_DEVICE_ID_JOYPAD RetroPad Input
 * @brief Digital buttons for the RetroPad.
 *
 * Button placement is comparable to that of a SNES controller,
 * combined with the shoulder buttons of a PlayStation controller.
 * These values can also be used for the \c id field of \c RETRO_DEVICE_INDEX_ANALOG_BUTTON
 * to represent analog buttons (usually shoulder triggers).
 * @{
 */

/** The equivalent of the SNES controller's south face button. */
#define RETRO_DEVICE_ID_JOYPAD_B        0

/** The equivalent of the SNES controller's west face button. */
#define RETRO_DEVICE_ID_JOYPAD_Y        1

/** The equivalent of the SNES controller's left-center button. */
#define RETRO_DEVICE_ID_JOYPAD_SELECT   2

/** The equivalent of the SNES controller's right-center button. */
#define RETRO_DEVICE_ID_JOYPAD_START    3

/** Up on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_UP       4

/** Down on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_DOWN     5

/** Left on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_LEFT     6

/** Right on the RetroPad's D-pad. */
#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7

/** The equivalent of the SNES controller's east face button. */
#define RETRO_DEVICE_ID_JOYPAD_A        8

/** The equivalent of the SNES controller's north face button. */
#define RETRO_DEVICE_ID_JOYPAD_X        9

/** The equivalent of the SNES controller's left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L       10

/** The equivalent of the SNES controller's right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R       11

/** The equivalent of the PlayStation's rear left shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_L2      12

/** The equivalent of the PlayStation's rear right shoulder button. */
#define RETRO_DEVICE_ID_JOYPAD_R2      13

/**
 * The equivalent of the PlayStation's left analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_L3      14

/**
 * The equivalent of the PlayStation's right analog stick button,
 * although the actual button need not be in this position.
 */
#define RETRO_DEVICE_ID_JOYPAD_R3      15

/**
 * Represents a bitmask that describes the state of all \c RETRO_DEVICE_ID_JOYPAD button constants,
 * rather than the state of a single button.
 *
 * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS
 * @see RETRO_DEVICE_JOYPAD
 */
#define RETRO_DEVICE_ID_JOYPAD_MASK    256

/** @} */

/** @defgroup RETRO_DEVICE_ID_ANALOG Analog RetroPad Input
 * @{
 */

/* Index / Id values for ANALOG device. */
#define RETRO_DEVICE_INDEX_ANALOG_LEFT       0
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT      1
#define RETRO_DEVICE_INDEX_ANALOG_BUTTON     2
#define RETRO_DEVICE_ID_ANALOG_X             0
#define RETRO_DEVICE_ID_ANALOG_Y             1

/** @} */

/* Id values for MOUSE. */
#define RETRO_DEVICE_ID_MOUSE_X                0
#define RETRO_DEVICE_ID_MOUSE_Y                1
#define RETRO_DEVICE_ID_MOUSE_LEFT             2
#define RETRO_DEVICE_ID_MOUSE_RIGHT            3
#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4
#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5
#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7
#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8
#define RETRO_DEVICE_ID_MOUSE_BUTTON_4         9
#define RETRO_DEVICE_ID_MOUSE_BUTTON_5         10

/* Id values for LIGHTGUN. */
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X        13 /*Absolute Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y        14 /*Absolute Position*/
/** Indicates if lightgun points off the screen or near the edge */
#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN    15 /*Status Check*/
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER          2
#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD          16 /*Forced off-screen shot*/
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A            3
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B            4
#define RETRO_DEVICE_ID_LIGHTGUN_START            6
#define RETRO_DEVICE_ID_LIGHTGUN_SELECT           7
#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C            8
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP          9
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN       10
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT       11
#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT      12
/* deprecated */
#define RETRO_DEVICE_ID_LIGHTGUN_X                0 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_Y                1 /*Relative Position*/
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR           3 /*Use Aux:A instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO            4 /*Use Aux:B instead*/
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE            5 /*Use Start instead*/

/* Id values for POINTER. */
#define RETRO_DEVICE_ID_POINTER_X             0
#define RETRO_DEVICE_ID_POINTER_Y             1
#define RETRO_DEVICE_ID_POINTER_PRESSED       2
#define RETRO_DEVICE_ID_POINTER_COUNT         3
/** Indicates if pointer is off the screen or near the edge */
#define RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN 15
/** @} */

/* Returned from retro_get_region(). */
#define RETRO_REGION_NTSC  0
#define RETRO_REGION_PAL   1

/**
 * Identifiers for supported languages.
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 */
enum retro_language
{
   RETRO_LANGUAGE_ENGLISH             = 0,
   RETRO_LANGUAGE_JAPANESE            = 1,
   RETRO_LANGUAGE_FRENCH              = 2,
   RETRO_LANGUAGE_SPANISH             = 3,
   RETRO_LANGUAGE_GERMAN              = 4,
   RETRO_LANGUAGE_ITALIAN             = 5,
   RETRO_LANGUAGE_DUTCH               = 6,
   RETRO_LANGUAGE_PORTUGUESE_BRAZIL   = 7,
   RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,
   RETRO_LANGUAGE_RUSSIAN             = 9,
   RETRO_LANGUAGE_KOREAN              = 10,
   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,
   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 12,
   RETRO_LANGUAGE_ESPERANTO           = 13,
   RETRO_LANGUAGE_POLISH              = 14,
   RETRO_LANGUAGE_VIETNAMESE          = 15,
   RETRO_LANGUAGE_ARABIC              = 16,
   RETRO_LANGUAGE_GREEK               = 17,
   RETRO_LANGUAGE_TURKISH             = 18,
   RETRO_LANGUAGE_SLOVAK              = 19,
   RETRO_LANGUAGE_PERSIAN             = 20,
   RETRO_LANGUAGE_HEBREW              = 21,
   RETRO_LANGUAGE_ASTURIAN            = 22,
   RETRO_LANGUAGE_FINNISH             = 23,
   RETRO_LANGUAGE_INDONESIAN          = 24,
   RETRO_LANGUAGE_SWEDISH             = 25,
   RETRO_LANGUAGE_UKRAINIAN           = 26,
   RETRO_LANGUAGE_CZECH               = 27,
   RETRO_LANGUAGE_CATALAN_VALENCIA    = 28,
   RETRO_LANGUAGE_CATALAN             = 29,
   RETRO_LANGUAGE_BRITISH_ENGLISH     = 30,
   RETRO_LANGUAGE_HUNGARIAN           = 31,
   RETRO_LANGUAGE_BELARUSIAN          = 32,
   RETRO_LANGUAGE_GALICIAN            = 33,
   RETRO_LANGUAGE_NORWEGIAN           = 34,
   RETRO_LANGUAGE_IRISH               = 35,
   RETRO_LANGUAGE_LAST,

   /** Defined to ensure that &lt;tt&gt;sizeof(retro_language) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_LANGUAGE_DUMMY          = INT_MAX
};

/** @defgroup RETRO_MEMORY Memory Types
 * @{
 */

/* Passed to retro_get_memory_data/size().
 * If the memory type doesn't apply to the
 * implementation NULL/0 can be returned.
 */
#define RETRO_MEMORY_MASK        0xff

/* Regular save RAM. This RAM is usually found on a game cartridge,
 * backed up by a battery.
 * If save game data is too complex for a single memory buffer,
 * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
 * callback can be used. */
#define RETRO_MEMORY_SAVE_RAM    0

/* Some games have a built-in clock to keep track of time.
 * This memory is usually just a couple of bytes to keep track of time.
 */
#define RETRO_MEMORY_RTC         1

/* System ram lets a frontend peek into a game systems main RAM. */
#define RETRO_MEMORY_SYSTEM_RAM  2

/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
#define RETRO_MEMORY_VIDEO_RAM   3

/** @} */

/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
enum retro_key
{
   RETROK_UNKNOWN        = 0,
   RETROK_FIRST          = 0,
   RETROK_BACKSPACE      = 8,
   RETROK_TAB            = 9,
   RETROK_CLEAR          = 12,
   RETROK_RETURN         = 13,
   RETROK_PAUSE          = 19,
   RETROK_ESCAPE         = 27,
   RETROK_SPACE          = 32,
   RETROK_EXCLAIM        = 33,
   RETROK_QUOTEDBL       = 34,
   RETROK_HASH           = 35,
   RETROK_DOLLAR         = 36,
   RETROK_AMPERSAND      = 38,
   RETROK_QUOTE          = 39,
   RETROK_LEFTPAREN      = 40,
   RETROK_RIGHTPAREN     = 41,
   RETROK_ASTERISK       = 42,
   RETROK_PLUS           = 43,
   RETROK_COMMA          = 44,
   RETROK_MINUS          = 45,
   RETROK_PERIOD         = 46,
   RETROK_SLASH          = 47,
   RETROK_0              = 48,
   RETROK_1              = 49,
   RETROK_2              = 50,
   RETROK_3              = 51,
   RETROK_4              = 52,
   RETROK_5              = 53,
   RETROK_6              = 54,
   RETROK_7              = 55,
   RETROK_8              = 56,
   RETROK_9              = 57,
   RETROK_COLON          = 58,
   RETROK_SEMICOLON      = 59,
   RETROK_LESS           = 60,
   RETROK_EQUALS         = 61,
   RETROK_GREATER        = 62,
   RETROK_QUESTION       = 63,
   RETROK_AT             = 64,
   RETROK_LEFTBRACKET    = 91,
   RETROK_BACKSLASH      = 92,
   RETROK_RIGHTBRACKET   = 93,
   RETROK_CARET          = 94,
   RETROK_UNDERSCORE     = 95,
   RETROK_BACKQUOTE      = 96,
   RETROK_a              = 97,
   RETROK_b              = 98,
   RETROK_c              = 99,
   RETROK_d              = 100,
   RETROK_e              = 101,
   RETROK_f              = 102,
   RETROK_g              = 103,
   RETROK_h              = 104,
   RETROK_i              = 105,
   RETROK_j              = 106,
   RETROK_k              = 107,
   RETROK_l              = 108,
   RETROK_m              = 109,
   RETROK_n              = 110,
   RETROK_o              = 111,
   RETROK_p              = 112,
   RETROK_q              = 113,
   RETROK_r              = 114,
   RETROK_s              = 115,
   RETROK_t              = 116,
   RETROK_u              = 117,
   RETROK_v              = 118,
   RETROK_w              = 119,
   RETROK_x              = 120,
   RETROK_y              = 121,
   RETROK_z              = 122,
   RETROK_LEFTBRACE      = 123,
   RETROK_BAR            = 124,
   RETROK_RIGHTBRACE     = 125,
   RETROK_TILDE          = 126,
   RETROK_DELETE         = 127,

   RETROK_KP0            = 256,
   RETROK_KP1            = 257,
   RETROK_KP2            = 258,
   RETROK_KP3            = 259,
   RETROK_KP4            = 260,
   RETROK_KP5            = 261,
   RETROK_KP6            = 262,
   RETROK_KP7            = 263,
   RETROK_KP8            = 264,
   RETROK_KP9            = 265,
   RETROK_KP_PERIOD      = 266,
   RETROK_KP_DIVIDE      = 267,
   RETROK_KP_MULTIPLY    = 268,
   RETROK_KP_MINUS       = 269,
   RETROK_KP_PLUS        = 270,
   RETROK_KP_ENTER       = 271,
   RETROK_KP_EQUALS      = 272,

   RETROK_UP             = 273,
   RETROK_DOWN           = 274,
   RETROK_RIGHT          = 275,
   RETROK_LEFT           = 276,
   RETROK_INSERT         = 277,
   RETROK_HOME           = 278,
   RETROK_END            = 279,
   RETROK_PAGEUP         = 280,
   RETROK_PAGEDOWN       = 281,

   RETROK_F1             = 282,
   RETROK_F2             = 283,
   RETROK_F3             = 284,
   RETROK_F4             = 285,
   RETROK_F5             = 286,
   RETROK_F6             = 287,
   RETROK_F7             = 288,
   RETROK_F8             = 289,
   RETROK_F9             = 290,
   RETROK_F10            = 291,
   RETROK_F11            = 292,
   RETROK_F12            = 293,
   RETROK_F13            = 294,
   RETROK_F14            = 295,
   RETROK_F15            = 296,

   RETROK_NUMLOCK        = 300,
   RETROK_CAPSLOCK       = 301,
   RETROK_SCROLLOCK      = 302,
   RETROK_RSHIFT         = 303,
   RETROK_LSHIFT         = 304,
   RETROK_RCTRL          = 305,
   RETROK_LCTRL          = 306,
   RETROK_RALT           = 307,
   RETROK_LALT           = 308,
   RETROK_RMETA          = 309,
   RETROK_LMETA          = 310,
   RETROK_LSUPER         = 311,
   RETROK_RSUPER         = 312,
   RETROK_MODE           = 313,
   RETROK_COMPOSE        = 314,

   RETROK_HELP           = 315,
   RETROK_PRINT          = 316,
   RETROK_SYSREQ         = 317,
   RETROK_BREAK          = 318,
   RETROK_MENU           = 319,
   RETROK_POWER          = 320,
   RETROK_EURO           = 321,
   RETROK_UNDO           = 322,
   RETROK_OEM_102        = 323,

   RETROK_BROWSER_BACK      = 324,
   RETROK_BROWSER_FORWARD   = 325,
   RETROK_BROWSER_REFRESH   = 326,
   RETROK_BROWSER_STOP      = 327,
   RETROK_BROWSER_SEARCH    = 328,
   RETROK_BROWSER_FAVORITES = 329,
   RETROK_BROWSER_HOME      = 330,
   RETROK_VOLUME_MUTE       = 331,
   RETROK_VOLUME_DOWN       = 332,
   RETROK_VOLUME_UP         = 333,
   RETROK_MEDIA_NEXT        = 334,
   RETROK_MEDIA_PREV        = 335,
   RETROK_MEDIA_STOP        = 336,
   RETROK_MEDIA_PLAY_PAUSE  = 337,
   RETROK_LAUNCH_MAIL       = 338,
   RETROK_LAUNCH_MEDIA      = 339,
   RETROK_LAUNCH_APP1       = 340,
   RETROK_LAUNCH_APP2       = 341,

   RETROK_LAST,

   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

enum retro_mod
{
   RETROKMOD_NONE       = 0x0000,

   RETROKMOD_SHIFT      = 0x01,
   RETROKMOD_CTRL       = 0x02,
   RETROKMOD_ALT        = 0x04,
   RETROKMOD_META       = 0x08,

   RETROKMOD_NUMLOCK    = 0x10,
   RETROKMOD_CAPSLOCK   = 0x20,
   RETROKMOD_SCROLLOCK  = 0x40,

   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};

/**
 * @defgroup RETRO_ENVIRONMENT Environment Callbacks
 * @{
 */

/**
 * This bit indicates that the associated environment call is experimental,
 * and may be changed or removed in the future.
 * Frontends should mask out this bit before handling the environment call.
 */
#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000

/** Frontend-internal environment callbacks should include this bit. */
#define RETRO_ENVIRONMENT_PRIVATE 0x20000

/* Environment commands. */
/**
 * Requests the frontend to set the screen rotation.
 *
 * @param[in] data &lt;tt&gt;const unsigned*&lt;/tt&gt;.
 * Valid values are 0, 1, 2, and 3.
 * These numbers respectively set the screen rotation to 0, 90, 180, and 270 degrees counter-clockwise.
 * @returns \c true if the screen rotation was set successfully.
 */
#define RETRO_ENVIRONMENT_SET_ROTATION  1

/**
 * Queries whether the core should use overscan or not.
 *
 * @param[out] data &lt;tt&gt;bool*&lt;/tt&gt;.
 * Set to \c true if the core should use overscan,
 * \c false if it should be cropped away.
 * @returns \c true if the environment call is available.
 * Does \em not indicate whether overscan should be used.
 * @deprecated As of 2019 this callback is considered deprecated in favor of
 * using core options to manage overscan in a more nuanced, core-specific way.
 */
#define RETRO_ENVIRONMENT_GET_OVERSCAN  2

/**
 * Queries whether the frontend supports frame duping,
 * in the form of passing \c NULL to the video frame callback.
 *
 * @param[out] data &lt;tt&gt;bool*&lt;/tt&gt;.
 * Set to \c true if the frontend supports frame duping.
 * @returns \c true if the environment call is available.
 * @see retro_video_refresh_t
 */
#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3

/*
 * Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
 * and reserved to avoid possible ABI clash.
 */

/**
 * @brief Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * \code{.c}
 * void set_message_example(void)
 * {
 *    struct retro_message msg;
 *    msg.frames = 60 * 5; // 5 seconds
 *    msg.msg = "Hello world!";
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &amp;msg);
 * }
 * \endcode
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT for new code,
 * as it offers more features.
 * Only use this environment call for compatibility with older cores or frontends.
 *
 * @param[in] data &lt;tt&gt;const struct retro_message*&lt;/tt&gt;.
 * Details about the message to show to the user.
 * Behavior is undefined if &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see retro_message
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 * @note The frontend must make its own copy of the message and the underlying string.
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE   6

/**
 * Requests the frontend to shutdown the core.
 * Should only be used if the core can exit on its own,
 * such as from a menu item in a game
 * or an emulated power-off in an emulator.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_SHUTDOWN      7

/**
 * Gives a hint to the frontend of how demanding this core is on the system.
 * For example, reporting a level of 2 means that
 * this implementation should run decently on frontends
 * of level 2 and above.
 *
 * It can be used by the frontend to potentially warn
 * about too demanding implementations.
 *
 * The levels are "floating".
 *
 * This function can be called on a per-game basis,
 * as a core may have different demands for different games or settings.
 * If called, it should be called in &lt;tt&gt;retro_load_game()&lt;/tt&gt;.
 * @param[in] data &lt;tt&gt;const unsigned*&lt;/tt&gt;.
*/
#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8

/**
 * Returns the path to the frontend's system directory,
 * which can be used to store system-specific configuration
 * such as BIOS files or cached data.
 *
 * @param[out] data &lt;tt&gt;const char**&lt;/tt&gt;.
 * Pointer to the \c char* in which the system directory will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no system directory is defined,
 * in which case the core should find an alternative directory.
 * @return \c true if the environment call is available,
 * even if the value returned in \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @note Historically, some cores would use this folder for save data such as memory cards or SRAM.
 * This is now discouraged in favor of \c RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY.
 * @see RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9

/**
 * Sets the internal pixel format used by the frontend for rendering.
 * The default pixel format is \c RETRO_PIXEL_FORMAT_0RGB1555 for compatibility reasons,
 * although it's considered deprecated and shouldn't be used by new code.
 *
 * @param[in] data &lt;tt&gt;const enum retro_pixel_format *&lt;/tt&gt;.
 * Pointer to the pixel format to use.
 * @returns \c true if the pixel format was set successfully,
 * \c false if it's not supported or this callback is unavailable.
 * @note This function should be called inside \c retro_load_game()
 * or &lt;tt&gt;retro_get_system_av_info()&lt;/tt&gt;.
 * @see retro_pixel_format
 */
#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10

/**
 * Sets an array of input descriptors for the frontend
 * to present to the user for configuring the core's controls.
 *
 * This function can be called at any time,
 * preferably early in the core's life cycle.
 * Ideally, no later than \c retro_load_game().
 *
 * @param[in] data &lt;tt&gt;const struct retro_input_descriptor *&lt;/tt&gt;.
 * An array of input descriptors terminated by one whose
 * \c retro_input_descriptor::description field is set to \c NULL.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is recognized.
 * @see retro_input_descriptor
 */
#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11

/**
 * Sets a callback function used to notify the core about keyboard events.
 * This should only be used for cores that specifically need keyboard input,
 * such as for home computer emulators or games with text entry.
 *
 * @param[in] data &lt;tt&gt;const struct retro_keyboard_callback *&lt;/tt&gt;.
 * Pointer to the callback function.
 * Behavior is undefined if &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if the environment call is recognized.
 * @see retro_keyboard_callback
 * @see retro_key
 */
#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12

/**
 * Sets an interface that the frontend can use to insert and remove disks
 * from the emulated console's disk drive.
 * Can be used for optical disks, floppy disks, or any other game storage medium
 * that can be swapped at runtime.
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * over this environment call, as it supports additional features.
 * Only use this callback to maintain compatibility
 * with older cores or frontends.
 *
 * @param[in] data &lt;tt&gt;const struct retro_disk_control_callback *&lt;/tt&gt;.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_callback
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13

/**
 * Requests that a frontend enable a particular hardware rendering API.
 *
 * If successful, the frontend will create a context (and other related resources)
 * that the core can use for rendering.
 * The framebuffer will be at least as large as
 * the maximum dimensions provided in &lt;tt&gt;retro_get_system_av_info&lt;/tt&gt;.
 *
 * @param[in, out] data &lt;tt&gt;struct retro_hw_render_callback *&lt;/tt&gt;.
 * Pointer to the hardware render callback struct.
 * Used to define callbacks for the hardware-rendering life cycle,
 * as well as to request a particular rendering API.
 * @return \c true if the environment call is recognized
 * and the requested rendering API is supported.
 * \c false if \c data is \c NULL
 * or the frontend can't provide the requested rendering API.
 * @see retro_hw_render_callback
 * @see retro_video_refresh_t
 * @see RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER
 * @note Should be called in &lt;tt&gt;retro_load_game()&lt;/tt&gt;.
 * @note If HW rendering is used, pass only \c RETRO_HW_FRAME_BUFFER_VALID or
 * \c NULL to &lt;tt&gt;retro_video_refresh_t&lt;/tt&gt;.
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER 14

/**
 * Retrieves a core option's value from the frontend.
 * \c retro_variable::key should be set to an option key
 * that was previously set in \c RETRO_ENVIRONMENT_SET_VARIABLES
 * (or a similar environment call).
 *
 * @param[in,out] data &lt;tt&gt;struct retro_variable *&lt;/tt&gt;.
 * Pointer to a single \c retro_variable struct.
 * See the documentation for \c retro_variable for details
 * on which fields are set by the frontend or core.
 * May be \c NULL.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL or the key it specifies is not found.
 * @note Passing \c NULL in to \c data can be useful to
 * test for support of this environment call without looking up any variables.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE 15

/**
 * Notifies the frontend of the core's available options.
 *
 * The core may check these options later using \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * The frontend may also present these options to the user
 * in its own configuration UI.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment.
 * The core may later call this function again
 * to communicate updated options to the frontend,
 * but the number of core options must not change.
 *
 * Here's an example that sets two options.
 *
 * @code
 * void set_variables_example(void)
 * {
 *    struct retro_variable options[] = {
 *        { "foo_speedhack", "Speed hack; false|true" }, // false by default
 *        { "foo_displayscale", "Display scale factor; 1|2|3|4" }, // 1 by default
 *        { NULL, NULL },
 *    };
 *
 *    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, &amp;options);
 * }
 * @endcode
 *
 * The possible values will generally be displayed and stored as-is by the frontend.
 *
 * @deprecated Prefer using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 for new code,
 * as it offers more features such as categories and translation.
 * Only use this environment call to maintain compatibility
 * with older frontends or cores.
 * @note Keep the available options (and their possible values) as low as possible;
 * it should be feasible to cycle through them without a keyboard.
 * @param[in] data &lt;tt&gt;const struct retro_variable *&lt;/tt&gt;.
 * Pointer to an array of \c retro_variable structs that define available core options,
 * terminated by a &lt;tt&gt;{ NULL, NULL }&lt;/tt&gt; element.
 * The frontend must maintain its own copy of this array.
 *
 * @returns \c true if the environment call is available,
 * even if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @see retro_variable
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_VARIABLES 16

/**
 * Queries whether at least one core option was updated by the frontend
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * This typically means that the user opened the core options menu and made some changes.
 *
 * Cores usually call this each frame before the core's main emulation logic.
 * Specific options can then be queried with \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 *
 * @param[out] data &lt;tt&gt;bool *&lt;/tt&gt;.
 * Set to \c true if at least one core option was updated
 * since the last call to \ref RETRO_ENVIRONMENT_GET_VARIABLE.
 * Behavior is undefined if this pointer is \c NULL.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17

/**
 * Notifies the frontend that this core can run without loading any content,
 * such as when emulating a console that has built-in software.
 * When a core is loaded without content,
 * \c retro_load_game receives an argument of &lt;tt&gt;NULL&lt;/tt&gt;.
 * This should be called within \c retro_set_environment() only.
 *
 * @param[in] data &lt;tt&gt;const bool *&lt;/tt&gt;.
 * Pointer to a single \c bool that indicates whether this frontend can run without content.
 * Can point to a value of \c false but this isn't necessary,
 * as contentless support is opt-in.
 * The behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see retro_load_game
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18

/**
 * Retrieves the absolute path from which this core was loaded.
 * Useful when loading assets from paths relative to the core,
 * as is sometimes the case when using &lt;tt&gt;RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME&lt;/tt&gt;.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to a string in which the core's path will be saved.
 * The string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if the core is statically linked to the frontend
 * or if the core's path otherwise cannot be determined.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19

/* Environment call 20 was an obsolete version of SET_AUDIO_CALLBACK.
 * It was not used by any known core at the time, and was removed from the API.
 * The number 20 is reserved to prevent ABI clashes.
 */

/**
 * Sets a callback that notifies the core of how much time has passed
 * since the last iteration of &lt;tt&gt;retro_run&lt;/tt&gt;.
 * If the frontend is not running the core in real time
 * (e.g. it's frame-stepping or running in slow motion),
 * then the reference value will be provided to the callback instead.
 *
 * @param[in] data &lt;tt&gt;const struct retro_frame_time_callback *&lt;/tt&gt;.
 * Pointer to a single \c retro_frame_time_callback struct.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @note Frontends may disable this environment call in certain situations.
 * It will return \c false in those cases.
 * @see retro_frame_time_callback
 */
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21

/**
 * Registers a set of functions that the frontend can use
 * to tell the core it's ready for audio output.
 *
 * It is intended for games that feature asynchronous audio.
 * It should not be used for emulators unless their audio is asynchronous.
 *
 *
 * The callback only notifies about writability; the libretro core still
 * has to call the normal audio callbacks
 * to write audio. The audio callbacks must be called from within the
 * notification callback.
 * The amount of audio data to write is up to the core.
 * Generally, the audio callback will be called continuously in a loop.
 *
 * A frontend may disable this callback in certain situations.
 * The core must be able to render audio with the "normal" interface.
 *
 * @param[in] data &lt;tt&gt;const struct retro_audio_callback *&lt;/tt&gt;.
 * Pointer to a set of functions that the frontend will call to notify the core
 * when it's ready to receive audio data.
 * May be \c NULL, in which case the frontend will return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @warning The provided callbacks can be invoked from any thread,
 * so their implementations \em must be thread-safe.
 * @note If a core uses this callback,
 * it should also use &lt;tt&gt;RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK&lt;/tt&gt;.
 * @see retro_audio_callback
 * @see retro_audio_sample_t
 * @see retro_audio_sample_batch_t
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22

/**
 * Gets an interface that a core can use to access a controller's rumble motors.
 *
 * The interface supports two independently-controlled motors,
 * one strong and one weak.
 *
 * Should be called from either \c retro_init() or \c retro_load_game(),
 * but not from \c retro_set_environment().
 *
 * @param[out] data &lt;tt&gt;struct retro_rumble_interface *&lt;/tt&gt;.
 * Pointer to the interface struct.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the current device doesn't support vibration.
 * @see retro_rumble_interface
 * @defgroup GET_RUMBLE_INTERFACE Rumble Interface
 */
#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23

/**
 * Returns the frontend's supported input device types.
 *
 * The supported device types are returned as a bitmask,
 * with each value of \ref RETRO_DEVICE corresponding to a bit.
 *
 * Should only be called in \c retro_run().
 *
 * @code
 * #define REQUIRED_DEVICES ((1 &lt;&lt; RETRO_DEVICE_JOYPAD) | (1 &lt;&lt; RETRO_DEVICE_ANALOG))
 * void get_input_device_capabilities_example(void)
 * {
 *    uint64_t capabilities;
 *    environ_cb(RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES, &amp;capabilities);
 *    if ((capabilities &amp; REQUIRED_DEVICES) == REQUIRED_DEVICES)
 *      printf("Joypad and analog device types are supported");
 * }
 * @endcode
 *
 * @param[out] data &lt;tt&gt;uint64_t *&lt;/tt&gt;.
 * Pointer to a bitmask of supported input device types.
 * If the frontend supports a particular \c RETRO_DEVICE_* type,
 * then the bit &lt;tt&gt;(1 &lt;&lt; RETRO_DEVICE_*)&lt;/tt&gt; will be set.
 *
 * Each bit represents a \c RETRO_DEVICE constant,
 * e.g. bit 1 represents \c RETRO_DEVICE_JOYPAD,
 * bit 2 represents \c RETRO_DEVICE_MOUSE, and so on.
 *
 * Bits that do not correspond to known device types will be set to zero
 * and are reserved for future use.
 *
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note If the frontend supports multiple input drivers,
 * availability of this environment call (and the reported capabilities)
 * may depend on the active driver.
 * @see RETRO_DEVICE
 */
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24

/**
 * Returns an interface that the core can use to access and configure available sensors,
 * such as an accelerometer or gyroscope.
 *
 * @param[out] data &lt;tt&gt;struct retro_sensor_interface *&lt;/tt&gt;.
 * Pointer to the sensor interface that the frontend will populate.
 * Behavior is undefined if is \c NULL.
 * @returns \c true if the environment call is available,
 * even if the device doesn't have any supported sensors.
 * @see retro_sensor_interface
 * @see retro_sensor_action
 * @see RETRO_SENSOR
 * @addtogroup RETRO_SENSOR
 */
#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface to the device's video camera.
 *
 * The frontend delivers new video frames via a user-defined callback
 * that runs in the same thread as \c retro_run().
 * Should be called in \c retro_load_game().
 *
 * @param[in,out] data &lt;tt&gt;struct retro_camera_callback *&lt;/tt&gt;.
 * Pointer to the camera driver interface.
 * Some fields in the struct must be filled in by the core,
 * others are provided by the frontend.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available,
 * even if an actual camera isn't.
 * @note This API only supports one video camera at a time.
 * If the device provides multiple cameras (e.g. inner/outer cameras on a phone),
 * the frontend will choose one to use.
 * @see retro_camera_callback
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for cross-platform logging.
 * Certain platforms don't have a console or &lt;tt&gt;stderr&lt;/tt&gt;,
 * or they have their own preferred logging methods.
 * The frontend itself may also display log output.
 *
 * @attention This should not be used for information that the player must immediately see,
 * such as major errors or warnings.
 * In most cases, this is best for information that will help you (the developer)
 * identify problems when debugging or providing support.
 * Unless a core or frontend is intended for advanced users,
 * the player might not check (or even know about) their logs.
 *
 * @param[out] data &lt;tt&gt;struct retro_log_callback *&lt;/tt&gt;.
 * Pointer to the callback where the function pointer will be saved.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see retro_log_callback
 * @note Cores can fall back to \c stderr if this interface is not available.
 */
#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27

/**
 * Returns an interface that the core can use for profiling code
 * and to access performance-related information.
 *
 * This callback supports performance counters, a high-resolution timer,
 * and listing available CPU features (mostly SIMD instructions).
 *
 * @param[out] data &lt;tt&gt;struct retro_perf_callback *&lt;/tt&gt;.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @see retro_perf_callback
 */
#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28

/**
 * Returns an interface that the core can use to retrieve the device's location,
 * including its current latitude and longitude.
 *
 * @param[out] data &lt;tt&gt;struct retro_location_callback *&lt;/tt&gt;.
 * Pointer to the callback interface.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call is available,
 * even if there's no location information available.
 * @see retro_location_callback
 */
#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29

/**
 * @deprecated An obsolete alias to \c RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY kept for compatibility.
 * @see RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY
 **/
#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30

/**
 * Returns the frontend's "core assets" directory,
 * which can be used to store assets that the core needs
 * such as art assets or level data.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to a string in which the core assets directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May be \c NULL if no core assets directory is defined,
 * in which case the core should find an alternative directory.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 */
#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30

/**
 * Returns the frontend's save data directory, if available.
 * This directory should be used to store game-specific save data,
 * including memory card images.
 *
 * Although libretro provides an interface for cores to expose SRAM to the frontend,
 * not all cores can support it correctly.
 * In this case, cores should use this environment callback
 * to save their game data to disk manually.
 *
 * Cores that use this environment callback
 * should flush their save data to disk periodically and when unloading.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to the string in which the save data directory will be saved.
 * This string is managed by the frontend and must not be modified or freed by the core.
 * May return \c NULL if no save data directory is defined.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available,
 * even if the value returned in \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @note Early libretro cores used \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY for save data.
 * This is still supported for backwards compatibility,
 * but new cores should use this environment call instead.
 * \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY should be used for game-agnostic data
 * such as BIOS files or core-specific configuration.
 * @note The returned directory may or may not be the same
 * as the one used for \c retro_get_memory_data.
 *
 * @see retro_get_memory_data
 * @see RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 */
#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31

/**
 * Sets new video and audio parameters for the core.
 * This can only be called from within &lt;tt&gt;retro_run&lt;/tt&gt;.
 *
 * This environment call may entail a full reinitialization of the frontend's audio/video drivers,
 * hence it should \em only be used if the core needs to make drastic changes
 * to audio/video parameters.
 *
 * This environment call should \em not be used when:
 * &lt;ul&gt;
 * &lt;li&gt;Changing the emulated system's internal resolution,
 * within the limits defined by the existing values of \c max_width and \c max_height.
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY instead,
 * and adjust \c retro_get_system_av_info to account for
 * supported scale factors and screen layouts
 * when computing \c max_width and \c max_height.
 * Only use this environment call if \c max_width or \c max_height needs to increase.
 * &lt;li&gt;Adjusting the screen's aspect ratio,
 * e.g. when changing the layout of the screen(s).
 * Use \c RETRO_ENVIRONMENT_SET_GEOMETRY or \c RETRO_ENVIRONMENT_SET_ROTATION instead.
 * &lt;/ul&gt;
 *
 * The frontend will reinitialize its audio and video drivers within this callback;
 * after that happens, audio and video callbacks will target the newly-initialized driver,
 * even within the same \c retro_run call.
 *
 * This callback makes it possible to support configurable resolutions
 * while avoiding the need to compute the "worst case" values of \c max_width and \c max_height.
 *
 * @param[in] data &lt;tt&gt;const struct retro_system_av_info *&lt;/tt&gt;.
 * Pointer to the new video and audio parameters that the frontend should adopt.
 * @returns \c true if the environment call is available
 * and the new av_info struct was accepted.
 * \c false if the environment call is unavailable or \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 */
#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32

/**
 * Provides an interface that a frontend can use
 * to get function pointers from the core.
 *
 * This allows cores to define their own extensions to the libretro API,
 * or to expose implementations of a frontend's libretro extensions.
 *
 * @param[in] data &lt;tt&gt;const struct retro_get_proc_address_interface *&lt;/tt&gt;.
 * Pointer to the interface that the frontend can use to get function pointers from the core.
 * The frontend must maintain its own copy of this interface.
 * @returns \c true if the environment call is available
 * and the returned interface was accepted.
 * @note The provided interface may be called at any time,
 * even before this environment call returns.
 * @note Extensions should be prefixed with the name of the frontend or core that defines them.
 * For example, a frontend named "foo" that defines a debugging extension
 * should expect the core to define functions prefixed with "foo_debug_".
 * @warning If a core wants to use this environment call,
 * it \em must do so from within \c retro_set_environment().
 * @see retro_get_proc_address_interface
 */
#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33

/**
 * Registers a core's ability to handle "subsystems",
 * which are secondary platforms that augment a core's primary emulated hardware.
 *
 * A core doesn't need to emulate a secondary platform
 * in order to use it as a subsystem;
 * as long as it can load a secondary file for some practical use,
 * then this environment call is most likely suitable.
 *
 * Possible use cases of a subsystem include:
 *
 * \li Installing software onto an emulated console's internal storage,
 * such as the Nintendo DSi.
 * \li Emulating accessories that are used to support another console's games,
 * such as the Super Game Boy or the N64 Transfer Pak.
 * \li Inserting a secondary ROM into a console
 * that features multiple cartridge ports,
 * such as the Nintendo DS's Slot-2.
 * \li Loading a save data file created and used by another core.
 *
 * Cores should \em not use subsystems for:
 *
 * \li Emulators that support multiple "primary" platforms,
 * such as a Game Boy/Game Boy Advance core
 * or a Sega Genesis/Sega CD/32X core.
 * Use \c retro_system_content_info_override, \c retro_system_info,
 * and/or runtime detection instead.
 * \li Selecting different memory card images.
 * Use dynamically-populated core options instead.
 * \li Different variants of a single console,
 * such the Game Boy vs. the Game Boy Color.
 * Use core options or runtime detection instead.
 * \li Games that span multiple disks.
 * Use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * and m3u-formatted playlists instead.
 * \li Console system files (BIOS, firmware, etc.).
 * Use \c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
 * and a common naming convention instead.
 *
 * When the frontend loads a game via a subsystem,
 * it must call \c retro_load_game_special() instead of \c retro_load_game().
 *
 * @param[in] data &lt;tt&gt;const struct retro_subsystem_info *&lt;/tt&gt;.
 * Pointer to an array of subsystem descriptors,
 * terminated by a zeroed-out \c retro_subsystem_info struct.
 * The frontend should maintain its own copy
 * of this array and the strings within it.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @note This environment call \em must be called from within \c retro_set_environment(),
 * as frontends may need the registered information before loading a game.
 * @see retro_subsystem_info
 * @see retro_load_game_special
 */
#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34

/**
 * Declares one or more types of controllers supported by this core.
 * The frontend may then allow the player to select one of these controllers in its menu.
 *
 * Many consoles had controllers that came in different versions,
 * were extensible with peripherals,
 * or could be held in multiple ways;
 * this environment call can be used to represent these differences
 * and adjust the core's behavior to match.
 *
 * Possible use cases include:
 *
 * \li Supporting different classes of a single controller that supported their own sets of games.
 *     For example, the SNES had two different lightguns (the Super Scope and the Justifier)
 *     whose games were incompatible with each other.
 * \li Representing a platform's alternative controllers.
 *     For example, several platforms had music/rhythm games that included controllers
 *     shaped like musical instruments.
 * \li Representing variants of a standard controller with additional inputs.
 *     For example, numerous consoles in the 90's introduced 6-button controllers for fighting games,
 *     steering wheels for racing games,
 *     or analog sticks for 3D platformers.
 * \li Representing add-ons for consoles or standard controllers.
 *     For example, the 3DS had a Circle Pad Pro attachment that added a second analog stick.
 * \li Selecting different configurations for a single controller.
 *     For example, the Wii Remote could be held sideways like a traditional game pad
 *     or in one hand like a wand.
 * \li Providing multiple ways to simulate the experience of using a particular controller.
 *     For example, the Game Boy Advance featured several games
 *     with motion or light sensors in their cartridges;
 *     a core could provide controller configurations
 *     that allow emulating the sensors with either analog axes
 *     or with their host device's sensors.
 *
 * Should be called in retro_load_game.
 * The frontend must maintain its own copy of the provided array,
 * including all strings and subobjects.
 * A core may exclude certain controllers for known incompatible games.
 *
 * When the frontend changes the active device for a particular port,
 * it must call \c retro_set_controller_port_device() with that port's index
 * and one of the IDs defined in its retro_controller_info::types field.
 *
 * Input ports are generally associated with different players
 * (and the frontend's UI may reflect this with "Player 1" labels),
 * but this is not required.
 * Some games use multiple controllers for a single player,
 * or some cores may use port indexes to represent an emulated console's
 * alternative input peripherals.
 *
 * @param[in] data &lt;tt&gt;const struct retro_controller_info *&lt;/tt&gt;.
 * Pointer to an array of controller types defined by this core,
 * terminated by a zeroed-out \c retro_controller_info.
 * Each element of this array represents a controller port on the emulated device.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_controller_info
 * @see retro_set_controller_port_device
 * @see RETRO_DEVICE_SUBCLASS
 */
#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35

/**
 * Notifies the frontend of the address spaces used by the core's emulated hardware,
 * and of the memory maps within these spaces.
 * This can be used by the frontend to provide cheats, achievements, or debugging capabilities.
 * Should only be used by emulators, as it makes little sense for game engines.
 *
 * @note Cores should also expose these address spaces
 * through retro_get_memory_data and \c retro_get_memory_size if applicable;
 * this environment call is not intended to replace those two functions,
 * as the emulated hardware may feature memory regions outside of its own address space
 * that are nevertheless useful for the frontend.
 *
 * @param[in] data &lt;tt&gt;const struct retro_memory_map *&lt;/tt&gt;.
 * Pointer to a single memory-map listing.
 * The frontend must maintain its own copy of this object and its contents,
 * including strings and nested objects.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_memory_map
 * @see retro_get_memory_data
 * @see retro_memory_descriptor
 */
#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Resizes the viewport without reinitializing the video driver.
 *
 * Similar to \c RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
 * but any changes that would require video reinitialization will not be performed.
 * Can only be called from within \c retro_run().
 *
 * This environment call allows a core to revise the size of the viewport at will,
 * which can be useful for emulated platforms that support dynamic resolution changes
 * or for cores that support multiple screen layouts.
 *
 * A frontend must guarantee that this environment call completes in
 * constant time.
 *
 * @param[in] data &lt;tt&gt;const struct retro_game_geometry *&lt;/tt&gt;.
 * Pointer to the new video parameters that the frontend should adopt.
 * \c retro_game_geometry::max_width and \c retro_game_geometry::max_height
 * will be ignored.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 */
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37

/**
 * Returns the name of the user, if possible.
 * This callback is suitable for cores that offer personalization,
 * such as online facilities or user profiles on the emulated system.
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * Pointer to the user name string.
 * May be \c NULL, in which case the core should use a default name.
 * The returned pointer is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * even if the frontend couldn't provide a name.
 */
#define RETRO_ENVIRONMENT_GET_USERNAME 38

/**
 * Returns the frontend's configured language.
 * It can be used to localize the core's UI,
 * or to customize the emulated firmware if applicable.
 *
 * @param[out] data &lt;tt&gt;retro_language *&lt;/tt&gt;.
 * Pointer to the language identifier.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available.
 * @note The returned language may not be the same as the operating system's language.
 * Cores should fall back to the operating system's language (or to English)
 * if the environment call is unavailable or the returned language is unsupported.
 * @see retro_language
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_GET_LANGUAGE 39

/**
 * Returns a frontend-managed framebuffer
 * that the core may render directly into
 *
 * This environment call is provided as an optimization
 * for cores that use software rendering
 * (i.e. that don't use \refitem RETRO_ENVIRONMENT_SET_HW_RENDER "a graphics hardware API");
 * specifically, the intended use case is to allow a core
 * to render directly into frontend-managed video memory,
 * avoiding the bandwidth use that copying a whole framebuffer from core to video memory entails.
 *
 * Must be called every frame if used,
 * as this may return a different framebuffer each frame
 * (e.g. for swap chains).
 * However, a core may render to a different buffer even if this call succeeds.
 *
 * @param[in,out] data &lt;tt&gt;struct retro_framebuffer *&lt;/tt&gt;.
 * Pointer to a frontend's frame buffer and accompanying data.
 * Some fields are set by the core, others are set by the frontend.
 * Only guaranteed to be valid for the duration of the current \c retro_run call,
 * and must not be used afterwards.
 * Behavior is undefined if \c NULL.
 * @return \c true if the environment call was recognized
 * and the framebuffer was successfully returned.
 * @see retro_framebuffer
 */
#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface for accessing the data of specific rendering APIs.
 * Not all hardware rendering APIs support or need this.
 *
 * The details of these interfaces are specific to each rendering API.
 *
 * @note \c retro_hw_render_callback::context_reset must be called by the frontend
 * before this environment call can be used.
 * Additionally, the contents of the returned interface are invalidated
 * after \c retro_hw_render_callback::context_destroyed has been called.
 * @param[out] data &lt;tt&gt;const struct retro_hw_render_interface **&lt;/tt&gt;.
 * The render interface for the currently-enabled hardware rendering API, if any.
 * The frontend will store a pointer to the interface at the address provided here.
 * The returned interface is owned by the frontend and must not be modified or freed by the core.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available,
 * the active graphics API has a libretro rendering interface,
 * and the frontend is able to return said interface.
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see retro_hw_render_interface
 * @note Since not every libretro-supported hardware rendering API
 * has a \c retro_hw_render_interface implementation,
 * a result of \c false is not necessarily an error.
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Explicitly notifies the frontend of whether this core supports achievements.
 * The core must expose its emulated address space via
 * \c retro_get_memory_data or \c RETRO_ENVIRONMENT_GET_MEMORY_MAPS.
 * Must be called before the first call to &lt;tt&gt;retro_run&lt;/tt&gt;.
 *
 * If \ref retro_get_memory_data returns a valid address
 * but this environment call is not used,
 * the frontend (at its discretion) may or may not opt in the core to its achievements support.
 * whether this core is opted in to the frontend's achievement support
 * is left to the frontend's discretion.
 * @param[in] data &lt;tt&gt;const bool *&lt;/tt&gt;.
 * Pointer to a single \c bool that indicates whether this core supports achievements.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if the environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 * @see retro_get_memory_data
 */
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Defines an interface that the frontend can use
 * to ask the core for the parameters it needs for a hardware rendering context.
 * The exact semantics depend on \ref RETRO_ENVIRONMENT_SET_HW_RENDER "the active rendering API".
 * Will be used some time after \c RETRO_ENVIRONMENT_SET_HW_RENDER is called,
 * but before \c retro_hw_render_callback::context_reset is called.
 *
 * @param[in] data &lt;tt&gt;const struct retro_hw_render_context_negotiation_interface *&lt;/tt&gt;.
 * Pointer to the context negotiation interface.
 * Will be populated by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported,
 * even if the current graphics API doesn't use
 * a context negotiation interface (in which case the argument is ignored).
 * @see retro_hw_render_context_negotiation_interface
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Notifies the frontend of any quirks associated with serialization.
 *
 * Should be set in either \c retro_init or \c retro_load_game, but not both.
 * @param[in, out] data &lt;tt&gt;uint64_t *&lt;/tt&gt;.
 * Pointer to the core's serialization quirks.
 * The frontend will set the flags of the quirks it supports
 * and clear the flags of those it doesn't.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is supported.
 * @see retro_serialize
 * @see retro_unserialize
 * @see RETRO_SERIALIZATION_QUIRK
 */
#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44

/**
 * The frontend will try to use a "shared" context when setting up a hardware context.
 * Mostly applicable to OpenGL.
 *
 * In order for this to have any effect,
 * the core must call \c RETRO_ENVIRONMENT_SET_HW_RENDER at some point
 * if it hasn't already.
 *
 * @param data Ignored.
 * @returns \c true if the environment call is available
 * and the frontend supports shared hardware contexts.
 */
#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use to access the file system.
 * Should be called as early as possible.
 *
 * @param[in,out] data &lt;tt&gt;struct retro_vfs_interface_info *&lt;/tt&gt;.
 * Information about the desired VFS interface,
 * as well as the interface itself.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available
 * and the frontend can provide a VFS interface of the requested version or newer.
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 */
#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns an interface that the core can use
 * to set the state of any accessible device LEDs.
 *
 * @param[out] data &lt;tt&gt;struct retro_led_interface *&lt;/tt&gt;.
 * Pointer to the LED interface that the frontend will populate.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL
 * or no LEDs are accessible.
 * @see retro_led_interface
 */
#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns hints about certain steps that the core may skip for this frame.
 *
 * A frontend may not need a core to generate audio or video in certain situations;
 * this environment call sets a bitmask that indicates
 * which steps the core may skip for this frame.
 *
 * This can be used to increase performance for some frontend features.
 *
 * @note Emulation accuracy should not be compromised;
 * for example, if a core emulates a platform that supports display capture
 * (i.e. looking at its own VRAM), then it should perform its rendering as normal
 * unless it can prove that the emulated game is not using display capture.
 *
 * @param[out] data &lt;tt&gt;retro_av_enable_flags *&lt;/tt&gt;.
 * Pointer to the bitmask of steps that the frontend will skip.
 * Other bits are set to zero and are reserved for future use.
 * If \c NULL, the frontend will only return whether this environment callback is available.
 * @returns \c true if the environment call is available,
 * regardless of the value output to \c data.
 * If \c false, the core should assume that the frontend will not skip any steps.
 * @see retro_av_enable_flags
 */
#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Gets an interface that the core can use for raw MIDI I/O.
 *
 * @param[out] data &lt;tt&gt;struct retro_midi_interface *&lt;/tt&gt;.
 * Pointer to the MIDI interface.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_midi_interface
 */
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend if it's currently in fast-forward mode.
 * @param[out] data &lt;tt&gt;bool *&lt;/tt&gt;.
 * Set to \c true if the frontend is currently fast-forwarding its main loop.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @returns \c true if this environment call is available,
 * regardless of the value returned in \c data.
 *
 * @see RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE
 */
#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the refresh rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal refresh rate.
 *
 * @param[out] data &lt;tt&gt;float *&lt;/tt&gt;.
 * Pointer to the \c float in which the frontend will store its target refresh rate.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns whether the frontend can return the state of all buttons at once as a bitmask,
 * rather than requiring a series of individual calls to \c retro_input_state_t.
 *
 * If this callback returns \c true,
 * you can get the state of all buttons by passing \c RETRO_DEVICE_ID_JOYPAD_MASK
 * as the \c id parameter to \c retro_input_state_t.
 * Bit #N represents the RETRO_DEVICE_ID_JOYPAD constant of value N,
 * e.g. &lt;tt&gt;(1 &lt;&lt; RETRO_DEVICE_ID_JOYPAD_A)&lt;/tt&gt; represents the A button.
 *
 * @param data Ignored.
 * @returns \c true if the frontend can report the complete digital joypad state as a bitmask.
 * @see retro_input_state_t
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_ID_JOYPAD_MASK
 */
#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the version of the core options API supported by the frontend.
 *
 * Over the years, libretro has used several interfaces
 * for allowing cores to define customizable options.
 * \ref SET_CORE_OPTIONS_V2 "Version 2 of the interface"
 * is currently preferred due to its extra features,
 * but cores and frontends should strive to support
 * versions \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS "1"
 * and \ref RETRO_ENVIRONMENT_SET_VARIABLES "0" as well.
 * This environment call provides the information that cores need for that purpose.
 *
 * If this environment call returns \c false,
 * then the core should assume version 0 of the core options API.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the integer that will store the frontend's
 * supported core options API version.
 * Behavior is undefined if \c NULL.
 * @returns \c true if the environment call is available,
 * \c false otherwise.
 * @see RETRO_ENVIRONMENT_SET_VARIABLES
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52

/**
 * @copybrief RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 *
 * @deprecated This environment call has been superseded
 * by RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
 * which supports categorizing options into groups.
 * This environment call should only be used to maintain compatibility
 * with older cores and frontends.
 *
 * This environment call is intended to replace \c RETRO_ENVIRONMENT_SET_VARIABLES,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 1.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * Example entry:
 * @code
 * {
 *     "foo_option",
 *     "Speed hack coprocessor X",
 *     "Provides increased performance at the expense of reduced accuracy",
 *     {
 *         { "false",    NULL },
 *         { "true",     NULL },
 *         { "unstable", "Turbo (Unstable)" },
 *         { NULL, NULL },
 *     },
 *     "false"
 * }
 * @endcode
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_option_definition *&lt;/tt&gt;.
 * Pointer to one or more core option definitions,
 * terminated by a \ref retro_core_option_definition whose values are all zero.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available.
 *
 * @see retro_core_option_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * that supports internationalization.
 *
 * @deprecated This environment call has been superseded
 * by \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
 * which supports categorizing options into groups
 * (plus translating the groups themselves).
 * Only use this environment call to maintain compatibility
 * with older cores and frontends.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_intl for some important details.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_intl *&lt;/tt&gt;.
 * Pointer to a core's option values and their translations.
 * @see retro_core_options_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54

/**
 * Notifies the frontend that it should show or hide the named core option.
 *
 * Some core options aren't relevant in all scenarios,
 * such as a submenu for hardware rendering flags
 * when the software renderer is configured.
 * This environment call asks the frontend to stop (or start)
 * showing the named core option to the player.
 * This is only a hint, not a requirement;
 * the frontend may ignore this environment call.
 * By default, all core options are visible.
 *
 * @note This environment call must \em only affect a core option's visibility,
 * not its functionality or availability.
 * \ref RETRO_ENVIRONMENT_GET_VARIABLE "Getting an invisible core option"
 * must behave normally.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_option_display *&lt;/tt&gt;.
 * Pointer to a descriptor for the option that the frontend should show or hide.
 * May be \c NULL, in which case the frontend will only return
 * whether this environment callback is available.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL
 * or the specified option doesn't exist.
 * @see retro_core_option_display
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55

/**
 * Returns the frontend's preferred hardware rendering API.
 * Cores should use this information to decide which API to use with \c RETRO_ENVIRONMENT_SET_HW_RENDER.
 * @param[out] data &lt;tt&gt;retro_hw_context_type *&lt;/tt&gt;.
 * Pointer to the hardware context type.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * This value will be set even if the environment call returns &lt;tt&gt;false&lt;/tt&gt;,
 * unless the frontend doesn't implement it.
 * @returns \c true if the environment call is available
 * and the frontend is able to use a hardware rendering API besides the one returned.
 * If \c false is returned and the core cannot use the preferred rendering API,
 * then it should exit or fall back to software rendering.
 * @note The returned value does not indicate which API is currently in use.
 * For example, the frontend may return \c RETRO_HW_CONTEXT_OPENGL
 * while a Direct3D context from a previous session is active;
 * this would signal that the frontend's current preference is for OpenGL,
 * possibly because the user changed their frontend's video driver while a game is running.
 * @see retro_hw_context_type
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 */
#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56

/**
 * Returns the minimum version of the disk control interface supported by the frontend.
 *
 * If this environment call returns \c false or \c data is 0 or greater,
 * then cores may use disk control callbacks
 * with \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
 * If the reported version is 1 or greater,
 * then cores should use \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE instead.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the unsigned integer that the frontend's supported disk control interface version will be stored in.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57

/**
 * @copybrief RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE
 *
 * This is intended for multi-disk games that expect the player
 * to manually swap disks at certain points in the game.
 * This version of the disk control interface provides
 * more information about disk images.
 * Should be called in \c retro_init.
 *
 * @param[in] data &lt;tt&gt;const struct retro_disk_control_ext_callback *&lt;/tt&gt;.
 * Pointer to the callback functions to use.
 * May be \c NULL, in which case the existing disk callback is deregistered.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_disk_control_ext_callback
 */
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58

/**
 * Returns the version of the message interface supported by the frontend.
 *
 * A version of 0 indicates that the frontend
 * only supports the legacy \c RETRO_ENVIRONMENT_SET_MESSAGE interface.
 * A version of 1 indicates that the frontend
 * supports \c RETRO_ENVIRONMENT_SET_MESSAGE_EXT as well.
 * If this environment call returns \c false,
 * the core should behave as if it had returned 0.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 */
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59

/**
 * Displays a user-facing message for a short time.
 *
 * Use this callback to convey important status messages,
 * such as errors or the result of long-running operations.
 * For trivial messages or logging, use \c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \c stderr.
 *
 * This environment call supersedes \c RETRO_ENVIRONMENT_SET_MESSAGE,
 * as it provides many more ways to customize
 * how a message is presented to the player.
 * However, a frontend that supports this environment call
 * must still support \c RETRO_ENVIRONMENT_SET_MESSAGE.
 *
 * @param[in] data &lt;tt&gt;const struct retro_message_ext *&lt;/tt&gt;.
 * Pointer to the message to display to the player.
 * Behavior is undefined if \c NULL.
 * @returns \c true if this environment call is available.
 * @see retro_message_ext
 * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION
 */
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60

/**
 * Returns the number of active input devices currently provided by the frontend.
 *
 * This may change between frames,
 * but will remain constant for the duration of each frame.
 *
 * If this callback returns \c true,
 * a core need not poll any input device
 * with an index greater than or equal to the returned value.
 *
 * If callback returns \c false,
 * the number of active input devices is unknown.
 * In this case, all input devices should be considered active.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the result returned by the frontend.
 * Behavior is undefined if \c NULL.
 * @return \c true if this environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61

/**
 * Registers a callback that the frontend can use to notify the core
 * of the audio output buffer's occupancy.
 * Can be used by a core to attempt frame-skipping to avoid buffer under-runs
 * (i.e. "crackling" sounds).
 *
 * @param[in] data &lt;tt&gt;const struct retro_audio_buffer_status_callback *&lt;/tt&gt;.
 * Pointer to the the buffer status callback,
 * or \c NULL to unregister any existing callback.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_audio_buffer_status_callback
 */
#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62

/**
 * Requests a minimum frontend audio latency in milliseconds.
 *
 * This is a hint; the frontend may assign a different audio latency
 * to accommodate hardware limits,
 * although it should try to honor requests up to 512ms.
 *
 * This callback has no effect if the requested latency
 * is less than the frontend's current audio latency.
 * If value is zero or \c data is \c NULL,
 * the frontend should set its default audio latency.
 *
 * May be used by a core to increase audio latency and
 * reduce the risk of buffer under-runs (crackling)
 * when performing 'intensive' operations.
 *
 * A core using RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 * to implement audio-buffer-based frame skipping can get good results
 * by setting the audio latency to a high (typically 6x or 8x)
 * integer multiple of the expected frame time.
 *
 * This can only be called from within \c retro_run().
 *
 * @warning This environment call may require the frontend to reinitialize its audio system.
 * This environment call should be used sparingly.
 * If the driver is reinitialized,
 * \ref retro_audio_callback_t "all audio callbacks" will be updated
 * to target the newly-initialized driver.
 *
 * @param[in] data &lt;tt&gt;const unsigned *&lt;/tt&gt;.
 * Minimum audio latency, in milliseconds.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
 */
#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63

/**
 * Allows the core to tell the frontend when it should enable fast-forwarding,
 * rather than relying solely on the frontend and user interaction.
 *
 * Possible use cases include:
 *
 * \li Temporarily disabling a core's fastforward support
 *     while investigating a related bug.
 * \li Disabling fastforward during netplay sessions,
 *     or when using an emulated console's network features.
 * \li Automatically speeding up the game when in a loading screen
 *     that cannot be shortened with high-level emulation.
 *
 * @param[in] data &lt;tt&gt;const struct retro_fastforwarding_override *&lt;/tt&gt;.
 * Pointer to the parameters that decide when and how
 * the frontend is allowed to enable fast-forward mode.
 * May be \c NULL, in which case the frontend will return \c true
 * without updating the fastforward state,
 * which can be used to detect support for this environment call.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 *
 * @see retro_fastforwarding_override
 * @see RETRO_ENVIRONMENT_GET_FASTFORWARDING
 */
#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64

#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65
                                           /* const struct retro_system_content_info_override * --
                                            * Allows an implementation to override 'global' content
                                            * info parameters reported by retro_get_system_info().
                                            * Overrides also affect subsystem content info parameters
                                            * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.
                                            * This function must be called inside retro_set_environment().
                                            * If callback returns false, content info overrides
                                            * are unsupported by the frontend, and will be ignored.
                                            * If callback returns true, extended game info may be
                                            * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
                                            * in retro_load_game() or retro_load_game_special().
                                            *
                                            * 'data' points to an array of retro_system_content_info_override
                                            * structs terminated by a { NULL, false, false } element.
                                            * If 'data' is NULL, no changes will be made to the frontend;
                                            * a core may therefore pass NULL in order to test whether
                                            * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported
                                            * by the frontend.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_system_content_info_override.
                                            *
                                            * Example:
                                            *
                                            * - struct retro_system_info:
                                            * {
                                            *    "My Core",                      // library_name
                                            *    "v1.0",                         // library_version
                                            *    "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
                                            *    true,                           // need_fullpath
                                            *    false                           // block_extract
                                            * }
                                            *
                                            * - Array of struct retro_system_content_info_override:
                                            * {
                                            *    {
                                            *       "md|sms|gg", // extensions
                                            *       false,       // need_fullpath
                                            *       true         // persistent_data
                                            *    },
                                            *    {
                                            *       "sg",        // extensions
                                            *       false,       // need_fullpath
                                            *       false        // persistent_data
                                            *    },
                                            *    { NULL, false, false }
                                            * }
                                            *
                                            * Result:
                                            * - Files of type m3u, cue, iso, chd will not be
                                            *   loaded by the frontend. Frontend will pass a
                                            *   valid path to the core, and core will handle
                                            *   loading internally
                                            * - Files of type md, sms, gg will be loaded by
                                            *   the frontend. A valid memory buffer will be
                                            *   passed to the core. This memory buffer will
                                            *   remain valid until retro_deinit() returns
                                            * - Files of type sg will be loaded by the frontend.
                                            *   A valid memory buffer will be passed to the core.
                                            *   This memory buffer will remain valid until
                                            *   retro_load_game() (or retro_load_game_special())
                                            *   returns
                                            *
                                            * NOTE: If an extension is listed multiple times in
                                            * an array of retro_system_content_info_override
                                            * structs, only the first instance will be registered
                                            */

#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66
                                           /* const struct retro_game_info_ext ** --
                                            * Allows an implementation to fetch extended game
                                            * information, providing additional content path
                                            * and memory buffer status details.
                                            * This function may only be called inside
                                            * retro_load_game() or retro_load_game_special().
                                            * If callback returns false, extended game information
                                            * is unsupported by the frontend. In this case, only
                                            * regular retro_game_info will be available.
                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed
                                            * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
                                            * returns true.
                                            *
                                            * 'data' points to an array of retro_game_info_ext structs.
                                            *
                                            * For struct member descriptions, see the definition of
                                            * struct retro_game_info_ext.
                                            *
                                            * - If function is called inside retro_load_game(),
                                            *   the retro_game_info_ext array is guaranteed to
                                            *   have a size of 1 - i.e. the returned pointer may
                                            *   be used to access directly the members of the
                                            *   first retro_game_info_ext struct, for example:
                                            *
                                            *      struct retro_game_info_ext *game_info_ext;
                                            *      if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &amp;game_info_ext))
                                            *         printf("Content Directory: %s\n", game_info_ext-&gt;dir);
                                            *
                                            * - If the function is called inside retro_load_game_special(),
                                            *   the retro_game_info_ext array is guaranteed to have a
                                            *   size equal to the num_info argument passed to
                                            *   retro_load_game_special()
                                            */

/**
 * Defines a set of core options that can be shown and configured by the frontend,
 * so that the player may customize their gameplay experience to their liking.
 *
 * @note This environment call is intended to replace
 * \c RETRO_ENVIRONMENT_SET_VARIABLES and \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
 * and should only be called if \c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
 * returns an API version of at least 2.
 *
 * This should be called the first time as early as possible,
 * ideally in \c retro_set_environment (but \c retro_load_game is acceptable).
 * It may then be called again later to update
 * the core's options and their associated values,
 * as long as the number of options doesn't change
 * from the number given in the first call.
 *
 * The core can retrieve option values at any time with \c RETRO_ENVIRONMENT_GET_VARIABLE.
 * If a saved value for a core option doesn't match the option definition's values,
 * the frontend may treat it as incorrect and revert to the default.
 *
 * Core options and their values are usually defined in a large static array,
 * but they may be generated at runtime based on the loaded game or system state.
 * Here are some use cases for that:
 *
 * @li Selecting a particular file from one of the
 *     \ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY "frontend's"
 *     \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "content"
 *     \ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY "directories",
 *     such as a memory card image or figurine data file.
 * @li Excluding options that are not relevant to the current game,
 *     for cores that define a large number of possible options.
 * @li Choosing a default value at runtime for a specific game,
 *     such as a BIOS file whose region matches that of the loaded content.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 * This implies that cores should keep the number of options and values
 * as low as possible.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_v2 *&lt;/tt&gt;.
 * Pointer to a core's options and their associated categories.
 * May be \c NULL, in which case the frontend will remove all existing core options.
 * The frontend must maintain its own copy of this object,
 * including all strings and subobjects.
 * @return \c true if this environment call is available
 * and the frontend supports categories.
 * Note that this environment call is guaranteed to successfully register
 * the provided core options,
 * so the return value does not indicate success or failure.
 *
 * @see retro_core_options_v2
 * @see retro_core_option_v2_category
 * @see retro_core_option_v2_definition
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 67

/**
 * A variant of \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * that supports internationalization.
 *
 * This should be called instead of \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * if the core provides translations for its options.
 * General use is largely the same,
 * but see \ref retro_core_options_v2_intl for some important details.
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_v2_intl *&lt;/tt&gt;.
 * Pointer to a core's option values and categories,
 * plus a translation for each option and category.
 * @see retro_core_options_v2_intl
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL 68

/**
 * Registers a callback that the frontend can use
 * to notify the core that at least one core option
 * should be made hidden or visible.
 * Allows a frontend to signal that a core must update
 * the visibility of any dynamically hidden core options,
 * and enables the frontend to detect visibility changes.
 * Used by the frontend to update the menu display status
 * of core options without requiring a call of retro_run().
 * Must be called in retro_set_environment().
 *
 * @param[in] data &lt;tt&gt;const struct retro_core_options_update_display_callback *&lt;/tt&gt;.
 * The callback that the frontend should use.
 * May be \c NULL, in which case the frontend will unset any existing callback.
 * Can be used to query visibility support.
 * @return \c true if this environment call is available,
 * even if \c data is \c NULL.
 * @see retro_core_options_update_display_callback
 */
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69

/**
 * Forcibly sets a core option's value.
 *
 * After changing a core option value with this callback,
 * it will be reflected in the frontend
 * and \ref RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE will return \c true.
 * \ref retro_variable::key must match
 * a \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 "previously-set core option",
 * and \ref retro_variable::value must match one of its defined values.
 *
 * Possible use cases include:
 *
 * @li Allowing the player to set certain core options
 *     without entering the frontend's option menu,
 *     using an in-core hotkey.
 * @li Adjusting invalid combinations of settings.
 * @li Migrating settings from older releases of a core.
 *
 * @param[in] data &lt;tt&gt;const struct retro_variable *&lt;/tt&gt;.
 * Pointer to a single option that the core is changing.
 * May be \c NULL, in which case the frontend will return \c true
 * to indicate that this environment call is available.
 * @return \c true if this environment call is available
 * and the option named by \c key was successfully
 * set to the given \c value.
 * \c false if the \c key or \c value fields are \c NULL, empty,
 * or don't match a previously set option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
 */
#define RETRO_ENVIRONMENT_SET_VARIABLE 70

#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
                                           /* struct retro_throttle_state * --
                                            * Allows an implementation to get details on the actual rate
                                            * the frontend is attempting to call retro_run().
                                            */

/**
 * Returns information about how the frontend will use savestates.
 *
 * @param[out] data &lt;tt&gt;retro_savestate_context *&lt;/tt&gt;.
 * Pointer to the current savestate context.
 * May be \c NULL, in which case the environment call
 * will return \c true to indicate its availability.
 * @returns \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_savestate_context
 */
#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Before calling \c SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, will query which interface is supported.
 *
 * Frontend looks at \c retro_hw_render_interface_type and returns the maximum supported
 * context negotiation interface version. If the \c retro_hw_render_interface_type is not
 * supported or recognized by the frontend, a version of 0 must be returned in
 * \c retro_hw_render_interface's \c interface_version and \c true is returned by frontend.
 *
 * If this environment call returns true with a \c interface_version greater than 0,
 * a core can always use a negotiation interface version larger than what the frontend returns,
 * but only earlier versions of the interface will be used by the frontend.
 *
 * A frontend must not reject a negotiation interface version that is larger than what the
 * frontend supports. Instead, the frontend will use the older entry points that it recognizes.
 * If this is incompatible with a particular core's requirements, it can error out early.
 *
 * @note Regarding backwards compatibility, this environment call was introduced after Vulkan v1
 * context negotiation. If this environment call is not supported by frontend, i.e. the environment
 * call returns \c false , only Vulkan v1 context negotiation is supported (if Vulkan HW rendering
 * is supported at all). If a core uses Vulkan negotiation interface with version &gt; 1, negotiation
 * may fail unexpectedly. All future updates to the context negotiation interface implies that
 * frontend must support this environment call to query support.
 *
 * @param[out] data &lt;tt&gt;struct retro_hw_render_context_negotiation_interface *&lt;/tt&gt;.
 * @return \c true if the environment call is available.
 * @see SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see retro_hw_render_interface_type
 * @see retro_hw_render_context_negotiation_interface
 */
#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Asks the frontend whether JIT compilation can be used.
 * Primarily used by iOS and tvOS.
 * @param[out] data &lt;tt&gt;bool *&lt;/tt&gt;.
 * Set to \c true if the frontend has verified that JIT compilation is possible.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74

/**
 * Returns an interface that the core can use to receive microphone input.
 *
 * @param[out] data &lt;tt&gt;retro_microphone_interface *&lt;/tt&gt;.
 * Pointer to the microphone interface.
 * @return \true if microphone support is available,
 * even if no microphones are plugged in.
 * \c false if microphone support is disabled unavailable,
 * or if \c data is \c NULL.
 * @see retro_microphone_interface
 */
#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/* Environment 76 was an obsolete version of RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
* It was not used by any known core at the time, and was removed from the API. */

/**
 * Returns the device's current power state as reported by the frontend.
 *
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
 *
 * @param[out] data &lt;struct retro_device_power *&gt;.
 * Indicates whether the frontend can provide this information, even if the parameter
 * is \c NULL. If the frontend does not support this functionality, then the provided
 * argument will remain unchanged.
 * @return \c true if the environment call is available.
 * @see retro_device_power
 */
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 78
                                           /* const struct retro_netpacket_callback * --
                                            * When set, a core gains control over network packets sent and
                                            * received during a multiplayer session. This can be used to
                                            * emulate multiplayer games that were originally played on two
                                            * or more separate consoles or computers connected together.
                                            *
                                            * The frontend will take care of connecting players together,
                                            * and the core only needs to send the actual data as needed for
                                            * the emulation, while handshake and connection management happen
                                            * in the background.
                                            *
                                            * When two or more players are connected and this interface has
                                            * been set, time manipulation features (such as pausing, slow motion,
                                            * fast forward, rewinding, save state loading, etc.) are disabled to
                                            * avoid interrupting communication.
                                            *
                                            * Should be set in either retro_init or retro_load_game, but not both.
                                            *
                                            * When not set, a frontend may use state serialization-based
                                            * multiplayer, where a deterministic core supporting multiple
                                            * input devices does not need to take any action on its own.
                                            */

/**
 * Returns the device's current power state as reported by the frontend.
 * This is useful for emulating the battery level in handheld consoles,
 * or for reducing power consumption when on battery power.
 *
 * The return value indicates whether the frontend can provide this information,
 * even if the parameter is \c NULL.
 *
 * If the frontend does not support this functionality,
 * then the provided argument will remain unchanged.
 * @param[out] data &lt;tt&gt;retro_device_power *&lt;/tt&gt;.
 * Pointer to the information that the frontend returns about its power state.
 * May be \c NULL.
 * @return \c true if the environment call is available,
 * even if \c data is \c NULL.
 * @see retro_device_power
 * @note This environment call describes the power state for the entire device,
 * not for individual peripherals like controllers.
*/
#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**
 * Returns the "playlist" directory of the frontend.
 *
 * This directory can be used to store core generated playlists, in case
 * this internal functionality is available (e.g. internal core game detection
 * engine).
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_PLAYLIST_DIRECTORY 79

/**
 * Returns the "file browser" start directory of the frontend.
 *
 * This directory can serve as a start directory for the core in case it
 * provides an internal way of loading content.
 *
 * @param[out] data &lt;tt&gt;const char **&lt;/tt&gt;.
 * May be \c NULL. If so, no such directory is defined, and it's up to the
 * implementation to find a suitable directory.
 * @return \c true if the environment call is available.
 */
#define RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY 80

/**
 * Returns the audio sample rate the frontend is targeting, in Hz.
 * The intended use case is for the core to use the result to select an ideal sample rate.
 *
 * @param[out] data &lt;tt&gt;unsigned *&lt;/tt&gt;.
 * Pointer to the \c unsigned integer in which the frontend will store its target sample rate.
 * Behavior is undefined if \c data is &lt;tt&gt;NULL&lt;/tt&gt;.
 * @return \c true if this environment call is available,
 * regardless of the value returned in \c data.
*/
#define RETRO_ENVIRONMENT_GET_TARGET_SAMPLE_RATE (81 | RETRO_ENVIRONMENT_EXPERIMENTAL)

/**@}*/

/**
 * @defgroup GET_VFS_INTERFACE File System Interface
 * @brief File system functionality.
 *
 * @section File Paths
 * File paths passed to all libretro filesystem APIs shall be well formed UNIX-style,
 * using "/" (unquoted forward slash) as the directory separator
 * regardless of the platform's native separator.
 *
 * Paths shall also include at least one forward slash
 * (e.g. use "./game.bin" instead of "game.bin").
 *
 * Other than the directory separator, cores shall not make assumptions about path format.
 * The following paths are all valid:
 * @li \c C:/path/game.bin
 * @li \c http://example.com/game.bin
 * @li \c #game/game.bin
 * @li \c ./game.bin
 *
 * Cores may replace the basename or remove path components from the end, and/or add new components;
 * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request from the front end.
 *
 * The frontend is encouraged to do the best it can when given an ill-formed path,
 * but it is allowed to give up.
 *
 * Frontends are encouraged, but not required, to support native file system paths
 * (including replacing the directory separator, if applicable).
 *
 * Cores are allowed to try using them, but must remain functional if the frontend rejects such requests.
 *
 * Cores are encouraged to use the libretro-common filestream functions for file I/O,
 * as they seamlessly integrate with VFS,
 * deal with directory separator replacement as appropriate
 * and provide platform-specific fallbacks
 * in cases where front ends do not provide their own VFS interface.
 *
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 * @see retro_vfs_interface_info
 * @see file_path
 * @see retro_dirent
 * @see file_stream
 *
 * @{
 */

/**
 * Opaque file handle.
 * @since VFS API v1
 */
struct retro_vfs_file_handle;

/**
 * Opaque directory handle.
 * @since VFS API v3
 */
struct retro_vfs_dir_handle;

/** @defgroup RETRO_VFS_FILE_ACCESS File Access Flags
 * File access flags.
 * @since VFS API v1
 * @{
 */

/** Opens a file for read-only access. */
#define RETRO_VFS_FILE_ACCESS_READ            (1 &lt;&lt; 0)

/**
 * Opens a file for write-only access.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_WRITE           (1 &lt;&lt; 1)

/**
 * Opens a file for reading and writing.
 * Any existing file at this path will be discarded and overwritten
 * unless \c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.
 */
#define RETRO_VFS_FILE_ACCESS_READ_WRITE      (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE)

/**
 * Opens a file without discarding its existing contents.
 * Only meaningful if \c RETRO_VFS_FILE_ACCESS_WRITE is specified.
 */
#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 &lt;&lt; 2) /* Prevents discarding content of existing files opened for writing */

/** @} */

/** @defgroup RETRO_VFS_FILE_ACCESS_HINT File Access Hints
 *
 * Hints to the frontend for how a file will be accessed.
 * The VFS implementation may use these to optimize performance,
 * react to external interference (such as concurrent writes),
 * or it may ignore them entirely.
 *
 * Hint flags do not change the behavior of each VFS function
 * unless otherwise noted.
 * @{
 */

/** No particular hints are given. */
#define RETRO_VFS_FILE_ACCESS_HINT_NONE              (0)

/**
 * Indicates that the file will be accessed frequently.
 *
 * The frontend should cache it or map it into memory.
 */
#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS   (1 &lt;&lt; 0)

/** @} */

/** @defgroup RETRO_VFS_SEEK_POSITION File Seek Positions
 * File access flags and hints.
 * @{
 */

/**
 * Indicates a seek relative to the start of the file.
 */
#define RETRO_VFS_SEEK_POSITION_START    0

/**
 * Indicates a seek relative to the current stream position.
 */
#define RETRO_VFS_SEEK_POSITION_CURRENT  1

/**
 * Indicates a seek relative to the end of the file.
 * @note The offset passed to \c retro_vfs_seek_t should be negative.
 */
#define RETRO_VFS_SEEK_POSITION_END      2

/** @} */

/** @defgroup RETRO_VFS_STAT File Status Flags
 * File stat flags.
 * @see retro_vfs_stat_t
 * @since VFS API v3
 * @{
 */

/** Indicates that the given path refers to a valid file. */
#define RETRO_VFS_STAT_IS_VALID               (1 &lt;&lt; 0)

/** Indicates that the given path refers to a directory. */
#define RETRO_VFS_STAT_IS_DIRECTORY           (1 &lt;&lt; 1)

/**
 * Indicates that the given path refers to a character special file,
 * such as \c /dev/null.
 */
#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL   (1 &lt;&lt; 2)

/** @} */

/**
 * Returns the path that was used to open this file.
 *
 * @param stream The opened file handle to get the path of.
 * Behavior is undefined if \c NULL or closed.
 * @return The path that was used to open \c stream.
 * The string is owned by \c stream and must not be modified.
 * @since VFS API v1
 * @see filestream_get_path
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);

/**
 * Open a file for reading or writing.
 *
 * @param path The path to open.
 * @param mode A bitwise combination of \c RETRO_VFS_FILE_ACCESS flags.
 * At a minimum, one of \c RETRO_VFS_FILE_ACCESS_READ or \c RETRO_VFS_FILE_ACCESS_WRITE must be specified.
 * @param hints A bitwise combination of \c RETRO_VFS_FILE_ACCESS_HINT flags.
 * @return A handle to the opened file,
 * or \c NULL upon failure.
 * Note that this will return \c NULL if \c path names a directory.
 * The returned file handle must be closed with \c retro_vfs_close_t.
 * @since VFS API v1
 * @see File Paths
 * @see RETRO_VFS_FILE_ACCESS
 * @see RETRO_VFS_FILE_ACCESS_HINT
 * @see retro_vfs_close_t
 * @see filestream_open
 */
typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);

/**
 * Close the file and release its resources.
 * All files returned by \c retro_vfs_open_t must be closed with this function.
 *
 * @param stream The file handle to close.
 * Behavior is undefined if already closed.
 * Upon completion of this function, \c stream is no longer valid
 * (even if it returns failure).
 * @return 0 on success, -1 on failure or if \c stream is \c NULL.
 * @see retro_vfs_open_t
 * @see filestream_close
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);

/**
 * Return the size of the file in bytes.
 *
 * @param stream The file to query the size of.
 * @return Size of the file in bytes, or -1 if there was an error.
 * @see filestream_get_size
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);

/**
 * Set the file's length.
 *
 * @param stream The file whose length will be adjusted.
 * @param length The new length of the file, in bytes.
 * If shorter than the original length, the extra bytes will be discarded.
 * If longer, the file's padding is unspecified (and likely platform-dependent).
 * @return 0 on success,
 * -1 on failure.
 * @see filestream_truncate
 * @since VFS API v2
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);

/**
 * Gets the given file's current read/write position.
 * This position is advanced with each call to \c retro_vfs_read_t or \c retro_vfs_write_t.
 *
 * @param stream The file to query the position of.
 * @return The current stream position in bytes
 * or -1 if there was an error.
 * @see filestream_tell
 * @since VFS API v1
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);

/**
 * Sets the given file handle's current read/write position.
 *
 * @param stream The file to set the position of.
 * @param offset The new position, in bytes.
 * @param seek_position The position to seek from.
 * @return The new position,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see File Seek Positions
 * @see filestream_seek
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);

/**
 * Read data from a file, if it was opened for reading.
 *
 * @param stream The file to read from.
 * @param s The buffer to read into.
 * @param len The number of bytes to read.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes read,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_read
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);

/**
 * Write data to a file, if it was opened for writing.
 *
 * @param stream The file handle to write to.
 * @param s The buffer to write from.
 * @param len The number of bytes to write.
 * The buffer pointed to by \c s must be this large.
 * @return The number of bytes written,
 * or -1 if there was an error.
 * @since VFS API v1
 * @see filestream_write
 */
typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);

/**
 * Flush pending writes to the file, if applicable.
 *
 * This does not mean that the changes will be immediately persisted to disk;
 * that may be scheduled for later, depending on the platform.
 *
 * @param stream The file handle to flush.
 * @return 0 on success, -1 on failure.
 * @since VFS API v1
 * @see filestream_flush
 */
typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);

/**
 * Deletes the file at the given path.
 *
 * @param path The path to the file that will be deleted.
 * @return 0 on success, -1 on failure.
 * @see filestream_delete
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);

/**
 * Rename the specified file.
 *
 * @param old_path Path to an existing file.
 * @param new_path The destination path.
 * Must not name an existing file.
 * @return 0 on success, -1 on failure
 * @see filestream_rename
 * @since VFS API v1
 */
typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);

/**
 * Gets information about the given file.
 *
 * @param path The path to the file to query.
 * @param[out] size The reported size of the file in bytes.
 * May be \c NULL, in which case this value is ignored.
 * @return A bitmask of \c RETRO_VFS_STAT flags,
 * or 0 if \c path doesn't refer to a valid file.
 * @see path_stat
 * @see path_get_size
 * @see RETRO_VFS_STAT
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);

/**
 * Creates a directory at the given path.
 *
 * @param dir The desired location of the new directory.
 * @return 0 if the directory was created,
 * -2 if the directory already exists,
 * or -1 if some other error occurred.
 * @see path_mkdir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);

/**
 * Opens a handle to a directory so its contents can be inspected.
 *
 * @param dir The path to the directory to open.
 * Must be an existing directory.
 * @param include_hidden Whether to include hidden files in the directory listing.
 * The exact semantics of this flag will depend on the platform.
 * @return A handle to the opened directory,
 * or \c NULL if there was an error.
 * @see retro_opendir
 * @since VFS API v3
 */
typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);

/**
 * Gets the next dirent ("directory entry")
 * within the given directory.
 *
 * @param[in,out] dirstream The directory to read from.
 * Updated to point to the next file, directory, or other path.
 * @return \c true when the next dirent was retrieved,
 * \c false if there are no more dirents to read.
 * @note This API iterates over all files and directories within \c dirstream.
 * Remember to check what the type of the current dirent is.
 * @note This function does not recurse,
 * i.e. it does not return the contents of subdirectories.
 * @note This may include "." and ".." on Unix-like platforms.
 * @see retro_readdir
 * @see retro_vfs_dirent_is_dir_t
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Gets the filename of the current dirent.
 *
 * The returned string pointer is valid
 * until the next call to \c retro_vfs_readdir_t or \c retro_vfs_closedir_t.
 *
 * @param dirstream The directory to read from.
 * @return The current dirent's name,
 * or \c NULL if there was an error.
 * @note This function only returns the file's \em name,
 * not a complete path to it.
 * @see retro_dirent_get_name
 * @since VFS API v3
 */
typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Checks whether the current dirent names a directory.
 *
 * @param dirstream The directory to read from.
 * @return \c true if \c dirstream's current dirent points to a directory,
 * \c false if not or if there was an error.
 * @see retro_dirent_is_dir
 * @since VFS API v3
 */
typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * Closes the given directory and release its resources.
 *
 * Must be called on any \c retro_vfs_dir_handle returned by \c retro_vfs_open_t.
 *
 * @param dirstream The directory to close.
 * When this function returns (even failure),
 * \c dirstream will no longer be valid and must not be used.
 * @return 0 on success, -1 on failure.
 * @see retro_closedir
 * @since VFS API v3
 */
typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);

/**
 * File system interface exposed by the frontend.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface
{
   /* VFS API v1 */
   /** @copydoc retro_vfs_get_path_t */
	retro_vfs_get_path_t get_path;

   /** @copydoc retro_vfs_open_t */
	retro_vfs_open_t open;

   /** @copydoc retro_vfs_close_t */
	retro_vfs_close_t close;

   /** @copydoc retro_vfs_size_t */
	retro_vfs_size_t size;

   /** @copydoc retro_vfs_tell_t */
	retro_vfs_tell_t tell;

   /** @copydoc retro_vfs_seek_t */
	retro_vfs_seek_t seek;

   /** @copydoc retro_vfs_read_t */
	retro_vfs_read_t read;

   /** @copydoc retro_vfs_write_t */
	retro_vfs_write_t write;

   /** @copydoc retro_vfs_flush_t */
	retro_vfs_flush_t flush;

   /** @copydoc retro_vfs_remove_t */
	retro_vfs_remove_t remove;

   /** @copydoc retro_vfs_rename_t */
	retro_vfs_rename_t rename;
   /* VFS API v2 */

   /** @copydoc retro_vfs_truncate_t */
   retro_vfs_truncate_t truncate;
   /* VFS API v3 */

   /** @copydoc retro_vfs_stat_t */
   retro_vfs_stat_t stat;

   /** @copydoc retro_vfs_mkdir_t */
   retro_vfs_mkdir_t mkdir;

   /** @copydoc retro_vfs_opendir_t */
   retro_vfs_opendir_t opendir;

   /** @copydoc retro_vfs_readdir_t */
   retro_vfs_readdir_t readdir;

   /** @copydoc retro_vfs_dirent_get_name_t */
   retro_vfs_dirent_get_name_t dirent_get_name;

   /** @copydoc retro_vfs_dirent_is_dir_t */
   retro_vfs_dirent_is_dir_t dirent_is_dir;

   /** @copydoc retro_vfs_closedir_t */
   retro_vfs_closedir_t closedir;
};

/**
 * Represents a request by the core for the frontend's file system interface,
 * as well as the interface itself returned by the frontend.
 *
 * You do not need to use these functions directly;
 * you may pass this struct to \c dirent_vfs_init,
 * \c filestream_vfs_init, or \c path_vfs_init
 * so that you can use the wrappers provided by these modules.
 *
 * @see dirent_vfs_init
 * @see filestream_vfs_init
 * @see path_vfs_init
 * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE
 */
struct retro_vfs_interface_info
{
   /**
    * The minimum version of the VFS API that the core requires.
    * libretro-common's wrapper API initializers will check this value as well.
    *
    * Set to the core's desired VFS version when requesting an interface,
    * and set by the frontend to indicate its actual API version.
    *
    * If the core asks for a newer VFS API version than the frontend supports,
    * the frontend must return \c false within the \c RETRO_ENVIRONMENT_GET_VFS_INTERFACE call.
    * @since VFS API v1
    */
   uint32_t required_interface_version;

   /**
    * Set by the frontend.
    * The frontend will set this to the VFS interface it provides.
    *
    * The interface is owned by the frontend
    * and must not be modified or freed by the core.
    * @since VFS API v1 */
   struct retro_vfs_interface *iface;
};

/** @} */

/** @defgroup GET_HW_RENDER_INTERFACE Hardware Rendering Interface
 * @{
 */

/**
 * Describes the hardware rendering API supported by
 * a particular subtype of \c retro_hw_render_interface.
 *
 * Not every rendering API supported by libretro has its own interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_interface_type
{
   /**
    * Indicates a \c retro_hw_render_interface for Vulkan.
    * @see retro_hw_render_interface_vulkan
    */
   RETRO_HW_RENDER_INTERFACE_VULKAN     = 0,

   /** Indicates a \c retro_hw_render_interface for Direct3D 9. */
   RETRO_HW_RENDER_INTERFACE_D3D9       = 1,

   /** Indicates a \c retro_hw_render_interface for Direct3D 10. */
   RETRO_HW_RENDER_INTERFACE_D3D10      = 2,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 11.
    * @see retro_hw_render_interface_d3d11
    */
   RETRO_HW_RENDER_INTERFACE_D3D11      = 3,

   /**
    * Indicates a \c retro_hw_render_interface for Direct3D 12.
    * @see retro_hw_render_interface_d3d12
    */
   RETRO_HW_RENDER_INTERFACE_D3D12      = 4,

   /**
    * Indicates a \c retro_hw_render_interface for
    * the PlayStation's 2 PSKit API.
    * @see retro_hw_render_interface_gskit_ps2
    */
   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2  = 5,

   /** @private Defined to ensure &lt;tt&gt;sizeof(retro_hw_render_interface_type) == sizeof(int)&lt;/tt&gt;.
    * Do not use. */
   RETRO_HW_RENDER_INTERFACE_DUMMY      = INT_MAX
};

/**
 * Base render interface type.
 * All \c retro_hw_render_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
struct retro_hw_render_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_interface_type interface_type;

   /**
    * The version of this rendering interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/**
 * @defgroup GET_LED_INTERFACE LED Interface
 * @{
 */

/** @copydoc retro_led_interface::set_led_state */
typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);

/**
 * Interface that the core can use to set the state of available LEDs.
 * @see RETRO_ENVIRONMENT_GET_LED_INTERFACE
 */
struct retro_led_interface
{
   /**
    * Sets the state of an LED.
    *
    * @param led The LED to set the state of.
    * @param state The state to set the LED to.
    * \c true to enable, \c false to disable.
    */
   retro_set_led_state_t set_led_state;
};

/** @} */

/** @defgroup GET_AUDIO_VIDEO_ENABLE Skipped A/V Steps
 * @{
 */

/**
 * Flags that define A/V steps that the core may skip for this frame.
 *
 * @see RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE
 */
enum retro_av_enable_flags
{
   /**
    * If set, the core should render video output with \c retro_video_refresh_t as normal.
    *
    * Otherwise, the frontend will discard any video data received this frame,
    * including frames presented via hardware acceleration.
    * \c retro_video_refresh_t will do nothing.
    *
    * @note After running the frame, the video output of the next frame
    * should be no different than if video was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's graphics pipeline state
    * should not be affected by this flag.
    *
    * @note If emulating a platform that supports display capture
    * (i.e. reading its own VRAM),
    * the core may not be able to completely skip rendering,
    * as the VRAM is part of the graphics pipeline's state.
    */
   RETRO_AV_ENABLE_VIDEO = (1 &lt;&lt; 0),

   /**
    * If set, the core should render audio output
    * with \c retro_audio_sample_t or \c retro_audio_sample_batch_t as normal.
    *
    * Otherwise, the frontend will discard any audio data received this frame.
    * The core should skip audio rendering if possible.
    *
    * @note After running the frame, the audio output of the next frame
    * should be no different than if audio was enabled,
    * and saving and loading state should have no issues.
    * This implies that the emulated console's audio pipeline state
    * should not be affected by this flag.
    */
   RETRO_AV_ENABLE_AUDIO = (1 &lt;&lt; 1),

   /**
    * If set, indicates that any savestates taken this frame
    * are guaranteed to be created by the same binary that will load them,
    * and will not be written to or read from the disk.
    *
    * The core may use these guarantees to:
    *
    * @li Assume that loading state will succeed.
    * @li Update its memory buffers in-place if possible.
    * @li Skip clearing memory.
    * @li Skip resetting the system.
    * @li Skip validation steps.
    *
    * @deprecated Use \c RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT instead,
    * except for compatibility purposes.
    */
   RETRO_AV_ENABLE_FAST_SAVESTATES = (1 &lt;&lt; 2),

   /**
    * If set, indicates that the frontend will never need audio from the core.
    * Used by a frontend for implementing runahead via a secondary core instance.
    *
    * The core may stop synthesizing audio if it can do so
    * without compromising emulation accuracy.
    *
    * Audio output for the next frame does not matter,
    * and the frontend will never need an accurate audio state in the future.
    *
    * State will never be saved while this flag is set.
    */
   RETRO_AV_ENABLE_HARD_DISABLE_AUDIO = (1 &lt;&lt; 3),

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(retro_av_enable_flags) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_AV_ENABLE_DUMMY = INT_MAX
};

/** @} */

/**
 * @defgroup GET_MIDI_INTERFACE MIDI Interface
 * @{
 */

/** @copydoc retro_midi_interface::input_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);

/** @copydoc retro_midi_interface::output_enabled */
typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);

/** @copydoc retro_midi_interface::read */
typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);

/** @copydoc retro_midi_interface::write */
typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);

/** @copydoc retro_midi_interface::flush */
typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);

/**
 * Interface that the core can use for raw MIDI I/O.
 */
struct retro_midi_interface
{
   /**
    * Retrieves the current state of MIDI input.
    *
    * @return \c true if MIDI input is enabled.
    */
   retro_midi_input_enabled_t input_enabled;

   /**
    * Retrieves the current state of MIDI output.
    * @return \c true if MIDI output is enabled.
    */
   retro_midi_output_enabled_t output_enabled;

   /**
    * Reads a byte from the MIDI input stream.
    *
    * @param[out] byte The byte received from the input stream.
    * @return \c true if a byte was read,
    * \c false if MIDI input is disabled or \c byte is \c NULL.
    */
   retro_midi_read_t read;

   /**
    * Writes a byte to the output stream.
    *
    * @param byte The byte to write to the output stream.
    * @param delta_time Time since the previous write, in microseconds.
    * @return \c true if c\ byte was written, false otherwise.
    */
   retro_midi_write_t write;

   /**
    * Flushes previously-written data.
    *
    * @return \c true if successful.
    */
   retro_midi_flush_t flush;
};

/** @} */

/** @defgroup SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE Render Context Negotiation
 * @{
 */

/**
 * Describes the hardware rendering API used by
 * a particular subtype of \c retro_hw_render_context_negotiation_interface.
 *
 * Not every rendering API supported by libretro has a context negotiation interface,
 * or even needs one.
 *
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 */
enum retro_hw_render_context_negotiation_interface_type
{
   /**
    * Denotes a context negotiation interface for Vulkan.
    * @see retro_hw_render_context_negotiation_interface_vulkan
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(retro_hw_render_context_negotiation_interface_type) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX
};

/**
 * Base context negotiation interface type.
 * All \c retro_hw_render_context_negotiation_interface implementations
 * will start with these two fields set to particular values.
 *
 * @see retro_hw_render_interface_type
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER
 * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE
 * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE
 */
struct retro_hw_render_context_negotiation_interface
{
   /**
    * Denotes the particular rendering API that this interface is for.
    * Each interface requires this field to be set to a particular value.
    * Use it to cast this interface to the appropriate pointer.
    */
   enum retro_hw_render_context_negotiation_interface_type interface_type;

   /**
    * The version of this negotiation interface.
    * @note This is not related to the version of the API itself.
    */
   unsigned interface_version;
};

/** @} */

/** @defgroup RETRO_SERIALIZATION_QUIRK Serialization Quirks
 * @{
 */

/**
 * Indicates that serialized state is incomplete in some way.
 *
 * Set if serialization is usable for the common case of saving and loading game state,
 * but should not be relied upon for frame-sensitive frontend features
 * such as netplay or rerecording.
 */
#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 &lt;&lt; 0)

/**
 * Indicates that core must spend some time initializing before serialization can be done.
 *
 * \c retro_serialize(), \c retro_unserialize(), and \c retro_serialize_size() will initially fail.
 */
#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 &lt;&lt; 1)

/** Set by the core to indicate that serialization size may change within a session. */
#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 &lt;&lt; 2)

/** Set by the frontend to acknowledge that it supports variable-sized states. */
#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 &lt;&lt; 3)

/** Serialized state can only be loaded during the same session. */
#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 &lt;&lt; 4)

/**
 * Serialized state cannot be loaded on an architecture
 * with a different endianness from the one it was saved on.
 */
#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 &lt;&lt; 5)

/**
 * Serialized state cannot be loaded on a different platform
 * from the one it was saved on for reasons other than endianness,
 * such as word size dependence.
 */
#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 &lt;&lt; 6)

/** @} */

/** @defgroup SET_MEMORY_MAPS Memory Descriptors
 * @{
 */

/** @defgroup RETRO_MEMDESC Memory Descriptor Flags
 * Information about how the emulated hardware uses this portion of its address space.
 * @{
 */

/**
 * Indicates that this memory area won't be modified
 * once \c retro_load_game has returned.
 */
#define RETRO_MEMDESC_CONST      (1 &lt;&lt; 0)

/**
 * Indicates a memory area with big-endian byte ordering,
 * as opposed to the default of little-endian.
 */
#define RETRO_MEMDESC_BIGENDIAN  (1 &lt;&lt; 1)

/**
 * Indicates a memory area that is used for the emulated system's main RAM.
 */
#define RETRO_MEMDESC_SYSTEM_RAM (1 &lt;&lt; 2)

/**
 * Indicates a memory area that is used for the emulated system's save RAM,
 * usually found on a game cartridge as battery-backed RAM or flash memory.
 */
#define RETRO_MEMDESC_SAVE_RAM   (1 &lt;&lt; 3)

/**
 * Indicates a memory area that is used for the emulated system's video RAM,
 * usually found on a console's GPU (or local equivalent).
 */
#define RETRO_MEMDESC_VIDEO_RAM  (1 &lt;&lt; 4)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 2 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_2    (1 &lt;&lt; 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 4 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_4    (2 &lt;&lt; 16)

/**
 * Indicates a memory area that requires all accesses
 * to be aligned to 8 bytes or their own size
 * (whichever is smaller).
 */
#define RETRO_MEMDESC_ALIGN_8    (3 &lt;&lt; 16)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 2 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_2  (1 &lt;&lt; 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 4 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_4  (2 &lt;&lt; 24)

/**
 * Indicates a memory area that requires all accesses
 * to be at least 8 bytes long.
 */
#define RETRO_MEMDESC_MINSIZE_8  (3 &lt;&lt; 24)

/** @} */

/**
 * A mapping from a region of the emulated console's address space
 * to the host's address space.
 *
 * Can be used to map an address in the console's address space
 * to the host's address space, like so:
 *
 * @code
 * void* emu_to_host(void* addr, struct retro_memory_descriptor* descriptor)
 * {
 *     return descriptor-&gt;ptr + (addr &amp; ~descriptor-&gt;disconnect) - descriptor-&gt;start;
 * }
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_descriptor
{
   /**
    * A bitwise \c OR of one or more \ref RETRO_MEMDESC "flags"
    * that describe how the emulated system uses this descriptor's address range.
    *
    * @note If \c ptr is \c NULL,
    * then no flags should be set.
    * @see RETRO_MEMDESC
    */
   uint64_t flags;

   /**
    * Pointer to the start of this memory region's buffer
    * within the \em host's address space.
    * The address listed here must be valid for the duration of the session;
    * it must not be freed or modified by the frontend
    * and it must not be moved by the core.
    *
    * May be \c NULL to indicate a lack of accessible memory
    * at the emulated address given in \c start.
    *
    * @note Overlapping descriptors that include the same byte
    * must have the same \c ptr value.
    */
   void *ptr;

   /**
    * The offset of this memory region,
    * relative to the address given by \c ptr.
    *
    * @note It is recommended to use this field for address calculations
    * instead of performing arithmetic on \c ptr.
    */
   size_t offset;

   /**
    * The starting address of this memory region
    * &lt;em&gt;within the emulated hardware's address space&lt;/em&gt;.
    *
    * @note Not represented as a pointer
    * because it's unlikely to be valid on the host device.
    */
   size_t start;

   /**
    * A bitmask that specifies which bits of an address must match
    * the bits of the \ref start address.
    *
    * Combines with \c disconnect to map an address to a memory block.
    *
    * If multiple memory descriptors can claim a particular byte,
    * the first one defined in the \ref retro_memory_descriptor array applies.
    * A bit which is set in \c start must also be set in this.
    *
    * Can be zero, in which case \c start and \c len represent
    * the complete mapping for this region of memory
    * (i.e. each byte is mapped exactly once).
    * In this case, \c len must be a power of two.
    */
   size_t select;

   /**
    * A bitmask of bits that are \em not used for addressing.
    *
    * Any set bits are assumed to be disconnected from
    * the emulated memory chip's address pins,
    * and are therefore ignored when memory-mapping.
    */
   size_t disconnect;

   /**
    * The length of this memory region, in bytes.
    *
    * If applying \ref start and \ref disconnect to an address
    * results in a value higher than this,
    * the highest bit of the address is cleared.
    *
    * If the address is still too high, the next highest bit is cleared.
    * Can be zero, in which case it's assumed to be
    * bounded only by \ref select and \ref disconnect.
    */
   size_t len;

   /**
    * A short name for this address space.
    *
    * Names must meet the following requirements:
    *
    * \li Characters must be in the set &lt;tt&gt;[a-zA-Z0-9_-]&lt;/tt&gt;.
    * \li No more than 8 characters, plus a \c NULL terminator.
    * \li Names are case-sensitive, but lowercase characters are discouraged.
    * \li A name must not be the same as another name plus a character in the set \c [A-F0-9]
    *     (i.e. if an address space named "RAM" exists,
    *     then the names "RAM0", "RAM1", ..., "RAMF" are forbidden).
    *     This is to allow addresses to be named by each descriptor unambiguously,
    *     even if the areas overlap.
    * \li May be \c NULL or empty (both are considered equivalent).
    *
    * Here are some examples of pairs of address space names:
    *
    * \li \em blank + \em blank: valid (multiple things may be mapped in the same namespace)
    * \li \c Sp + \c Sp: valid (multiple things may be mapped in the same namespace)
    * \li \c SRAM + \c VRAM: valid (neither is a prefix of the other)
    * \li \c V + \em blank: valid (\c V is not in \c [A-F0-9])
    * \li \c a + \em blank: valid but discouraged (\c a is not in \c [A-F0-9])
    * \li \c a + \c A: valid but discouraged (neither is a prefix of the other)
    * \li \c AR + \em blank: valid (\c R is not in \c [A-F0-9])
    * \li \c ARB + \em blank: valid (there's no \c AR namespace,
    *     so the \c B doesn't cause ambiguity).
    * \li \em blank + \c B: invalid, because it's ambiguous which address space \c B1234 would refer to.
    *
    * The length of the address space's name can't be used to disambugiate,
    * as extra information may be appended to it without a separator.
    */
   const char *addrspace;

   /* TODO: When finalizing this one, add a description field, which should be
    * "WRAM" or something roughly equally long. */

   /* TODO: When finalizing this one, replace 'select' with 'limit', which tells
    * which bits can vary and still refer to the same address (limit = ~select).
    * TODO: limit? range? vary? something else? */

   /* TODO: When finalizing this one, if 'len' is above what 'select' (or
    * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'
    * and 'select' != 0, and the mappings don't tell how the system switches the
    * banks. */

   /* TODO: When finalizing this one, fix the 'len' bit removal order.
    * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.
    * Algorithm: Take bits highest to lowest, but if it goes above len, clear
    * the most recent addition and continue on the next bit.
    * TODO: Can the above be optimized? Is "remove the lowest bit set in both
    * pointer and 'len'" equivalent? */

   /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing
    * the emulated memory in 32-bit chunks, native endian. But that's nothing
    * compared to Darek Mihocka &lt;http://www.emulators.com/docs/nx07_vm101.htm&gt;
    * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE
    * RAM backwards! I'll want to represent both of those, via some flags.
    *
    * I suspect MAME either didn't think of that idea, or don't want the #ifdef.
    * Not sure which, nor do I really care. */

   /* TODO: Some of those flags are unused and/or don't really make sense. Clean
    * them up. */
};

/**
 * A list of regions within the emulated console's address space.
 *
 * The frontend may use the largest value of
 * \ref retro_memory_descriptor::start + \ref retro_memory_descriptor::select
 * in a certain namespace to infer the overall size of the address space.
 * If the address space is larger than that,
 * the last mapping in \ref descriptors should have \ref retro_memory_descriptor::ptr set to \c NULL
 * and \ref retro_memory_descriptor::select should have all bits used in the address space set to 1.
 *
 * Here's an example set of descriptors for the SNES.
 *
 * @code{.c}
 * struct retro_memory_map snes_descriptors = retro_memory_map
 * {
 *    .descriptors = (struct retro_memory_descriptor[])
 *    {
 *       // WRAM; must usually be mapped before the ROM,
 *       // as some SNES ROM mappers try to claim 0x7E0000
 *       { .addrspace="WRAM", .start=0x7E0000, .len=0x20000 },
 *
 *       // SPC700 RAM
 *       { .addrspace="SPC700", .len=0x10000 },
 *
 *       // WRAM mirrors
 *       { .addrspace="WRAM", .start=0x000000, .select=0xC0E000, .len=0x2000 },
 *       { .addrspace="WRAM", .start=0x800000, .select=0xC0E000, .len=0x2000 },
 *
 *       // WRAM mirror, alternate equivalent descriptor
 *       // (Various similar constructions can be created by combining parts of the above two.)
 *       { .addrspace="WRAM", .select=0x40E000, .disconnect=~0x1FFF },
 *
 *       // LoROM (512KB, mirrored a couple of times)
 *       { .addrspace="LoROM", .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="LoROM", .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },
 *
 *       // HiROM (4MB)
 *       { .addrspace="HiROM", .start=0x400000, .select=0x400000, .len=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="HiROM", .start=0x008000, .select=0x408000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // ExHiROM (8MB)
 *       { .addrspace="ExHiROM", .start=0xC00000, .select=0xC00000, .len=4*1024*1024, .offset=0, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x400000, .select=0xC00000, .len=4*1024*1024, .offset=4*1024*1024, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x808000, .select=0xC08000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },
 *       { .addrspace="ExHiROM", .start=0x008000, .select=0xC08000, .len=4*1024*1024, .offset=4*1024*1024+0x8000, .flags=RETRO_MEMDESC_CONST },
 *
 *       // Clarifying the full size of the address space
 *       { .select=0xFFFFFF, .ptr=NULL },
 *    },
 *    .num_descriptors = 14,
 * };
 * @endcode
 *
 * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS
 */
struct retro_memory_map
{
   /**
    * Pointer to an array of memory descriptors,
    * each of which describes part of the emulated console's address space.
    */
   const struct retro_memory_descriptor *descriptors;

   /** The number of descriptors in \c descriptors. */
   unsigned num_descriptors;
};

/** @} */

/** @defgroup SET_CONTROLLER_INFO Controller Info
 * @{
 */

/**
 * Details about a controller (or controller configuration)
 * supported by one of a core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_description
{
   /**
    * A human-readable label for the controller or configuration
    * represented by this device type.
    * Most likely the device's original brand name.
    */
   const char *desc;

   /**
    * A unique identifier that will be passed to \c retro_set_controller_port_device()'s \c device parameter.
    * May be the ID of one of \ref RETRO_DEVICE "the generic controller types",
    * or a subclass ID defined with \c RETRO_DEVICE_SUBCLASS.
    *
    * @see RETRO_DEVICE_SUBCLASS
    */
   unsigned id;
};

/**
 * Lists the types of controllers supported by
 * one of core's emulated input ports.
 *
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
struct retro_controller_info
{

   /**
    * A pointer to an array of device types supported by this controller port.
    *
    * @note Ports that support the same devices
    * may share the same underlying array.
    */
   const struct retro_controller_description *types;

   /** The number of elements in \c types. */
   unsigned num_types;
};

/** @} */

/** @defgroup SET_SUBSYSTEM_INFO Subsystems
 * @{
 */

/**
 * Information about a type of memory associated with a subsystem.
 * Usually used for SRAM (save RAM).
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_get_memory_data
 * @see retro_get_memory_size
 */
struct retro_subsystem_memory_info
{
   /**
    * The file extension the frontend should use
    * to save this memory region to disk, e.g. "srm" or "sav".
    */
   const char *extension;

   /**
    * A constant that identifies this type of memory.
    * Should be at least 0x100 (256) to avoid conflict
    * with the standard libretro memory types,
    * unless a subsystem uses the main platform's memory region.
    * @see RETRO_MEMORY
    */
   unsigned type;
};

/**
 * Information about a type of ROM that a subsystem may use.
 * Subsystems may use one or more ROMs at once,
 * possibly of different types.
 *
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_subsystem_info
 */
struct retro_subsystem_rom_info
{
   /**
    * Human-readable description of what the content represents,
    * e.g. "Game Boy ROM".
    */
   const char *desc;

   /** @copydoc retro_system_info::valid_extensions */
   const char *valid_extensions;

   /** @copydoc retro_system_info::need_fullpath */
   bool need_fullpath;

   /** @copydoc retro_system_info::block_extract */
   bool block_extract;

   /**
    * Indicates whether this particular subsystem ROM is required.
    * If \c true and the user doesn't provide a ROM,
    * the frontend should not load the core.
    * If \c false and the user doesn't provide a ROM,
    * the frontend should pass a zeroed-out \c retro_game_info
    * to the corresponding entry in \c retro_load_game_special().
    */
   bool required;

   /**
    * Pointer to an array of memory descriptors that this subsystem ROM type uses.
    * Useful for secondary cartridges that have their own save data.
    * May be \c NULL, in which case this subsystem ROM's memory is not persisted by the frontend
    * and \c num_memory should be zero.
    */
   const struct retro_subsystem_memory_info *memory;

   /** The number of elements in the array pointed to by \c memory. */
   unsigned num_memory;
};

/**
 * Information about a secondary platform that a core supports.
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 */
struct retro_subsystem_info
{
   /**
    * A human-readable description of the subsystem type,
    * usually the brand name of the original platform
    * (e.g. "Super Game Boy").
    */
   const char *desc;

   /**
    * A short machine-friendly identifier for the subsystem,
    * usually an abbreviation of the platform name.
    * For example, a Super Game Boy subsystem for a SNES core
    * might use an identifier of "sgb".
    * This identifier can be used for command-line interfaces,
    * configuration, or other purposes.
    * Must use lower-case alphabetical characters only (i.e. from a-z).
    */
   const char *ident;

   /**
    * The list of ROM types that this subsystem may use.
    *
    * The first entry is considered to be the "most significant" content,
    * for the purposes of the frontend's categorization.
    * E.g. with Super GameBoy, the first content should be the GameBoy ROM,
    * as it is the most "significant" content to a user.
    *
    * If a frontend creates new files based on the content used (e.g. for savestates),
    * it should derive the filenames from the name of the first ROM in this list.
    *
    * @note \c roms can have a single element,
    * but this is usually a sign that the core should broaden its
    * primary system info instead.
    *
    * @see \c retro_system_info
    */
   const struct retro_subsystem_rom_info *roms;

   /** The length of the array given in \c roms. */
   unsigned num_roms;

   /** A unique identifier passed to retro_load_game_special(). */
   unsigned id;
};

/** @} */

/** @defgroup SET_PROC_ADDRESS_CALLBACK Core Function Pointers
 * @{ */

/**
 * The function pointer type that \c retro_get_proc_address_t returns.
 *
 * Despite the signature shown here, the original function may include any parameters and return type
 * that respects the calling convention and C ABI.
 *
 * The frontend is expected to cast the function pointer to the correct type.
 */
typedef void (RETRO_CALLCONV *retro_proc_address_t)(void);

/**
 * Get a symbol from a libretro core.
 *
 * Cores should only return symbols that serve as libretro extensions.
 * Frontends should not use this to obtain symbols to standard libretro entry points;
 * instead, they should link to the core statically or use \c dlsym (or local equivalent).
 *
 * The symbol name must be equal to the function name.
 * e.g. if &lt;tt&gt;void retro_foo(void);&lt;/tt&gt; exists, the symbol in the compiled library must be called \c retro_foo.
 * The returned function pointer must be cast to the corresponding type.
 *
 * @param \c sym The name of the symbol to look up.
 * @return Pointer to the exposed function with the name given in \c sym,
 * or \c NULL if one couldn't be found.
 * @note The frontend is expected to know the returned pointer's type in advance
 * so that it can be cast correctly.
 * @note The core doesn't need to expose every possible function through this interface.
 * It's enough to only expose the ones that it expects the frontend to use.
 * @note The functions exposed through this interface
 * don't need to be publicly exposed in the compiled library
 * (e.g. via \c __declspec(dllexport)).
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);

/**
 * An interface that the frontend can use to get function pointers from the core.
 *
 * @note The returned function pointer will be invalidated once the core is unloaded.
 * How and when that happens is up to the frontend.
 *
 * @see retro_get_proc_address_t
 * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK
 */
struct retro_get_proc_address_interface
{
   /** Set by the core. */
   retro_get_proc_address_t get_proc_address;
};

/** @} */

/** @defgroup GET_LOG_INTERFACE Logging
 * @{
 */

/**
 * The severity of a given message.
 * The frontend may log messages differently depending on the level.
 * It may also ignore log messages of a certain level.
 * @see retro_log_callback
 */
enum retro_log_level
{
   /** The logged message is most likely not interesting to the user. */
   RETRO_LOG_DEBUG = 0,

   /** Information about the core operating normally. */
   RETRO_LOG_INFO,

   /** Indicates a potential problem, possibly one that the core can recover from. */
   RETRO_LOG_WARN,

   /** Indicates a degraded experience, if not failure. */
   RETRO_LOG_ERROR,

   /** Defined to ensure that sizeof(enum retro_log_level) == sizeof(int). Do not use. */
   RETRO_LOG_DUMMY = INT_MAX
};

/**
 * Logs a message to the frontend.
 *
 * @param level The log level of the message.
 * @param fmt The format string to log.
 * Same format as \c printf.
 * Behavior is undefined if this is \c NULL.
 * @param ... Zero or more arguments used by the format string.
 * Behavior is undefined if these don't match the ones expected by \c fmt.
 * @see retro_log_level
 * @see retro_log_callback
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 * @see printf
 */
typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,
      const char *fmt, ...);

/**
 * Details about how to make log messages.
 *
 * @see retro_log_printf_t
 * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE
 */
struct retro_log_callback
{
   /**
    * Called when logging a message.
    *
    * @note Set by the frontend.
    */
   retro_log_printf_t log;
};

/** @} */

/** @defgroup GET_PERF_INTERFACE Performance Interface
 * @{
 */

/** @defgroup RETRO_SIMD CPU Features
 * @{
 */

/**
 * Indicates CPU support for the SSE instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE
 */
#define RETRO_SIMD_SSE      (1 &lt;&lt; 0)

/**
 * Indicates CPU support for the SSE2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE2
 */
#define RETRO_SIMD_SSE2     (1 &lt;&lt; 1)

/** Indicates CPU support for the AltiVec (aka VMX or Velocity Engine) instruction set. */
#define RETRO_SIMD_VMX      (1 &lt;&lt; 2)

/** Indicates CPU support for the VMX128 instruction set. Xbox 360 only. */
#define RETRO_SIMD_VMX128   (1 &lt;&lt; 3)

/**
 * Indicates CPU support for the AVX instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX
 */
#define RETRO_SIMD_AVX      (1 &lt;&lt; 4)

/**
 * Indicates CPU support for the NEON instruction set.
 * @see https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[Neon]
 */
#define RETRO_SIMD_NEON     (1 &lt;&lt; 5)

/**
 * Indicates CPU support for the SSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE3
 */
#define RETRO_SIMD_SSE3     (1 &lt;&lt; 6)

/**
 * Indicates CPU support for the SSSE3 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSSE3
 */
#define RETRO_SIMD_SSSE3    (1 &lt;&lt; 7)

/**
 * Indicates CPU support for the MMX instruction set.
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=MMX
 */
#define RETRO_SIMD_MMX      (1 &lt;&lt; 8)

/** Indicates CPU support for the MMXEXT instruction set. */
#define RETRO_SIMD_MMXEXT   (1 &lt;&lt; 9)

/**
 * Indicates CPU support for the SSE4 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_1
 */
#define RETRO_SIMD_SSE4     (1 &lt;&lt; 10)

/**
 * Indicates CPU support for the SSE4.2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_2
 */
#define RETRO_SIMD_SSE42    (1 &lt;&lt; 11)

/**
 * Indicates CPU support for the AVX2 instruction set.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX2
 */
#define RETRO_SIMD_AVX2     (1 &lt;&lt; 12)

/** Indicates CPU support for the VFPU instruction set. PS2 and PSP only.
 *
 * @see https://pspdev.github.io/vfpu-docs
 */
#define RETRO_SIMD_VFPU     (1 &lt;&lt; 13)

/**
 * Indicates CPU support for Gekko SIMD extensions. GameCube only.
 */
#define RETRO_SIMD_PS       (1 &lt;&lt; 14)

/**
 * Indicates CPU support for AES instructions.
 *
 * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#aestechs=AES&amp;othertechs=AES
 */
#define RETRO_SIMD_AES      (1 &lt;&lt; 15)

/**
 * Indicates CPU support for the VFPv3 instruction set.
 */
#define RETRO_SIMD_VFPV3    (1 &lt;&lt; 16)

/**
 * Indicates CPU support for the VFPv4 instruction set.
 */
#define RETRO_SIMD_VFPV4    (1 &lt;&lt; 17)

/** Indicates CPU support for the POPCNT instruction. */
#define RETRO_SIMD_POPCNT   (1 &lt;&lt; 18)

/** Indicates CPU support for the MOVBE instruction. */
#define RETRO_SIMD_MOVBE    (1 &lt;&lt; 19)

/** Indicates CPU support for the CMOV instruction. */
#define RETRO_SIMD_CMOV     (1 &lt;&lt; 20)

/** Indicates CPU support for the ASIMD instruction set. */
#define RETRO_SIMD_ASIMD    (1 &lt;&lt; 21)

/** @} */

/**
 * An abstract unit of ticks.
 *
 * Usually nanoseconds or CPU cycles,
 * but it depends on the platform and the frontend.
 */
typedef uint64_t retro_perf_tick_t;

/** Time in microseconds. */
typedef int64_t retro_time_t;

/**
 * A performance counter.
 *
 * Use this to measure the execution time of a region of code.
 * @see retro_perf_callback
 */
struct retro_perf_counter
{
   /**
    * A human-readable identifier for the counter.
    *
    * May be displayed by the frontend.
    * Behavior is undefined if this is \c NULL.
    */
   const char *ident;

   /**
    * The time of the most recent call to \c retro_perf_callback::perf_start
    * on this performance counter.
    *
    * @see retro_perf_start_t
    */
   retro_perf_tick_t start;

   /**
    * The total time spent within this performance counter's measured code,
    * i.e. between calls to \c retro_perf_callback::perf_start and \c retro_perf_callback::perf_stop.
    *
    * Updated after each call to \c retro_perf_callback::perf_stop.
    * @see retro_perf_stop_t
    */
   retro_perf_tick_t total;

   /**
    * The number of times this performance counter has been started.
    *
    * Updated after each call to \c retro_perf_callback::perf_start.
    * @see retro_perf_start_t
    */
   retro_perf_tick_t call_cnt;

   /**
    * \c true if this performance counter has been registered by the frontend.
    * Must be initialized to \c false by the core before registering it.
    * @see retro_perf_register_t
    */
   bool registered;
};

/**
 * @returns The current system time in microseconds.
 * @note Accuracy may vary by platform.
 * The frontend should use the most accurate timer possible.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);

/**
 * @returns The number of ticks since some unspecified epoch.
 * The exact meaning of a "tick" depends on the platform,
 * but it usually refers to nanoseconds or CPU cycles.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);

/**
 * Returns a bitmask of detected CPU features.
 *
 * Use this for runtime dispatching of CPU-specific code.
 *
 * @returns A bitmask of detected CPU features.
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see RETRO_SIMD
 */
typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);

/**
 * Asks the frontend to log or display the state of performance counters.
 * How this is done depends on the frontend.
 * Performance counters can be reviewed manually as well.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 * @see retro_perf_counter
 */
typedef void (RETRO_CALLCONV *retro_perf_log_t)(void);

/**
 * Registers a new performance counter.
 *
 * If \c counter has already been registered beforehand,
 * this function does nothing.
 *
 * @param counter The counter to register.
 * \c counter::ident must be set to a unique identifier,
 * and all other values in \c counter must be set to zero or \c false.
 * Behavior is undefined if \c NULL.
 * @post If \c counter is successfully registered,
 * then \c counter::registered will be set to \c true.
 * Otherwise, it will be set to \c false.
 * Registration may fail if the frontend's maximum number of counters (if any) has been reached.
 * @note The counter is owned by the core and must not be freed by the frontend.
 * The frontend must also clean up any references to a core's performance counters
 * before unloading it, otherwise undefined behavior may occur.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);

/**
 * Starts a registered performance counter.
 *
 * Call this just before the code you want to measure.
 *
 * @param counter The counter to start.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);

/**
 * Stops a registered performance counter.
 *
 * Call this just after the code you want to measure.
 *
 * @param counter The counter to stop.
 * Behavior is undefined if \c NULL.
 * @see retro_perf_start_t
 * @see retro_perf_stop_t
 */
typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);

/**
 * An interface that the core can use to get performance information.
 *
 * Here's a usage example:
 *
 * @code{.c}
 * #ifdef PROFILING
 * // Wrapper macros to simplify using performance counters.
 * // Optional; tailor these to your project's needs.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&amp;(name))
 * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&amp;(name))
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&amp;(name))
 * #else
 * // Exclude the performance counters if profiling is disabled.
 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_START(perf_cb, name) ((void)0)
 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) ((void)0)
 * #endif
 *
 * // Defined somewhere else in the core.
 * extern struct retro_perf_callback perf_cb;
 *
 * void retro_run(void)
 * {
 *    RETRO_PERFORMANCE_INIT(cb, interesting);
 *    RETRO_PERFORMANCE_START(cb, interesting);
 *    interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, interesting);
 *
 *    RETRO_PERFORMANCE_INIT(cb, maybe_slow);
 *    RETRO_PERFORMANCE_START(cb, maybe_slow);
 *    more_interesting_work();
 *    RETRO_PERFORMANCE_STOP(cb, maybe_slow);
 * }
 *
 * void retro_deinit(void)
 * {
 *    // Asks the frontend to log the results of all performance counters.
 *    perf_cb.perf_log();
 * }
 * @endcode
 *
 * All functions are set by the frontend.
 *
 * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE
 */
struct retro_perf_callback
{
   /** @copydoc retro_perf_get_time_usec_t */
   retro_perf_get_time_usec_t    get_time_usec;

   /** @copydoc retro_perf_get_counter_t */
   retro_get_cpu_features_t      get_cpu_features;

   /** @copydoc retro_perf_get_counter_t */
   retro_perf_get_counter_t      get_perf_counter;

   /** @copydoc retro_perf_register_t */
   retro_perf_register_t         perf_register;

   /** @copydoc retro_perf_start_t */
   retro_perf_start_t            perf_start;

   /** @copydoc retro_perf_stop_t */
   retro_perf_stop_t             perf_stop;

   /** @copydoc retro_perf_log_t */
   retro_perf_log_t              perf_log;
};

/** @} */

/**
 * @defgroup RETRO_SENSOR Sensor Interface
 * @{
 */

/**
 * Defines actions that can be performed on sensors.
 * @note Cores should only enable sensors while they're actively being used;
 * depending on the frontend and platform,
 * enabling these sensors may impact battery life.
 *
 * @see RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE
 * @see retro_sensor_interface
 * @see retro_set_sensor_state_t
 */
enum retro_sensor_action
{
   /** Enables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,

   /** Disables accelerometer input, if one exists. */
   RETRO_SENSOR_ACCELEROMETER_DISABLE,

   /** Enables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_ENABLE,

   /** Disables gyroscope input, if one exists. */
   RETRO_SENSOR_GYROSCOPE_DISABLE,

   /** Enables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_ENABLE,

   /** Disables ambient light input, if a luminance sensor exists. */
   RETRO_SENSOR_ILLUMINANCE_DISABLE,

   /** @private Defined to ensure &lt;tt&gt;sizeof(enum retro_sensor_action) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_SENSOR_DUMMY = INT_MAX
};

/** @defgroup RETRO_SENSOR_ID Sensor Value IDs
 * @{
 */
/* Id values for SENSOR types. */

/**
 * Returns the device's acceleration along its local X axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating to the right.
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_X 0

/**
 * Returns the device's acceleration along its local Y axis minus the effect of gravity, in m/s^2.
 *
 * Positive values mean that the device is accelerating upwards,
 * assuming the user is looking at it head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Y 1

/**
 * Returns the the device's acceleration along its local Z axis minus the effect of gravity, in m/s^2.
 *
 * Positive values indicate forward acceleration towards the user,
 * assuming the user is looking at the device head-on.
 */
#define RETRO_SENSOR_ACCELEROMETER_Z 2

/**
 * Returns the angular velocity of the device around its local X axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_X 3

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Y 4

/**
 * Returns the angular velocity of the device around its local Z axis, in radians per second.
 *
 * Positive values indicate counter-clockwise rotation.
 *
 * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.
 * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope
 * for guidance on using this value to derive a device's orientation.
 */
#define RETRO_SENSOR_GYROSCOPE_Z 5

/**
 * Returns the ambient illuminance (light intensity) of the device's environment, in lux.
 *
 * @see https://en.wikipedia.org/wiki/Lux for a table of common lux values.
 */
#define RETRO_SENSOR_ILLUMINANCE 6
/** @} */

/**
 * Adjusts the state of a sensor.
 *
 * @param port The device port of the controller that owns the sensor given in \c action.
 * @param action The action to perform on the sensor.
 * Different devices support different sensors.
 * @param rate The rate at which the underlying sensor should be updated, in Hz.
 * This should be treated as a hint,
 * as some device sensors may not support the requested rate
 * (if it's configurable at all).
 * @returns \c true if the sensor state was successfully adjusted, \c false otherwise.
 * @note If one of the \c RETRO_SENSOR_*_ENABLE actions fails,
 * this likely means that the given sensor is not available
 * on the provided \c port.
 * @see retro_sensor_action
 */
typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
      enum retro_sensor_action action, unsigned rate);

/**
 * Retrieves the current value reported by sensor.
 * @param port The device port of the controller that owns the sensor given in \c id.
 * @param id The sensor value to query.
 * @returns The current sensor value.
 * Exact semantics depend on the value given in \c id,
 * but will return 0 for invalid arguments.
 *
 * @see RETRO_SENSOR_ID
 */
typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);

/**
 * An interface that cores can use to access device sensors.
 *
 * All function pointers are set by the frontend.
 */
struct retro_sensor_interface
{
   /** @copydoc retro_set_sensor_state_t */
   retro_set_sensor_state_t set_sensor_state;

   /** @copydoc retro_sensor_get_input_t */
   retro_sensor_get_input_t get_sensor_input;
};

/** @} */

/** @defgroup GET_CAMERA_INTERFACE Camera Interface
 * @{
 */

/**
 * Denotes the type of buffer in which the camera will store its input.
 *
 * Different camera drivers may support different buffer types.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 * @see retro_camera_callback
 */
enum retro_camera_buffer
{
   /**
    * Indicates that camera frames should be delivered to the core as an OpenGL texture.
    *
    * Requires that the core is using an OpenGL context via \c RETRO_ENVIRONMENT_SET_HW_RENDER.
    *
    * @see retro_camera_frame_opengl_texture_t
    */
   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,

   /**
    * Indicates that camera frames should be delivered to the core as a raw buffer in memory.
    *
    * @see retro_camera_frame_raw_framebuffer_t
    */
   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(enum retro_camera_buffer) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
};

/**
 * Starts an initialized camera.
 * The camera is disabled by default,
 * and must be enabled with this function before being used.
 *
 * Set by the frontend.
 *
 * @returns \c true if the camera was successfully started, \c false otherwise.
 * Failure may occur if no actual camera is available,
 * or if the frontend doesn't have permission to access it.
 * @note Must be called in \c retro_run().
 * @see retro_camera_callback
 */
typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);

/**
 * Stops the running camera.
 *
 * Set by the frontend.
 *
 * @note Must be called in \c retro_run().
 * @warning The frontend may close the camera on its own when unloading the core,
 * but this behavior is not guaranteed.
 * Cores should clean up the camera before exiting.
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);

/**
 * Called by the frontend to report the state of the camera driver.
 *
 * @see retro_camera_callback
 */
typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as a raw buffer in memory.
 *
 * Set by the core.
 *
 * @param buffer Pointer to the camera's most recent video frame.
 * Each pixel is in XRGB8888 format.
 * The first pixel represents the top-left corner of the image
 * (i.e. the Y axis goes downward).
 * @param width The width of the frame given in \c buffer, in pixels.
 * @param height The height of the frame given in \c buffer, in pixels.
 * @param pitch The width of the frame given in \c buffer, in bytes.
 * @warning \c buffer may be invalidated when this function returns,
 * so the core should make its own copy of \c buffer if necessary.
 * @see RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
      unsigned width, unsigned height, size_t pitch);

/**
 * Called by the frontend to report a new camera frame,
 * delivered as an OpenGL texture.
 *
 * @param texture_id The ID of the OpenGL texture that represents the camera's most recent frame.
 * Owned by the frontend, and must not be modified by the core.
 * @param texture_target The type of the texture given in \c texture_id.
 * Usually either \c GL_TEXTURE_2D or \c GL_TEXTURE_RECTANGLE,
 * but other types are allowed.
 * @param affine A pointer to a 3x3 column-major affine matrix
 * that can be used to transform pixel coordinates to texture coordinates.
 * After transformation, the bottom-left corner should have coordinates of &lt;tt&gt;(0, 0)&lt;/tt&gt;
 * and the top-right corner should have coordinates of &lt;tt&gt;(1, 1)&lt;/tt&gt;
 * (or &lt;tt&gt;(width, height)&lt;/tt&gt; for \c GL_TEXTURE_RECTANGLE).
 *
 * @note GL-specific typedefs (e.g. \c GLfloat and \c GLuint) are avoided here
 * so that the API doesn't rely on gl.h.
 * @warning \c texture_id and \c affine may be invalidated when this function returns,
 * so the core should make its own copy of them if necessary.
 */
typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,
      unsigned texture_target, const float *affine);

/**
 * An interface that the core can use to access a device's camera.
 *
 * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE
 */
struct retro_camera_callback
{
   /**
    * Requested camera capabilities,
    * given as a bitmask of \c retro_camera_buffer values.
    * Set by the core.
    *
    * Here's a usage example:
    * @code
    * // Requesting support for camera data delivered as both an OpenGL texture and a pixel buffer:
    * struct retro_camera_callback callback;
    * callback.caps = (1 &lt;&lt; RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 &lt;&lt; RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);
    * @endcode
    */
   uint64_t caps;

   /**
    * The desired width of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
    * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned width;

   /**
    * The desired height of the camera frame, in pixels.
    * This is only a hint; the frontend may provide a different size.
     * Set by the core.
    * Use zero to let the frontend decide.
    */
   unsigned height;

   /**
    * @copydoc retro_camera_start_t
    * @see retro_camera_callback
    */
   retro_camera_start_t start;

   /**
    * @copydoc retro_camera_stop_t
    * @see retro_camera_callback
    */
   retro_camera_stop_t stop;

   /**
    * @copydoc retro_camera_frame_raw_framebuffer_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;

   /**
    * @copydoc retro_camera_frame_opengl_texture_t
    * @note If \c NULL, this function will not be called.
    */
   retro_camera_frame_opengl_texture_t frame_opengl_texture;

   /**
    * Core-defined callback invoked by the frontend right after the camera driver is initialized
    * (\em not when calling \c start).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t initialized;

   /**
    * Core-defined callback invoked by the frontend
    * right before the video camera driver is deinitialized
    * (\em not when calling \c stop).
    * May be \c NULL, in which case this function is skipped.
    */
   retro_camera_lifetime_status_t deinitialized;
};

/** @} */

/** @defgroup GET_LOCATION_INTERFACE Location Interface
 * @{
 */

/** @copydoc retro_location_callback::set_interval */
typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,
      unsigned interval_distance);

/** @copydoc retro_location_callback::start */
typedef bool (RETRO_CALLCONV *retro_location_start_t)(void);

/** @copydoc retro_location_callback::stop */
typedef void (RETRO_CALLCONV *retro_location_stop_t)(void);

/** @copydoc retro_location_callback::get_position */
typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,
      double *horiz_accuracy, double *vert_accuracy);

/** Function type that reports the status of the location service. */
typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);

/**
 * An interface that the core can use to access a device's location.
 *
 * @note It is the frontend's responsibility to request the necessary permissions
 * from the operating system.
 * @see RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE
 */
struct retro_location_callback
{
   /**
    * Starts listening the device's location service.
    *
    * The frontend will report changes to the device's location
    * at the interval defined by \c set_interval.
    * Set by the frontend.
    *
    * @return true if location services were successfully started, false otherwise.
    * Note that this will return \c false if location services are disabled
    * or the frontend doesn't have permission to use them.
    * @note The device's location service may or may not have been enabled
    * before the core calls this function.
    */
   retro_location_start_t         start;

   /**
    * Stop listening to the device's location service.
    *
    * Set by the frontend.
    *
    * @note The location service itself may or may not
    * be turned off by this function,
    * depending on the platform and the frontend.
    * @post The core will stop receiving location service updates.
    */
   retro_location_stop_t          stop;

   /**
    * Returns the device's current coordinates.
    *
    * Set by the frontend.
    *
    * @param[out] lat Pointer to latitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] lon Pointer to longitude, in degrees.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] horiz_accuracy Pointer to horizontal accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    * @param[out] vert_accuracy Pointer to vertical accuracy.
    * Will be set to 0 if no change has occurred since the last call.
    * Behavior is undefined if \c NULL.
    */
   retro_location_get_position_t  get_position;

   /**
    * Sets the rate at which the location service should report updates.
    *
    * This is only a hint; the actual rate may differ.
    * Sets the interval of time and/or distance at which to update/poll
    * location-based data.
    *
    * Some platforms may only support one of the two parameters;
    * cores should provide both to ensure compatibility.
    *
    * Set by the frontend.
    *
    * @param interval_ms The desired period of time between location updates, in milliseconds.
    * @param interval_distance The desired distance between location updates, in meters.
    */
   retro_location_set_interval_t  set_interval;

   /** Called when the location service is initialized. Set by the core. Optional. */
   retro_location_lifetime_status_t initialized;

   /** Called when the location service is deinitialized. Set by the core. Optional. */
   retro_location_lifetime_status_t deinitialized;
};

/** @} */

/** @addtogroup GET_RUMBLE_INTERFACE
 * @{ */

/**
 * The type of rumble motor in a controller.
 *
 * Both motors can be controlled independently,
 * and the strong motor does not override the weak motor.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
enum retro_rumble_effect
{
   RETRO_RUMBLE_STRONG = 0,
   RETRO_RUMBLE_WEAK = 1,

   /** @private Defined to ensure &lt;tt&gt;sizeof(enum retro_rumble_effect) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_RUMBLE_DUMMY = INT_MAX
};

/**
 * Requests a rumble state change for a controller.
 * Set by the frontend.
 *
 * @param port The controller port to set the rumble state for.
 * @param effect The rumble motor to set the strength of.
 * @param strength The desired intensity of the rumble motor, ranging from \c 0 to \c 0xffff (inclusive).
 * @return \c true if the requested rumble state was honored.
 * If the controller doesn't support rumble, will return \c false.
 * @note Calling this before the first \c retro_run() may return \c false.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,
      enum retro_rumble_effect effect, uint16_t strength);

/**
 * An interface that the core can use to set the rumble state of a controller.
 * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE
 */
struct retro_rumble_interface
{
   /** @copydoc retro_set_rumble_state_t */
   retro_set_rumble_state_t set_rumble_state;
};

/** @} */

/**
 * Called by the frontend to request audio samples.
 * The core should render audio within this function
 * using the callback provided by \c retro_set_audio_sample or \c retro_set_audio_sample_batch.
 *
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_sample_batch_t
 * @see retro_audio_sample_t
 */
typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);

/**
 * Called by the frontend to notify the core that it should pause or resume audio rendering.
 * The initial state of the audio driver after registering this callback is \c false (inactive).
 *
 * @param enabled \c true if the frontend's audio driver is active.
 * If so, the registered audio callback will be called regularly.
 * If not, the audio callback will not be invoked until the next time
 * the frontend calls this function with \c true.
 * @warning This function may be called by any thread,
 * therefore it must be thread-safe.
 * @note Even if no audio samples are rendered,
 * the core should continue to update its emulated platform's audio engine if necessary.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 * @see retro_audio_callback
 * @see retro_audio_callback_t
 */
typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);

/**
 * An interface that the frontend uses to request audio samples from the core.
 * @note To unregister a callback, pass a \c retro_audio_callback_t
 * with both fields set to &lt;tt&gt;NULL&lt;/tt&gt;.
 * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK
 */
struct retro_audio_callback
{
   /** @see retro_audio_callback_t */
   retro_audio_callback_t callback;

   /** @see retro_audio_set_state_callback_t */
   retro_audio_set_state_callback_t set_state;
};

typedef int64_t retro_usec_t;

/**
 * Called right before each iteration of \c retro_run
 * if registered via &lt;tt&gt;RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK&lt;/tt&gt;.
 *
 * @param usec Time since the last call to &lt;tt&gt;retro_run&lt;/tt&gt;, in microseconds.
 * If the frontend is manipulating the frame time
 * (e.g. via fast-forward or slow motion),
 * this value will be the reference value initially provided to the environment call.
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 * @see retro_frame_time_callback
 */
typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);

/**
 * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK
 */
struct retro_frame_time_callback
{
   /**
    * Called to notify the core of the current frame time.
    * If &lt;tt&gt;NULL&lt;/tt&gt;, the frontend will clear its registered callback.
    */
   retro_frame_time_callback_t callback;

   /**
    * The ideal duration of one frame, in microseconds.
    * Compute it as &lt;tt&gt;1000000 / fps&lt;/tt&gt;.
    * The frontend will resolve rounding to ensure that framestepping, etc is exact.
    */
   retro_usec_t reference;
};

/** @defgroup SET_AUDIO_BUFFER_STATUS_CALLBACK Audio Buffer Occupancy
 * @{
 */

/**
 * Notifies a libretro core of how full the frontend's audio buffer is.
 * Set by the core, called by the frontend.
 * It will be called right before \c retro_run() every frame.
 *
 * @param active \c true if the frontend's audio buffer is currently in use,
 * \c false if audio is disabled in the frontend.
 * @param occupancy A value between 0 and 100 (inclusive),
 * corresponding to the frontend's audio buffer occupancy percentage.
 * @param underrun_likely \c true if the frontend expects an audio buffer underrun
 * during the next frame, which indicates that a core should attempt frame-skipping.
 */
typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
      bool active, unsigned occupancy, bool underrun_likely);

/**
 * A callback to register with the frontend to receive audio buffer occupancy information.
 */
struct retro_audio_buffer_status_callback
{
   /** @copydoc retro_audio_buffer_status_callback_t */
   retro_audio_buffer_status_callback_t callback;
};

/** @} */

/* Pass this to retro_video_refresh_t if rendering to hardware.
 * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
 * */
#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)

/* Invalidates the current HW context.
 * Any GL state is lost, and must not be deinitialized explicitly.
 * If explicit deinitialization is desired by the libretro core,
 * it should implement context_destroy callback.
 * If called, all GPU resources must be reinitialized.
 * Usually called when frontend reinits video driver.
 * Also called first time video driver is initialized,
 * allowing libretro core to initialize resources.
 */
typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);

/* Gets current framebuffer which is to be rendered to.
 * Could change every frame potentially.
 */
typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);

/* Get a symbol from HW context. */
typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);

enum retro_hw_context_type
{
   RETRO_HW_CONTEXT_NONE             = 0,
   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
   RETRO_HW_CONTEXT_OPENGL           = 1,
   /* OpenGL ES 2.0. */
   RETRO_HW_CONTEXT_OPENGLES2        = 2,
   /* Modern desktop core GL context. Use version_major/
    * version_minor fields to set GL version. */
   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,
   /* OpenGL ES 3.0 */
   RETRO_HW_CONTEXT_OPENGLES3        = 4,
   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
    * use the corresponding enums directly. */
   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,

   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
   RETRO_HW_CONTEXT_VULKAN           = 6,

   /* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D11            = 7,

   /* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D10            = 8,

   /* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D12            = 9,

   /* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
   RETRO_HW_CONTEXT_D3D9             = 10,

   /** Dummy value to ensure sizeof(enum retro_hw_context_type) == sizeof(int). Do not use. */
   RETRO_HW_CONTEXT_DUMMY = INT_MAX
};

struct retro_hw_render_callback
{
   /* Which API to use. Set by libretro core. */
   enum retro_hw_context_type context_type;

   /* Called when a context has been created or when it has been reset.
    * An OpenGL context is only valid after context_reset() has been called.
    *
    * When context_reset is called, OpenGL resources in the libretro
    * implementation are guaranteed to be invalid.
    *
    * It is possible that context_reset is called multiple times during an
    * application lifecycle.
    * If context_reset is called without any notification (context_destroy),
    * the OpenGL context was lost and resources should just be recreated
    * without any attempt to "free" old resources.
    */
   retro_hw_context_reset_t context_reset;

   /* Set by frontend.
    * TODO: This is rather obsolete. The frontend should not
    * be providing preallocated framebuffers. */
   retro_hw_get_current_framebuffer_t get_current_framebuffer;

   /* Set by frontend.
    * Can return all relevant functions, including glClear on Windows. */
   retro_hw_get_proc_address_t get_proc_address;

   /* Set if render buffers should have depth component attached.
    * TODO: Obsolete. */
   bool depth;

   /* Set if stencil buffers should be attached.
    * TODO: Obsolete. */
   bool stencil;

   /* If depth and stencil are true, a packed 24/8 buffer will be added.
    * Only attaching stencil is invalid and will be ignored. */

   /* Use conventional bottom-left origin convention. If false,
    * standard libretro top-left origin semantics are used.
    * TODO: Move to GL specific interface. */
   bool bottom_left_origin;

   /* Major version number for core GL context or GLES 3.1+. */
   unsigned version_major;

   /* Minor version number for core GL context or GLES 3.1+. */
   unsigned version_minor;

   /* If this is true, the frontend will go very far to avoid
    * resetting context in scenarios like toggling fullscreen, etc.
    * TODO: Obsolete? Maybe frontend should just always assume this ...
    */
   bool cache_context;

   /* The reset callback might still be called in extreme situations
    * such as if the context is lost beyond recovery.
    *
    * For optimal stability, set this to false, and allow context to be
    * reset at any time.
    */

   /* A callback to be called before the context is destroyed in a
    * controlled way by the frontend. */
   retro_hw_context_reset_t context_destroy;

   /* OpenGL resources can be deinitialized cleanly at this step.
    * context_destroy can be set to NULL, in which resources will
    * just be destroyed without any notification.
    *
    * Even when context_destroy is non-NULL, it is possible that
    * context_reset is called without any destroy notification.
    * This happens if context is lost by external factors (such as
    * notified by GL_ARB_robustness).
    *
    * In this case, the context is assumed to be already dead,
    * and the libretro implementation must not try to free any OpenGL
    * resources in the subsequent context_reset.
    */

   /* Creates a debug context. */
   bool debug_context;
};

/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
 * Called by the frontend in response to keyboard events.
 * down is set if the key is being pressed, or false if it is being released.
 * keycode is the RETROK value of the char.
 * character is the text character of the pressed key. (UTF-32).
 * key_modifiers is a set of RETROKMOD values or'ed together.
 *
 * The pressed/keycode state can be independent of the character.
 * It is also possible that multiple characters are generated from a
 * single keypress.
 * Keycode events should be treated separately from character events.
 * However, when possible, the frontend should try to synchronize these.
 * If only a character is posted, keycode should be RETROK_UNKNOWN.
 *
 * Similarly if only a keycode event is generated with no corresponding
 * character, character should be 0.
 */
typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,
      uint32_t character, uint16_t key_modifiers);

struct retro_keyboard_callback
{
   retro_keyboard_event_t callback;
};

/** @defgroup SET_DISK_CONTROL_INTERFACE Disk Control
 *
 * Callbacks for inserting and removing disks from the emulated console at runtime.
 * Should be provided by cores that support doing so.
 * Cores should automate this process if possible,
 * but some cases require the player's manual input.
 *
 * The steps for swapping disk images are generally as follows:
 *
 * \li Eject the emulated console's disk drive with \c set_eject_state(true).
 * \li Insert the new disk image with \c set_image_index(index).
 * \li Close the virtual disk tray with \c set_eject_state(false).
 *
 * @{
 */

/**
 * Called by the frontend to open or close the emulated console's virtual disk tray.
 *
 * The frontend may only set the disk image index
 * while the emulated tray is opened.
 *
 * If the emulated console's disk tray is already in the state given by \c ejected,
 * then this function should return \c true without doing anything.
 * The core should return \c false if it couldn't change the disk tray's state;
 * this may happen if the console itself limits when the disk tray can be open or closed
 * (e.g. to wait for the disc to stop spinning).
 *
 * @param ejected \c true if the virtual disk tray should be "ejected",
 * \c false if it should be "closed".
 * @return \c true if the virtual disk tray's state has been set to the given state,
 * false if there was an error.
 * @see retro_get_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);

/**
 * Gets the current ejected state of the disk drive.
 * The initial state is closed, i.e. \c false.
 *
 * @return \c true if the virtual disk tray is "ejected",
 * i.e. it's open and a disk can be inserted.
 * @see retro_set_eject_state_t
 */
typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);

/**
 * Gets the index of the current disk image,
 * as determined by however the frontend orders disk images
 * (such as m3u-formatted playlists or special directories).
 *
 * @return The index of the current disk image
 * (starting with 0 for the first disk),
 * or a value greater than or equal to \c get_num_images() if no disk is inserted.
 * @see retro_get_num_images_t
 */
typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);

/**
 * Inserts the disk image at the given index into the emulated console's drive.
 * Can only be called while the disk tray is ejected
 * (i.e. \c retro_get_eject_state_t returns \c true).
 *
 * If the emulated disk tray is ejected
 * and already contains the disk image named by \c index,
 * then this function should do nothing and return \c true.
 *
 * @param index The index of the disk image to insert,
 * starting from 0 for the first disk.
 * A value greater than or equal to \c get_num_images()
 * represents the frontend removing the disk without inserting a new one.
 * @return \c true if the disk image was successfully set.
 * \c false if the disk tray isn't ejected or there was another error
 * inserting a new disk image.
 */
typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);

/**
 * @return The number of disk images which are available to use.
 * These are most likely defined in a playlist file.
 */
typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);

struct retro_game_info;

/**
 * Replaces the disk image at the given index with a new disk.
 *
 * Replaces the disk image associated with index.
 * Arguments to pass in info have same requirements as retro_load_game().
 * Virtual disk tray must be ejected when calling this.
 *
 * Passing \c NULL to this function indicates
 * that the frontend has removed this disk image from its internal list.
 * As a result, calls to this function can change the number of available disk indexes.
 *
 * For example, calling &lt;tt&gt;replace_image_index(1, NULL)&lt;/tt&gt;
 * will remove the disk image at index 1,
 * and the disk image at index 2 (if any)
 * will be moved to the newly-available index 1.
 *
 * @param index The index of the disk image to replace.
 * @param info Details about the new disk image,
 * or \c NULL if the disk image at the given index should be discarded.
 * The semantics of each field are the same as in \c retro_load_game.
 * @return \c true if the disk image was successfully replaced
 * or removed from the playlist,
 * \c false if the tray is not ejected
 * or if there was an error.
 */
typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
      const struct retro_game_info *info);

/**
 * Adds a new index to the core's internal disk list.
 * This will increment the return value from \c get_num_images() by 1.
 * This image index cannot be used until a disk image has been set
 * with \c replace_image_index.
 *
 * @return \c true if the core has added space for a new disk image
 * and is ready to receive one.
 */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);

/**
 * Sets the disk image that will be inserted into the emulated disk drive
 * before \c retro_load_game is called.
 *
 * \c retro_load_game does not provide a way to ensure
 * that a particular disk image in a playlist is inserted into the console;
 * this function makes up for that.
 * Frontends should call it immediately before \c retro_load_game,
 * and the core should use the arguments
 * to validate the disk image in \c retro_load_game.
 *
 * When content is loaded, the core should verify that the
 * disk specified by \c index can be found at \c path.
 * This is to guard against auto-selecting the wrong image
 * if (for example) the user should modify an existing M3U playlist.
 * We have to let the core handle this because
 * \c set_initial_image() must be called before loading content,
 * i.e. the frontend cannot access image paths in advance
 * and thus cannot perform the error check itself.
 * If \c index is invalid (i.e. &lt;tt&gt;index &gt;= get_num_images()&lt;/tt&gt;)
 * or the disk image doesn't match the value given in \c path,
 * the core should ignore the arguments
 * and insert the disk at index 0 into the virtual disk tray.
 *
 * @warning If \c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE is called within \c retro_load_game,
 * then this function may not be executed.
 * Set the disk control interface in \c retro_init if possible.
 *
 * @param index The index of the disk image within the playlist to set.
 * @param path The path of the disk image to set as the first.
 * The core should not load this path immediately;
 * instead, it should use it within \c retro_load_game
 * to verify that the correct disk image was loaded.
 * @return \c true if the initial disk index was set,
 * \c false if the arguments are invalid
 * or the core doesn't support this function.
 */
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);

/**
 * Returns the path of the disk image at the given index
 * on the host's file system.
 *
 * @param index The index of the disk image to get the path of.
 * @param s A buffer to store the path in.
 * @param len The size of \c s, in bytes.
 * @return \c true if the disk image's location was successfully
 * queried and copied into \c s,
 * \c false if the index is invalid
 * or the core couldn't locate the disk image.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *s, size_t len);

/**
 * Returns a friendly label for the given disk image.
 *
 * In the simplest case, this may be the disk image's file name
 * with the extension omitted.
 * For cores or games with more complex content requirements,
 * the label can be used to provide information to help the player
 * select a disk image to insert;
 * for example, a core may label different kinds of disks
 * (save data, level disk, installation disk, bonus content, etc.).
 * with names that correspond to in-game prompts,
 * so that the frontend can provide better guidance to the player.
 *
 * @param index The index of the disk image to return a label for.
 * @param s A buffer to store the resulting label in.
 * @param len The length of \c s, in bytes.
 * @return \c true if the disk image at \c index is valid
 * and a label was copied into \c s.
 */
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *s, size_t len);

/**
 * An interface that the frontend can use to exchange disks
 * within the emulated console's disk drive.
 *
 * All function pointers are required.
 *
 * @deprecated This struct is superseded by \ref retro_disk_control_ext_callback.
 * Only use this one to maintain compatibility
 * with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 * @see retro_disk_control_ext_callback
 */
struct retro_disk_control_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;
};

/**
 * @copybrief retro_disk_control_callback
 *
 * All function pointers are required unless otherwise noted.
 *
 * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE
 */
struct retro_disk_control_ext_callback
{
   /** @copydoc retro_set_eject_state_t */
   retro_set_eject_state_t set_eject_state;

   /** @copydoc retro_get_eject_state_t */
   retro_get_eject_state_t get_eject_state;

   /** @copydoc retro_get_image_index_t */
   retro_get_image_index_t get_image_index;

   /** @copydoc retro_set_image_index_t */
   retro_set_image_index_t set_image_index;

   /** @copydoc retro_get_num_images_t */
   retro_get_num_images_t  get_num_images;

   /** @copydoc retro_replace_image_index_t */
   retro_replace_image_index_t replace_image_index;

   /** @copydoc retro_add_image_index_t */
   retro_add_image_index_t add_image_index;

   /** @copydoc retro_set_initial_image_t
    *
    * Optional; not called if \c NULL.
    *
    * @note The frontend will only try to record/restore the last-used disk index
    * if both \c set_initial_image and \c get_image_path are implemented.
    */
   retro_set_initial_image_t set_initial_image;

   /**
    * @copydoc retro_get_image_path_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_path_t get_image_path;

   /**
    * @copydoc retro_get_image_label_t
    *
    * Optional; not called if \c NULL.
    */
   retro_get_image_label_t get_image_label;
};

/** @} */

/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
 * A core can set it if sending and receiving custom network packets
 * during a multiplayer session is desired.
 */

/* Netpacket flags for retro_netpacket_send_t */
#define RETRO_NETPACKET_UNRELIABLE  0        /* Packet to be sent unreliable, depending on network quality it might not arrive. */
#define RETRO_NETPACKET_RELIABLE    (1 &lt;&lt; 0) /* Reliable packets are guaranteed to arrive at the target in the order they were sent. */
#define RETRO_NETPACKET_UNSEQUENCED (1 &lt;&lt; 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */
#define RETRO_NETPACKET_FLUSH_HINT  (1 &lt;&lt; 2) /* Request the packet and any previously buffered ones to be sent immediately */

/* Broadcast client_id for retro_netpacket_send_t */
#define RETRO_NETPACKET_BROADCAST 0xFFFF

/* Used by the core to send a packet to one or all connected players.
 * A single packet sent via this interface can contain up to 64 KB of data.
 *
 * The client_id RETRO_NETPACKET_BROADCAST sends the packet as a broadcast to
 * all connected players. This is supported from the host as well as clients.
*  Otherwise, the argument indicates the player to send the packet to.
 *
 * A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).
 * Unreliable packets might not be supported by the frontend, but the flags can
 * still be specified. Reliable transmission will be used instead.
 *
 * Calling this with the flag RETRO_NETPACKET_FLUSH_HINT will send off the
 * packet and any previously buffered ones immediately and without blocking.
 * To only flush previously queued packets, buf or len can be passed as NULL/0.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id);

/* Optionally read any incoming packets without waiting for the end of the
 * frame. While polling, retro_netpacket_receive_t and retro_netpacket_stop_t
 * can be called. The core can perform this in a loop to do a blocking read,
 * i.e., wait for incoming data, but needs to handle stop getting called and
 * also give up after a short while to avoid freezing on a connection problem.
 * It is a good idea to manually flush outgoing packets before calling this.
 *
 * This function is not guaranteed to be thread-safe and must be called during
 * retro_run or any of the netpacket callbacks passed with this interface.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_receive_t)(void);

/* Called by the frontend to signify that a multiplayer session has started.
 * If client_id is 0 the local player is the host of the session and at this
 * point no other player has connected yet.
 *
 * If client_id is &gt; 0 the local player is a client connected to a host and
 * at this point is already fully connected to the host.
 *
 * The core must store the function pointer send_fn and use it whenever it
 * wants to send a packet. Optionally poll_receive_fn can be stored and used
 * when regular receiving between frames is not enough. These function pointers
 * remain valid until the frontend calls retro_netpacket_stop_t.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn, retro_netpacket_poll_receive_t poll_receive_fn);

/* Called by the frontend when a new packet arrives which has been sent from
 * another player with retro_netpacket_send_t. The client_id argument indicates
 * who has sent the packet.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);

/* Called by the frontend when the multiplayer session has ended.
 * Once this gets called the function pointers passed to
 * retro_netpacket_start_t will not be valid anymore.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);

/* Called by the frontend every frame (between calls to retro_run while
 * updating the state of the multiplayer session.
 * This is a good place for the core to call retro_netpacket_send_t from.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);

/* Called by the frontend when a new player connects to the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 * If this function returns false, the newly connected player gets dropped.
 * This can be used for example to limit the number of players.
 */
typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);

/* Called by the frontend when a player leaves or disconnects from the hosted session.
 * This is only called on the host side, not for clients connected to the host.
 */
typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);

/**
 * A callback interface for giving a core the ability to send and receive custom
 * network packets during a multiplayer session between two or more instances
 * of a libretro frontend.
 *
 * Normally during connection handshake the frontend will compare library_version
 * used by both parties and show a warning if there is a difference. When the core
 * supplies protocol_version, the frontend will check against this instead.
 *
 * @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE
 */
struct retro_netpacket_callback
{
   retro_netpacket_start_t        start;
   retro_netpacket_receive_t      receive;
   retro_netpacket_stop_t         stop;         /* Optional - may be NULL */
   retro_netpacket_poll_t         poll;         /* Optional - may be NULL */
   retro_netpacket_connected_t    connected;    /* Optional - may be NULL */
   retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */
   const char* protocol_version; /* Optional - if not NULL will be used instead of core version to decide if communication is compatible */
};

/**
 * The pixel format used for rendering.
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 */
enum retro_pixel_format
{
   /**
    * 0RGB1555, native endian.
    * Used as the default if \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT is not called.
    * The most significant bit must be set to 0.
    * @deprecated This format remains supported to maintain compatibility.
    * New code should use &lt;tt&gt;RETRO_PIXEL_FORMAT_RGB565&lt;/tt&gt; instead.
    * @see RETRO_PIXEL_FORMAT_RGB565
    */
   RETRO_PIXEL_FORMAT_0RGB1555 = 0,

   /**
    * XRGB8888, native endian.
    * The most significant byte (the &lt;tt&gt;X&lt;/tt&gt;) is ignored.
    */
   RETRO_PIXEL_FORMAT_XRGB8888 = 1,

   /**
    * RGB565, native endian.
    * This format is recommended if 16-bit pixels are desired,
    * as it is available on a variety of devices and APIs.
    */
   RETRO_PIXEL_FORMAT_RGB565   = 2,

   /** Defined to ensure that &lt;tt&gt;sizeof(retro_pixel_format) == sizeof(int)&lt;/tt&gt;. Do not use. */
   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX
};

/** @defgroup GET_SAVESTATE_CONTEXT Savestate Context
 * @{
 */

/**
 * Details about how the frontend will use savestates.
 *
 * @see RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT
 * @see retro_serialize
 */
enum retro_savestate_context
{
   /**
    * Standard savestate written to disk.
    * May be loaded at any time,
    * even in a separate session or on another device.
    *
    * Should not contain any pointers to code or data.
    */
   RETRO_SAVESTATE_CONTEXT_NORMAL                 = 0,

   /**
    * The savestate is guaranteed to be loaded
    * within the same session, address space, and binary.
    * Will not be written to disk or sent over the network;
    * therefore, internal pointers to code or data are acceptable.
    * May still be loaded or saved at any time.
    *
    * @note This context generally implies the use of runahead or rewinding,
    * which may work by taking savestates multiple times per second.
    * Savestate code that runs in this context should be fast.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,

   /**
    * The savestate is guaranteed to be loaded
    * in the same session and by the same binary,
    * but possibly by a different address space
    * (e.g. for "second instance" runahead)
    *
    * Will not be written to disk or sent over the network,
    * but may be loaded in a different address space.
    * Therefore, the savestate &lt;em&gt;must not&lt;/em&gt; contain pointers.
    */
   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY   = 2,

   /**
    * The savestate will not be written to disk,
    * but no other guarantees are made.
    * The savestate will almost certainly be loaded
    * by a separate binary, device, and address space.
    *
    * This context is intended for use with frontends that support rollback netplay.
    * Serialized state should omit any data that would unnecessarily increase bandwidth usage.
    * Must not contain pointers, and integers must be saved in big-endian format.
    * @see retro_endianness.h
    * @see network_stream
    */
   RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY       = 3,

   /**
    * @private Defined to ensure &lt;tt&gt;sizeof(retro_savestate_context) == sizeof(int)&lt;/tt&gt;.
    * Do not use.
    */
   RETRO_SAVESTATE_CONTEXT_UNKNOWN                = INT_MAX
};

/** @} */

/** @defgroup SET_MESSAGE User-Visible Messages
 *
 * @{
 */

/**
 * Defines a message that the frontend will display to the user,
 * as determined by &lt;tt&gt;RETRO_ENVIRONMENT_SET_MESSAGE&lt;/tt&gt;.
 *
 * @deprecated This struct is superseded by \ref retro_message_ext,
 * which provides more control over how a message is presented.
 * Only use it for compatibility with older cores and frontends.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE
 * @see retro_message_ext
 */
struct retro_message
{
   /**
    * Null-terminated message to be displayed.
    * If \c NULL or empty, the message will be ignored.
    */
   const char *msg;

   /** Duration to display \c msg in frames. */
   unsigned    frames;
};

/**
 * The method that the frontend will use to display a message to the player.
 * @see retro_message_ext
 */
enum retro_message_target
{
   /**
    * Indicates that the frontend should display the given message
    * using all other targets defined by \c retro_message_target at once.
    */
   RETRO_MESSAGE_TARGET_ALL = 0,

   /**
    * Indicates that the frontend should display the given message
    * using the frontend's on-screen display, if available.
    *
    * @attention If the frontend allows players to customize or disable notifications,
    * then they may not see messages sent to this target.
    */
   RETRO_MESSAGE_TARGET_OSD,

   /**
    * Indicates that the frontend should log the message
    * via its usual logging mechanism, if available.
    *
    * This is not intended to be a substitute for \c RETRO_ENVIRONMENT_SET_LOG_INTERFACE.
    * It is intended for the common use case of
    * logging a player-facing message.
    *
    * This target should not be used for messages
    * of type \c RETRO_MESSAGE_TYPE_STATUS or \c RETRO_MESSAGE_TYPE_PROGRESS,
    * as it may add unnecessary noise to a log file.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   RETRO_MESSAGE_TARGET_LOG
};

/**
 * A broad category for the type of message that the frontend will display.
 *
 * Each message type has its own use case,
 * therefore the frontend should present each one differently.
 *
 * @note This is a hint that the frontend may ignore.
 * The frontend should fall back to \c RETRO_MESSAGE_TYPE_NOTIFICATION
 * for message types that it doesn't support.
 */
enum retro_message_type
{
   /**
    * A standard on-screen message.
    *
    * Suitable for a variety of use cases,
    * such as messages about errors
    * or other important events.
    *
    * Frontends that display their own messages
    * should display this type of core-generated message the same way.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION = 0,

   /**
    * An on-screen message that should be visually distinct
    * from \c RETRO_MESSAGE_TYPE_NOTIFICATION messages.
    *
    * The exact meaning of "visually distinct" is left to the frontend,
    * but this usually implies that the frontend shows the message
    * in a way that it doesn't typically use for its own notices.
    */
   RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,

   /**
    * Indicates a frequently-updated status display,
    * rather than a standard notification.
    * Status messages are intended to be displayed permanently while a core is running
    * in a way that doesn't suggest user action is required.
    *
    * Here are some possible use cases for status messages:
    *
    * @li An internal framerate counter.
    * @li Debugging information.
    *     Remember to let the player disable it in the core options.
    * @li Core-specific state, such as when a microphone is active.
    *
    * The status message is displayed for the given duration,
    * unless another status message of equal or greater priority is shown.
    */
   RETRO_MESSAGE_TYPE_STATUS,

   /**
    * Denotes a message that reports the progress
    * of a long-running asynchronous task,
    * such as when a core loads large files from disk or the network.
    *
    * The frontend should display messages of this type as a progress bar
    * (or a progress spinner for indefinite tasks),
    * where \c retro_message_ext::msg is the progress bar's title
    * and \c retro_message_ext::progress sets the progress bar's length.
    *
    * This message type shouldn't be used for tasks that are expected to complete quickly.
    */
   RETRO_MESSAGE_TYPE_PROGRESS
};

/**
 * A core-provided message that the frontend will display to the player.
 *
 * @note The frontend is encouraged store these messages in a queue.
 * However, it should not empty the queue of core-submitted messages upon exit;
 * if a core exits with an error, it may want to use this API
 * to show an error message to the player.
 *
 * The frontend should maintain its own copy of the submitted message
 * and all subobjects, including strings.
 *
 * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT
 */
struct retro_message_ext
{
   /**
    * The \c NULL-terminated text of a message to show to the player.
    * Must not be \c NULL.
    *
    * @note The frontend must honor newlines in this string
    * when rendering text to \c RETRO_MESSAGE_TARGET_OSD.
    */
   const char *msg;

   /**
    * The duration that \c msg will be displayed on-screen, in milliseconds.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned duration;

   /**
    * The relative importance of this message
    * when targeting \c RETRO_MESSAGE_TARGET_OSD.
    * Higher values indicate higher priority.
    *
    * The frontend should use this to prioritize messages
    * when it can't show all active messages at once,
    * or to remove messages from its queue if it's full.
    *
    * The relative display order of messages with the same priority
    * is left to the frontend's discretion,
    * although we suggest breaking ties
    * in favor of the most recently-submitted message.
    *
    * Frontends may handle deprioritized messages at their discretion;
    * such messages may have their \c duration altered,
    * be hidden without being delayed,
    * or even be discarded entirely.
    *
    * @note In the reference frontend (RetroArch),
    * the same priority values are used for frontend-generated notifications,
    * which are typically between 0 and 3 depending upon importance.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    */
   unsigned priority;

   /**
    * The severity level of this message.
    *
    * The frontend may use this to filter or customize messages
    * depending on the player's preferences.
    * Here are some ideas:
    *
    * @li Use this to prioritize errors and warnings
    *     over higher-ranking info and debug messages.
    * @li Render warnings or errors with extra visual feedback,
    *     e.g. with brighter colors or accompanying sound effects.
    *
    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE
    */
   enum retro_log_level level;

   /**
    * The intended destination of this message.
    *
    * @see retro_message_target
    */
   enum retro_message_target target;

   /**
    * The intended semantics of this message.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG.
    *
    * @see retro_message_type
    */
   enum retro_message_type type;

   /**
    * The progress of an asynchronous task.
    *
    * A value between 0 and 100 (inclusive) indicates the task's percentage,
    * and a value of -1 indicates a task of unknown completion.
    *
    * @note Since message type is a hint, a frontend may ignore progress values.
    * Where relevant, a core should include progress percentage within the message string,
    * such that the message intent remains clear when displayed
    * as a standard frontend-generated notification.
    *
    * Ignored for \c RETRO_MESSAGE_TARGET_LOG and for
    * message types other than \c RETRO_MESSAGE_TYPE_PROGRESS.
    */
   int8_t progress;
};

/** @} */

/* Describes how the libretro implementation maps a libretro input bind
 * to its internal input system through a human readable string.
 * This string can be used to better let a user configure input. */
struct retro_input_descriptor
{
   /* Associates given parameters with a description. */
   unsigned port;
   unsigned device;
   unsigned index;
   unsigned id;

   /* Human readable description for parameters.
    * The pointer must remain valid until
    * retro_unload_game() is called. */
   const char *description;
};

/**
 * Contains basic information about the core.
 *
 * @see retro_get_system_info
 * @warning All pointers are owned by the core
 * and must remain valid throughout its lifetime.
 */
struct retro_system_info
{
   /**
    * Descriptive name of the library.
    *
    * @note Should not contain any version numbers, etc.
    */
   const char *library_name;

   /**
    * Descriptive version of the core.
    */
   const char *library_version;

   /**
    * A pipe-delimited string list of file extensions that this core can load, e.g. "bin|rom|iso".
    * Typically used by a frontend for filtering or core selection.
    */
   const char *valid_extensions;

   /* Libretro cores that need to have direct access to their content
    * files, including cores which use the path of the content files to
    * determine the paths of other files, should set need_fullpath to true.
    *
    * Cores should strive for setting need_fullpath to false,
    * as it allows the frontend to perform patching, etc.
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to have a valid path
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * See also:
    *    - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
    *    - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
    */
   bool        need_fullpath;

   /* If true, the frontend is not allowed to extract any archives before
    * loading the real content.
    * Necessary for certain libretro implementations that load games
    * from zipped archives. */
   bool        block_extract;
};

/* Defines overrides which modify frontend handling of
 * specific content file types.
 * An array of retro_system_content_info_override is
 * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_system_content_info_override
{
   /* A list of file extensions for which the override
    * should apply, delimited by a 'pipe' character
    * (e.g. "md|sms|gg")
    * Permitted file extensions are limited to those
    * included in retro_system_info::valid_extensions
    * and/or retro_subsystem_rom_info::valid_extensions */
   const char *extensions;

   /* Overrides the need_fullpath value set in
    * retro_system_info and/or retro_subsystem_rom_info.
    * To reiterate:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info::path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info::data and retro_game_info::size are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - retro_game_info::path may be NULL
    *    - retro_game_info::data and retro_game_info::size are guaranteed
    *      to be valid
    *
    * In addition:
    *
    * If need_fullpath is true and retro_load_game() is called:
    *    - retro_game_info_ext::full_path is guaranteed to contain a valid
    *      path to an existent file
    *    - retro_game_info_ext::archive_path may be NULL
    *    - retro_game_info_ext::archive_file may be NULL
    *    - retro_game_info_ext::dir is guaranteed to contain a valid path
    *      to the directory in which the content file exists
    *    - retro_game_info_ext::name is guaranteed to contain the
    *      basename of the content file, without extension
    *    - retro_game_info_ext::ext is guaranteed to contain the
    *      extension of the content file in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are invalid
    *
    * If need_fullpath is false and retro_load_game() is called:
    *    - If retro_game_info_ext::file_in_archive is false:
    *       - retro_game_info_ext::full_path is guaranteed to contain
    *         a valid path to an existent file
    *       - retro_game_info_ext::archive_path may be NULL
    *       - retro_game_info_ext::archive_file may be NULL
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the content file exists
    *       - retro_game_info_ext::name is guaranteed to contain the
    *         basename of the content file, without extension
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file in lower case format
    *    - If retro_game_info_ext::file_in_archive is true:
    *       - retro_game_info_ext::full_path may be NULL
    *       - retro_game_info_ext::archive_path is guaranteed to
    *         contain a valid path to an existent compressed file
    *         inside which the content file is located
    *       - retro_game_info_ext::archive_file is guaranteed to
    *         contain a valid path to an existent content file
    *         inside the compressed file referred to by
    *         retro_game_info_ext::archive_path
    *            e.g. for a compressed file '/path/to/foo.zip'
    *            containing 'bar.sfc'
    *             &gt; retro_game_info_ext::archive_path will be '/path/to/foo.zip'
    *             &gt; retro_game_info_ext::archive_file will be 'bar.sfc'
    *       - retro_game_info_ext::dir is guaranteed to contain a
    *         valid path to the directory in which the compressed file
    *         (containing the content file) exists
    *       - retro_game_info_ext::name is guaranteed to contain
    *         EITHER
    *         1) the basename of the compressed file (containing
    *            the content file), without extension
    *         OR
    *         2) the basename of the content file inside the
    *            compressed file, without extension
    *         In either case, a core should consider 'name' to
    *         be the canonical name/ID of the the content file
    *       - retro_game_info_ext::ext is guaranteed to contain the
    *         extension of the content file inside the compressed file,
    *         in lower case format
    *    - retro_game_info_ext::data and retro_game_info_ext::size are
    *      guaranteed to be valid */
   bool need_fullpath;

   /* If need_fullpath is false, specifies whether the content
    * data buffer available in retro_load_game() is 'persistent'
    *
    * If persistent_data is false and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid only until retro_load_game() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid only until retro_load_game() returns
    *
    * If persistent_data is true and retro_load_game() is called:
    *    - retro_game_info::data and retro_game_info::size
    *      are valid until retro_deinit() returns
    *    - retro_game_info_ext::data and retro_game_info_ext::size
    *      are valid until retro_deinit() returns */
   bool persistent_data;
};

/* Similar to retro_game_info, but provides extended
 * information about the source content file and
 * game memory buffer status.
 * And array of retro_game_info_ext is returned by
 * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * NOTE: In the following descriptions, references to
 *       retro_load_game() may be replaced with
 *       retro_load_game_special() */
struct retro_game_info_ext
{
   /* - If file_in_archive is false, contains a valid
    *   path to an existent content file (UTF-8 encoded)
    * - If file_in_archive is true, may be NULL */
   const char *full_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contains a valid path
    *   to an existent compressed file inside which the
    *   content file is located (UTF-8 encoded) */
   const char *archive_path;

   /* - If file_in_archive is false, may be NULL
    * - If file_in_archive is true, contain a valid path
    *   to an existent content file inside the compressed
    *   file referred to by archive_path (UTF-8 encoded)
    *      e.g. for a compressed file '/path/to/foo.zip'
    *      containing 'bar.sfc'
    *      &gt; archive_path will be '/path/to/foo.zip'
    *      &gt; archive_file will be 'bar.sfc' */
   const char *archive_file;

   /* - If file_in_archive is false, contains a valid path
    *   to the directory in which the content file exists
    *   (UTF-8 encoded)
    * - If file_in_archive is true, contains a valid path
    *   to the directory in which the compressed file
    *   (containing the content file) exists (UTF-8 encoded) */
   const char *dir;

   /* Contains the canonical name/ID of the content file
    * (UTF-8 encoded). Intended for use when identifying
    * 'complementary' content named after the loaded file -
    * i.e. companion data of a different format (a CD image
    * required by a ROM), texture packs, internally handled
    * save files, etc.
    * - If file_in_archive is false, contains the basename
    *   of the content file, without extension
    * - If file_in_archive is true, then string is
    *   implementation specific. A frontend may choose to
    *   set a name value of:
    *   EITHER
    *   1) the basename of the compressed file (containing
    *      the content file), without extension
    *   OR
    *   2) the basename of the content file inside the
    *      compressed file, without extension
    *   RetroArch sets the 'name' value according to (1).
    *   A frontend that supports routine loading of
    *   content from archives containing multiple unrelated
    *   content files may set the 'name' value according
    *   to (2). */
   const char *name;

   /* - If file_in_archive is false, contains the extension
    *   of the content file in lower case format
    * - If file_in_archive is true, contains the extension
    *   of the content file inside the compressed file,
    *   in lower case format */
   const char *ext;

   /* String of implementation specific meta-data. */
   const char *meta;

   /* Memory buffer of loaded game content. Will be NULL:
    * IF
    * - retro_system_info::need_fullpath is true and
    *   retro_system_content_info_override::need_fullpath
    *   is unset
    * OR
    * - retro_system_content_info_override::need_fullpath
    *   is true */
   const void *data;

   /* Size of game content memory buffer, in bytes */
   size_t size;

   /* True if loaded content file is inside a compressed
    * archive */
   bool file_in_archive;

   /* - If data is NULL, value is unset/ignored
    * - If data is non-NULL:
    *   - If persistent_data is false, data and size are
    *     valid only until retro_load_game() returns
    *   - If persistent_data is true, data and size are
    *     are valid until retro_deinit() returns */
   bool persistent_data;
};

/**
 * Parameters describing the size and shape of the video frame.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see RETRO_ENVIRONMENT_SET_GEOMETRY
 * @see retro_get_system_av_info
 */
struct retro_game_geometry
{
   /**
    * Nominal video width of game, in pixels.
    * This will typically be the emulated platform's native video width
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_width;

   /**
    * Nominal video height of game, in pixels.
    * This will typically be the emulated platform's native video height
    * (or its smallest, if the original hardware supports multiple resolutions).
    */
   unsigned base_height;

   /**
    * Maximum possible width of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video width.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's widest possible screen layout (e.g. side-by-side).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_width;

   /**
    * Maximum possible height of the game screen, in pixels.
    * This will typically be the emulated platform's maximum video height.
    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),
    * this should assume the core's tallest possible screen layout (e.g. vertical).
    * For cores that support upscaling the resolution,
    * this should assume the highest supported scale factor is active.
    */
   unsigned max_height;    /* Maximum possible height of game. */

   /**
    * Nominal aspect ratio of game.
    * If zero or less,
    * an aspect ratio of &lt;tt&gt;base_width / base_height&lt;/tt&gt; is assumed.
    *
    * @note A frontend may ignore this setting.
    */
   float    aspect_ratio;
};

/**
 * Parameters describing the timing of the video and audio.
 * @see retro_system_av_info
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_timing
{
   /** Video output refresh rate, in frames per second. */
   double fps;

   /** The audio output sample rate, in Hz. */
   double sample_rate;
};

/**
 * Configures how the core's audio and video should be updated.
 * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO
 * @see retro_get_system_av_info
 */
struct retro_system_av_info
{
   /** Parameters describing the size and shape of the video frame. */
   struct retro_game_geometry geometry;

   /** Parameters describing the timing of the video and audio. */
   struct retro_system_timing timing;
};

/** @defgroup SET_CORE_OPTIONS Core Options
 *  @{
 */

/**
 * Represents \ref RETRO_ENVIRONMENT_GET_VARIABLE "a core option query".
 *
 * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
 * (which is a deprecated API),
 * this \c struct serves as an option definition.
 *
 * @see RETRO_ENVIRONMENT_GET_VARIABLE
 */
struct retro_variable
{
   /**
    * A unique key identifying this option.
    *
    * Should be a key for an option that was previously defined
    * with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 or similar.
    *
    * Should be prefixed with the core's name
    * to minimize the risk of collisions with another core's options,
    * as frontends are not required to use a namespacing scheme for storing options.
    * For example, a core named "foo" might define an option named "foo_option".
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is used to define an option
    * named by this key.
    */
   const char *key;

   /**
    * Value to be obtained.
    *
    * Set by the frontend to \c NULL if
    * the option named by \ref key does not exist.
    *
    * @note In \ref RETRO_ENVIRONMENT_SET_VARIABLES
    * (which is a deprecated API),
    * this field is set by the core to define the possible values
    * for an option named by \ref key.
    * When used this way, it must be formatted as follows:
    * @li The text before the first ';' is the option's human-readable title.
    * @li A single space follows the ';'.
    * @li The rest of the string is a '|'-delimited list of possible values,
    * with the first one being the default.
    */
   const char *value;
};

/**
 * An argument that's used to show or hide a core option in the frontend.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 */
struct retro_core_option_display
{
   /**
    * The key for a core option that was defined with \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
    * \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
    * or their legacy equivalents.
    */
   const char *key;

   /**
    * Whether the option named by \c key
    * should be displayed to the player in the frontend's core options menu.
    *
    * @note This value is a hint, \em not a requirement;
    * the frontend is free to ignore this field.
    */
   bool visible;
};

/**
 * The maximum number of choices that can be defined for a given core option.
 *
 * This limit was chosen as a compromise between
 * a core's flexibility and a streamlined user experience.
 *
 * @note A guiding principle of libretro's API design is that
 * all common interactions (gameplay, menu navigation, etc.)
 * should be possible without a keyboard.
 *
 * If you need more than 128 choices for a core option,
 * consider simplifying your option structure.
 * Here are some ideas:
 *
 * \li If a core option represents a numeric value,
 *     consider reducing the option's granularity
 *     (e.g. define time limits in increments of 5 seconds instead of 1 second).
 *     Providing a fixed set of values based on experimentation
 *     is also a good idea.
 * \li If a core option represents a dynamically-built list of files,
 *     consider leaving out files that won't be useful.
 *     For example, if a core allows the player to choose a specific BIOS file,
 *     it can omit files of the wrong length or without a valid header.
 *
 * @see retro_core_option_definition
 * @see retro_core_option_v2_definition
 */
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128

/**
 * A descriptor for a particular choice within a core option.
 *
 * @note All option values are represented as strings.
 * If you need to represent any other type,
 * parse the string in \ref value.
 *
 * @see retro_core_option_v2_category
 */
struct retro_core_option_value
{
   /**
    * The option value that the frontend will serialize.
    *
    * Must not be \c NULL or empty.
    * No other hard limits are placed on this value's contents,
    * but here are some suggestions:
    *
    * \li If the value represents a number,
    *     don't include any non-digit characters (units, separators, etc.).
    *     Instead, include that information in \c label.
    *     This will simplify parsing.
    * \li If the value represents a file path,
    *     store it as a relative path with respect to one of the common libretro directories
    *     (e.g. \ref RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY "the system directory"
    *     or \ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY "the save directory"),
    *     and use forward slashes (\c "/") as directory separators.
    *     This will simplify cloud storage if supported by the frontend,
    *     as the same file may be used on multiple devices.
    */
   const char *value;

   /**
    * Human-readable name for \c value that the frontend should show to players.
    *
    * May be \c NULL, in which case the frontend
    * should display \c value itself.
    *
    * Here are some guidelines for writing a good label:
    *
    * \li Make the option labels obvious
    *     so that they don't need to be explained in the description.
    * \li Keep labels short, and don't use unnecessary words.
    *     For example, "OpenGL" is a better label than "OpenGL Mode".
    * \li If the option represents a number,
    *     consider adding units, separators, or other punctuation
    *     into the label itself.
    *     For example, "5 seconds" is a better label than "5".
    * \li If the option represents a number, use intuitive units
    *     that don't take a lot of digits to express.
    *     For example, prefer "1 minute" over "60 seconds" or "60,000 milliseconds".
    */
   const char *label;
};

/**
 * @copybrief retro_core_option_v2_definition
 *
 * @deprecated Use \ref retro_core_option_v2_definition instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 */
struct retro_core_option_definition
{
   /** @copydoc retro_core_option_v2_definition::key */
   const char *key;

   /** @copydoc retro_core_option_v2_definition::desc */
   const char *desc;

   /** @copydoc retro_core_option_v2_definition::info */
   const char *info;

   /** @copydoc retro_core_option_v2_definition::values */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /** @copydoc retro_core_option_v2_definition::default_value */
   const char *default_value;
};

#ifdef __PS3__
#undef local
#endif

/**
 * A variant of \ref retro_core_options that supports internationalization.
 *
 * @deprecated Use \ref retro_core_options_v2_intl instead,
 * as it supports categorizing options into groups.
 * Only use this \c struct to support older frontends or cores.
 *
 * @see retro_core_options
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_intl
{
   /** @copydoc retro_core_options_v2_intl::us */
   struct retro_core_option_definition *us;

   /** @copydoc retro_core_options_v2_intl::local */
   struct retro_core_option_definition *local;
};

/**
 * A descriptor for a group of related core options.
 *
 * Here's an example category:
 *
 * @code
 * {
 *     "cpu",
 *     "CPU Emulation",
 *     "Settings for CPU quirks."
 * }
 * @endcode
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_category
{
   /**
    * A string that uniquely identifies this category within the core's options.
    * Any \c retro_core_option_v2_definition whose \c category_key matches this
    * is considered to be within this category.
    * Different cores may use the same category keys,
    * so namespacing them is not necessary.
    * Valid characters are &lt;tt&gt;[a-zA-Z0-9_-]&lt;/tt&gt;.
    *
    * Frontends should use this category to organize core options,
    * but may customize this category's presentation in other ways.
    * For example, a frontend may use common keys like "audio" or "gfx"
    * to select an appropriate icon in its UI.
    *
    * Required; must not be \c NULL.
    */
   const char *key;

   /**
    * A brief human-readable name for this category,
    * intended for the frontend to display to the player.
    * This should be a name that's concise and descriptive, such as "Audio" or "Video".
    *
    * Required; must not be \c NULL.
    */
   const char *desc;

   /**
    * A human-readable description for this category,
    * intended for the frontend to display to the player
    * as secondary help text (e.g. a sublabel or a tooltip).
    * Optional; may be \c NULL or an empty string.
    */
   const char *info;
};

/**
 * A descriptor for a particular core option and the values it may take.
 *
 * Supports categorizing options into groups,
 * so as not to overwhelm the player.
 *
 * @see retro_core_option_v2_category
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 */
struct retro_core_option_v2_definition
{
   /**
    * A unique identifier for this option that cores may use
    * \ref RETRO_ENVIRONMENT_GET_VARIABLE "to query its value from the frontend".
    * Must be unique within this core.
    *
    * Should be unique globally;
    * the recommended method for doing so
    * is to prefix each option with the core's name.
    * For example, an option that controls the resolution for a core named "foo"
    * should be named \c "foo_resolution".
    *
    * Valid key characters are in the set &lt;tt&gt;[a-zA-Z0-9_-]&lt;/tt&gt;.
    */
   const char *key;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * Required; must not be \c NULL or empty.
    */
   const char *desc;

   /**
    * A human-readable name for this option,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version may be slightly more concise than \ref desc,
    * as it can rely on the structure of the options menu.
    * For example, "Interface" is a good \c desc_categorized,
    * as it can be displayed as a sublabel for a "Network" category.
    * For \c desc, "Network Interface" would be more suitable.
    *
    * Optional; if this field or \c category_key is empty or \c NULL,
    * \c desc will be used instead.
    */
   const char *desc_categorized;

   /**
    * A human-readable description of this option and its effects,
    * intended to be displayed by frontends that don't support
    * categorizing core options.
    *
    * @details Intended to be displayed as secondary help text,
    * such as a tooltip or a sublabel.
    *
    * Here are some suggestions for writing a good description:
    *
    * \li Avoid technical jargon unless this option is meant for advanced users.
    *     If unavoidable, suggest one of the default options for those unsure.
    * \li Don't repeat the option name in the description;
    *     instead, describe what the option name means.
    * \li If an option requires a core restart or game reset to take effect,
    *     be sure to say so.
    * \li Try to make the option labels obvious
    *     so that they don't need to be explained in the description.
    *
    * Optional; may be \c NULL.
    */
   const char *info;

   /**
    * @brief A human-readable description of this option and its effects,
    * intended to be displayed by frontends that support
    * categorizing core options.
    *
    * This version is provided to accommodate descriptions
    * that reference other options by name,
    * as options may have different user-facing names
    * depending on whether the frontend supports categorization.
    *
    * @copydetails info
    *
    * If empty or \c NULL, \c info will be used instead.
    * Will be ignored if \c category_key is empty or \c NULL.
    */
   const char *info_categorized;

   /**
    * The key of the category that this option belongs to.
    *
    * Optional; if equal to \ref retro_core_option_v2_category::key "a defined category",
    * then this option shall be displayed by the frontend
    * next to other options in this same category,
    * assuming it supports doing so.
    * Option categories are intended to be displayed in a submenu,
    * but this isn't a hard requirement.
    *
    * If \c NULL, empty, or not equal to a defined category,
    * then this option is considered uncategorized
    * and the frontend shall display it outside of any category
    * (most likely at a top-level menu).
    *
    * @see retro_core_option_v2_category
    */
   const char *category_key;

   /**
    * One or more possible values for this option,
    * up to the limit of \ref RETRO_NUM_CORE_OPTION_VALUES_MAX.
    *
    * Terminated by a \c { NULL, NULL } element,
    * although frontends should work even if all elements are used.
    */
   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];

   /**
    * The default value for this core option.
    * Used if it hasn't been set, e.g. for new cores.
    * Must equal one of the \ref value members in the \c values array,
    * or else this option will be ignored.
    */
   const char *default_value;
};

/**
 * A set of core option descriptors and the categories that group them,
 * suitable for enabling a core to be customized.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
 */
struct retro_core_options_v2
{
   /**
    * An array of \ref retro_core_option_v2_category "option categories",
    * terminated by a zeroed-out category \c struct.
    *
    * Will be ignored if the frontend doesn't support core option categories.
    *
    * If \c NULL or ignored, all options will be treated as uncategorized.
    * This most likely means that a frontend will display them at a top-level menu
    * without any kind of hierarchy or grouping.
    */
   struct retro_core_option_v2_category *categories;

   /**
    * An array of \ref retro_core_option_v2_definition "core option descriptors",
    * terminated by a zeroed-out definition \c struct.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_option_v2_definition *definitions;
};

/**
 * A variant of \ref retro_core_options_v2 that supports internationalization.
 *
 * @see retro_core_options_v2
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
 * @see RETRO_ENVIRONMENT_GET_LANGUAGE
 * @see retro_language
 */
struct retro_core_options_v2_intl
{
   /**
    * Pointer to a core options set
    * whose text is written in American English.
    *
    * This may be passed to \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 as-is
    * if not using \c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL.
    *
    * Required; must not be \c NULL.
    */
   struct retro_core_options_v2 *us;

   /**
    * Pointer to a core options set
    * whose text is written in one of libretro's \ref retro_language "supported languages",
    * most likely the one returned by \ref RETRO_ENVIRONMENT_GET_LANGUAGE.
    *
    * Structure is the same, but usage is slightly different:
    *
    * \li All text (except for keys and option values)
    *     should be written in whichever language
    *     is returned by \c RETRO_ENVIRONMENT_GET_LANGUAGE.
    * \li All fields besides keys and option values may be \c NULL,
    *     in which case the corresponding string in \c us
    *     is used instead.
    * \li All \ref retro_core_option_v2_definition::default_value "default option values"
    *     are taken from \c us.
    *     The defaults in this field are ignored.
    *
    * May be \c NULL, in which case \c us is used instead.
    */
   struct retro_core_options_v2 *local;
};

/**
 * Called by the frontend to determine if any core option's visibility has changed.
 *
 * Each time a frontend sets a core option,
 * it should call this function to see if
 * any core option should be made visible or invisible.
 *
 * May also be called after \ref retro_load_game "loading a game",
 * to determine what the initial visibility of each option should be.
 *
 * Within this function, the core must update the visibility
 * of any dynamically-hidden options
 * using \ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.
 *
 * @note All core options are visible by default,
 * even during this function's first call.
 *
 * @return \c true if any core option's visibility was adjusted
 * since the last call to this function.
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
typedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void);

/**
 * Callback registered by the core for the frontend to use
 * when setting the visibility of each core option.
 *
 * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY
 * @see retro_core_option_display
 */
struct retro_core_options_update_display_callback
{
   /**
    * @copydoc retro_core_options_update_display_callback_t
    *
    * Set by the core.
    */
   retro_core_options_update_display_callback_t callback;
};

/** @} */

struct retro_game_info
{
   const char *path;       /* Path to game, UTF-8 encoded.
                            * Sometimes used as a reference for building other paths.
                            * May be NULL if game was loaded from stdin or similar,
                            * but in this case some cores will be unable to load `data`.
                            * So, it is preferable to fabricate something here instead
                            * of passing NULL, which will help more cores to succeed.
                            * retro_system_info::need_fullpath requires
                            * that this path is valid. */
   const void *data;       /* Memory buffer of loaded game. Will be NULL
                            * if need_fullpath was set. */
   size_t      size;       /* Size of memory buffer. */
   const char *meta;       /* String of implementation specific meta-data. */
};

/** @defgroup GET_CURRENT_SOFTWARE_FRAMEBUFFER Frontend-Owned Framebuffers
 * @{
 */

/** @defgroup RETRO_MEMORY_ACCESS Framebuffer Memory Access Types
 * @{
 */

/** Indicates that core will write to the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_WRITE (1 &lt;&lt; 0)

/** Indicates that the core will read from the framebuffer returned by the frontend. */
#define RETRO_MEMORY_ACCESS_READ (1 &lt;&lt; 1)

/** @} */

/** @defgroup RETRO_MEMORY_TYPE Framebuffer Memory Types
 * @{
 */

/**
 * Indicates that the returned framebuffer's memory is cached.
 * If not set, random access to the buffer may be very slow.
 */
#define RETRO_MEMORY_TYPE_CACHED (1 &lt;&lt; 0)

/** @} */

/**
 * A frame buffer owned by the frontend that a core may use for rendering.
 *
 * @see GET_CURRENT_SOFTWARE_FRAMEBUFFER
 * @see retro_video_refresh_t
 */
struct retro_framebuffer
{
   /**
    * Pointer to the beginning of the framebuffer provided by the frontend.
    * The initial contents of this buffer are unspecified,
    * as is the means used to map the memory;
    * this may be defined in software,
    * or it may be GPU memory mapped to RAM.
    *
    * If the framebuffer is used,
    * this pointer must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to pass an offset to this pointer.
    *
    * @warning This pointer is only guaranteed to be valid
    * for the duration of the same \c retro_run iteration
    * \ref GET_CURRENT_SOFTWARE_FRAMEBUFFER "that requested the framebuffer".
    * Reuse of this pointer is undefined.
    */
   void *data;

   /**
    * The width of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other width.
    */
   unsigned width;

   /**
    * The height of the framebuffer given in \c data, in pixels.
    * Set by the core.
    *
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined behavior to try to render \c data with any other height.
    */
   unsigned height;

   /**
    * The distance between the start of one scanline and the beginning of the next, in bytes.
    * In practice this is usually equal to \c width times the pixel size,
    * but that's not guaranteed.
    * Sometimes called the "stride".
    *
    * @setby{frontend}
    * @warning If the framebuffer is used,
    * this value must be passed to \c retro_video_refresh_t as-is.
    * It is undefined to try to render \c data with any other pitch.
    */
   size_t pitch;

   /**
    * The pixel format of the returned framebuffer.
    * May be different than the format specified by the core in \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT,
    * e.g. due to conversions.
    * Set by the frontend.
    *
    * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
    */
   enum retro_pixel_format format;

   /**
    * One or more \ref RETRO_MEMORY_ACCESS "memory access flags"
    * that specify how the core will access the memory in \c data.
    *
    * @setby{core}
    */
   unsigned access_flags;

   /**
    * Zero or more \ref RETRO_MEMORY_TYPE "memory type flags"
    * that describe how the framebuffer's memory has been mapped.
    *
    * @setby{frontend}
    */
   unsigned memory_flags;
};

/** @} */

/** @defgroup SET_FASTFORWARDING_OVERRIDE Fast-Forward Override
 * @{
 */

/**
 * Parameters that govern when and how the core takes control
 * of fast-forwarding mode.
 */
struct retro_fastforwarding_override
{
   /**
    * The factor by which the core will be sped up
    * when \c fastforward is \c true.
    * This value is used as follows:
    *
    * @li A value greater than 1.0 will run the core at
    *     the specified multiple of normal speed.
    *     For example, a value of 5.0
    *     combined with a normal target rate of 60 FPS
    *     will result in a target rate of 300 FPS.
    *     The actual rate may be lower if the host's hardware can't keep up.
    * @li A value of 1.0 will run the core at normal speed.
    * @li A value between 0.0 (inclusive) and 1.0 (exclusive)
    *     will run the core as fast as the host system can manage.
    * @li A negative value will let the frontend choose a factor.
    * @li An infinite value or \c NaN results in undefined behavior.
    *
    * @attention Setting this value to less than 1.0 will \em not
    * slow down the core.
    */
   float ratio;

   /**
    * If \c true, the frontend should activate fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool fastforward;

   /**
    * If \c true, the frontend should display an on-screen notification or icon
    * while \c fastforward is \c true (where supported).
    * Otherwise, the frontend should not display any such notification.
    */
   bool notification;

   /**
    * If \c true, the core has exclusive control
    * over enabling and disabling fast-forwarding
    * via the \c fastforward field.
    * The frontend will not be able to start or stop fast-forwarding
    * until this field is set to \c false or the core is unloaded.
    */
   bool inhibit_toggle;
};

/** @} */

/**
 * During normal operation.
 *
 * @note Rate will be equal to the core's internal FPS.
 */
#define RETRO_THROTTLE_NONE              0

/**
 * While paused or stepping single frames.
 *
 * @note Rate will be 0.
 */
#define RETRO_THROTTLE_FRAME_STEPPING    1

/**
 * During fast forwarding.
 *
 * @note Rate will be 0 if not specifically limited to a maximum speed.
 */
#define RETRO_THROTTLE_FAST_FORWARD      2

/**
 * During slow motion.
 *
 * @note Rate will be less than the core's internal FPS.
 */
#define RETRO_THROTTLE_SLOW_MOTION       3

/**
 * While rewinding recorded save states.
 *
 * @note Rate can vary depending on the rewind speed or be 0 if the frontend
 * is not aiming for a specific rate.
 */
#define RETRO_THROTTLE_REWINDING         4

/**
 * While vsync is active in the video driver, and the target refresh rate is lower than the core's internal FPS.
 *
 * @note Rate is the target refresh rate.
 */
#define RETRO_THROTTLE_VSYNC             5

/**
 * When the frontend does not throttle in any way.
 *
 * @note Rate will be 0. An example could be if no vsync or audio output is active.
 */
#define RETRO_THROTTLE_UNBLOCKED         6

/**
 * Details about the actual rate an implementation is calling \c retro_run() at.
 *
 * @see RETRO_ENVIRONMENT_GET_THROTTLE_STATE
 */
struct retro_throttle_state
{
   /**
    * The current throttling mode.
    *
    * @note Should be one of the \c RETRO_THROTTLE_* values.
    * @see RETRO_THROTTLE_NONE
    * @see RETRO_THROTTLE_FRAME_STEPPING
    * @see RETRO_THROTTLE_FAST_FORWARD
    * @see RETRO_THROTTLE_SLOW_MOTION
    * @see RETRO_THROTTLE_REWINDING
    * @see RETRO_THROTTLE_VSYNC
    * @see RETRO_THROTTLE_UNBLOCKED
    */
   unsigned mode;

   /**
    * How many times per second the frontend aims to call retro_run.
    *
    * @note Depending on the mode, it can be 0 if there is no known fixed rate.
    * This won't be accurate if the total processing time of the core and
    * the frontend is longer than what is available for one frame.
    */
   float rate;
};

/** @defgroup GET_MICROPHONE_INTERFACE Microphone Interface
 * @{
 */

/**
 * Opaque handle to a microphone that's been opened for use.
 * The underlying object is accessed or created with \c retro_microphone_interface_t.
 */
typedef struct retro_microphone retro_microphone_t;

/**
 * Parameters for configuring a microphone.
 * Some of these might not be honored,
 * depending on the available hardware and driver configuration.
 */
typedef struct retro_microphone_params
{
   /**
    * The desired sample rate of the microphone's input, in Hz.
    * The microphone's input will be resampled,
    * so cores can ask for whichever frequency they need.
    *
    * If zero, some reasonable default will be provided by the frontend
    * (usually from its config file).
    *
    * @see retro_get_mic_rate_t
    */
   unsigned rate;
} retro_microphone_params_t;

/**
 * @copydoc retro_microphone_interface::open_mic
 */
typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::close_mic
 */
typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::get_params
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);

/**
 * @copydoc retro_microphone_interface::set_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);

/**
 * @copydoc retro_microphone_interface::get_mic_state
 */
typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);

/**
 * @copydoc retro_microphone_interface::read_mic
 */
typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);

/**
 * The current version of the microphone interface.
 * Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t
 * receive new fields.
 *
 * Frontends using cores built against older mic interface versions
 * should not access fields introduced in newer versions.
 */
#define RETRO_MICROPHONE_INTERFACE_VERSION 1

/**
 * An interface for querying the microphone and accessing data read from it.
 *
 * @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE
 */
struct retro_microphone_interface
{
   /**
    * The version of this microphone interface.
    * Set by the core to request a particular version,
    * and set by the frontend to indicate the returned version.
    * 0 indicates that the interface is invalid or uninitialized.
    */
   unsigned interface_version;

   /**
    * Initializes a new microphone.
    * Assuming that microphone support is enabled and provided by the frontend,
    * cores may call this function whenever necessary.
    * A microphone could be opened throughout a core's lifetime,
    * or it could wait until a microphone is plugged in to the emulated device.
    *
    * The returned handle will be valid until it's freed,
    * even if the audio driver is reinitialized.
    *
    * This function is not guaranteed to be thread-safe.
    *
    * @param[in] args Parameters used to create the microphone.
    * May be \c NULL, in which case the default value of each parameter will be used.
    *
    * @returns Pointer to the newly-opened microphone,
    * or \c NULL if one couldn't be opened.
    * This likely means that no microphone is plugged in and recognized,
    * or the maximum number of supported microphones has been reached.
    *
    * @note Microphones are \em inactive by default;
    * to begin capturing audio, call \c set_mic_state.
    * @see retro_microphone_params_t
    */
   retro_open_mic_t open_mic;

   /**
    * Closes a microphone that was initialized with \c open_mic.
    * Calling this function will stop all microphone activity
    * and free up the resources that it allocated.
    * Afterwards, the handle is invalid and must not be used.
    *
    * A frontend may close opened microphones when unloading content,
    * but this behavior is not guaranteed.
    * Cores should close their microphones when exiting, just to be safe.
    *
    * @param microphone Pointer to the microphone that was allocated by \c open_mic.
    * If \c NULL, this function does nothing.
    *
    * @note The handle might be reused if another microphone is opened later.
    */
   retro_close_mic_t close_mic;

   /**
    * Returns the configured parameters of this microphone.
    * These may differ from what was requested depending on
    * the driver and device configuration.
    *
    * Cores should check these values before they start fetching samples.
    *
    * Will not change after the mic was opened.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose parameters will be retrieved.
    * @param[out] params The parameters object that the
    * microphone's parameters will be copied to.
    *
    * @return \c true if the parameters were retrieved,
    * \c false if there was an error.
    */
   retro_get_mic_params_t get_params;

   /**
    * Enables or disables the given microphone.
    * Microphones are disabled by default
    * and must be explicitly enabled before they can be used.
    * Disabled microphones will not process incoming audio samples,
    * and will therefore have minimal impact on overall performance.
    * Cores may enable microphones throughout their lifetime,
    * or only for periods where they're needed.
    *
    * Cores that accept microphone input should be able to operate without it;
    * we suggest substituting silence in this case.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be adjusted.
    * This will have been provided by \c open_mic.
    * @param state \c true if the microphone should receive audio input,
    * \c false if it should be idle.
    * @returns \c true if the microphone's state was successfully set,
    * \c false if \c microphone is invalid
    * or if there was an error.
    */
   retro_set_mic_state_t set_mic_state;

   /**
    * Queries the active state of a microphone at the given index.
    * Will return whether the microphone is enabled,
    * even if the driver is paused.
    *
    * @param microphone Opaque handle to the microphone
    * whose state will be queried.
    * @return \c true if the provided \c microphone is valid and active,
    * \c false if not or if there was an error.
    */
   retro_get_mic_state_t get_mic_state;

   /**
    * Retrieves the input processed by the microphone since the last call.
    * \em Must be called every frame unless \c microphone is disabled,
    * similar to how \c retro_audio_sample_batch_t works.
    *
    * @param[in] microphone Opaque handle to the microphone
    * whose recent input will be retrieved.
    * @param[out] samples The buffer that will be used to store the microphone's data.
    * Microphone input is in mono (i.e. one number per sample).
    * Should be large enough to accommodate the expected number of samples per frame;
    * for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.
    * @param[in] num_samples The size of the data buffer in samples (\em not bytes).
    * Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here.
    *
    * @return The number of samples that were copied into \c samples.
    * If \c microphone is pending driver initialization,
    * this function will copy silence of the requested length into \c samples.
    *
    * Will return -1 if the microphone is disabled,
    * the audio driver is paused,
    * or there was an error.
    */
   retro_read_mic_t read_mic;
};

/** @} */

/** @defgroup GET_DEVICE_POWER Device Power
 * @{
 */

/**
 * Describes how a device is being powered.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
enum retro_power_state
{
   /**
    * Indicates that the frontend cannot report its power state at this time,
    * most likely due to a lack of support.
    *
    * \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value;
    * instead, the environment callback will return \c false.
    */
   RETRO_POWERSTATE_UNKNOWN = 0,

   /**
    * Indicates that the device is running on its battery.
    * Usually applies to portable devices such as handhelds, laptops, and smartphones.
    */
   RETRO_POWERSTATE_DISCHARGING,

   /**
    * Indicates that the device's battery is currently charging.
    */
   RETRO_POWERSTATE_CHARGING,

   /**
    * Indicates that the device is connected to a power source
    * and that its battery has finished charging.
    */
   RETRO_POWERSTATE_CHARGED,

   /**
    * Indicates that the device is connected to a power source
    * and that it does not have a battery.
    * This usually suggests a desktop computer or a non-portable game console.
    */
   RETRO_POWERSTATE_PLUGGED_IN
};

/**
 * Indicates that an estimate is not available for the battery level or time remaining,
 * even if the actual power state is known.
 */
#define RETRO_POWERSTATE_NO_ESTIMATE (-1)

/**
 * Describes the power state of the device running the frontend.
 * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER
 */
struct retro_device_power
{
   /**
    * The current state of the frontend's power usage.
    */
   enum retro_power_state state;

   /**
    * A rough estimate of the amount of time remaining (in seconds)
    * before the device powers off.
    * This value depends on a variety of factors,
    * so it is not guaranteed to be accurate.
    *
    * Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING.
    * May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate.
    */
   int seconds;

   /**
    * The approximate percentage of battery charge,
    * ranging from 0 to 100 (inclusive).
    * The device may power off before this reaches 0.
    *
    * The user might have configured their device
    * to stop charging before the battery is full,
    * so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state.
    */
   int8_t percent;
};

/** @} */

/**
 * @defgroup Callbacks
 * @{
 */

/**
 * Environment callback to give implementations a way of performing uncommon tasks.
 *
 * @note Extensible.
 *
 * @param cmd The command to run.
 * @param data A pointer to the data associated with the command.
 *
 * @return Varies by callback,
 * but will always return \c false if the command is not recognized.
 *
 * @see RETRO_ENVIRONMENT_SET_ROTATION
 * @see retro_set_environment()
 */
typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);

/**
 * Render a frame.
 *
 * @note For performance reasons, it is highly recommended to have a frame
 * that is packed in memory, i.e. pitch == width * byte_per_pixel.
 * Certain graphic APIs, such as OpenGL ES, do not like textures
 * that are not packed in memory.
 *
 * @param data A pointer to the frame buffer data with a pixel format of 15-bit \c 0RGB1555 native endian, unless changed with \c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT.
 * @param width The width of the frame buffer, in pixels.
 * @param height The height frame buffer, in pixels.
 * @param pitch The width of the frame buffer, in bytes.
 *
 * @see retro_set_video_refresh()
 * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT
 * @see retro_pixel_format
 */
typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,
      unsigned height, size_t pitch);

/**
 * Renders a single audio frame. Should only be used if implementation generates a single sample at a time.
 *
 * @param left The left audio sample represented as a signed 16-bit native endian.
 * @param right The right audio sample represented as a signed 16-bit native endian.
 *
 * @see retro_set_audio_sample()
 * @see retro_set_audio_sample_batch()
 */
typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);

/**
 * Renders multiple audio frames in one go.
 *
 * @note Only one of the audio callbacks must ever be used.
 *
 * @param data A pointer to the audio sample data pairs to render.
 * @param frames The number of frames that are represented in the data. One frame
 *     is defined as a sample of left and right channels, interleaved.
 *     For example: &lt;tt&gt;int16_t buf[4] = { l, r, l, r };&lt;/tt&gt; would be 2 frames.
 *
 * @return The number of frames that were processed.
 *
 * @see retro_set_audio_sample_batch()
 * @see retro_set_audio_sample()
 */
typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,
      size_t frames);

/**
 * Polls input.
 *
 * @see retro_set_input_poll()
 */
typedef void (RETRO_CALLCONV *retro_input_poll_t)(void);

/**
 * Queries for input for player 'port'.
 *
 * @param port Which player 'port' to query.
 * @param device Which device to query for. Will be masked with \c RETRO_DEVICE_MASK.
 * @param index The input index to retrieve.
 * The exact semantics depend on the device type given in \c device.
 * @param id The ID of which value to query, like \c RETRO_DEVICE_ID_JOYPAD_B.
 * @returns Depends on the provided arguments,
 * but will return 0 if their values are unsupported
 * by the frontend or the backing physical device.
 * @note Specialization of devices such as \c RETRO_DEVICE_JOYPAD_MULTITAP that
 * have been set with \c retro_set_controller_port_device() will still use the
 * higher level \c RETRO_DEVICE_JOYPAD to request input.
 *
 * @see retro_set_input_state()
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 */
typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,
      unsigned index, unsigned id);

/**
 * Sets the environment callback.
 *
 * @param cb The function which is used when making environment calls.
 *
 * @note Guaranteed to be called before \c retro_init().
 *
 * @see RETRO_ENVIRONMENT
 */
RETRO_API void retro_set_environment(retro_environment_t cb);

/**
 * Sets the video refresh callback.
 *
 * @param cb The function which is used when rendering a frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_video_refresh(retro_video_refresh_t cb);

/**
 * Sets the audio sample callback.
 *
 * @param cb The function which is used when rendering a single audio frame.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample(retro_audio_sample_t cb);

/**
 * Sets the audio sample batch callback.
 *
 * @param cb The function which is used when rendering multiple audio frames in one go.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);

/**
 * Sets the input poll callback.
 *
 * @param cb The function which is used to poll the active input.
 *
 * @note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_poll(retro_input_poll_t cb);

/**
 * Sets the input state callback.
 *
 * @param cb The function which is used to query the input state.
 *
 *@note Guaranteed to have been called before the first call to \c retro_run() is made.
 */
RETRO_API void retro_set_input_state(retro_input_state_t cb);

/**
 * @}
 */

/**
 * Called by the frontend when initializing a libretro core.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * &lt;ul&gt;
 * &lt;li&gt;Do not assume that the core was loaded by the operating system
 * for the first time within this call.
 * It may have been statically linked or retained from a previous session.
 * Consequently, cores must not rely on global variables being initialized
 * to their default values before this function is called;
 * this also goes for object constructors in C++.
 * &lt;li&gt;Although C++ requires that constructors be called for global variables,
 * it does not require that their destructors be called
 * if stored within a dynamic library's global scope.
 * &lt;li&gt;If the core is statically linked to the frontend,
 * global variables may be initialized when the frontend itself is initially executed.
 * &lt;/ul&gt;
 * @see retro_deinit
 */
RETRO_API void retro_init(void);

/**
 * Called by the frontend when deinitializing a libretro core.
 * The core must release all of its allocated resources before this function returns.
 *
 * @warning There are many possible "gotchas" with global state in dynamic libraries.
 * Here are some to keep in mind:
 * &lt;ul&gt;
 * &lt;li&gt;Do not assume that the operating system will unload the core after this function returns,
 * as the core may be linked statically or retained in memory.
 * Cores should use this function to clean up all allocated resources
 * and reset all global variables to their default states.
 * &lt;li&gt;Do not assume that this core won't be loaded again after this function returns.
 * It may be kept in memory by the frontend for later use,
 * or it may be statically linked.
 * Therefore, all global variables should be reset to their default states within this function.
 * &lt;li&gt;C++ does not require that destructors be called
 * for variables within a dynamic library's global scope.
 * Therefore, global objects that own dynamically-managed resources
 * (such as \c std::string or &lt;tt&gt;std::vector&lt;/tt&gt;)
 * should be kept behind pointers that are explicitly deallocated within this function.
 * &lt;/ul&gt;
 * @see retro_init
 */
RETRO_API void retro_deinit(void);

/**
 * Retrieves which version of the libretro API is being used.
 *
 * @note This is used to validate ABI compatibility when the API is revised.
 *
 * @return Must return \c RETRO_API_VERSION.
 *
 * @see RETRO_API_VERSION
 */
RETRO_API unsigned retro_api_version(void);

/**
 * Gets statically known system info.
 *
 * @note Can be called at any time, even before retro_init().
 *
 * @param info A pointer to a \c retro_system_info where the info is to be loaded into. This must be statically allocated.
 */
RETRO_API void retro_get_system_info(struct retro_system_info *info);

/**
 * Gets information about system audio/video timings and geometry.
 *
 * @note Can be called only after \c retro_load_game() has successfully completed.
 *
 * @note The implementation of this function might not initialize every variable
 * if needed. For example, \c geom.aspect_ratio might not be initialized if
 * the core doesn't desire a particular aspect ratio.
 *
 * @param info A pointer to a \c retro_system_av_info where the audio/video information should be loaded into.
 *
 * @see retro_system_av_info
 */
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);

/**
 * Sets device to be used for player 'port'.
 *
 * By default, \c RETRO_DEVICE_JOYPAD is assumed to be plugged into all
 * available ports.
 *
 * @note Setting a particular device type is not a guarantee that libretro cores
 * will only poll input based on that particular device type. It is only a
 * hint to the libretro core when a core cannot automatically detect the
 * appropriate input device type on its own. It is also relevant when a
 * core can change its behavior depending on device type.
 *
 * @note As part of the core's implementation of retro_set_controller_port_device,
 * the core should call \c RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
 * frontend if the descriptions for any controls have changed as a
 * result of changing the device type.
 *
 * @param port Which port to set the device for, usually indicates the player number.
 * @param device Which device the given port is using. By default, \c RETRO_DEVICE_JOYPAD is assumed for all ports.
 *
 * @see RETRO_DEVICE_NONE
 * @see RETRO_DEVICE_JOYPAD
 * @see RETRO_DEVICE_MOUSE
 * @see RETRO_DEVICE_KEYBOARD
 * @see RETRO_DEVICE_LIGHTGUN
 * @see RETRO_DEVICE_ANALOG
 * @see RETRO_DEVICE_POINTER
 * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO
 */
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);

/**
 * Resets the currently-loaded game.
 * Cores should treat this as a soft reset (i.e. an emulated reset button) if possible,
 * but hard resets are acceptable.
 */
RETRO_API void retro_reset(void);

/**
 * Runs the game for one video frame.
 *
 * During \c retro_run(), the \c retro_input_poll_t callback must be called at least once.
 *
 * @note If a frame is not rendered for reasons where a game "dropped" a frame,
 * this still counts as a frame, and \c retro_run() should explicitly dupe
 * a frame if \c RETRO_ENVIRONMENT_GET_CAN_DUPE returns true. In this case,
 * the video callback can take a NULL argument for data.
 *
 * @see retro_input_poll_t
 */
RETRO_API void retro_run(void);

/**
 * Returns the amount of data the implementation requires to serialize internal state (save states).
 *
 * @note Between calls to \c retro_load_game() and \c retro_unload_game(), the
 * returned size is never allowed to be larger than a previous returned
 * value, to ensure that the frontend can allocate a save state buffer once.
 *
 * @return The amount of data the implementation requires to serialize the internal state.
 *
 * @see retro_serialize()
 */
RETRO_API size_t retro_serialize_size(void);

/**
 * Serializes the internal state.
 *
 * @param data A pointer to where the serialized data should be saved to.
 * @param size The size of the memory.
 *
 * @return If failed, or size is lower than \c retro_serialize_size(), it
 * should return false. On success, it will return true.
 *
 * @see retro_serialize_size()
 * @see retro_unserialize()
 */
RETRO_API bool retro_serialize(void *data, size_t len);

/**
 * Unserialize the given state data, and load it into the internal state.
 *
 * @return Returns true if loading the state was successful, false otherwise.
 *
 * @see retro_serialize()
 */
RETRO_API bool retro_unserialize(const void *data, size_t len);

/**
 * Reset all the active cheats to their default disabled state.
 *
 * @see retro_cheat_set()
 */
RETRO_API void retro_cheat_reset(void);

/**
 * Enable or disable a cheat.
 *
 * @param index The index of the cheat to act upon.
 * @param enabled Whether to enable or disable the cheat.
 * @param code A string of the code used for the cheat.
 *
 * @see retro_cheat_reset()
 */
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);

/**
 * Loads a game.
 *
 * @param game A pointer to a \c retro_game_info detailing information about the game to load.
 * May be \c NULL if the core is loaded without content.
 *
 * @return Will return true when the game was loaded successfully, or false otherwise.
 *
 * @see retro_game_info
 * @see RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME
 */
RETRO_API bool retro_load_game(const struct retro_game_info *game);

/**
 * Called when the frontend has loaded one or more "special" content files,
 * typically through subsystems.
 *
 * @note Only necessary for cores that support subsystems.
 * Others may return \c false or delegate to &lt;tt&gt;retro_load_game&lt;/tt&gt;.
 *
 * @param game_type The type of game to load,
 * as determined by \c retro_subsystem_info.
 * @param info A pointer to an array of \c retro_game_info objects
 * providing information about the loaded content.
 * @param num_info The number of \c retro_game_info objects passed into the info parameter.
 * @return \c true if loading is successful, false otherwise.
 * If the core returns \c false,
 * the frontend should abort the core
 * and return to its main menu (if applicable).
 *
 * @see RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
 * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
 * @see retro_load_game()
 * @see retro_subsystem_info
 */
RETRO_API bool retro_load_game_special(
  unsigned game_type,
  const struct retro_game_info *info, size_t num_info
);

/**
 * Unloads the currently loaded game.
 *
 * @note This is called before \c retro_deinit(void).
 *
 * @see retro_load_game()
 * @see retro_deinit()
 */
RETRO_API void retro_unload_game(void);

/**
 * Gets the region of the actively loaded content as either \c RETRO_REGION_NTSC or \c RETRO_REGION_PAL.
 * @note This refers to the region of the content's intended television standard,
 * not necessarily the region of the content's origin.
 * For emulated consoles that don't use either standard
 * (e.g. handhelds or post-HD platforms),
 * the core should return \c RETRO_REGION_NTSC.
 * @return The region of the actively loaded content.
 *
 * @see RETRO_REGION_NTSC
 * @see RETRO_REGION_PAL
 */
RETRO_API unsigned retro_get_region(void);

/**
 * Get a region of memory.
 *
 * @param id The ID for the memory block that's desired to retrieve. Can be \c RETRO_MEMORY_SAVE_RAM, \c RETRO_MEMORY_RTC, \c RETRO_MEMORY_SYSTEM_RAM, or \c RETRO_MEMORY_VIDEO_RAM.
 *
 * @return A pointer to the desired region of memory, or NULL when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API void *retro_get_memory_data(unsigned id);

/**
 * Gets the size of the given region of memory.
 *
 * @param id The ID for the memory block to check the size of. Can be RETRO_MEMORY_SAVE_RAM, RETRO_MEMORY_RTC, RETRO_MEMORY_SYSTEM_RAM, or RETRO_MEMORY_VIDEO_RAM.
 *
 * @return The size of the region in memory, or 0 when not available.
 *
 * @see RETRO_MEMORY_SAVE_RAM
 * @see RETRO_MEMORY_RTC
 * @see RETRO_MEMORY_SYSTEM_RAM
 * @see RETRO_MEMORY_VIDEO_RAM
 */
RETRO_API size_t retro_get_memory_size(unsigned id);

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/lists/dir_list.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (dir_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;

#if defined(_WIN32) &amp;&amp; defined(_XBOX)
#include &lt;xtl.h&gt;
#elif defined(_WIN32)
#include &lt;windows.h&gt;
#endif

#include &lt;lists/dir_list.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;file/file_path.h&gt;

#include &lt;compat/strl.h&gt;
#include &lt;retro_dirent.h&gt;

#include &lt;string/stdstring.h&gt;
#include &lt;retro_miscellaneous.h&gt;

static int qstrcmp_plain(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;

   return strcasecmp(a-&gt;data, b-&gt;data);
}

static int qstrcmp_plain_noext(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;

   const char *ext_a = path_get_extension(a-&gt;data);
   size_t l_a = string_is_empty(ext_a) ? strlen(a-&gt;data) : (size_t)(ext_a - a-&gt;data - 1);
   const char *ext_b = path_get_extension(b-&gt;data);
   size_t l_b = string_is_empty(ext_b) ? strlen(b-&gt;data) : (size_t)(ext_b - b-&gt;data - 1);

   int rv = strncasecmp(a-&gt;data, b-&gt;data, MIN(l_a, l_b));
   if (rv == 0 &amp;&amp; l_a != l_b)
       return (int)(l_a - l_b);
   return rv;
}

static int qstrcmp_dir(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;
   int a_type = a-&gt;attr.i;
   int b_type = b-&gt;attr.i;

   /* Sort directories before files. */
   if (a_type != b_type)
      return b_type - a_type;
   return strcasecmp(a-&gt;data, b-&gt;data);
}

static int qstrcmp_dir_noext(const void *a_, const void *b_)
{
   const struct string_list_elem *a = (const struct string_list_elem*)a_;
   const struct string_list_elem *b = (const struct string_list_elem*)b_;
   int a_type = a-&gt;attr.i;
   int b_type = b-&gt;attr.i;

   /* Sort directories before files. */
   if (a_type != b_type)
      return b_type - a_type;
   return qstrcmp_plain_noext(a, b);
}

/**
 * dir_list_sort:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing.
 **/
void dir_list_sort(struct string_list *list, bool dir_first)
{
   if (list)
      qsort(list-&gt;elems, list-&gt;size, sizeof(struct string_list_elem),
            dir_first ? qstrcmp_dir : qstrcmp_plain);
}

/**
 * dir_list_sort_ignore_ext:
 * @list      : pointer to the directory listing.
 * @dir_first : move the directories in the listing to the top?
 *
 * Sorts a directory listing. File extensions are ignored.
 **/
void dir_list_sort_ignore_ext(struct string_list *list, bool dir_first)
{
   if (list)
      qsort(list-&gt;elems, list-&gt;size, sizeof(struct string_list_elem),
            dir_first ? qstrcmp_dir_noext : qstrcmp_plain_noext);
}

/**
 * dir_list_free:
 * @list : pointer to the directory listing
 *
 * Frees a directory listing.
 **/
void dir_list_free(struct string_list *list)
{
   string_list_free(list);
}

bool dir_list_deinitialize(struct string_list *list)
{
   if (!list)
      return false;
   return string_list_deinitialize(list);
}

/**
 * dir_list_read:
 * @dir                : directory path.
 * @list               : the string list to add files to
 * @ext_list           : the string list of extensions to include
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Add files within a directory to an existing string list
 *
 * @return -1 on error, 0 on success.
 **/
static int dir_list_read(const char *dir,
      struct string_list *list, struct string_list *ext_list,
      bool include_dirs, bool include_hidden,
      bool include_compressed, bool recursive)
{
   struct RDIR *entry = retro_opendir_include_hidden(dir, include_hidden);

   if (!entry)
      return -1;
   if (retro_dirent_error(entry))
   {
      retro_closedir(entry);
      return -1;
   }

   while (retro_readdir(entry))
   {
      union string_list_elem_attr attr;
      char file_path[PATH_MAX_LENGTH];
      const char *name                = retro_dirent_get_name(entry);

      if (name[0] == '.' || name[0] == '$')
      {
         /* Do not include hidden files and directories */
         if (!include_hidden)
            continue;

         /* char-wise comparisons to avoid string comparison */

         /* Do not include current dir */
         if (name[1] == '\0')
            continue;
         /* Do not include parent dir */
         if (name[1] == '.' &amp;&amp; name[2] == '\0')
            continue;
      }

      fill_pathname_join_special(file_path, dir, name, sizeof(file_path));

      if (retro_dirent_is_dir(entry, NULL))
      {
         /* Exclude this frequent hidden dir on platforms which can not handle hidden attribute */
         if (!include_hidden &amp;&amp; strcmp(name, "System Volume Information") == 0)
            continue;

#if defined(IOS) || defined(OSX)
         if (string_ends_with(name, ".framework"))
         {
            attr.i = RARCH_PLAIN_FILE;
            if (!string_list_append(list, file_path, attr))
            {
               retro_closedir(entry);
               return -1;
            }
            continue;
         }
#endif
         if (recursive)
            dir_list_read(file_path, list, ext_list, include_dirs,
                  include_hidden, include_compressed, recursive);

         if (!include_dirs)
            continue;
         attr.i = RARCH_DIRECTORY;
      }
      else
      {
         const char *file_ext    = path_get_extension(name);

         attr.i                  = RARCH_FILETYPE_UNSET;

         /*
          * If the file format is explicitly supported by the libretro-core, we
          * need to immediately load it and not designate it as a compressed file.
          *
          * Example: .zip could be supported as a image by the core and as a
          * compressed_file. In that case, we have to interpret it as a image.
          *
          * */
         if (string_list_find_elem_prefix(ext_list, ".", file_ext))
            attr.i            = RARCH_PLAIN_FILE;
         else
         {
            bool is_compressed_file;
            if ((is_compressed_file = path_is_compressed_file(file_path)))
               attr.i               = RARCH_COMPRESSED_ARCHIVE;

            if (ext_list &amp;&amp;
                  (!is_compressed_file || !include_compressed))
               continue;
         }
      }

      if (!string_list_append(list, file_path, attr))
      {
         retro_closedir(entry);
         return -1;
      }
   }

   retro_closedir(entry);

   return 0;
}

/**
 * dir_list_append:
 * @list               : existing list to append to.
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing, appending to an existing list
 *
 * @return Returns true on success, otherwise false.
 **/
bool dir_list_append(struct string_list *list,
      const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive)
{
   bool ret                         = false;
   struct string_list ext_list      = {0};
   struct string_list *ext_list_ptr = NULL;

   if (ext)
   {
      string_list_initialize(&amp;ext_list);
      string_split_noalloc(&amp;ext_list, ext, "|");
      ext_list_ptr                  = &amp;ext_list;
   }
   ret                            = dir_list_read(dir, list, ext_list_ptr,
         include_dirs, include_hidden, include_compressed, recursive) != -1;
   string_list_deinitialize(&amp;ext_list);
   return ret;
}

/**
 * dir_list_new:
 * @dir                : directory path.
 * @ext                : allowed extensions of file directory entries to include.
 * @include_dirs       : include directories as part of the finished directory listing?
 * @include_hidden     : include hidden files and directories as part of the finished directory listing?
 * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
 * @recursive          : list directory contents recursively
 *
 * Create a directory listing.
 *
 * @return pointer to a directory listing of type 'struct string_list *' on success,
 * NULL in case of error. Has to be freed manually.
 **/
struct string_list *dir_list_new(const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive)
{
   struct string_list *list       = string_list_new();

   if (!list)
      return NULL;

   if (!dir_list_append(list, dir, ext, include_dirs,
            include_hidden, include_compressed, recursive))
   {
      string_list_free(list);
      return NULL;
   }

   return list;
}

/**
 * dir_list_initialize:
 *
 * NOTE: @list must zero initialised before
 * calling this function, otherwise UB.
 **/
bool dir_list_initialize(struct string_list *list,
      const char *dir,
      const char *ext, bool include_dirs,
      bool include_hidden, bool include_compressed,
      bool recursive)
{
   if (list &amp;&amp; string_list_initialize(list))
      return dir_list_append(list, dir, ext, include_dirs,
            include_hidden, include_compressed, recursive);
   return false;
}</pre>
<h2>./include/libretro-common/lists/file_list.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_common.h&gt;
#include &lt;lists/file_list.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;compat/strcasestr.h&gt;

static bool file_list_deinitialize_internal(file_list_t *list)
{
   size_t i;
   for (i = 0; i &lt; list-&gt;size; i++)
   {
      file_list_free_userdata(list, i);
      file_list_free_actiondata(list, i);

      if (list-&gt;list[i].path)
         free(list-&gt;list[i].path);
      list-&gt;list[i].path = NULL;

      if (list-&gt;list[i].label)
         free(list-&gt;list[i].label);
      list-&gt;list[i].label = NULL;

      if (list-&gt;list[i].alt)
         free(list-&gt;list[i].alt);
      list-&gt;list[i].alt = NULL;
   }
   if (list-&gt;list)
      free(list-&gt;list);
   list-&gt;list = NULL;
   return true;
}

bool file_list_reserve(file_list_t *list, size_t nitems)
{
   const size_t item_size = sizeof(struct item_file);
   struct item_file *new_data;

   if (nitems &lt; list-&gt;capacity || nitems &gt; (size_t)-1/item_size)
      return false;

   if (!(new_data = (struct item_file*)realloc(list-&gt;list, nitems * item_size)))
      return false;

   memset(&amp;new_data[list-&gt;capacity], 0, item_size * (nitems - list-&gt;capacity));

   list-&gt;list     = new_data;
   list-&gt;capacity = nitems;

   return true;
}

/* Helper function to initialize item_file structure */
static INLINE void init_item_file(struct item_file *item,
    const char *path, const char *label, unsigned type,
    size_t directory_ptr, size_t entry_idx)
{
    item-&gt;path          = strdup(path);
    item-&gt;label         = strdup(label);
    item-&gt;alt           = NULL;
    item-&gt;type          = type;
    item-&gt;directory_ptr = directory_ptr;
    item-&gt;entry_idx     = entry_idx;
    item-&gt;userdata      = NULL;
    item-&gt;actiondata    = NULL;
}

bool file_list_insert(file_list_t *list,
      const char *path, const char *label,
      unsigned type, size_t directory_ptr,
      size_t entry_idx,
      size_t idx)
{
   /* Expand file list if needed */
   if (list-&gt;size &gt;= list-&gt;capacity)
   {
      size_t new_capacity = list-&gt;capacity &gt; 0 ? list-&gt;capacity * 2 : 1;
      if (!file_list_reserve(list, new_capacity))
         return false;
   }

   /* Shift elements to the right using memmove */
   if (idx &lt; list-&gt;size)
      memmove(&amp;list-&gt;list[idx + 1], &amp;list-&gt;list[idx],
            (list-&gt;size - idx) * sizeof(struct item_file));

   init_item_file(&amp;list-&gt;list[idx], path, label, type, directory_ptr, entry_idx);
   list-&gt;size++;

   return true;
}

bool file_list_append(file_list_t *list,
      const char *path, const char *label,
      unsigned type, size_t directory_ptr,
      size_t entry_idx)
{
   unsigned idx = (unsigned)list-&gt;size;
   /* Expand file list if needed */
   if (idx &gt;= list-&gt;capacity)
      if (!file_list_reserve(list, list-&gt;capacity * 2 + 1))
         return false;

   list-&gt;list[idx].path          = NULL;
   list-&gt;list[idx].label         = NULL;
   list-&gt;list[idx].alt           = NULL;
   list-&gt;list[idx].type          = type;
   list-&gt;list[idx].directory_ptr = directory_ptr;
   list-&gt;list[idx].entry_idx     = entry_idx;
   list-&gt;list[idx].userdata      = NULL;
   list-&gt;list[idx].actiondata    = NULL;

   if (label)
      list-&gt;list[idx].label      = strdup(label);
   if (path)
      list-&gt;list[idx].path       = strdup(path);

   list-&gt;size++;

   return true;
}

void file_list_pop(file_list_t *list, size_t *directory_ptr)
{
   if (!list)
      return;

   if (list-&gt;size != 0)
   {
      --list-&gt;size;
      if (list-&gt;list[list-&gt;size].path)
         free(list-&gt;list[list-&gt;size].path);
      list-&gt;list[list-&gt;size].path = NULL;

      if (list-&gt;list[list-&gt;size].label)
         free(list-&gt;list[list-&gt;size].label);
      list-&gt;list[list-&gt;size].label = NULL;
   }

   if (directory_ptr)
      *directory_ptr = list-&gt;list[list-&gt;size].directory_ptr;
}

void file_list_free(file_list_t *list)
{
   if (!list)
      return;
   file_list_deinitialize_internal(list);
   free(list);
}

bool file_list_deinitialize(file_list_t *list)
{
   if (!list)
      return false;
   if (!file_list_deinitialize_internal(list))
      return false;
   list-&gt;capacity = 0;
   list-&gt;size     = 0;
   return true;
}

void file_list_clear(file_list_t *list)
{
   size_t i;

   if (!list)
      return;

   for (i = 0; i &lt; list-&gt;size; i++)
   {
      if (list-&gt;list[i].path)
         free(list-&gt;list[i].path);
      list-&gt;list[i].path = NULL;

      if (list-&gt;list[i].label)
         free(list-&gt;list[i].label);
      list-&gt;list[i].label = NULL;

      if (list-&gt;list[i].alt)
         free(list-&gt;list[i].alt);
      list-&gt;list[i].alt = NULL;
   }

   list-&gt;size = 0;
}

static void file_list_get_label_at_offset(const file_list_t *list, size_t idx,
      const char **label)
{
   if (!label || !list)
      return;

   *label = list-&gt;list[idx].path;
   if (list-&gt;list[idx].label)
      *label = list-&gt;list[idx].label;
}

void file_list_set_alt_at_offset(file_list_t *list, size_t idx,
      const char *alt)
{
   if (!list || !alt)
      return;
   if (list-&gt;list[idx].alt)
      free(list-&gt;list[idx].alt);
   list-&gt;list[idx].alt   = strdup(alt);
}

static int file_list_alt_cmp(const void *a_, const void *b_)
{
   const struct item_file *a = (const struct item_file*)a_;
   const struct item_file *b = (const struct item_file*)b_;
   const char *cmp_a         = a-&gt;alt ? a-&gt;alt : a-&gt;path;
   const char *cmp_b         = b-&gt;alt ? b-&gt;alt : b-&gt;path;
   return strcasecmp(cmp_a, cmp_b);
}

static int file_list_type_cmp(const void *a_, const void *b_)
{
   const struct item_file *a = (const struct item_file*)a_;
   const struct item_file *b = (const struct item_file*)b_;
   if (a-&gt;type &lt; b-&gt;type)
      return -1;
   if (a-&gt;type == b-&gt;type)
      return 0;

   return 1;
}

void file_list_sort_on_alt(file_list_t *list)
{
   qsort(list-&gt;list, list-&gt;size, sizeof(list-&gt;list[0]), file_list_alt_cmp);
}

void file_list_sort_on_type(file_list_t *list)
{
   qsort(list-&gt;list, list-&gt;size, sizeof(list-&gt;list[0]), file_list_type_cmp);
}

void *file_list_get_userdata_at_offset(const file_list_t *list, size_t idx)
{
   if (!list)
      return NULL;
   return list-&gt;list[idx].userdata;
}

void *file_list_get_actiondata_at_offset(const file_list_t *list, size_t idx)
{
   if (!list)
      return NULL;
   return list-&gt;list[idx].actiondata;
}

void file_list_free_actiondata(const file_list_t *list, size_t idx)
{
   if (!list)
      return;
   if (list-&gt;list[idx].actiondata)
       free(list-&gt;list[idx].actiondata);
   list-&gt;list[idx].actiondata = NULL;
}

void file_list_free_userdata(const file_list_t *list, size_t idx)
{
   if (!list)
      return;
   if (list-&gt;list[idx].userdata)
       free(list-&gt;list[idx].userdata);
   list-&gt;list[idx].userdata = NULL;
}

bool file_list_search(const file_list_t *list, const char *needle, size_t *idx)
{
   size_t i;
   bool ret        = false;

   if (!list)
      return false;

   for (i = 0; i &lt; list-&gt;size; i++)
   {
      const char *str = NULL;
      const char *alt = list-&gt;list[i].alt
            ? list-&gt;list[i].alt
            : list-&gt;list[i].path;

      if (!alt)
      {
         file_list_get_label_at_offset(list, i, &amp;alt);
         if (!alt)
            continue;
      }

      if ((str = (const char *)strcasestr(alt, needle)) == alt)
      {
         /* Found match with first chars, best possible match. */
         *idx = i;
         ret  = true;
         break;
      }
      else if (str &amp;&amp; !ret)
      {
         /* Found mid-string match, but try to find a match with
          * first characters before we settle. */
         *idx = i;
         ret  = true;
      }
   }

   return ret;
}</pre>
<h2>./include/libretro-common/lists/linked_list.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (linked_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;boolean.h&gt;
#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;lists/linked_list.h&gt;

struct linked_list_item_t
{
   void *value;
   struct linked_list_item_t *previous;
   struct linked_list_item_t *next;
};

struct linked_list
{
   struct linked_list_item_t *first_item;
   struct linked_list_item_t *last_item;
   size_t length;
};

struct linked_list_iterator
{
   linked_list_t *list;
   struct linked_list_item_t *item;
   bool forward;
};

linked_list_t *linked_list_new(void)
{
   linked_list_t *list;

   list = (linked_list_t *)calloc(1, sizeof(linked_list_t));
   return list;
}

void linked_list_free(linked_list_t *list, void (*free_value)(void *value))
{
   if (!list)
   {
      return;
   }

   while (list-&gt;first_item)
   {
      struct linked_list_item_t *next;

      next = list-&gt;first_item-&gt;next;
      if (free_value)
         free_value(list-&gt;first_item-&gt;value);
      free(list-&gt;first_item);

      list-&gt;first_item = next;
   }

   free (list);
}

void linked_list_add(linked_list_t *list, void *value)
{
   struct linked_list_item_t *new_item;

   if (!list)
      return;

   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));
   new_item-&gt;value = value;
   new_item-&gt;previous = list-&gt;last_item;
   new_item-&gt;next = NULL;

   if (list-&gt;length == 0)
      list-&gt;first_item = new_item;
   else
      list-&gt;last_item-&gt;next = new_item;

   list-&gt;last_item = new_item;
   list-&gt;length++;
}

void linked_list_insert(linked_list_t *list, size_t index, void *value)
{
   size_t i;
   struct linked_list_item_t *previous_item;
   struct linked_list_item_t *next_item;
   struct linked_list_item_t *new_item;

   if (!list || index &gt; list-&gt;length)
      return;

   previous_item = NULL;
   next_item = list-&gt;first_item;
   for (i = 1; i &lt;= index; i++)
   {
      previous_item = next_item;
      next_item = next_item-&gt;next;
   }

   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));
   new_item-&gt;value = value;

   if (previous_item)
      previous_item-&gt;next = new_item;
   else
      list-&gt;first_item = new_item;
   new_item-&gt;previous = previous_item;

   if (next_item)
      next_item-&gt;previous = new_item;
   else
      list-&gt;last_item = new_item;
   new_item-&gt;next = next_item;

   list-&gt;length++;
}

void *linked_list_get(linked_list_t *list, size_t index)
{
   size_t i;
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   if (index &gt;= list-&gt;length)
      return NULL;

   item = list-&gt;first_item;
   for (i = 1; i &lt;= index; i++)
      item = item-&gt;next;

   return item-&gt;value;
}

void *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)
{
   struct linked_list_item_t *item;

   if (!list || !matches)
      return NULL;

   for (item = list-&gt;first_item; item; item = item-&gt;next)
   {
      if (matches(item-&gt;value, usrptr))
         return item-&gt;value;
   }

   return NULL;
}

void *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)
{
   struct linked_list_item_t *item;

   if (!list || !matches)
      return NULL;

   for (item = list-&gt;last_item; item; item = item-&gt;previous)
   {
      if (matches(item-&gt;value, usrptr))
         return item-&gt;value;
   }

   return NULL;
}

static void _linked_list_remove_item(linked_list_t *list, struct linked_list_item_t *item)
{
   struct linked_list_item_t *previous_item;
   struct linked_list_item_t *next_item;

   previous_item = item-&gt;previous;
   next_item = item-&gt;next;
   free(item);
   list-&gt;length--;

   if (previous_item)
      previous_item-&gt;next = next_item;
   else
      list-&gt;first_item = next_item;

   if (next_item)
      next_item-&gt;previous = previous_item;
   else
      list-&gt;last_item = previous_item;
}

void *linked_list_remove_at(linked_list_t *list, size_t index)
{
   size_t i = 0;
   struct linked_list_item_t *item;
   void *value;

   if (!list || list-&gt;length == 0 || index &gt;= list-&gt;length)
      return NULL;

   item = list-&gt;first_item;
   for (i = 1; i &lt;= index; i++)
      item = item-&gt;next;

   value = item-&gt;value;
   _linked_list_remove_item(list, item);
   return value;
}

void *linked_list_remove_first(linked_list_t *list, void *value)
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list-&gt;first_item; item; item = item-&gt;next)
   {
      if (item-&gt;value == value)
         break;
   }

   if (item)
   {
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void *linked_list_remove_last(linked_list_t *list, void *value)
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list-&gt;last_item; item; item = item-&gt;previous)
   {
      if (item-&gt;value == value)
         break;
   }

   if (item)
   {
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void *linked_list_remove_all(linked_list_t *list, void *value)
{
   struct linked_list_item_t *item;
   bool found = false;

   if (!list)
      return NULL;

   for (item = list-&gt;first_item; item;)
   {
      if (item-&gt;value == value)
      {
         struct linked_list_item_t *next_item;

         next_item = item-&gt;next;
         _linked_list_remove_item(list, item);
         found = true;
         item = next_item;
      } else
      {
         item = item-&gt;next;
      }
   }

   return found ? value : NULL;
}

void *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value))
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list-&gt;first_item; item; item = item-&gt;next)
   {
      if (matches(item-&gt;value))
         break;
   }

   if (item)
   {
      void *value;

      value = item-&gt;value;
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value))
{
   struct linked_list_item_t *item;

   if (!list)
      return NULL;

   for (item = list-&gt;last_item; item; item = item-&gt;previous)
   {
      if (matches(item-&gt;value))
         break;
   }

   if (item)
   {
      void *value;

      value = item-&gt;value;
      _linked_list_remove_item(list, item);
      return value;
   }

   return NULL;
}

void linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value))
{
   struct linked_list_item_t *item;

   if (!list)
      return;

   for (item = list-&gt;first_item; item;)
   {
      if (matches(item-&gt;value))
      {
         struct linked_list_item_t *next_item;

         next_item = item-&gt;next;
         _linked_list_remove_item(list, item);
         item = next_item;
      } else
      {
         item = item-&gt;next;
      }
   }
}

bool linked_list_set_at(linked_list_t *list, size_t index, void *value)
{
   struct linked_list_item_t *item;
   size_t i;

   if (!list || list-&gt;length == 0 || index &gt;= list-&gt;length)
      return false;

   item = list-&gt;first_item;
   for (i = 1; i &lt;= index; i++)
      item = item-&gt;next;

   if (item)
   {
      item-&gt;value = value;
      return true;
   }

   return false;
}

size_t linked_list_size(linked_list_t *list)
{
   if (list)
      return list-&gt;length;

   return 0;
}

linked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward)
{
   linked_list_iterator_t *iterator;

   if (!list || !list-&gt;first_item)
      return NULL;

   iterator = (linked_list_iterator_t *)malloc(sizeof(linked_list_iterator_t));
   iterator-&gt;list = list;
   iterator-&gt;item = forward ? list-&gt;first_item : list-&gt;last_item;
   iterator-&gt;forward = forward;

   return iterator;
}

linked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator)
{
   struct linked_list_item_t *item;

   if (!iterator)
      return NULL;

   item = iterator-&gt;forward ? iterator-&gt;item-&gt;next : iterator-&gt;item-&gt;previous;
   if (item)
   {
      iterator-&gt;item = item;
      return iterator;
   } else
   {
      free(iterator);
      return NULL;
   }
}

void *linked_list_iterator_value(linked_list_iterator_t *iterator)
{
   if (iterator)
      return iterator-&gt;item-&gt;value;

   return NULL;
}

linked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator)
{
   struct linked_list_item_t *next_item;

   if (!iterator)
      return NULL;

   next_item = iterator-&gt;forward ? iterator-&gt;item-&gt;next : iterator-&gt;item-&gt;previous;
   _linked_list_remove_item(iterator-&gt;list, iterator-&gt;item);

   if (next_item)
   {
      iterator-&gt;item = next_item;
      return iterator;
   } else
   {
      free(iterator);
      return NULL;
   }
}

void linked_list_iterator_free(linked_list_iterator_t *iterator)
{
   if (iterator)
      free(iterator);
}

void linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value))
{
   size_t i;
   struct linked_list_item_t *item;

   if (!list || !fn)
      return;

   i = 0;
   for (item = list-&gt;first_item; item; item = item-&gt;next)
      fn(i++, item-&gt;value);
}</pre>
<h2>./include/libretro-common/lists/nested_list.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (nested_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;string/stdstring.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;array/rbuf.h&gt;
#include &lt;array/rhmap.h&gt;

#include &lt;lists/nested_list.h&gt;

struct nested_list_item
{
   nested_list_item_t *parent_item;
   nested_list_t *parent_list;
   nested_list_t *children;
   char *id;
   const void *value;
};

struct nested_list
{
   nested_list_item_t **items;
   nested_list_item_t **item_map;
};

/**************************************/
/* Initialisation / De-Initialisation */
/**************************************/

/* Forward declaration - required since
 * nested_list_free_list() is recursive */
static void nested_list_free_list(nested_list_t *list);

/* Frees contents of a nested list item */
static void nested_list_free_item(nested_list_item_t *item)
{
   if (!item)
      return;

   item-&gt;parent_item = NULL;
   item-&gt;parent_list = NULL;

   if (item-&gt;children)
   {
      nested_list_free_list(item-&gt;children);
      item-&gt;children = NULL;
   }

   if (item-&gt;id)
   {
      free(item-&gt;id);
      item-&gt;id = NULL;
   }

   item-&gt;value = NULL;
   free(item);
}

/* Frees contents of a nested list */
static void nested_list_free_list(nested_list_t *list)
{
   size_t i;

   if (!list)
      return;

   for (i = 0; i &lt; RBUF_LEN(list-&gt;items); i++)
      nested_list_free_item(list-&gt;items[i]);

   RBUF_FREE(list-&gt;items);
   RHMAP_FREE(list-&gt;item_map);
   free(list);
}

/**
 * nested_list_init:
 *
 * Creates a new empty nested list. Returned pointer
 * must be freed using nested_list_free.
 *
 * Returns: Valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_init(void)
{
   /* Create nested list */
   nested_list_t *list = (nested_list_t*)malloc(sizeof(*list));

   if (!list)
      return NULL;

   /* Initialise members */
   list-&gt;items    = NULL;
   list-&gt;item_map = NULL;

   return list;
}

/**
 * nested_list_free:
 * @list : pointer to nested_list_t object
 *
 * Frees specified nested list.
 */
void nested_list_free(nested_list_t *list)
{
   nested_list_free_list(list);
}

/***********/
/* Setters */
/***********/

/* Creates and adds a new item to the specified
 * nested list. Returns NULL if item matching 'id'
 * already exists */
static nested_list_item_t *nested_list_add_item_to_list(nested_list_t *list,
      nested_list_item_t *parent_item, const char *id, const void *value)
{
   size_t num_items             = 0;
   nested_list_item_t *new_item = NULL;
   nested_list_t *child_list    = NULL;

   if (!list || string_is_empty(id))
      goto end;

   num_items = RBUF_LEN(list-&gt;items);

   /* Ensure that item does not already exist */
   if (RHMAP_HAS_STR(list-&gt;item_map, id))
      goto end;

   /* Attempt to allocate a buffer slot for the
    * new item */
   if (!RBUF_TRYFIT(list-&gt;items, num_items + 1))
      goto end;

   /* Create new empty child list */
   child_list = nested_list_init();
   if (!child_list)
      goto end;

   /* Create new list item */
   new_item = (nested_list_item_t*)malloc(sizeof(*new_item));
   if (!new_item)
   {
      nested_list_free(child_list);
      goto end;
   }

   /* Assign members */
   new_item-&gt;parent_item = parent_item;
   new_item-&gt;parent_list = list;
   new_item-&gt;children    = child_list;
   new_item-&gt;id          = strdup(id);
   new_item-&gt;value       = value;

   /* Increment item buffer size */
   RBUF_RESIZE(list-&gt;items, num_items + 1);

   /* Add new item to buffer */
   list-&gt;items[num_items] = new_item;

   /* Update map */
   RHMAP_SET_STR(list-&gt;item_map, id, new_item);
end:
   return new_item;
}

/**
 * nested_list_add_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 * @value   : optional value (user data) associated with
 *            new list item. This is added to the last
 *            item specified by @address
 *
 * Appends a new item to the specified nested list.
 * If @delim is NULL, item is added to the top level
 * list (@list itself) with id equal to @address.
 * Otherwise, @address is split by @delim and each
 * id is added as new 'layer'. For example:
 *
 * &gt; @address = "one:two:three", @delim = ":" will
 *   produce:
 *      top_level_list:one
 *                     `- "one" list:two
 *                                   `- "two" list:three
 *   where @value is assigned to the "two" list:three
 *   item.
 *
 * Returns: true if successful, otherwise false. Will
 * always return false if item specified by @address
 * already exists in the nested list.
 */
bool nested_list_add_item(nested_list_t *list,
      const char *address, const char *delim, const void *value)
{
   struct string_list id_list = {0};
   const char *top_id         = NULL;
   bool success               = false;

   if (!list || string_is_empty(address))
      return false;

   /* If delim is NULL or address contains a single
    * token, then we are adding an item to the top
    * level list */
   if (string_is_empty(delim))
      top_id = address;
   else
   {
      string_list_initialize(&amp;id_list);
      if (  !string_split_noalloc(&amp;id_list, address, delim)
          || (id_list.size &lt; 1))
         goto end;

      if (id_list.size == 1)
         top_id = id_list.elems[0].data;
   }

   if (!string_is_empty(top_id))
   {
      if (nested_list_add_item_to_list(list, NULL, top_id, value))
         success = true;
   }
   else
   {
      size_t i;
      nested_list_t *current_list     = list;
      nested_list_item_t *parent_item = NULL;
      nested_list_item_t *next_item   = NULL;

      /* Loop over list item ids */
      for (i = 0; i &lt; id_list.size; i++)
      {
         const char *id = id_list.elems[i].data;

         if (string_is_empty(id))
            goto end;

         /* If this is the last entry in the id list,
          * then we are adding the item itself */
         if (i == (id_list.size - 1))
         {
            if (nested_list_add_item_to_list(current_list,
                  parent_item, id, value))
               success = true;

            break;
         }
         /* Otherwise, id corresponds to a 'category' */
         else
         {
            /* Check whether category item already exists */
            next_item = RHMAP_GET_STR(current_list-&gt;item_map, id);

            /* Create it, if required */
            if (!next_item)
               next_item = nested_list_add_item_to_list(current_list,
                     parent_item, id, NULL);

            if (!next_item)
               break;

            /* Update pointers */
            parent_item  = next_item;
            current_list = next_item-&gt;children;
         }
      }
   }

end:
   string_list_deinitialize(&amp;id_list);
   return success;
}

/***********/
/* Getters */
/***********/

/**
 * nested_list_get_size:
 *
 * @list : pointer to nested_list_t object
 *
 * Fetches the current size (number of items) in
 * the specified list.
 *
 * Returns: list size.
 */
size_t nested_list_get_size(nested_list_t *list)
{
   if (!list)
      return 0;

   return RBUF_LEN(list-&gt;items);
}

/**
 * nested_list_get_item:
 *
 * @list    : pointer to nested_list_t object
 * @address : a delimited list of item identifiers,
 *            corresponding to item 'levels'
 * @delim   : delimiter to use when splitting @address
 *            into individual ids
 *
 * Searches for (and returns) the list item corresponding
 * to @address. If @delim is NULL, the top level list
 * (@list itself) is searched for an item with an id
 * equal to @address. Otherwise, @address is split by
 * @delim and each id is searched for in a subsequent
 * list level.
 *
 * Returns: valid nested_list_item_t pointer if item
 * is found, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item(nested_list_t *list,
      const char *address, const char *delim)
{
   nested_list_item_t *search_item = NULL;
   struct string_list id_list      = {0};
   const char *top_id              = NULL;

   if (!list || string_is_empty(address))
      goto end;

   /* If delim is NULL or address contains a single
    * token, then we are fetching an item from the
    * top level list */
   if (string_is_empty(delim))
      top_id = address;
   else
   {
      string_list_initialize(&amp;id_list);
      if (  !string_split_noalloc(&amp;id_list, address, delim)
          || (id_list.size &lt; 1))
         goto end;

      if (id_list.size == 1)
         top_id = id_list.elems[0].data;
   }

   if (!string_is_empty(top_id))
      search_item = RHMAP_GET_STR(list-&gt;item_map, top_id);
   else
   {
      /* Otherwise, search 'category' levels */
      nested_list_t *current_list   = list;
      nested_list_item_t *next_item = NULL;
      size_t i;

      /* Loop over list item ids */
      for (i = 0; i &lt; id_list.size; i++)
      {
         const char *id = id_list.elems[i].data;

         if (string_is_empty(id))
            goto end;

         /* If this is the last entry in the id list,
          * then we are searching for the item itself */
         if (i == (id_list.size - 1))
         {
            search_item = RHMAP_GET_STR(current_list-&gt;item_map, id);
            break;
         }
         /* Otherwise, id corresponds to a 'category' */
         else
         {
            next_item = RHMAP_GET_STR(current_list-&gt;item_map, id);

            if (!next_item)
               break;

            /* Update pointer */
            current_list = next_item-&gt;children;
         }
      }
   }

end:
   string_list_deinitialize(&amp;id_list);
   return search_item;
}

/**
 * nested_list_get_item_idx:
 *
 * @list : pointer to nested_list_t object
 * @idx  : item index
 *
 * Fetches the item corresponding to index @idx in
 * the top level list (@list itself) of the specified
 * nested list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * exists, otherwise NULL.
 */
nested_list_item_t *nested_list_get_item_idx(nested_list_t *list,
      size_t idx)
{
   if (!list || (idx &gt;= RBUF_LEN(list-&gt;items)))
      return NULL;

   return list-&gt;items[idx];
}

/**
 * nested_list_item_get_parent:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the parent item of the specified nested
 * list item. If returned value is NULL, specified
 * nested list item belongs to a top level list.
 *
 * Returns: valid nested_list_item_t pointer if item
 * has a parent, otherwise NULL.
 */
nested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;

   return list_item-&gt;parent_item;
}

/**
 * nested_list_item_get_parent_list:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of which the
 * specified list item is a direct member.
 *
 * Returns: valid nested_list_t pointer if successful,
 * otherwise NULL.
 */
nested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;

   return list_item-&gt;parent_list;
}

/**
 * nested_list_item_get_children:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches a pointer to the nested list of child items
 * belonging to the specified list item.
 *
 * Returns: valid nested_list_t pointer if item has
 * children, otherwise NULL.
 */
nested_list_t *nested_list_item_get_children(nested_list_item_t *list_item)
{
   if (   !list_item
       || !list_item-&gt;children
       || (RBUF_LEN(list_item-&gt;children-&gt;items) &lt; 1))
      return NULL;

   return list_item-&gt;children;
}

/**
 * nested_list_item_get_id:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the id string of the specified list item,
 * as set by nested_list_add_item().
 *
 * Returns: item id if successful, otherwise NULL.
 */
const char *nested_list_item_get_id(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;
   return list_item-&gt;id;
}

/**
 * nested_list_item_get_address:
 *
 * @list_item : pointer to nested_list_item_t object
 * @delim     : delimiter to use when concatenating
 *              individual item ids into a an @address
 *              string
 * @s         : a delimited list of item identifiers,
 *              corresponding to item 'levels'
 * @len       : length of supplied @address char array

 * Fetches a compound @address string corresponding to
 * the specified item's 'position' in the top level
 * nested list of which it is a member. The resultant
 * @address may be used to find the item when calling
 * nested_list_get_item() on the top level nested list.
 *
 * Returns: true if successful, otherwise false.
 */
bool nested_list_item_get_address(nested_list_item_t *list_item,
      const char *delim, char *s, size_t len)
{
   if (  !list_item
       || string_is_empty(delim)
       || !s
       || (len &lt; 1))
      return false;

   s[0] = '\0';

   /* We have to combine the IDs
    * of the item and all of its 'ancestors' */
   if (list_item-&gt;parent_item)
   {
      size_t i;
      union string_list_elem_attr attr;
      struct string_list id_list       = {0};
      nested_list_item_t *current_item = list_item;

      string_list_initialize(&amp;id_list);
      attr.i     = 0;

      /* Fetch all ids */
      do
      {
         const char *id = current_item-&gt;id;
         if (    string_is_empty(id)
             || !string_list_append(&amp;id_list, id, attr))
         {
            string_list_deinitialize(&amp;id_list);
            return false;
         }

         current_item = current_item-&gt;parent_item;
      } while (current_item);

      /* Build address string */
      for (i = id_list.size; i &gt; 0; i--)
      {
         size_t _len;
         const char *id = id_list.elems[i - 1].data;

         if (string_is_empty(id))
         {
            string_list_deinitialize(&amp;id_list);
            return false;
         }

         _len = strlcat(s, id, len);
         if (i &gt; 1)
            strlcpy(s + _len, delim, len - _len);
      }
      string_list_deinitialize(&amp;id_list);
   }
   /* If this is an item of the top level
    * list, just copy the item ID directly */
   else
      strlcpy(s, list_item-&gt;id, len);

   return true;
}

/**
 * nested_list_item_get_value:
 *
 * @list_item : pointer to nested_list_item_t object
 *
 * Fetches the value (user data) associated with the
 * specified list item.
 *
 * Returns: pointer to user data if set, otherwise
 * NULL.
 */
const void *nested_list_item_get_value(nested_list_item_t *list_item)
{
   if (!list_item)
      return NULL;

   return list_item-&gt;value;
}</pre>
<h2>./include/libretro-common/lists/string_list.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (string_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;

#include &lt;lists/string_list.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;compat/posix_string.h&gt;
#include &lt;string/stdstring.h&gt;

static bool string_list_deinitialize_internal(struct string_list *list)
{
   if (!list)
      return false;

   if (list-&gt;elems)
   {
      unsigned i;
      for (i = 0; i &lt; (unsigned)list-&gt;size; i++)
      {
         if (list-&gt;elems[i].data)
            free(list-&gt;elems[i].data);
         if (list-&gt;elems[i].userdata)
            free(list-&gt;elems[i].userdata);
         list-&gt;elems[i].data     = NULL;
         list-&gt;elems[i].userdata = NULL;
      }

      free(list-&gt;elems);
   }

   list-&gt;elems = NULL;

   return true;
}

bool string_list_capacity(struct string_list *list, size_t cap)
{
   struct string_list_elem *new_data = (struct string_list_elem*)
      realloc(list-&gt;elems, cap * sizeof(*new_data));

   if (!new_data)
      return false;

   if (cap &gt; list-&gt;cap)
      memset(&amp;new_data[list-&gt;cap], 0, sizeof(*new_data) * (cap - list-&gt;cap));

   list-&gt;elems = new_data;
   list-&gt;cap   = cap;
   return true;
}

void string_list_free(struct string_list *list)
{
   if (!list)
      return;

   string_list_deinitialize_internal(list);

   free(list);
}

bool string_list_deinitialize(struct string_list *list)
{
   if (!list)
      return false;
   if (!string_list_deinitialize_internal(list))
      return false;
   list-&gt;elems              = NULL;
   list-&gt;size               = 0;
   list-&gt;cap                = 0;
   return true;
}

struct string_list *string_list_new(void)
{
   struct string_list_elem *
      elems                 = NULL;
   struct string_list *list = (struct string_list*)
      malloc(sizeof(*list));
   if (!list)
      return NULL;

   list-&gt;cap                = 0;
   list-&gt;size               = 0;
   list-&gt;elems              = NULL;

   if (!(elems = (struct string_list_elem*)
      calloc(32, sizeof(*elems))))
   {
      string_list_free(list);
      return NULL;
   }

   list-&gt;elems              = elems;
   list-&gt;cap                = 32;

   return list;
}

bool string_list_initialize(struct string_list *list)
{
   struct string_list_elem *
      elems                 = NULL;
   if (!list)
      return false;
   if (!(elems = (struct string_list_elem*)
      calloc(32, sizeof(*elems))))
   {
      string_list_deinitialize(list);
      return false;
   }
   list-&gt;elems              = elems;
   list-&gt;size               = 0;
   list-&gt;cap                = 32;
   return true;
}

bool string_list_append(struct string_list *list, const char *elem,
      union string_list_elem_attr attr)
{
   char *data_dup = NULL;

   /* Note: If 'list' is incorrectly initialised
    * (i.e. if struct is zero initialised and
    * string_list_initialize() is not called on
    * it) capacity will be zero. This will cause
    * a segfault. Handle this case by forcing the new
    * capacity to a fixed size of 32 */
   if (      list-&gt;size &gt;= list-&gt;cap
         &amp;&amp; !string_list_capacity(list,
               (list-&gt;cap &gt; 0) ? (list-&gt;cap * 2) : 32))
      return false;

   if (!(data_dup = strdup(elem)))
      return false;

   list-&gt;elems[list-&gt;size].data = data_dup;
   list-&gt;elems[list-&gt;size].attr = attr;

   list-&gt;size++;
   return true;
}

void string_list_join_concat(char *s, size_t len,
      const struct string_list *list, const char *delim)
{
   size_t _len = strlen(s);

   /* If @s is already 'full', nothing
    * further can be added
    * &gt; This condition will also be triggered
    *   if @s is not NULL-terminated,
    *   in which case any attempt to increment
    *   @s or decrement @len would lead to
    *   undefined behaviour */
   if (_len &lt; len)
   {
      size_t i;
      for (i = 0; i &lt; list-&gt;size; i++)
      {
         _len += strlcpy(s + _len, list-&gt;elems[i].data, len - _len);
         if ((i + 1) &lt; list-&gt;size)
            _len += strlcpy(s + _len, delim, len - _len);
      }
   }
}

void string_list_join_concat_special(char *s, size_t len,
      const struct string_list *list, const char *delim)
{
   size_t i;
   size_t _len = strlen(s);
   for (i = 0; i &lt; list-&gt;size; i++)
   {
      _len += strlcpy(s + _len, list-&gt;elems[i].data, len - _len);
      if ((i + 1) &lt; list-&gt;size)
         _len += strlcpy(s + _len, delim, len - _len);
   }
}

struct string_list *string_split(const char *str, const char *delim)
{
   char *save      = NULL;
   char *copy      = NULL;
   const char *tmp = NULL;
   struct string_list *list = string_list_new();

   if (!list)
      return NULL;

   if (!(copy = strdup(str)))
      goto error;

   tmp = strtok_r(copy, delim, &amp;save);
   while (tmp)
   {
      union string_list_elem_attr attr;

      attr.i = 0;

      if (!string_list_append(list, tmp, attr))
         goto error;

      tmp = strtok_r(NULL, delim, &amp;save);
   }

   free(copy);
   return list;

error:
   string_list_free(list);
   free(copy);
   return NULL;
}

bool string_split_noalloc(struct string_list *list,
      const char *str, const char *delim)
{
   char *save      = NULL;
   char *copy      = NULL;
   const char *tmp = NULL;

   if (!list)
      return false;

   if (!(copy = strdup(str)))
      return false;

   tmp             = strtok_r(copy, delim, &amp;save);
   while (tmp)
   {
      union string_list_elem_attr attr;

      attr.i = 0;

      if (!string_list_append(list, tmp, attr))
      {
         free(copy);
         return false;
      }

      tmp = strtok_r(NULL, delim, &amp;save);
   }

   free(copy);
   return true;
}

int string_list_find_elem(const struct string_list *list, const char *elem)
{
   if (list)
   {
      size_t i;
      for (i = 0; i &lt; list-&gt;size; i++)
      {
         if (string_is_equal_noncase(list-&gt;elems[i].data, elem))
            return (int)(i + 1);
      }
   }
   return 0;
}

bool string_list_find_elem_prefix(const struct string_list *list,
      const char *prefix, const char *elem)
{
   if (list)
   {
      size_t i;
      char prefixed[255];
      size_t _len  = strlcpy(prefixed, prefix, sizeof(prefixed));
      strlcpy(prefixed + _len, elem, sizeof(prefixed) - _len);
      for (i = 0; i &lt; list-&gt;size; i++)
      {
         if (     string_is_equal_noncase(list-&gt;elems[i].data, elem)
               || string_is_equal_noncase(list-&gt;elems[i].data, prefixed))
            return true;
      }
   }
   return false;
}

struct string_list *string_list_clone(const struct string_list *src)
{
   size_t i;
   struct string_list_elem *elems = NULL;
   struct string_list *dest       = (struct string_list*)
      malloc(sizeof(struct string_list));

   if (!dest)
      return NULL;

   dest-&gt;elems               = NULL;
   dest-&gt;size                = src-&gt;size;
   if (src-&gt;cap &lt; dest-&gt;size)
      dest-&gt;cap              = dest-&gt;size;
   else
      dest-&gt;cap              = src-&gt;cap;

   if (!(elems = (struct string_list_elem*)
      calloc(dest-&gt;cap, sizeof(struct string_list_elem))))
   {
      free(dest);
      return NULL;
   }

   dest-&gt;elems               = elems;

   for (i = 0; i &lt; src-&gt;size; i++)
   {
      const char *_src    = src-&gt;elems[i].data;
      size_t      len     = _src ? strlen(_src) : 0;

      dest-&gt;elems[i].data = NULL;
      dest-&gt;elems[i].attr = src-&gt;elems[i].attr;

      if (len != 0)
      {
         char *ret        = (char*)malloc(len + 1);
         if (ret)
         {
            strcpy(ret, _src);
            dest-&gt;elems[i].data = ret;
         }
      }
   }

   return dest;
}</pre>
<h2>./include/libretro-common/lists/vector_list.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (vector_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;boolean.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;

/* default type is void*, override by defining VECTOR_LIST_TYPE before inclusion */
#ifndef VECTOR_LIST_TYPE
#define VECTOR_LIST_TYPE void*
#define VECTOR_LIST_TYPE_DEFINED
#endif

/* default name is void, override by defining VECTOR_LIST_NAME before inclusion */
#ifndef VECTOR_LIST_NAME
#define VECTOR_LIST_NAME void
#define VECTOR_LIST_NAME_DEFINED
#endif

#define CAT_I(a,b) a##b
#define CAT(a,b) CAT_I(a, b)
#define MAKE_TYPE_NAME() CAT(VECTOR_LIST_NAME, _vector_list)
#define TYPE_NAME() MAKE_TYPE_NAME()

struct TYPE_NAME()
{
   /* VECTOR_LIST_TYPE for pointers will expand to a pointer-to-pointer */
   VECTOR_LIST_TYPE *data;
   unsigned size;
   unsigned count;
};

static struct TYPE_NAME()* CAT(TYPE_NAME(), _new(void))
{
   struct TYPE_NAME() *list = (struct TYPE_NAME()*)calloc(1, sizeof(*list));

   list-&gt;size = 8;
   list-&gt;data = (VECTOR_LIST_TYPE*)calloc(list-&gt;size, sizeof(*list-&gt;data));

   return list;
}

static bool CAT(TYPE_NAME(), _append(struct TYPE_NAME() *list, VECTOR_LIST_TYPE elem))
{
   if (list-&gt;size == list-&gt;count)
   {
      list-&gt;size *= 2;
      list-&gt;data = (VECTOR_LIST_TYPE*)realloc(list-&gt;data, list-&gt;size * sizeof(*list-&gt;data));

      if (!list-&gt;data)
         return false;
   }

   list-&gt;data[list-&gt;count] = elem;
   list-&gt;count++;

   return true;
}

static void CAT(TYPE_NAME(), _free(struct TYPE_NAME() *list))
{
   if (list)
   {
      if (list-&gt;data)
         free(list-&gt;data);
      free(list);
   }
}

#ifdef VECTOR_LIST_TYPE_DEFINED
#undef VECTOR_LIST_TYPE
#endif

#ifdef VECTOR_LIST_NAME_DEFINED
#undef VECTOR_LIST_NAME
#endif</pre>
<h2>./include/libretro-common/Makefile.test</h2>
<pre>
OBJDIR = ../obj-unix

TEST_UNIT_CFLAGS = $(CFLAGS) -Iinclude $(LDFLAGS) -lcheck $(LIBCHECK_CFLAGS) -Werror -Wdeclaration-after-statement -fsanitize=address -fsanitize=undefined -ftest-coverage -fprofile-arcs -ggdb

TEST_GENERIC_QUEUE = test/queues/test_generic_queue
TEST_GENERIC_QUEUE_SRC = test/queues/test_generic_queue.c queues/generic_queue.c

TEST_LINKED_LIST = test/lists/test_linked_list
TEST_LINKED_LIST_SRC = test/lists/test_linked_list.c lists/linked_list.c

TEST_STDSTRING = test/string/test_stdstring
TEST_STDSTRING_SRC = test/string/test_stdstring.c string/stdstring.c encodings/encoding_utf.c \
		     compat/compat_strl.c

TEST_UTILS = test/utils/test_utils
TEST_UTILS_SRC = test/utils/test_utils.c utils/md5.c encodings/encoding_crc32.c \
		streams/file_stream.c vfs/vfs_implementation.c file/file_path.c \
		compat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c

TEST_HASH = test/hash/test_hash
TEST_HASH_SRC = test/hash/test_hash.c hash/lrc_hash.c \
		streams/file_stream.c vfs/vfs_implementation.c file/file_path.c \
		compat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c

all:
	# Build and execute tests in order, to avoid coverage file collision
	# string
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_STDSTRING_SRC) -o $(TEST_STDSTRING)
	$(TEST_STDSTRING)
	lcov -c -d . -o `dirname $(TEST_STDSTRING)`/coverage.info
	# utils
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_UTILS_SRC) -o $(TEST_UTILS)
	$(TEST_UTILS)
	lcov -c -d . -o `dirname $(TEST_UTILS)`/coverage.info
	# utils
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_HASH_SRC) -o $(TEST_HASH)
	$(TEST_HASH)
	lcov -c -d . -o `dirname $(TEST_HASH)`/coverage.info
	# list
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_LINKED_LIST_SRC) -o $(TEST_LINKED_LIST)
	$(TEST_LINKED_LIST)
	lcov -c -d . -o `dirname $(TEST_LINKED_LIST)`/coverage.info
	# queue
	$(CC) $(TEST_UNIT_CFLAGS) $(TEST_GENERIC_QUEUE_SRC) -o $(TEST_GENERIC_QUEUE)
	$(TEST_GENERIC_QUEUE)
	lcov -c -d . -o `dirname $(TEST_GENERIC_QUEUE)`/coverage.info
	
	lcov -o test/coverage.info \
	     -a test/utils/coverage.info \
	     -a test/string/coverage.info \
	     -a test/lists/coverage.info \
	     -a test/queues/coverage.info
	genhtml -o test/coverage/ test/coverage.info

clean:
	rm -f *.gcda *.gcno</pre>
<h2>./include/libretro-common/media/media_detect_cd.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (media_detect_cd.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include &lt;media/media_detect_cd.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;retro_miscellaneous.h&gt;

/*#define MEDIA_CUE_PARSE_DEBUG*/

static void media_zero_trailing_spaces(char *s, size_t len)
{
   int i;
   for (i = len - 1; i &gt;= 0; i--)
   {
      if (s[i] == ' ')
         s[i] = '\0';
      else if (s[i] != '\0')
         break;
   }
}

static bool media_skip_spaces(const char **s, size_t len)
{
   if (s &amp;&amp; *s &amp;&amp; **s)
   {
      size_t i;
      for (i = 0; i &lt; len; i++)
      {
         if ((*s)[i] == ' ' || (*s)[i] == '\t')
            continue;
         *s += i;
         return true;
      }
   }
   return false;
}

/* Fill in "info" with detected CD info. Use this when you have a cue file and want it parsed to find the first data track and any pregap info. */
bool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info)
{
   RFILE *file                          = NULL;
   char *line                           = NULL;
   char track_path[PATH_MAX_LENGTH]     = {0};
   char track_abs_path[PATH_MAX_LENGTH] = {0};
   char track_mode[11]                  = {0};
   bool found_file                      = false;
   bool found_track                     = false;
   unsigned first_data_track            = 0;
   uint64_t data_track_pregap_bytes     = 0;

   if (string_is_empty(path) || !info)
      return false;

   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))
   {
#ifdef MEDIA_CUE_PARSE_DEBUG
      printf("[MEDIA] Could not open cue path for reading: %s\n", path);
      fflush(stdout);
#endif
      return false;
   }

   while (!filestream_eof(file) &amp;&amp; (line = filestream_getline(file)))
   {
      size_t _len = 0;
      const char *command = NULL;

      if (string_is_empty(line))
      {
         free(line);
         continue;
      }

      _len    = strlen(line);
      command = line;

      media_skip_spaces(&amp;command, _len);

      if (!found_file &amp;&amp; !strncasecmp(command, "FILE", 4))
      {
         const char *file = command + 4;
         media_skip_spaces(&amp;file, _len - 4);

         if (!string_is_empty(file))
         {
            const char *file_end = NULL;
            size_t file_len      = 0;
            bool quoted          = false;

            if (file[0] == '"')
            {
               quoted = true;
               file++;
            }

            if (quoted)
               file_end = strchr(file, '\"');
            else
               file_end = strchr(file, ' ');

            if (file_end)
            {
               file_len = file_end - file;
               memcpy(track_path, file, file_len);
               found_file = true;
#ifdef MEDIA_CUE_PARSE_DEBUG
               printf("Found file: %s\n", track_path);
               fflush(stdout);
#endif
            }
         }
      }
      else if (found_file &amp;&amp; !found_track &amp;&amp; !strncasecmp(command, "TRACK", 5))
      {
         const char *track = command + 5;
         media_skip_spaces(&amp;track, _len - 5);

         if (!string_is_empty(track))
         {
            char *ptr             = NULL;
            unsigned track_number = (unsigned)strtol(track, &amp;ptr, 10);
#ifdef MEDIA_CUE_PARSE_DEBUG
            printf("Found track: %d\n", track_number);
            fflush(stdout);
#endif
            track++;

            if (track[0] &amp;&amp; track[0] != ' ' &amp;&amp; track[0] != '\t')
               track++;

            if (!string_is_empty(track))
            {
               media_skip_spaces(&amp;track, strlen(track));
#ifdef MEDIA_CUE_PARSE_DEBUG
               printf("Found track type: %s\n", track);
               fflush(stdout);
#endif
               if (!strncasecmp(track, "MODE", 4))
               {
                  first_data_track = track_number;
                  found_track = true;
                  strlcpy(track_mode, track, sizeof(track_mode));
               }
               else
                  found_file = false;
            }
         }
      }
      else if (found_file &amp;&amp; found_track &amp;&amp; first_data_track &amp;&amp; !strncasecmp(command, "INDEX", 5))
      {
         const char *index = command + 5;
         media_skip_spaces(&amp;index, _len - 5);

         if (!string_is_empty(index))
         {
            char *ptr             = NULL;
            unsigned index_number = (unsigned)strtol(index, &amp;ptr, 10);

            if (index_number == 1)
            {
               const char *pregap = index + 1;

               if (pregap[0] &amp;&amp; pregap[0] != ' ' &amp;&amp; pregap[0] != '\t')
                  pregap++;

               if (!string_is_empty(pregap))
               {
                  media_skip_spaces(&amp;pregap, strlen(pregap));
                  found_file  = false;
                  found_track = false;

                  if (first_data_track &amp;&amp; !string_is_empty(track_mode))
                  {
                     unsigned track_sector_size = 0;
                     unsigned track_mode_number = 0;

                     if (strlen(track_mode) == 10)
                     {
                        sscanf(track_mode, "MODE%d/%d", (int*)&amp;track_mode_number, (int*)&amp;track_sector_size);
#ifdef MEDIA_CUE_PARSE_DEBUG
                        printf("Found track mode %d with sector size %d\n", track_mode_number, track_sector_size);
                        fflush(stdout);
#endif
                        if ((track_mode_number == 1 || track_mode_number == 2) &amp;&amp; track_sector_size)
                        {
                           unsigned min = 0;
                           unsigned sec = 0;
                           unsigned frame = 0;
                           sscanf(pregap, "%02d:%02d:%02d", (int*)&amp;min, (int*)&amp;sec, (int*)&amp;frame);

                           if (min || sec || frame || strstr(pregap, "00:00:00"))
                           {
                              data_track_pregap_bytes = ((min * 60 + sec) * 75 + frame) * track_sector_size;
#ifdef MEDIA_CUE_PARSE_DEBUG
                              printf("Found pregap of %02d:%02d:%02d (bytes: %" PRIu64 ")\n", min, sec, frame, data_track_pregap_bytes);
                              fflush(stdout);
#endif
                              break;
                           }
                        }
                     }
                  }
               }
            }
         }
      }

      free(line);
   }

   filestream_close(file);

   if (!string_is_empty(track_path))
   {
      size_t _len;
      if (strstr(track_path, "/") || strstr(track_path, "\\"))
      {
#ifdef MEDIA_CUE_PARSE_DEBUG
         printf("using path %s\n", track_path);
         fflush(stdout);
#endif
         return media_detect_cd_info(track_path, data_track_pregap_bytes, info);
      }

      _len = fill_pathname_basedir(track_abs_path, path, sizeof(track_abs_path));
      strlcpy(track_abs_path + _len, track_path, sizeof(track_abs_path) - _len);
#ifdef MEDIA_CUE_PARSE_DEBUG
      printf("using abs path %s\n", track_abs_path);
      fflush(stdout);
#endif
      return media_detect_cd_info(track_abs_path, data_track_pregap_bytes, info);
   }

   return true;
}

/* Fill in "info" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */
bool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info)
{
   RFILE *file;

   if (string_is_empty(path) || !info)
      return false;

   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))
   {
#ifdef MEDIA_CUE_PARSE_DEBUG
      printf("[MEDIA] Could not open path for reading: %s\n", path);
      fflush(stdout);
#endif
      return false;
   }

   {
      unsigned offset      = 0;
      unsigned sector_size = 0;
      unsigned buf_size    = 17 * 2352;
      char *buf            = (char*)calloc(1, buf_size);
      int64_t read_bytes   = 0;

      if (!buf)
         return false;

      if (pregap_bytes)
         filestream_seek(file, pregap_bytes, RETRO_VFS_SEEK_POSITION_START);

      read_bytes = filestream_read(file, buf, buf_size);

      if (read_bytes != buf_size)
      {
#ifdef MEDIA_CUE_PARSE_DEBUG
         printf("[MEDIA] Could not read from media: got %" PRId64 " bytes instead of %d.\n", read_bytes, buf_size);
         fflush(stdout);
#endif
         filestream_close(file);
         free(buf);
         return false;
      }

      /* 12-byte sync field at the start of every sector, common to both mode1 and mode2 data tracks
       * (when at least sync data is requested). This is a CD-ROM standard feature and not specific to any game devices,
       * and as such should not be part of any system-specific detection or "magic" bytes.
       * Depending on what parts of a sector were requested from the disc, the user data might start at
       * byte offset 0, 4, 8, 12, 16 or 24. Cue sheets only specify the total number of bytes requested from the sectors
       * of a track (like 2048 or 2352) and it is then assumed based on the size/mode as to what fields are present. */
      if (!memcmp(buf, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12))
      {
         /* Assume track data contains all fields. */
         sector_size = 2352;

         /* Assume Mode 2 formed (formless is rarely used) */
         if (buf[15] == 2)
            offset   = 24;
         else /* Assume Mode 1 */
            offset   = 16;
      }
      else /* Assume sectors only contain user data instead. */
         sector_size = 2048;

      if (!memcmp(buf + offset, "SEGADISCSYSTEM",
               STRLEN_CONST("SEGADISCSYSTEM")))
      {
         const char *title_pos  = NULL;
         const char *serial_pos = NULL;

         /* All discs currently in Redump for MCD start with SEGADISCSYSTEM. There are other strings mentioned elsewhere online,
          * but I have not seen any real examples of them. */
         info-&gt;system_id = MEDIA_CD_SYSTEM_MEGA_CD;

         strlcpy(info-&gt;system, "Sega CD / Mega CD", sizeof(info-&gt;system));

         title_pos = buf + offset + 0x150;

         if (media_skip_spaces(&amp;title_pos, 48))
         {
            memcpy(info-&gt;title, title_pos, 48 - (title_pos - (buf + offset + 0x150)));
            media_zero_trailing_spaces(info-&gt;title, sizeof(info-&gt;title));
         }
         else
            strlcpy(info-&gt;title, "N/A", sizeof(info-&gt;title));

         serial_pos = buf + offset + 0x183;

         if (media_skip_spaces(&amp;serial_pos, 8))
         {
            memcpy(info-&gt;serial, serial_pos, 8 - (serial_pos - (buf + offset + 0x183)));
            media_zero_trailing_spaces(info-&gt;serial, sizeof(info-&gt;serial));
         }
         else
         {
            info-&gt;serial[0] = 'N';
            info-&gt;serial[1] = '/';
            info-&gt;serial[2] = 'A';
            info-&gt;serial[3] = '\0';
         }
      }
      else if (!memcmp(buf + offset, "SEGA SEGASATURN",
               STRLEN_CONST("SEGA SEGASATURN")))
      {
         const char *title_pos        = NULL;
         const char *serial_pos       = NULL;
         const char *version_pos      = NULL;
         const char *release_date_pos = NULL;

         info-&gt;system_id = MEDIA_CD_SYSTEM_SATURN;

         strlcpy(info-&gt;system, "Sega Saturn", sizeof(info-&gt;system));

         title_pos = buf + offset + 0x60;

         if (media_skip_spaces(&amp;title_pos, 112))
         {
            memcpy(info-&gt;title, title_pos, 112 - (title_pos - (buf + offset + 0x60)));
            media_zero_trailing_spaces(info-&gt;title, sizeof(info-&gt;title));
         }
         else
            strlcpy(info-&gt;title, "N/A", sizeof(info-&gt;title));

         serial_pos = buf + offset + 0x20;

         if (media_skip_spaces(&amp;serial_pos, 10))
         {
            memcpy(info-&gt;serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x20)));
            media_zero_trailing_spaces(info-&gt;serial, sizeof(info-&gt;serial));
         }
         else
         {
            info-&gt;serial[0] = 'N';
            info-&gt;serial[1] = '/';
            info-&gt;serial[2] = 'A';
            info-&gt;serial[3] = '\0';
         }

         version_pos = buf + offset + 0x2a;

         if (media_skip_spaces(&amp;version_pos, 6))
         {
            memcpy(info-&gt;version, version_pos, 6 - (version_pos - (buf + offset + 0x2a)));
            media_zero_trailing_spaces(info-&gt;version, sizeof(info-&gt;version));
         }
         else
         {
            info-&gt;version[0] = 'N';
            info-&gt;version[1] = '/';
            info-&gt;version[2] = 'A';
            info-&gt;version[3] = '\0';
         }

         release_date_pos = buf + offset + 0x30;

         if (media_skip_spaces(&amp;release_date_pos, 8))
         {
            memcpy(info-&gt;release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x30)));
            media_zero_trailing_spaces(info-&gt;release_date, sizeof(info-&gt;release_date));
         }
         else
         {
            info-&gt;release_date[0] = 'N';
            info-&gt;release_date[1] = '/';
            info-&gt;release_date[2] = 'A';
            info-&gt;release_date[3] = '\0';
         }
      }
      else if (!memcmp(buf + offset, "SEGA SEGAKATANA", STRLEN_CONST("SEGA SEGAKATANA")))
      {
         const char *title_pos        = NULL;
         const char *serial_pos       = NULL;
         const char *version_pos      = NULL;
         const char *release_date_pos = NULL;

         info-&gt;system_id = MEDIA_CD_SYSTEM_DREAMCAST;

         strlcpy(info-&gt;system, "Sega Dreamcast", sizeof(info-&gt;system));

         title_pos = buf + offset + 0x80;

         if (media_skip_spaces(&amp;title_pos, 96))
         {
            memcpy(info-&gt;title, title_pos, 96 - (title_pos - (buf + offset + 0x80)));
            media_zero_trailing_spaces(info-&gt;title, sizeof(info-&gt;title));
         }
         else
            strlcpy(info-&gt;title, "N/A", sizeof(info-&gt;title));

         serial_pos = buf + offset + 0x40;

         if (media_skip_spaces(&amp;serial_pos, 10))
         {
            memcpy(info-&gt;serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x40)));
            media_zero_trailing_spaces(info-&gt;serial, sizeof(info-&gt;serial));
         }
         else
         {
            info-&gt;serial      [0] = 'N';
            info-&gt;serial      [1] = '/';
            info-&gt;serial      [2] = 'A';
            info-&gt;serial      [3] = '\0';
         }

         version_pos = buf + offset + 0x4a;

         if (media_skip_spaces(&amp;version_pos, 6))
         {
            memcpy(info-&gt;version, version_pos, 6 - (version_pos - (buf + offset + 0x4a)));
            media_zero_trailing_spaces(info-&gt;version, sizeof(info-&gt;version));
         }
         else
         {
            info-&gt;version     [0] = 'N';
            info-&gt;version     [1] = '/';
            info-&gt;version     [2] = 'A';
            info-&gt;version     [3] = '\0';
         }

         release_date_pos = buf + offset + 0x50;

         if (media_skip_spaces(&amp;release_date_pos, 8))
         {
            memcpy(info-&gt;release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x50)));
            media_zero_trailing_spaces(info-&gt;release_date, sizeof(info-&gt;release_date));
         }
         else
         {
            info-&gt;release_date[0] = 'N';
            info-&gt;release_date[1] = '/';
            info-&gt;release_date[2] = 'A';
            info-&gt;release_date[3] = '\0';
         }
      }
      /* Primary Volume Descriptor fields of ISO9660 */
      else if (!memcmp(buf + offset + (16 * sector_size), "\1CD001\1\0PLAYSTATION", 19))
      {
         const char *title_pos = NULL;

         info-&gt;system_id = MEDIA_CD_SYSTEM_PSX;

         strlcpy(info-&gt;system, "Sony PlayStation", sizeof(info-&gt;system));

         title_pos = buf + offset + (16 * sector_size) + 40;

         if (media_skip_spaces(&amp;title_pos, 32))
         {
            memcpy(info-&gt;title, title_pos, 32 - (title_pos - (buf + offset + (16 * sector_size) + 40)));
            media_zero_trailing_spaces(info-&gt;title, sizeof(info-&gt;title));
         }
         else
            strlcpy(info-&gt;title, "N/A", sizeof(info-&gt;title));
      }
      else if (!memcmp(buf + offset, "\x01\x5a\x5a\x5a\x5a\x5a\x01\x00\x00\x00\x00\x00", 12))
      {
         info-&gt;system_id = MEDIA_CD_SYSTEM_3DO;
         strlcpy(info-&gt;system, "3DO", sizeof(info-&gt;system));
      }
      else if (!memcmp(buf + offset + 0x950, "PC Engine CD-ROM SYSTEM", 23))
      {
         info-&gt;system_id = MEDIA_CD_SYSTEM_PC_ENGINE_CD;
         strlcpy(info-&gt;system, "TurboGrafx-CD / PC-Engine CD", sizeof(info-&gt;system));
      }

      free(buf);
   }

   filestream_close(file);

   return true;
}</pre>
<h2>./include/libretro-common/memmap/memalign.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memalign.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;memalign.h&gt;

void *memalign_alloc(size_t boundary, size_t len)
{
   void **place   = NULL;
   uintptr_t addr = 0;
   void *ptr      = (void*)malloc(boundary + len + sizeof(uintptr_t));
   if (!ptr)
      return NULL;
   addr           = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary)
      &amp; ~(boundary - 1);
   place          = (void**)addr;
   place[-1]      = ptr;
   return (void*)addr;
}

void memalign_free(void *ptr)
{
   void **p = NULL;
   if (!ptr)
      return;

   p = (void**)ptr;
   free(p[-1]);
}

void *memalign_alloc_aligned(size_t len)
{
#if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_M_X64) || defined(_WIN64)
   return memalign_alloc(64, len);
#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(GEKKO) || defined(_M_IX86)
   return memalign_alloc(32, len);
#else
   return memalign_alloc(32, len);
#endif
}</pre>
<h2>./include/libretro-common/memmap/memmap.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memmap.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;memmap.h&gt;

#ifndef PROT_READ
#define PROT_READ         0x1  /* Page can be read */
#endif

#ifndef PROT_WRITE
#define PROT_WRITE        0x2  /* Page can be written. */
#endif

#ifndef PROT_READWRITE
#define PROT_READWRITE    0x3  /* Page can be written to and read from. */
#endif

#ifndef PROT_EXEC
#define PROT_EXEC         0x4  /* Page can be executed. */
#endif

#ifndef PROT_NONE
#define PROT_NONE         0x0  /* Page can not be accessed. */
#endif

#ifndef MAP_FAILED
#define MAP_FAILED        ((void *) -1)
#endif

#ifdef _WIN32
void* mmap(void *addr, size_t len, int prot, int flags,
      int fildes, size_t offset)
{
   void     *map = (void*)NULL;
   HANDLE handle = INVALID_HANDLE_VALUE;

   switch (prot)
   {
      case PROT_READ:
      default:
         handle = CreateFileMapping((HANDLE)
               _get_osfhandle(fildes), 0, PAGE_READONLY, 0,
               len, 0);
         if (!handle)
            break;
         map = (void*)MapViewOfFile(handle, FILE_MAP_READ, 0, 0, len);
         CloseHandle(handle);
         break;
      case PROT_WRITE:
         handle = CreateFileMapping((HANDLE)
               _get_osfhandle(fildes),0,PAGE_READWRITE,0,
               len, 0);
         if (!handle)
            break;
         map = (void*)MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, len);
         CloseHandle(handle);
         break;
      case PROT_READWRITE:
         handle = CreateFileMapping((HANDLE)
               _get_osfhandle(fildes),0,PAGE_READWRITE,0,
               len, 0);
         if (!handle)
            break;
         map = (void*)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, len);
         CloseHandle(handle);
         break;
   }

   if (map == (void*)NULL)
      return((void*)MAP_FAILED);
   return((void*) ((int8_t*)map + offset));
}

int munmap(void *addr, size_t len)
{
   return (UnmapViewOfFile(addr)) ? 0 : -1;
}

int mprotect(void *addr, size_t len, int prot)
{
   /* Incomplete, just assumes PAGE_EXECUTE_READWRITE right now
    * instead of correctly handling prot */
   prot = 0;
   if (prot &amp; (PROT_READ | PROT_WRITE | PROT_EXEC))
      prot = PAGE_EXECUTE_READWRITE;
   return VirtualProtect(addr, len, prot, 0);
}

#elif !defined(HAVE_MMAN)
void* mmap(void *addr, size_t len, int prot, int flags,
      int fildes, size_t offset)
{
   return malloc(len);
}

int munmap(void *addr, size_t len)
{
   free(addr);
   return 0;
}

int mprotect(void *addr, size_t len, int prot)
{
   /* stub - not really needed at this point
    * since this codepath has no dynarecs. */
   return 0;
}

#endif

#if defined(__MACH__) &amp;&amp; defined(__arm__)
#include &lt;libkern/OSCacheControl.h&gt;
#endif

int memsync(void *start, void *end)
{
#if defined(__MACH__) &amp;&amp; defined(__arm__)
   size_t _len = (char*)end - (char*)start;
   sys_dcache_flush(start, _len);
   sys_icache_invalidate(start, _len);
   return 0;
#elif defined(__arm__) &amp;&amp; !defined(__QNX__)
   __clear_cache(start, end);
   return 0;
#elif defined(HAVE_MMAN)
   size_t _len = (char*)end - (char*)start;
   return msync(start, _len, MS_SYNC | MS_INVALIDATE
#ifdef __QNX__
         MS_CACHE_ONLY
#endif
         );
#else
   return 0;
#endif
}

int memprotect(void *addr, size_t len)
{
   return mprotect(addr, len, PROT_READ | PROT_WRITE | PROT_EXEC);
}</pre>
<h2>./include/libretro-common/net/net_compat.c</h2>
<pre>/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_compat.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

#include &lt;compat/strl.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;retro_timers.h&gt;

#include &lt;net/net_compat.h&gt;

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#if !defined(_WIN32_WINNT) || _WIN32_WINNT &lt; 0x0600
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
   struct sockaddr_storage addr;

   switch (af)
   {
      case AF_INET:
         memcpy(&amp;((struct sockaddr_in*)&amp;addr)-&gt;sin_addr, src,
            sizeof(struct in_addr));
         break;
#ifdef HAVE_INET6
      case AF_INET6:
         memcpy(&amp;((struct sockaddr_in6*)&amp;addr)-&gt;sin6_addr, src,
            sizeof(struct in6_addr));
         break;
#endif
      default:
         return NULL;
   }

   addr.ss_family = af;
   if (getnameinfo((struct sockaddr*)&amp;addr, sizeof(addr), dst, size, NULL, 0,
         NI_NUMERICHOST))
      return NULL;

   return dst;
}

int inet_pton(int af, const char *src, void *dst)
{
   struct addrinfo *addr = NULL;
   struct addrinfo hints = {0};

   switch (af)
   {
      case AF_INET:
#ifdef HAVE_INET6
      case AF_INET6:
#endif
         break;
      default:
         return -1;
   }

   hints.ai_family = af;
   hints.ai_flags  = AI_NUMERICHOST;
   switch (getaddrinfo(src, NULL, &amp;hints, &amp;addr))
   {
      case 0:
         break;
      case EAI_NONAME:
         return 0;
      default:
         return -1;
   }

   if (!addr)
      return -1;

   switch (af)
   {
      case AF_INET:
         memcpy(dst, &amp;((struct sockaddr_in*)addr-&gt;ai_addr)-&gt;sin_addr,
            sizeof(struct in_addr));
         break;
#ifdef HAVE_INET6
      case AF_INET6:
         memcpy(dst, &amp;((struct sockaddr_in6*)addr-&gt;ai_addr)-&gt;sin6_addr,
            sizeof(struct in6_addr));
         break;
#endif
      default:
         break;
   }

   freeaddrinfo(addr);

   return 1;
}
#endif

#elif defined(_XBOX)
struct hostent *gethostbyname(const char *name)
{
   static struct in_addr addr = {0};
   static struct hostent he   = {0};
   WSAEVENT event;
   XNDNS          *dns = NULL;
   struct hostent *ret = NULL;

   if (!name)
      return NULL;

   event = WSACreateEvent();

   XNetDnsLookup(name, event, &amp;dns);
   if (!dns)
   {
      WSACloseEvent(event);
      return NULL;
   }

   WaitForSingleObject((HANDLE)event, INFINITE);

   if (!dns-&gt;iStatus)
   {
      memcpy(&amp;addr, dns-&gt;aina, sizeof(addr));

      he.h_name      = NULL;
      he.h_aliases   = NULL;
      he.h_addrtype  = AF_INET;
      he.h_length    = sizeof(addr);
      he.h_addr_list = &amp;he.h_addr;
      he.h_addr      = (char*)&amp;addr;

      ret = &amp;he;
   }

   WSACloseEvent(event);
   XNetDnsRelease(dns);

   return ret;
}

#elif defined(VITA)
#define COMPAT_NET_INIT_SIZE 0x80000

char *inet_ntoa(struct in_addr in)
{
   static char ip_addr[16];

   sceNetInetNtop(AF_INET, &amp;in, ip_addr, sizeof(ip_addr));

   return ip_addr;
}

int inet_aton(const char *cp, struct in_addr *inp)
{
   return sceNetInetPton(AF_INET, cp, inp);
}

uint32_t inet_addr(const char *cp)
{
   struct in_addr in;

   return (sceNetInetPton(AF_INET, cp, &amp;in) == 1) ? in.s_addr : INADDR_NONE;
}

struct hostent *gethostbyname(const char *name)
{
   static struct SceNetInAddr addr = {0};
   static struct hostent      he   = {0};
   int rid;
   struct hostent *ret = NULL;

   if (!name)
      return NULL;

   rid = sceNetResolverCreate("resolver", NULL, 0);
   if (rid &lt; 0)
      return NULL;

   if (sceNetResolverStartNtoa(rid, name, &amp;addr, 0, 0, 0) &lt; 0)
      goto done;

   he.h_name      = NULL;
   he.h_aliases   = NULL;
   he.h_addrtype  = AF_INET;
   he.h_length    = sizeof(addr);
   he.h_addr_list = &amp;he.h_addr;
   he.h_addr      = (char*)&amp;addr;

   ret = &amp;he;

done:
   sceNetResolverDestroy(rid);

   return ret;
}

#elif defined(GEKKO)
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
   const char *addr_str = inet_ntoa(*(struct in_addr*)src);

   if (addr_str)
   {
      strlcpy(dst, addr_str, size);

      return dst;
   }

   return NULL;
}

int inet_pton(int af, const char *src, void *dst)
{
   if (inet_aton(src, (struct in_addr*)dst))
      return 1;

   return 0;
}

#elif defined(WIIU)
#include &lt;malloc.h&gt;

static int _net_compat_thread_entry(int argc, const char **argv)
{
   void *buf = memalign(128, WIIU_RCVBUF + WIIU_SNDBUF);

   if (!buf)
      return -1;

   somemopt(1, buf, WIIU_RCVBUF + WIIU_SNDBUF, 0);

   free(buf);

   return 0;
}

static void _net_compat_thread_cleanup(OSThread *thread, void *stack)
{
   free(stack);
}

#elif defined(_3DS)
#include &lt;malloc.h&gt;
#include &lt;3ds/types.h&gt;
#include &lt;3ds/services/soc.h&gt;

#define SOC_ALIGN      0x1000
#define SOC_BUFFERSIZE 0x100000
#endif

int getaddrinfo_retro(const char *node, const char *service,
      struct addrinfo *hints, struct addrinfo **res)
{
#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
   struct addrinfo default_hints = {0};

   if (!hints)
      hints            = &amp;default_hints;
   if (!hints-&gt;ai_family)
      hints-&gt;ai_family = AF_INET;

   if (!node)
      node = (hints-&gt;ai_flags &amp; AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
#endif

#ifdef HAVE_SOCKET_LEGACY
   {
      struct addrinfo    *info = (struct addrinfo*)calloc(1, sizeof(*info));
      struct sockaddr_in *addr = (struct sockaddr_in*)malloc(sizeof(*addr));

      if (!info || !addr)
         goto failure;

      info-&gt;ai_family   = AF_INET;
      info-&gt;ai_socktype = hints-&gt;ai_socktype;
      info-&gt;ai_protocol = hints-&gt;ai_protocol;
      info-&gt;ai_addrlen  = sizeof(*addr);
      info-&gt;ai_addr     = (struct sockaddr*)addr;
      /* We ignore AI_CANONNAME; ai_canonname is always NULL. */

      addr-&gt;sin_family = AF_INET;

      if (service)
      {
         /* We can only handle numeric ports; ignore AI_NUMERICSERV. */
         char *service_end = NULL;
         uint16_t port     = (uint16_t)strtoul(service, &amp;service_end, 10);

         if (service_end == service || *service_end)
            goto failure;

         addr-&gt;sin_port = htons(port);
      }

      if (hints-&gt;ai_flags &amp; AI_NUMERICHOST)
      {
         if (!inet_aton(node, &amp;addr-&gt;sin_addr))
            goto failure;
      }
      else
      {
         struct hostent *host = gethostbyname(node);

         if (!host || !host-&gt;h_addr)
            goto failure;

         memcpy(&amp;addr-&gt;sin_addr, host-&gt;h_addr, sizeof(addr-&gt;sin_addr));
      }

      *res = info;

      return 0;

failure:
      free(addr);
      free(info);

      return -1;
   }
#else
   return getaddrinfo(node, service, hints, res);
#endif
}

void freeaddrinfo_retro(struct addrinfo *res)
{
#ifdef HAVE_SOCKET_LEGACY
   if (res)
   {
      free(res-&gt;ai_addr);
      free(res);
   }
#else
   freeaddrinfo(res);
#endif
}

int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
{
#ifdef HAVE_SOCKET_LEGACY
   const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;

   /* We cannot perform reverse DNS lookups here; ignore the following flags:
      NI_NAMEREQD
      NI_NOFQDN
      NI_NUMERICHOST (always enforced)
    */
   if (host &amp;&amp; hostlen)
   {
      const char *_host = inet_ntoa(addr4-&gt;sin_addr);

      if (!_host)
         return -1;

      strlcpy(host, _host, hostlen);
   }

   /* We cannot get service names here; ignore the following flags:
      NI_DGRAM
      NI_NUMERICSERV (always enforced)
    */
   if (serv &amp;&amp; servlen)
      snprintf(serv, servlen, "%hu", (unsigned short)ntohs(addr4-&gt;sin_port));

   return 0;
#else
   return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
#endif
}

bool addr_6to4(struct sockaddr_storage *addr)
{
#ifdef HAVE_INET6
   /* ::ffff:a.b.c.d */
   static const uint16_t prefix[] = {0,0,0,0,0,0xffff};
   uint32_t address;
   uint16_t port;
   struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)addr;
   struct sockaddr_in  *addr4 = (struct sockaddr_in*)addr;

   switch (addr-&gt;ss_family)
   {
      case AF_INET:
         /* No need to convert. */
         return true;
      case AF_INET6:
         /* Is the address provided an IPv4? */
         if (!memcmp(&amp;addr6-&gt;sin6_addr, prefix, sizeof(prefix)))
            break;
      default:
         /* We don't know how to handle this. */
         return false;
   }

   memcpy(&amp;address, ((uint8_t*)&amp;addr6-&gt;sin6_addr) + sizeof(prefix),
      sizeof(address));
   port = addr6-&gt;sin6_port;

   memset(addr, 0, sizeof(*addr));

   addr4-&gt;sin_family = AF_INET;
   addr4-&gt;sin_port   = port;
   memcpy(&amp;addr4-&gt;sin_addr, &amp;address, sizeof(addr4-&gt;sin_addr));
#endif

   return true;
}

bool ipv4_is_lan_address(const struct sockaddr_in *addr)
{
   static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000};
   static const uint32_t masks[]   = {0xFF000000, 0xFFF00000, 0xFFFF0000};
   size_t i;
   uint32_t uaddr;

   memcpy(&amp;uaddr, &amp;addr-&gt;sin_addr, sizeof(uaddr));
   uaddr = ntohl(uaddr);

   for (i = 0; i &lt; ARRAY_SIZE(subnets); i++)
      if ((uaddr &amp; masks[i]) == subnets[i])
         return true;

   return false;
}

bool ipv4_is_cgnat_address(const struct sockaddr_in *addr)
{
   static const uint32_t subnet = 0x64400000;
   static const uint32_t mask   = 0xFFC00000;
   uint32_t uaddr;

   memcpy(&amp;uaddr, &amp;addr-&gt;sin_addr, sizeof(uaddr));
   uaddr = ntohl(uaddr);

   return (uaddr &amp; mask) == subnet;
}

/**
 * network_init:
 *
 * Platform specific socket library initialization.
 *
 * @return true if successful, otherwise false.
 **/
bool network_init(void)
{
#if defined(_WIN32)
   static bool initialized = false;

   if (!initialized)
   {
      WSADATA wsaData;

      if (WSAStartup(MAKEWORD(2, 2), &amp;wsaData))
      {
         WSACleanup();

         return false;
      }

      initialized = true;
   }

   return true;
#elif defined(__PSL1GHT__) || defined(__PS3__)
   static bool initialized = false;

   if (!initialized)
   {
      int tries;

      sysModuleLoad(SYSMODULE_NET);

      netInitialize();
      if (netCtlInit() &lt; 0)
         goto failure;

      for (tries = 10;;)
      {
         int state;

         if (netCtlGetState(&amp;state) &lt; 0)
            goto failure;
         if (state == NET_CTL_STATE_IPObtained)
            break;

         if (!(--tries))
            goto failure;

         retro_sleep(500);
      }

      initialized = true;
   }

   return true;

failure:
   netCtlTerm();
   netFinalizeNetwork();

   sysModuleUnload(SYSMODULE_NET);

   return false;
#elif defined(VITA)
   if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
   {
      SceNetInitParam param;
      void *net_compat_memory = malloc(COMPAT_NET_INIT_SIZE);

      if (!net_compat_memory)
         return false;

      param.memory = net_compat_memory;
      param.size   = COMPAT_NET_INIT_SIZE;
      param.flags  = 0;

      if (sceNetInit(&amp;param) &lt; 0)
         goto failure;
      if (sceNetCtlInit() &lt; 0)
         goto failure;

      return true;

failure:
      sceNetCtlTerm();
      sceNetTerm();

      free(net_compat_memory);

      return false;
   }

   return true;
#elif defined(GEKKO)
   static bool initialized = false;

   if (!initialized)
   {
      char localip[16] = {0};
      char netmask[16] = {0};
      char gateway[16] = {0};

      if (if_config(localip, netmask, gateway, true, 10) &lt; 0)
      {
         net_deinit();

         return false;
      }

      initialized = true;
   }

   return true;
#elif defined(WIIU)
   static OSThread net_compat_thread;
   static bool initialized = false;

   if (!initialized)
   {
      void *stack = malloc(0x1000);

      if (!stack)
         return false;

      socket_lib_init();

      if (!OSCreateThread(&amp;net_compat_thread, _net_compat_thread_entry,
            0, NULL, (void*)((size_t)stack + 0x1000), 0x1000, 3,
            OS_THREAD_ATTRIB_AFFINITY_ANY))
      {
         free(stack);

         return false;
      }

      OSSetThreadName(&amp;net_compat_thread, "Network compat thread");
      OSSetThreadDeallocator(&amp;net_compat_thread, _net_compat_thread_cleanup);
      OSResumeThread(&amp;net_compat_thread);

      initialized = true;
   }

   return true;
#elif defined(_3DS)
   static bool initialized = false;

   if (!initialized)
   {
      u32 *net_compat_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);

      if (!net_compat_memory)
         return false;

      /* WIFI init */
      if (socInit(net_compat_memory, SOC_BUFFERSIZE))
      {
         socExit();

         free(net_compat_memory);

         return false;
      }

      initialized = true;
   }

   return true;
#else
   static bool initialized = false;

   if (!initialized)
   {
      /* Do not like SIGPIPE killing our app. */
      signal(SIGPIPE, SIG_IGN);

      initialized = true;
   }

   return true;
#endif
}</pre>
<h2>./include/libretro-common/net/net_http.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;

#include &lt;net/net_http.h&gt;
#include &lt;net/net_compat.h&gt;
#include &lt;net/net_socket.h&gt;
#ifdef HAVE_SSL
#include &lt;net/net_socket_ssl.h&gt;
#endif
#include &lt;compat/strl.h&gt;
#include &lt;features/features_cpu.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;string.h&gt;
#include &lt;lists/string_list.h&gt;
#include &lt;retro_common_api.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#ifdef HAVE_THREADS
#include &lt;rthreads/rthreads.h&gt;
#endif

enum response_part
{
   P_HEADER_TOP = 0,
   P_HEADER,
   P_BODY,
   P_BODY_CHUNKLEN,
   P_DONE
};

enum bodytype
{
   T_FULL = 0,
   T_LEN,
   T_CHUNK
};

struct conn_pool_entry
{
   char *domain;
   int port;
   int fd;
   void *ssl_ctx;
   bool ssl;
   bool connected;
   bool in_use;
   struct conn_pool_entry *next;
};

static struct conn_pool_entry *conn_pool = NULL;
#ifdef HAVE_THREADS
static slock_t *conn_pool_lock = NULL;
#define LOCK_POOL() slock_lock(conn_pool_lock)
#define UNLOCK_POOL() slock_unlock(conn_pool_lock)
#else
#define LOCK_POOL()
#define UNLOCK_POOL()
#endif

typedef struct response
{
   char *data;
   struct string_list *headers;
   size_t pos;
   size_t len;
   size_t buflen;
   int status;
   enum response_part part;
   enum bodytype bodytype;
} response_t;

typedef struct request
{
   char *domain;
   char *path;
   char *method;
   char *contenttype;
   void *postdata;
   char *useragent;
   char *headers;
   size_t contentlength;
   int port;
} request_t;

struct http_t
{
   bool err;

   struct conn_pool_entry *conn;
   bool ssl;
   bool request_sent;

   request_t request;
   response_t response;
};

struct http_connection_t
{
   char *domain;
   char *path;
   char *url;
   char *scan;
   char *method;
   char *contenttype;
   void *postdata;
   char *useragent;
   char *headers;
   size_t contentlength; /* ptr alignment */
   int port;
   bool ssl;
};

struct dns_cache_entry
{
   char *domain;
   int port;
   struct addrinfo *addr;
   retro_time_t timestamp;
   bool valid;
   struct dns_cache_entry *next;
};

static struct dns_cache_entry *dns_cache = NULL;
/* 5 min timeout, in usec */
static const retro_time_t dns_cache_timeout = 1000 /* usec/ms */ * 1000 /* ms/s */ * 60 /* s/min */ * 5 /* min */;
/* only cache failures for 30 seconds */
static const retro_time_t dns_cache_fail_timeout = 1000 /* usec/ms */ * 1000 /* ms/s */ * 30 /* s */;
#ifdef HAVE_THREADS
static slock_t *dns_cache_lock = NULL;
#define LOCK_DNS_CACHE() slock_lock(dns_cache_lock)
#define UNLOCK_DNS_CACHE() slock_unlock(dns_cache_lock)
#else
#define LOCK_DNS_CACHE()
#define UNLOCK_DNS_CACHE()
#endif

/**
 * net_http_urlencode:
 *
 * URL Encode a string
 * caller is responsible for deleting the destination buffer
 **/
void net_http_urlencode(char **dest, const char *source)
{
   static const char urlencode_lut[] =
   {
      0,       /* 0   */
      0,       /* 1   */
      0,       /* 2   */
      0,       /* 3   */
      0,       /* 4   */
      0,       /* 5   */
      0,       /* 6   */
      0,       /* 7   */
      0,       /* 8   */
      0,       /* 9   */
      0,       /* 10  */
      0,       /* 11  */
      0,       /* 12  */
      0,       /* 13  */
      0,       /* 14  */
      0,       /* 15  */
      0,       /* 16  */
      0,       /* 17  */
      0,       /* 18  */
      0,       /* 19  */
      0,       /* 20  */
      0,       /* 21  */
      0,       /* 22  */
      0,       /* 23  */
      0,       /* 24  */
      0,       /* 25  */
      0,       /* 26  */
      0,       /* 27  */
      0,       /* 28  */
      0,       /* 29  */
      0,       /* 30  */
      0,       /* 31  */
      0,       /* 32  */
      0,       /* 33  */
      0,       /* 34  */
      0,       /* 35  */
      0,       /* 36  */
      0,       /* 37  */
      0,       /* 38  */
      0,       /* 39  */
      0,       /* 40  */
      0,       /* 41  */
      '*',     /* 42  */
      0,       /* 43  */
      0,       /* 44  */
      '-',     /* 45  */
      '.',     /* 46  */
      '/',     /* 47  */
      '0',     /* 48  */
      '1',     /* 49  */
      '2',     /* 50  */
      '3',     /* 51  */
      '4',     /* 52  */
      '5',     /* 53  */
      '6',     /* 54  */
      '7',     /* 55  */
      '8',     /* 56  */
      '9',     /* 57  */
      0,       /* 58  */
      0,       /* 59  */
      0,       /* 60  */
      0,       /* 61  */
      0,       /* 62  */
      0,       /* 63  */
      0,       /* 64  */
      'A',     /* 65  */
      'B',     /* 66  */
      'C',     /* 67  */
      'D',     /* 68  */
      'E',     /* 69  */
      'F',     /* 70  */
      'G',     /* 71  */
      'H',     /* 72  */
      'I',     /* 73  */
      'J',     /* 74  */
      'K',     /* 75  */
      'L',     /* 76  */
      'M',     /* 77  */
      'N',     /* 78  */
      'O',     /* 79  */
      'P',     /* 80  */
      'Q',     /* 81  */
      'R',     /* 82  */
      'S',     /* 83  */
      'T',     /* 84  */
      'U',     /* 85  */
      'V',     /* 86  */
      'W',     /* 87  */
      'X',     /* 88  */
      'Y',     /* 89  */
      'Z',     /* 90  */
      0,       /* 91  */
      0,       /* 92  */
      0,       /* 93  */
      0,       /* 94  */
      '_',     /* 95  */
      0,       /* 96  */
      'a',     /* 97  */
      'b',     /* 98  */
      'c',     /* 99  */
      'd',     /* 100 */
      'e',     /* 101 */
      'f',     /* 102 */
      'g',     /* 103 */
      'h',     /* 104 */
      'i',     /* 105 */
      'j',     /* 106 */
      'k',     /* 107 */
      'l',     /* 108 */
      'm',     /* 109 */
      'n',     /* 110 */
      'o',     /* 111 */
      'p',     /* 112 */
      'q',     /* 113 */
      'r',     /* 114 */
      's',     /* 115 */
      't',     /* 116 */
      'u',     /* 117 */
      'v',     /* 118 */
      'w',     /* 119 */
      'x',     /* 120 */
      'y',     /* 121 */
      'z'      /* 122 */
   };

   /* Assume every character will be encoded, so we need 3 times the space. */
   size_t _len                      = strlen(source) * 3 + 1;
   size_t count                     = _len;
   char *enc                        = (char*)calloc(1, _len);
   *dest                            = enc;

   for (; *source; source++)
   {
      int written = 0;

      /* any non-ASCII character will just be encoded without question */
      if ((unsigned)*source &lt; sizeof(urlencode_lut) &amp;&amp; urlencode_lut[(unsigned)*source])
         written = snprintf(enc, count, "%c", urlencode_lut[(unsigned)*source]);
      else
         written = snprintf(enc, count, "%%%02X", *source &amp; 0xFF);

      if (written &gt; 0)
         count -= written;

      while (*++enc);
   }

   (*dest)[_len - 1] = '\0';
}

/**
 * net_http_urlencode_full:
 *
 * Re-encode a full URL
 **/
void net_http_urlencode_full(char *s, const char *source, size_t len)
{
   size_t buf_pos;
   size_t tmp_len;
   char url_domain[256];
   char url_path[PATH_MAX_LENGTH];
   int count      = 0;
   char *tmp      = url_path;

   strlcpy(url_path, source, sizeof(url_path));

   while (count &lt; 3 &amp;&amp; tmp[0] != '\0')
   {
      tmp = strchr(tmp, '/');
      if (!tmp)
         break;
      count++;
      tmp++;
   }

   tmp_len        = strlen(tmp);
   buf_pos        = ((strlcpy(url_domain, source, tmp - url_path)) - tmp_len) - 1;
   strlcpy(url_path,
         source  + buf_pos + 1,
         tmp_len           + 1
         );

   tmp             = NULL;
   net_http_urlencode(&amp;tmp, url_path);
   buf_pos         = strlcpy(s, url_domain, len);
   s[  buf_pos] = '/';
   s[++buf_pos] = '\0';
   strlcpy(s + buf_pos, tmp, len - buf_pos);
   free(tmp);
}

struct http_connection_t *net_http_connection_new(const char *url,
      const char *method, const char *data)
{
   struct http_connection_t *conn = NULL;

   if (!url)
      return NULL;
   if (!(conn = (struct http_connection_t*)calloc(1, sizeof(*conn))))
      return NULL;

   if (method)
      conn-&gt;method         = strdup(method);

   if (data)
   {
      conn-&gt;postdata       = strdup(data);
      conn-&gt;contentlength  = strlen(data);
   }

   if ((conn-&gt;url = strdup(url)))
   {
      if (!strncmp(url, "http://", STRLEN_CONST("http://")))
      {
         conn-&gt;scan   = conn-&gt;url + STRLEN_CONST("http://");

         if (!string_is_empty(conn-&gt;scan))
         {
            conn-&gt;domain = conn-&gt;scan;
            return conn;
         }
      }
      else if (!strncmp(url, "https://", STRLEN_CONST("https://")))
      {
         conn-&gt;scan   = conn-&gt;url + STRLEN_CONST("https://");
         conn-&gt;ssl    = true;

         if (!string_is_empty(conn-&gt;scan))
         {
            conn-&gt;domain = conn-&gt;scan;
            return conn;
         }
      }
   }

   if (conn-&gt;url)
      free(conn-&gt;url);
   if (conn-&gt;method)
      free(conn-&gt;method);
   if (conn-&gt;postdata)
      free(conn-&gt;postdata);
   free(conn);
   return NULL;
}

/**
 * net_http_connection_iterate:
 *
 * Leaf function.
 **/
bool net_http_connection_iterate(struct http_connection_t *conn)
{
   if (!conn)
      return false;

   while (*conn-&gt;scan != '/' &amp;&amp; *conn-&gt;scan != ':' &amp;&amp; *conn-&gt;scan != '\0')
      conn-&gt;scan++;

   return true;
}

bool net_http_connection_done(struct http_connection_t *conn)
{
   int has_port = 0;

   if (!conn || !conn-&gt;domain || !*conn-&gt;domain)
      return false;

   if (*conn-&gt;scan == ':')
   {
      /* domain followed by port, split off the port */
      *conn-&gt;scan++ = '\0';

      if (!isdigit((int)(*conn-&gt;scan)))
         return false;

      conn-&gt;port = (int)strtoul(conn-&gt;scan, &amp;conn-&gt;scan, 10);
      has_port   = 1;
   }
   else if (conn-&gt;port == 0)
   {
      /* port not specified, default to standard HTTP or HTTPS port */
      if (conn-&gt;ssl)
         conn-&gt;port = 443;
      else
         conn-&gt;port = 80;
   }

   if (*conn-&gt;scan == '/')
   {
      /* domain followed by path - split off the path */
      /*   site.com/path.html   or   site.com:80/path.html   */
      *conn-&gt;scan    = '\0';
      conn-&gt;path = conn-&gt;scan + 1;
      return true;
   }
   else if (!*conn-&gt;scan)
   {
      /* domain with no path - point path at empty string */
      /*   site.com   or   site.com:80   */
      conn-&gt;path = conn-&gt;scan;
      return true;
   }
   else if (*conn-&gt;scan == '?')
   {
      /* domain with no path, but still has query parms - point path at the query parms */
      /*   site.com?param=3   or  site.com:80?param=3   */
      if (!has_port)
      {
         /* if there wasn't a port, we have to expand the urlcopy so we can separate the two parts */
         size_t domain_len   = strlen(conn-&gt;domain);
         size_t path_len     = strlen(conn-&gt;scan);
         char* urlcopy       = (char*)malloc(domain_len + path_len + 2);
         memcpy(urlcopy, conn-&gt;domain, domain_len);
         urlcopy[domain_len] = '\0';
         memcpy(urlcopy + domain_len + 1, conn-&gt;scan, path_len + 1);

         free(conn-&gt;url);
         conn-&gt;domain        = conn-&gt;url     = urlcopy;
         conn-&gt;path          = conn-&gt;scan    = urlcopy + domain_len + 1;
      }
      else /* There was a port, so overwriting the : will terminate the domain and we can just point at the ? */
         conn-&gt;path          = conn-&gt;scan;

      return true;
   }

   /* invalid character after domain/port */
   return false;
}

void net_http_connection_free(struct http_connection_t *conn)
{
   if (!conn)
      return;

   if (conn-&gt;url)
      free(conn-&gt;url);

   if (conn-&gt;method)
      free(conn-&gt;method);

   if (conn-&gt;contenttype)
      free(conn-&gt;contenttype);

   if (conn-&gt;postdata)
      free(conn-&gt;postdata);

   if (conn-&gt;useragent)
      free(conn-&gt;useragent);

   if (conn-&gt;headers)
      free(conn-&gt;headers);

   free(conn);
}

void net_http_connection_set_user_agent(
      struct http_connection_t *conn, const char *user_agent)
{
   if (conn-&gt;useragent)
      free(conn-&gt;useragent);

   conn-&gt;useragent = user_agent ? strdup(user_agent) : NULL;
}

void net_http_connection_set_headers(
      struct http_connection_t *conn, const char *headers)
{
   if (conn-&gt;headers)
      free(conn-&gt;headers);

   conn-&gt;headers = headers ? strdup(headers) : NULL;
}

void net_http_connection_set_content(
      struct http_connection_t *conn, const char *content_type,
      size_t content_length, const void *content)

{
   if (conn-&gt;contenttype)
      free(conn-&gt;contenttype);
   if (conn-&gt;postdata)
      free(conn-&gt;postdata);

   conn-&gt;contenttype   = content_type ? strdup(content_type) : NULL;
   conn-&gt;contentlength = content_length;
   if (content_length)
   {
      conn-&gt;postdata = malloc(content_length);
      memcpy(conn-&gt;postdata, content, content_length);
   }
}

const char *net_http_connection_url(struct http_connection_t *conn)
{
   return conn-&gt;url;
}

const char* net_http_connection_method(struct http_connection_t* conn)
{
   return conn-&gt;method;
}

static void net_http_dns_cache_remove_expired(void)
{
   struct dns_cache_entry *entry = dns_cache;
   struct dns_cache_entry *prev = NULL;
   while (entry)
   {
      if (     (entry-&gt;addr &amp;&amp; (entry-&gt;timestamp + dns_cache_timeout &lt; cpu_features_get_time_usec()))
            || (!entry-&gt;addr &amp;&amp; (entry-&gt;timestamp + dns_cache_fail_timeout &lt; cpu_features_get_time_usec())))
      {
         if (prev)
            prev-&gt;next = entry-&gt;next;
         else
            dns_cache = entry-&gt;next;
         if (entry-&gt;addr)
            freeaddrinfo_retro(entry-&gt;addr);
         free(entry-&gt;domain);
         free(entry);
         entry = prev ? prev-&gt;next : dns_cache;
      }
      else
      {
         prev = entry;
         entry = entry-&gt;next;
      }
   }
}

static struct dns_cache_entry *net_http_dns_cache_find(const char *domain, int port)
{
   struct dns_cache_entry *entry;

   net_http_dns_cache_remove_expired();

   entry = dns_cache;
   while (entry)
   {
      if (port == entry-&gt;port &amp;&amp; string_is_equal(entry-&gt;domain, domain))
      {
         /* don't bump timeestamp for failures */
         if (entry-&gt;addr)
            entry-&gt;timestamp = cpu_features_get_time_usec();
         return entry;
      }
      entry = entry-&gt;next;
   }
   return NULL;
}

static struct dns_cache_entry *net_http_dns_cache_add(const char *domain, int port, struct addrinfo *addr)
{
   struct dns_cache_entry *entry = (struct dns_cache_entry*)calloc(1, sizeof(*entry));
   if (!entry)
      return NULL;
   entry-&gt;domain = strdup(domain);
   entry-&gt;port = port;
   entry-&gt;addr = addr;
   entry-&gt;timestamp = cpu_features_get_time_usec();
   entry-&gt;valid = (addr != NULL);
   entry-&gt;next = dns_cache;
   dns_cache = entry;
   return entry;
}

static void net_http_conn_pool_free(struct conn_pool_entry *entry)
{
#ifdef HAVE_SSL
   if (entry-&gt;ssl &amp;&amp; entry-&gt;ssl_ctx)
   {
      ssl_socket_close(entry-&gt;ssl_ctx);
      ssl_socket_free(entry-&gt;ssl_ctx);
   }
#endif
   if (entry-&gt;fd &gt;= 0)
      socket_close(entry-&gt;fd);
   free(entry-&gt;domain);
   free(entry);
}

static void net_http_conn_pool_remove(struct conn_pool_entry *entry)
{
   struct conn_pool_entry *prev = NULL;
   struct conn_pool_entry *current;
   if (!entry)
      return;

   LOCK_POOL();
   current = conn_pool;
   while (current)
   {
      if (current == entry)
      {
         if (prev)
            prev-&gt;next = current-&gt;next;
         else
            conn_pool = current-&gt;next;
         net_http_conn_pool_free(current);
         UNLOCK_POOL();
         return;
      }
      prev = current;
      current = current-&gt;next;
   }
   UNLOCK_POOL();
}

/* *NOT* thread safe, caller must lock */
static void net_http_conn_pool_remove_expired(void)
{
   fd_set fds;
   struct conn_pool_entry *entry = NULL;
   struct conn_pool_entry *prev  = NULL;
   struct timeval tv             = { 0 };
   int max                       = 0;
   FD_ZERO(&amp;fds);
   entry = conn_pool;
   while (entry)
   {
      if (!entry-&gt;in_use)
      {
         FD_SET(entry-&gt;fd, &amp;fds);
         if (entry-&gt;fd &gt;= max)
            max = entry-&gt;fd + 1;
      }
      entry = entry-&gt;next;
   }
   if (select(max, &amp;fds, NULL, NULL, &amp;tv) &lt;= 0)
      return;
   entry = conn_pool;
   while (entry)
   {
      if (!entry-&gt;in_use &amp;&amp; FD_ISSET(entry-&gt;fd, &amp;fds))
      {
         char buf[4096];
         bool err = false;
#ifdef HAVE_SSL
         if (entry-&gt;ssl &amp;&amp; entry-&gt;ssl_ctx)
            ssl_socket_receive_all_nonblocking(entry-&gt;ssl_ctx, &amp;err, buf, sizeof(buf));
         else
#endif
            socket_receive_all_nonblocking(entry-&gt;fd, &amp;err, buf, sizeof(buf));

         if (!err)
            continue;

         if (prev)
            prev-&gt;next = entry-&gt;next;
         else
            conn_pool = entry-&gt;next;
         /* if it's not in use and it's reaadable we assume that means it's closed without checking recv */
         net_http_conn_pool_free(entry);
         entry = prev ? prev-&gt;next : conn_pool;
      }
      else
      {
         prev = entry;
         entry = entry-&gt;next;
      }
   }
}

/* if it's not already in the pool, will add to end.
   *NOT* thread safe, caller must lock */
static void net_http_conn_pool_move_to_end(struct conn_pool_entry *entry)
{
   struct conn_pool_entry *prev    = NULL;
   struct conn_pool_entry *current = conn_pool;
   /* 0 items in pool */
   if (!conn_pool)
   {
      conn_pool   = entry;
      entry-&gt;next = NULL;
      return;
   }
   /* already only item in pool */
   if (conn_pool == entry &amp;&amp; !conn_pool-&gt;next)
      return;
   while (current)
   {
      if (current != entry)
         prev = current;
      else
      {
         /* need to remove current */
         if (prev)
            prev-&gt;next = current-&gt;next;
         else
            conn_pool = current-&gt;next;
      }
      current = current-&gt;next;
   }

   if (prev)
      prev-&gt;next  = entry;
   if (entry)
      entry-&gt;next = NULL;
}

static struct conn_pool_entry *net_http_conn_pool_find(const char *domain, int port)
{
   struct conn_pool_entry *entry;

   LOCK_POOL();

   net_http_conn_pool_remove_expired();

   entry = conn_pool;
   while (entry)
   {
      if (!entry-&gt;in_use &amp;&amp; port == entry-&gt;port &amp;&amp; string_is_equal(entry-&gt;domain, domain))
      {
         entry-&gt;in_use = true;
         net_http_conn_pool_move_to_end(entry);
         UNLOCK_POOL();
         return entry;
      }
      entry = entry-&gt;next;
   }
   UNLOCK_POOL();
   return NULL;
}

static struct conn_pool_entry *net_http_conn_pool_add(const char *domain, int port, int fd, bool ssl)
{
   struct conn_pool_entry *entry = (struct conn_pool_entry*)calloc(1, sizeof(*entry));
   if (!entry)
      return NULL;
   entry-&gt;domain = strdup(domain);
   entry-&gt;port = port;
   entry-&gt;fd = fd;
   entry-&gt;in_use = true;
   entry-&gt;ssl = ssl;
   entry-&gt;connected = false;
   LOCK_POOL();
   net_http_conn_pool_move_to_end(entry);
   UNLOCK_POOL();
   return entry;
}

struct http_t *net_http_new(struct http_connection_t *conn)
{
   struct http_t *state;

   if (!conn)
      return NULL;

   state = (struct http_t*)calloc(1, sizeof(struct http_t));
   if (!state)
      return NULL;

   state-&gt;ssl  = conn-&gt;ssl;
   state-&gt;conn = NULL;

   state-&gt;request.domain        = strdup(conn-&gt;domain);
   state-&gt;request.path          = strdup(conn-&gt;path);
   state-&gt;request.method        = strdup(conn-&gt;method);
   state-&gt;request.contenttype   = conn-&gt;contenttype ? strdup(conn-&gt;contenttype) : NULL;
   state-&gt;request.contentlength = conn-&gt;contentlength;
   if (conn-&gt;postdata &amp;&amp; conn-&gt;contentlength)
   {
      state-&gt;request.postdata   = malloc(conn-&gt;contentlength);
      memcpy(state-&gt;request.postdata, conn-&gt;postdata, conn-&gt;contentlength);
   }
   state-&gt;request.useragent     = conn-&gt;useragent ? strdup(conn-&gt;useragent) : NULL;
   state-&gt;request.headers       = conn-&gt;headers ? strdup(conn-&gt;headers) : NULL;
   state-&gt;request.port          = conn-&gt;port;

   state-&gt;response.status  = -1;
   state-&gt;response.buflen  = 64 * 1024;  /* Start with larger buffer to reduce reallocations */
   state-&gt;response.data    = (char*)malloc(state-&gt;response.buflen);
   state-&gt;response.headers = string_list_new();

   return state;
}

static void net_http_resolve(void *data)
{
   struct dns_cache_entry *entry = (struct dns_cache_entry*)data;
   struct addrinfo hints         = {0};
   struct addrinfo *addr         = NULL;
   char *domain;
   int port;
   char port_buf[6];
#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
   int family                    = AF_INET;
#else
   int family                    = AF_UNSPEC;
#endif

   hints.ai_family = family;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags |= AI_NUMERICSERV;

   LOCK_DNS_CACHE();
   domain = strdup(entry-&gt;domain);
   port = entry-&gt;port;
   UNLOCK_DNS_CACHE();

   if (!network_init())
   {
      LOCK_DNS_CACHE();
      entry-&gt;valid = true;
      entry-&gt;addr = NULL;
      UNLOCK_DNS_CACHE();
      free(domain);
      return;
   }

   snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);

   getaddrinfo_retro(domain, port_buf, &amp;hints, &amp;addr);
   free(domain);

   LOCK_DNS_CACHE();
   entry-&gt;valid = true;
   entry-&gt;addr = addr;
   UNLOCK_DNS_CACHE();
}

static bool net_http_new_socket(struct http_t *state)
{
   struct addrinfo *addr = NULL;
   struct dns_cache_entry *entry;

#ifdef HAVE_THREADS
   sthread_t *thread;

   if (!dns_cache_lock)
      dns_cache_lock = slock_new();
   LOCK_DNS_CACHE();

   /* need some place to create this, I guess */
   if (!conn_pool_lock)
      conn_pool_lock = slock_new();
#endif

   entry = net_http_dns_cache_find(state-&gt;request.domain, state-&gt;request.port);
   if (entry)
   {
      if (entry-&gt;valid)
      {
         int fd;
         if (!entry-&gt;addr)
         {
            UNLOCK_DNS_CACHE();
            return false;
         }
         addr = entry-&gt;addr;
         fd = socket(addr-&gt;ai_family, addr-&gt;ai_socktype, addr-&gt;ai_protocol);
         if (fd &gt;= 0)
            state-&gt;conn = net_http_conn_pool_add(state-&gt;request.domain, state-&gt;request.port, fd, state-&gt;ssl);
         /* still waiting on thread */
         UNLOCK_DNS_CACHE();
         return (fd &gt;= 0);
      }
      else
      {
         /* still waiting on thread */
         UNLOCK_DNS_CACHE();
         return true;
      }
   }
   else
   {
      entry = net_http_dns_cache_add(state-&gt;request.domain, state-&gt;request.port, NULL);
#ifdef HAVE_THREADS
      /* create the entry for it as an indicator that the request is underway */
      thread = sthread_create(net_http_resolve, entry);
      sthread_detach(thread);
#else
      net_http_resolve(entry);
#endif
   }

   UNLOCK_DNS_CACHE();

   return true;
}

static bool net_http_connect(struct http_t *state)
{
   struct addrinfo *addr = NULL, *next_addr = NULL;
   struct conn_pool_entry *conn = state-&gt;conn;
   struct dns_cache_entry *dns_entry = net_http_dns_cache_find(state-&gt;request.domain, state-&gt;request.port);
   /* we just used/added this in _new_socket above, if it's not there it's a big bug */
   addr = dns_entry-&gt;addr;

#ifndef HAVE_SSL
   if (state-&gt;ssl)
      return false;
#else
   if (state-&gt;ssl)
   {
      if (!conn)
         return false;

      for (next_addr = addr; conn-&gt;fd &gt;= 0; conn-&gt;fd = socket_next((void**)&amp;next_addr))
      {
         if (!(conn-&gt;ssl_ctx = ssl_socket_init(conn-&gt;fd, state-&gt;request.domain)))
         {
            socket_close(conn-&gt;fd);
            break;
         }

         /* TODO: Properly figure out what's going wrong when the newer
          timeout/poll code interacts with mbed and winsock
          https://github.com/libretro/RetroArch/issues/14742 */

         /* Temp fix, don't use new timeout/poll code for cheevos http requests */
         bool timeout = true;
#ifdef __WIN32
         if (!strcmp(state-&gt;request.domain, "retroachievements.org"))
            timeout = false;
#endif

         if (ssl_socket_connect(conn-&gt;ssl_ctx, next_addr, timeout, true) &lt; 0)
         {
            ssl_socket_close(conn-&gt;ssl_ctx);
            ssl_socket_free(conn-&gt;ssl_ctx);
            conn-&gt;ssl_ctx = NULL;
         }
         else
         {
            conn-&gt;connected = true;
            return true;
         }
      }
      conn-&gt;fd    = -1; /* already closed */
      net_http_conn_pool_remove(conn);
      state-&gt;conn = NULL;
      state-&gt;err  = true;
      return false;
   }
   else
#endif
   {
      for (next_addr = addr; conn-&gt;fd &gt;= 0; conn-&gt;fd = socket_next((void**)&amp;next_addr))
      {
         if (socket_connect_with_timeout(conn-&gt;fd, next_addr, 5000))
         {
            conn-&gt;connected = true;
            return true;
         }

         socket_close(conn-&gt;fd);
      }
      conn-&gt;fd    = -1; /* already closed */
      net_http_conn_pool_remove(conn);
      state-&gt;conn = NULL;
      state-&gt;err  = true;
      return false;
   }
}

static void net_http_send_str(
      struct http_t *state, const char *text, size_t text_size)
{
   if (state-&gt;err)
      return;
#ifdef HAVE_SSL
   if (state-&gt;ssl)
   {
      if (!ssl_socket_send_all_blocking(
                  state-&gt;conn-&gt;ssl_ctx, text, text_size, true))
         state-&gt;err = true;
   }
   else
#endif
   {
      if (!socket_send_all_blocking(
                  state-&gt;conn-&gt;fd, text, text_size, true))
         state-&gt;err = true;
   }
}

static bool net_http_send_request(struct http_t *state)
{
   struct request *request = (struct request*)&amp;state-&gt;request;

   /* This is a bit lazy, but it works. */
   if (request-&gt;method)
   {
      net_http_send_str(state, request-&gt;method, strlen(request-&gt;method));
      net_http_send_str(state, " /", STRLEN_CONST(" /"));
   }
   else
      net_http_send_str(state, "GET /", STRLEN_CONST("GET /"));

   net_http_send_str(state, request-&gt;path, strlen(request-&gt;path));
   net_http_send_str(state, " HTTP/1.1\r\n", STRLEN_CONST(" HTTP/1.1\r\n"));

   net_http_send_str(state, "Host: ", STRLEN_CONST("Host: "));
   net_http_send_str(state, request-&gt;domain, strlen(request-&gt;domain));

   if (request-&gt;port &amp;&amp; request-&gt;port != 80 &amp;&amp; request-&gt;port != 443)
   {
      char portstr[16];
      size_t _len     = 0;
      portstr[  _len] = ':';
      portstr[++_len] = '\0';
      _len           += snprintf(portstr + _len, sizeof(portstr) - _len,
            "%i", request-&gt;port);
      net_http_send_str(state, portstr, _len);
   }

   net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

   /* Pre-formatted headers */
   if (request-&gt;headers)
      net_http_send_str(state, request-&gt;headers, strlen(request-&gt;headers));
   if (request-&gt;contenttype)
   {
      net_http_send_str(state, "Content-Type: ", STRLEN_CONST("Content-Type: "));
      net_http_send_str(state, request-&gt;contenttype, strlen(request-&gt;contenttype));
      net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));
   }

   if (request-&gt;method &amp;&amp; (string_is_equal(request-&gt;method, "POST") || string_is_equal(request-&gt;method, "PUT")))
   {
      size_t _len, len;
      char *len_str = NULL;

      if (!request-&gt;postdata &amp;&amp; !string_is_equal(request-&gt;method, "PUT"))
      {
         state-&gt;err = true;
         return true;
      }

      if (!request-&gt;headers &amp;&amp; !request-&gt;contenttype)
         net_http_send_str(state,
               "Content-Type: application/x-www-form-urlencoded\r\n",
               STRLEN_CONST("Content-Type: application/x-www-form-urlencoded\r\n"));

      net_http_send_str(state, "Content-Length: ", STRLEN_CONST("Content-Length: "));

      _len = request-&gt;contentlength;
#ifdef _WIN32
      len     = snprintf(NULL, 0, "%" PRIuPTR, _len);
      len_str = (char*)malloc(len + 1);
      snprintf(len_str, len + 1, "%" PRIuPTR, _len);
#else
      len     = snprintf(NULL, 0, "%llu", (long long unsigned)_len);
      len_str = (char*)malloc(len + 1);
      snprintf(len_str, len + 1, "%llu", (long long unsigned)_len);
#endif

      len_str[len] = '\0';

      net_http_send_str(state, len_str, strlen(len_str));
      net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

      free(len_str);
   }

   net_http_send_str(state, "User-Agent: ", STRLEN_CONST("User-Agent: "));
   if (request-&gt;useragent)
      net_http_send_str(state, request-&gt;useragent, strlen(request-&gt;useragent));
   else
      net_http_send_str(state, "libretro", STRLEN_CONST("libretro"));
   net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

   net_http_send_str(state, "\r\n", STRLEN_CONST("\r\n"));

   if (request-&gt;postdata &amp;&amp; request-&gt;contentlength)
      net_http_send_str(state, (const char*)request-&gt;postdata,
            request-&gt;contentlength);

   state-&gt;request_sent = true;
   return state-&gt;err;
}

/**
 * net_http_fd:
 *
 * Leaf function.
 *
 * You can use this to call net_http_update
 * only when something will happen; select() it for reading.
 **/
int net_http_fd(struct http_t *state)
{
   if (!state || !state-&gt;conn)
      return -1;
   return state-&gt;conn-&gt;fd;
}

static ssize_t net_http_receive_header(struct http_t *state, ssize_t len)
{
   struct response *response = (struct response*)&amp;state-&gt;response;

   response-&gt;pos += len;

   while (response-&gt;part &lt; P_BODY)
   {
      char *dataend  = response-&gt;data + response-&gt;pos;
      char *lineend  = (char*)memchr(response-&gt;data, '\n', response-&gt;pos);

      if (!lineend)
         break;

      *lineend       = '\0';

      if (lineend != response-&gt;data &amp;&amp; lineend[-1]=='\r')
         lineend[-1] = '\0';

      if (response-&gt;part == P_HEADER_TOP)
      {
         if (strncmp(response-&gt;data, "HTTP/1.", STRLEN_CONST("HTTP/1."))!=0)
         {
            response-&gt;part = P_DONE;
            state-&gt;err     = true;
            return -1;
         }
         response-&gt;status = (int)strtoul(response-&gt;data
               + STRLEN_CONST("HTTP/1.1 "), NULL, 10);
         response-&gt;part   = P_HEADER;
      }
      else
      {
         if (string_starts_with_case_insensitive(response-&gt;data, "Content-Length:"))
         {
            char* ptr = response-&gt;data + STRLEN_CONST("Content-Length:");
            while (ISSPACE(*ptr))
               ++ptr;

            response-&gt;bodytype = T_LEN;
            response-&gt;len      = strtol(ptr, NULL, 10);
         }
         else if (string_is_equal_case_insensitive(response-&gt;data, "Transfer-Encoding: chunked"))
            response-&gt;bodytype = T_CHUNK;

         if (response-&gt;data[0]=='\0')
         {
            if (response-&gt;status == 100)
            {
               response-&gt;part = P_HEADER_TOP;
            }
            else
            {
               response-&gt;part = P_BODY;
               if (response-&gt;bodytype == T_CHUNK)
                  response-&gt;part = P_BODY_CHUNKLEN;
            }
         }
         else
         {
            union string_list_elem_attr attr;
            attr.i = 0;
            string_list_append(response-&gt;headers, response-&gt;data, attr);
         }
      }

      memmove(response-&gt;data, lineend + 1, dataend-(lineend+1));
      response-&gt;pos = (dataend-(lineend + 1));
   }

   if (response-&gt;part &gt;= P_BODY)
   {
      len           = response-&gt;pos;
      response-&gt;pos = 0;
      if (response-&gt;bodytype == T_LEN)
      {
         response-&gt;buflen = response-&gt;len;
         response-&gt;data   = (char*)realloc(response-&gt;data, response-&gt;buflen);
      }
   }
   else
   {
      if (response-&gt;pos &gt;= response-&gt;buflen - 64)
      {
         response-&gt;buflen *= 2;
         response-&gt;data    = (char*)realloc(response-&gt;data, response-&gt;buflen);
      }
   }
   return len;
}

static bool net_http_receive_body(struct http_t *state, ssize_t newlen)
{
   struct response *response = (struct response*)&amp;state-&gt;response;

   if (newlen &lt; 0 || state-&gt;err)
   {
      if (response-&gt;bodytype != T_FULL)
         return false;
      response-&gt;part      = P_DONE;
      if (response-&gt;buflen != response-&gt;len)
         response-&gt;data      = (char*)realloc(response-&gt;data, response-&gt;len);
      return true;
   }

parse_again:
   if (response-&gt;bodytype == T_CHUNK)
   {
      if (response-&gt;part == P_BODY_CHUNKLEN)
      {
         response-&gt;pos      += newlen;

         if (response-&gt;pos - response-&gt;len &gt;= 2)
         {
            /*
             * len=start of chunk including \r\n
             * pos=end of data
             */

            char *fullend = response-&gt;data + response-&gt;pos;
            char *end     = (char*)memchr(response-&gt;data + response-&gt;len + 2, '\n',
                  response-&gt;pos - response-&gt;len - 2);

            if (end)
            {
               size_t chunklen = strtoul(response-&gt;data + response-&gt;len, NULL, 16);
               response-&gt;pos   = response-&gt;len;
               end++;

               memmove(response-&gt;data + response-&gt;len, end, fullend-end);

               response-&gt;len   = chunklen;
               newlen          = (fullend - end);

               /*
                 len=num bytes
                 newlen=unparsed bytes after \n
                 pos=start of chunk including \r\n
               */

               response-&gt;part = P_BODY;
               if (response-&gt;len == 0)
               {
                  response-&gt;part = P_DONE;
                  response-&gt;len  = response-&gt;pos;
                  response-&gt;data = (char*)realloc(response-&gt;data, response-&gt;len);
                  return true;
               }
               goto parse_again;
            }
         }
      }
      else if (response-&gt;part == P_BODY)
      {
         if ((size_t)newlen &gt;= response-&gt;len)
         {
            response-&gt;pos += response-&gt;len;
            newlen        -= response-&gt;len;
            response-&gt;len  = response-&gt;pos;
            response-&gt;part = P_BODY_CHUNKLEN;
            goto parse_again;
         }
         response-&gt;pos += newlen;
         response-&gt;len -= newlen;
      }
   }
   else
   {
      response-&gt;pos += newlen;

      if (response-&gt;pos &gt; response-&gt;len)
         return false;
      else if (response-&gt;pos == response-&gt;len)
      {
         response-&gt;part = P_DONE;
         if (response-&gt;buflen != response-&gt;len)
            response-&gt;data = (char*)realloc(response-&gt;data, response-&gt;len);
         return true;
      }
   }

   if (response-&gt;pos &gt;= response-&gt;buflen)
   {
      response-&gt;buflen *= 2;
      response-&gt;data    = (char*)realloc(response-&gt;data, response-&gt;buflen);
   }
   return true;
}

static bool net_http_redirect(struct http_t *state, const char *location)
{
   /* this reinitializes state based on the new location */

   /* url may be absolute or relative to the current url */
   bool absolute = (strstr(location, "://") != NULL);

   if (absolute)
   {
      /* this block is a little wasteful, memory-wise */
      struct http_connection_t *new_url = net_http_connection_new(location, NULL, NULL);
      net_http_connection_iterate(new_url);
      if (!net_http_connection_done(new_url))
      {
         net_http_connection_free(new_url);
         return true;
      }
      state-&gt;ssl = new_url-&gt;ssl;
      if (state-&gt;request.domain)
         free(state-&gt;request.domain);
      state-&gt;request.domain = strdup(new_url-&gt;domain);
      state-&gt;request.port = new_url-&gt;port;
      if (state-&gt;request.path)
         free(state-&gt;request.path);
      state-&gt;request.path = strdup(new_url-&gt;path);
      net_http_connection_free(new_url);
   }
   else
   {
      if (*location == '/')
      {
         if (state-&gt;request.path)
            free(state-&gt;request.path);
         state-&gt;request.path = strdup(location);
      }
      else
      {
         char *path = (char*)malloc(PATH_MAX_LENGTH);
         fill_pathname_resolve_relative(path, state-&gt;request.path, location, PATH_MAX_LENGTH);
         free(state-&gt;request.path);
         state-&gt;request.path = path;
      }
   }
   state-&gt;request_sent       = false;
   state-&gt;response.part      = P_HEADER_TOP;
   state-&gt;response.status    = -1;
   state-&gt;response.buflen    = 64 * 1024;  /* Start with larger buffer to reduce reallocations */
   state-&gt;response.data      = (char*)realloc(state-&gt;response.data, state-&gt;response.buflen);
   state-&gt;response.pos       = 0;
   state-&gt;response.len       = 0;
   state-&gt;response.bodytype  = T_FULL;
   /* after this, assume location is invalid */
   string_list_deinitialize(state-&gt;response.headers);
   string_list_initialize(state-&gt;response.headers);
   /* keep going */
   return false;
}

/**
 * net_http_update:
 *
 * @return true if it's done, or if something broke.
 * @total will be 0 if it's not known.
 **/
bool net_http_update(struct http_t *state, size_t* progress, size_t* total)
{
   struct response *response;
   ssize_t _len = 0;

   if (!state || state-&gt;err)
      return true;

   if (!state-&gt;conn)
   {
      state-&gt;conn = net_http_conn_pool_find(state-&gt;request.domain, state-&gt;request.port);
      if (!state-&gt;conn)
      {
         if (!net_http_new_socket(state))
            state-&gt;err = true;
         return state-&gt;err;
      }
   }

   if (!state-&gt;conn-&gt;connected)
   {
      if (!net_http_connect(state))
         state-&gt;err = true;
      return state-&gt;err;
   }

   if (!state-&gt;request_sent)
      return net_http_send_request(state);

   response = (struct response*)&amp;state-&gt;response;

#ifdef HAVE_SSL
   if (state-&gt;ssl &amp;&amp; state-&gt;conn-&gt;ssl_ctx)
      _len = ssl_socket_receive_all_nonblocking(state-&gt;conn-&gt;ssl_ctx, &amp;state-&gt;err,
            (uint8_t*)response-&gt;data + response-&gt;pos,
            response-&gt;buflen - response-&gt;pos);
   else
#endif
      _len = socket_receive_all_nonblocking(state-&gt;conn-&gt;fd, &amp;state-&gt;err,
            (uint8_t*)response-&gt;data + response-&gt;pos,
            response-&gt;buflen - response-&gt;pos);

   if (response-&gt;part &lt; P_BODY)
   {
      if (_len &lt; 0 || state-&gt;err)
      {
         net_http_conn_pool_remove(state-&gt;conn);
         state-&gt;err       = true;
         response-&gt;part   = P_DONE;
         response-&gt;status = -1;
         return true;
      }
      _len = net_http_receive_header(state, _len);
   }

   if (response-&gt;part &gt;= P_BODY &amp;&amp; response-&gt;part &lt; P_DONE)
   {
      if (!net_http_receive_body(state, _len))
      {
         net_http_conn_pool_remove(state-&gt;conn);
         state-&gt;err       = true;
         response-&gt;part   = P_DONE;
         response-&gt;status = -1;
         return true;
      }
   }

   if (progress)
      *progress = response-&gt;pos;

   if (total)
   {
      if (response-&gt;bodytype == T_LEN)
         *total = response-&gt;len;
      else
         *total = 0;
   }

   if (response-&gt;part != P_DONE)
      return false;

   for (_len = 0; (size_t)_len &lt; response-&gt;headers-&gt;size; _len++)
   {
      if (string_is_equal_case_insensitive(response-&gt;headers-&gt;elems[_len].data, "connection: close"))
      {
         net_http_conn_pool_remove(state-&gt;conn);
         state-&gt;conn = NULL;
         break;
      }
   }

   if (state-&gt;conn)
      state-&gt;conn-&gt;in_use = false;
   state-&gt;conn = NULL;

   if (response-&gt;status &gt;= 300 &amp;&amp; response-&gt;status &lt; 400)
   {
      for (_len = 0; (size_t)_len &lt; response-&gt;headers-&gt;size; _len++)
      {
         if (string_starts_with_case_insensitive(response-&gt;headers-&gt;elems[_len].data, "Location: "))
            return net_http_redirect(state, response-&gt;headers-&gt;elems[_len].data + STRLEN_CONST("Location: "));
      }
   }

   return true;
}

/**
 * net_http_status:
 *
 * Report HTTP status. 200, 404, or whatever.
 *
 * Leaf function.
 *
 * @return HTTP status code.
 **/
int net_http_status(struct http_t *state)
{
   if (!state)
      return -1;
   return state-&gt;response.status;
}

/**
 * net_http_headers:
 *
 * Leaf function.
 *
 * @return the response headers. The returned buffer is owned by the
 * caller of net_http_new; it is not freed by net_http_delete().
 * If the status is not 20x and accept_err is false, it returns NULL.
 **/
struct string_list *net_http_headers(struct http_t *state)
{
   if (!state || !state-&gt;err)
      return NULL;
   return state-&gt;response.headers;
}

/**
 * net_http_data:
 *
 * Leaf function.
 *
 * @return the downloaded data. The returned buffer is owned by the
 * HTTP handler; it's freed by net_http_delete().
 * If the status is not 20x and accept_err is false, it returns NULL.
 **/
uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_err)
{
   if (!state)
      return NULL;

   if (!accept_err &amp;&amp; (state-&gt;err || state-&gt;response.status &lt; 200 || state-&gt;response.status &gt; 299))
   {
      if (len)
         *len = 0;
      return NULL;
   }

   if (len)
      *len    = state-&gt;response.len;

   return (uint8_t*)state-&gt;response.data;
}

/**
 * net_http_delete:
 *
 * Cleans up all memory.
 **/
void net_http_delete(struct http_t *state)
{
   if (!state)
      return;

   if (state-&gt;conn)
      net_http_conn_pool_remove(state-&gt;conn);
   if (state-&gt;request.domain)
      free(state-&gt;request.domain);
   if (state-&gt;request.path)
      free(state-&gt;request.path);
   if (state-&gt;request.method)
      free(state-&gt;request.method);
   if (state-&gt;request.contenttype)
      free(state-&gt;request.contenttype);
   if (state-&gt;request.postdata)
      free(state-&gt;request.postdata);
   if (state-&gt;request.useragent)
      free(state-&gt;request.useragent);
   if (state-&gt;request.headers)
      free(state-&gt;request.headers);
   free(state);
}

/**
 * net_http_error:
 *
 * Leaf function
 **/
bool net_http_error(struct http_t *state)
{
   return (state-&gt;err || state-&gt;response.status &lt; 200 || state-&gt;response.status &gt; 299);
}</pre>
<h2>./include/libretro-common/net/net_http_parse.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http_parse.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;compat/strcasestr.h&gt;

/**
 * string_parse_html_anchor:
 * @line               : Buffer where the &lt;a&gt; tag is stored
 * @link               : Buffer to store the link URL in
 * @name               : Buffer to store the link URL in
 * @link_size          : Size of the link buffer including the NUL-terminator
 * @name_size          : Size of the name buffer including the NUL-terminator
 *
 * Parses an HTML anchor link stored in @line in the form of: &lt;a href="/path/to/url"&gt;Title&lt;/a&gt;
 * The buffer pointed to by @link is filled with the URL path the link points to,
 * and @name is filled with the title portion of the link.
 *
 * @return 0 if URL was parsed completely, otherwise 1.
 **/
int string_parse_html_anchor(const char *line, char *link, char *name,
      size_t link_size, size_t name_size)
{
   if (!line || !link || !name)
      return 1;

   memset(link, 0, link_size);
   memset(name, 0, name_size);

   line = strcasestr(line, "&lt;a href=\"");

   if (!line)
      return 1;

   line += 9;

   if (line &amp;&amp; *line)
   {
      if (!*link)
      {
         const char *end = strstr(line, "\"");

         if (!end)
            return 1;

         memcpy(link, line, end - line);

         *(link + (end - line)) = '\0';
         line += end - line;
      }

      if (!*name)
      {
         const char *start = strstr(line, "\"&gt;");
         const char *end   = start ? strstr(start, "&lt;/a&gt;") : NULL;

         if (!start || !end)
            return 1;

         memcpy(name, start + 2, end - start - 2);

         *(name + (end - start - 2)) = '\0';
      }
   }

   return 0;
}</pre>
<h2>./include/libretro-common/net/net_ifinfo.c</h2>
<pre>/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_ifinfo.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

#include &lt;string/stdstring.h&gt;
#include &lt;net/net_compat.h&gt;

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#ifdef _MSC_VER
#pragma comment(lib, "Iphlpapi")
#endif

#include &lt;iphlpapi.h&gt;

#elif !defined(VITA) &amp;&amp; !defined(GEKKO)
#if defined(WANT_IFADDRS)
#include &lt;compat/ifaddrs.h&gt;
#elif !defined(HAVE_LIBNX) &amp;&amp; !defined(_3DS)
#include &lt;ifaddrs.h&gt;
#ifndef WIIU
#include &lt;net/if.h&gt;
#endif
#endif
#endif

#include &lt;net/net_ifinfo.h&gt;

bool net_ifinfo_new(net_ifinfo_t *list)
{
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
   /* Microsoft docs recommend doing it this way. */
   char buf[512];
   ULONG ret;
   PIP_ADAPTER_ADDRESSES addr;
   struct net_ifinfo_entry *entry;
   size_t                interfaces = 0;
   ULONG                 flags      = GAA_FLAG_SKIP_ANYCAST
                                    | GAA_FLAG_SKIP_MULTICAST
                                    | GAA_FLAG_SKIP_DNS_SERVER;
   ULONG                 len        = 15 * 1024;
   PIP_ADAPTER_ADDRESSES addresses  = (PIP_ADAPTER_ADDRESSES)calloc(1, len);

   list-&gt;entries                    = NULL;

   if (!addresses)
      goto failure;

   ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addresses, &amp;len);
   if (ret == ERROR_BUFFER_OVERFLOW)
   {
      PIP_ADAPTER_ADDRESSES new_addresses =
         (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);

      if (new_addresses)
      {
         memset(new_addresses, 0, len);

         addresses = new_addresses;
         ret       = GetAdaptersAddresses(AF_UNSPEC, flags, NULL,
            addresses, &amp;len);
      }
   }
   if (ret != ERROR_SUCCESS)
      goto failure;

   /* Count the number of valid interfaces first. */
   addr = addresses;

   do
   {
      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr-&gt;FirstUnicastAddress;

      if (!unicast_addr)
         continue;
      if (addr-&gt;OperStatus != IfOperStatusUp)
         continue;

      do
      {
         interfaces++;
      } while ((unicast_addr = unicast_addr-&gt;Next));
   } while ((addr = addr-&gt;Next));

   if (!interfaces)
      goto failure;

   if (!(list-&gt;entries =
      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list-&gt;entries))))
      goto failure;

   list-&gt;size    = 0;
   /* Now create the entries. */
   addr          = addresses;
   entry         = list-&gt;entries;

   do
   {
      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr-&gt;FirstUnicastAddress;

      if (!unicast_addr)
         continue;
      if (addr-&gt;OperStatus != IfOperStatusUp)
         continue;

      buf[0] = '\0';
      if (addr-&gt;FriendlyName)
      {
         if (!WideCharToMultiByte(CP_UTF8, 0, addr-&gt;FriendlyName, -1,
               buf, sizeof(buf), NULL, NULL))
            buf[0] = '\0'; /* Empty name on conversion failure. */
      }

      do
      {
         if (getnameinfo_retro(unicast_addr-&gt;Address.lpSockaddr,
               unicast_addr-&gt;Address.iSockaddrLength,
               entry-&gt;host, sizeof(entry-&gt;host), NULL, 0, NI_NUMERICHOST))
            continue;

         strlcpy(entry-&gt;name, buf, sizeof(entry-&gt;name));

         if (++list-&gt;size &gt;= interfaces)
            break;

         entry++;
      } while ((unicast_addr = unicast_addr-&gt;Next));

      if (list-&gt;size &gt;= interfaces)
         break;
   } while ((addr = addr-&gt;Next));

   free(addresses);

   return true;

failure:
   free(addresses);
   net_ifinfo_free(list);

   return false;
#elif defined(VITA)
   SceNetCtlInfo info;
   if (!(list-&gt;entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list-&gt;entries))))
   {
      list-&gt;size = 0;
      return false;
   }

   strlcpy(list-&gt;entries[0].name, "lo",        sizeof(list-&gt;entries[0].name));
   strlcpy(list-&gt;entries[0].host, "127.0.0.1", sizeof(list-&gt;entries[0].host));
   list-&gt;size = 1;

   if (!sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &amp;info))
   {
      strlcpy(list-&gt;entries[1].name, "wlan", sizeof(list-&gt;entries[1].name));
      strlcpy(list-&gt;entries[1].host, info.ip_address,
         sizeof(list-&gt;entries[1].host));
      list-&gt;size++;
   }

   return true;
#elif defined(HAVE_LIBNX) || defined(_3DS) || defined(GEKKO)
   uint32_t addr = 0;
   if (!(list-&gt;entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list-&gt;entries))))
   {
      list-&gt;size = 0;
      return false;
   }

   strlcpy(list-&gt;entries[0].name, "lo", sizeof(list-&gt;entries[0].name));
   strlcpy(list-&gt;entries[0].host, "127.0.0.1", sizeof(list-&gt;entries[0].host));
   list-&gt;size = 1;

#if defined(HAVE_LIBNX)
   {
      Result rc = nifmGetCurrentIpAddress(&amp;addr);

      if (!R_SUCCEEDED(rc))
         return true;
   }
#elif defined(_3DS)
   addr = gethostid();
#else
   addr = net_gethostip();
#endif
   if (addr)
   {
      uint8_t *addr8 = (uint8_t*)&amp;addr;
      strlcpy(list-&gt;entries[1].name,
#if defined(HAVE_LIBNX)
         "switch"
#elif defined(_3DS)
         "wlan"
#else
         "gekko"
#endif
      , sizeof(list-&gt;entries[1].name));
      snprintf(list-&gt;entries[1].host, sizeof(list-&gt;entries[1].host),
         "%d.%d.%d.%d",
         (int)addr8[0], (int)addr8[1], (int)addr8[2], (int)addr8[3]);
      list-&gt;size++;
   }

   return true;
#else
   struct ifaddrs *addr;
   struct net_ifinfo_entry *entry;
   size_t         interfaces = 0;
   struct ifaddrs *addresses = NULL;

   list-&gt;entries             = NULL;

   if (getifaddrs(&amp;addresses) || !addresses)
      goto failure;

   /* Count the number of valid interfaces first. */
   addr                      = addresses;

   do
   {
      if (!addr-&gt;ifa_addr)
         continue;
#ifndef WIIU
      if (!(addr-&gt;ifa_flags &amp; IFF_UP))
         continue;
#endif

      switch (addr-&gt;ifa_addr-&gt;sa_family)
      {
         case AF_INET:
#ifdef HAVE_INET6
         case AF_INET6:
#endif
            interfaces++;
            break;
         default:
            break;
      }
   } while ((addr = addr-&gt;ifa_next));

   if (!interfaces)
      goto failure;

   list-&gt;entries =
      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list-&gt;entries));
   if (!list-&gt;entries)
      goto failure;
   list-&gt;size    = 0;

   /* Now create the entries. */
   addr  = addresses;
   entry = list-&gt;entries;

   do
   {
      socklen_t addrlen;

      if (!addr-&gt;ifa_addr)
         continue;
#ifndef WIIU
      if (!(addr-&gt;ifa_flags &amp; IFF_UP))
         continue;
#endif

      switch (addr-&gt;ifa_addr-&gt;sa_family)
      {
         case AF_INET:
            addrlen = sizeof(struct sockaddr_in);
            break;
#ifdef HAVE_INET6
         case AF_INET6:
            addrlen = sizeof(struct sockaddr_in6);
            break;
#endif
         default:
            continue;
      }

      if (getnameinfo_retro(addr-&gt;ifa_addr, addrlen,
            entry-&gt;host, sizeof(entry-&gt;host), NULL, 0, NI_NUMERICHOST))
         continue;

      if (addr-&gt;ifa_name)
         strlcpy(entry-&gt;name, addr-&gt;ifa_name, sizeof(entry-&gt;name));

      if (++list-&gt;size &gt;= interfaces)
         break;

      entry++;
   } while ((addr = addr-&gt;ifa_next));

   freeifaddrs(addresses);

   return true;

failure:
   freeifaddrs(addresses);
   net_ifinfo_free(list);

   return false;
#endif
}

void net_ifinfo_free(net_ifinfo_t *list)
{
   free(list-&gt;entries);

   list-&gt;entries = NULL;
   list-&gt;size    = 0;
}

bool net_ifinfo_best(const char *dst, void *src, bool ipv6)
{
/* TODO/FIXME: Implement for other platforms, if necessary. */
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
   if (!ipv6)
   {
      /* Courtesy of MiniUPnP: https://github.com/miniupnp/miniupnp */
      DWORD index;
#ifdef __WINRT__
      struct sockaddr_in dst_addr = {0};
#endif
      ULONG dst_ip               = (ULONG)inet_addr(dst);

      if (!src)
         return false;
      if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY)
         return false;

#ifdef __WINRT__
      dst_addr.sin_family      = AF_INET;
      dst_addr.sin_addr.s_addr = dst_ip;
      if (GetBestInterfaceEx((struct sockaddr*)&amp;dst_addr, &amp;index) == NO_ERROR)
#else
      if (GetBestInterface(dst_ip, &amp;index) == NO_ERROR)
#endif
      {
         /* Microsoft docs recommend doing it this way. */
         ULONG                 len       = 15 * 1024;
         PIP_ADAPTER_ADDRESSES addresses =
            (PIP_ADAPTER_ADDRESSES)calloc(1, len);

         if (addresses)
         {
            ULONG flags  = GAA_FLAG_SKIP_ANYCAST    | GAA_FLAG_SKIP_MULTICAST
                         | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
            ULONG ret    = GetAdaptersAddresses(AF_INET, flags, NULL,
               addresses, &amp;len);

            if (ret == ERROR_BUFFER_OVERFLOW)
            {
               PIP_ADAPTER_ADDRESSES new_addresses =
                  (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);

               if (new_addresses)
               {
                  memset(new_addresses, 0, len);

                  addresses = new_addresses;
                  ret       = GetAdaptersAddresses(AF_INET, flags, NULL,
                     addresses, &amp;len);
               }
            }

            if (ret == NO_ERROR)
            {
               bool found = false;
               PIP_ADAPTER_ADDRESSES addr = addresses;

               do
               {
                  if (addr-&gt;IfIndex == index)
                  {
                     if (addr-&gt;FirstUnicastAddress)
                     {
                        struct sockaddr_in *addr_unicast =
                           (struct sockaddr_in*)
                              addr-&gt;FirstUnicastAddress-&gt;Address.lpSockaddr;

                        memcpy(src, &amp;addr_unicast-&gt;sin_addr,
                           sizeof(addr_unicast-&gt;sin_addr));

                        found = true;
                     }

                     break;
                  }
               } while ((addr = addr-&gt;Next));
               return found;
            }

            free(addresses);
         }
      }
   }
#endif
   return false;
}</pre>
<h2>./include/libretro-common/net/net_socket.c</h2>
<pre>/* Copyright  (C) 2010-2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#ifdef _MSC_VER
#include &lt;compat/msvc.h&gt;
#endif

#include &lt;features/features_cpu.h&gt;

#include &lt;net/net_socket.h&gt;

int socket_init(void **address, uint16_t port, const char *server,
      enum socket_type type, int family)
{
   char port_buf[6];
   struct addrinfo hints      = {0};
   struct addrinfo **addrinfo = (struct addrinfo**)address;
   struct addrinfo *addr      = NULL;

   if (!family)
#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
      family = AF_INET;
#else
      family = AF_UNSPEC;
#endif

   hints.ai_family = family;

   switch (type)
   {
      case SOCKET_TYPE_DATAGRAM:
         hints.ai_socktype = SOCK_DGRAM;
         break;
      case SOCKET_TYPE_STREAM:
         hints.ai_socktype = SOCK_STREAM;
         break;
      default:
         return -1;
   }

   if (!server)
      hints.ai_flags = AI_PASSIVE;

   if (!network_init())
      return -1;

   snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
   hints.ai_flags |= AI_NUMERICSERV;

   if (getaddrinfo_retro(server, port_buf, &amp;hints, addrinfo))
      return -1;

   addr = *addrinfo;
   if (!addr)
      return -1;

   return socket(addr-&gt;ai_family, addr-&gt;ai_socktype, addr-&gt;ai_protocol);
}

int socket_next(void **address)
{
   struct addrinfo **addrinfo = (struct addrinfo**)address;
   struct addrinfo *addr      = *addrinfo;

   if ((*addrinfo = addr = addr-&gt;ai_next))
      return socket(addr-&gt;ai_family, addr-&gt;ai_socktype, addr-&gt;ai_protocol);

   return -1;
}

ssize_t socket_receive_all_nonblocking(int fd, bool *err,
      void *data_, size_t len)
{
   ssize_t ret = recv(fd, (char*)data_, len, 0);
   if (ret &gt; 0)
      return ret;
   if (ret &lt; 0 &amp;&amp; isagain((int)ret))
      return 0;
   *err = true;
   return -1;
}

bool socket_receive_all_blocking(int fd, void *data_, size_t len)
{
   const uint8_t *data = (const uint8_t*)data_;

   while (len)
   {
      ssize_t ret = recv(fd, (char*)data, len, 0);

      if (!ret)
         return false;

      if (ret &lt; 0)
      {
         if (!isagain((int)ret))
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

bool socket_receive_all_blocking_with_timeout(int fd,
      void *data_, size_t len, int timeout)
{
   const uint8_t *data    = (const uint8_t*)data_;
   retro_time_t  deadline = cpu_features_get_time_usec();

   if (timeout &gt; 0)
      deadline += (retro_time_t)timeout * 1000;
   else
      deadline += 5000000;

   while (len)
   {
      ssize_t ret = recv(fd, (char*)data, len, 0);

      if (!ret)
         return false;

      if (ret &lt; 0)
      {
         int _timeout;
         bool ready = true;

         if (!isagain((int)ret))
            return false;

         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);
         if (_timeout &lt;= 0)
            return false;

         if (!socket_wait(fd, &amp;ready, NULL, _timeout) || !ready)
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

bool socket_set_block(int fd, bool block)
{
#if defined(_WIN32)
   u_long i = !block;

   return !ioctlsocket(fd, FIONBIO, &amp;i);
#elif defined(__PS3__) || defined(VITA) || defined(WIIU)
   int i = !block;

   return !setsockopt(fd, SOL_SOCKET, SO_NBIO, &amp;i, sizeof(i));
#elif defined(GEKKO)
   u32 i = !block;

   return !net_ioctl(fd, FIONBIO, &amp;i);
#else
   int flags = fcntl(fd, F_GETFL);

   if (block)
      flags &amp;= ~O_NONBLOCK;
   else
      flags |= O_NONBLOCK;

   return !fcntl(fd, F_SETFL, flags);
#endif
}

bool socket_nonblock(int fd)
{
   return socket_set_block(fd, false);
}

int socket_close(int fd)
{
#if defined(_WIN32) &amp;&amp; !defined(_XBOX360)
   /* WinSock has headers from the stone age. */
   return closesocket(fd);
#elif defined(__PS3__) || defined(WIIU)
   return socketclose(fd);
#elif defined(VITA)
   return sceNetSocketClose(fd);
#else
   return close(fd);
#endif
}

int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
      fd_set *err_fds, struct timeval *timeout)
{
#if defined(__PS3__)
   return socketselect(nfds, readfds, writefds, err_fds, timeout);
#elif defined(VITA)
   int i, j;
   fd_set rfds, wfds, efds;
   int epoll_fd;
   SceNetEpollEvent *events     = NULL;
   int              event_count = 0;
   int              timeout_us  = -1;
   int              ret         = -1;

   if (nfds &lt; 0 || nfds &gt; 1024)
      return SCE_NET_ERROR_EINVAL;
   if (timeout &amp;&amp; (timeout-&gt;tv_sec &lt; 0 || timeout-&gt;tv_usec &lt; 0))
      return SCE_NET_ERROR_EINVAL;

   epoll_fd = sceNetEpollCreate("socket_select", 0);
   if (epoll_fd &lt; 0)
      return SCE_NET_ERROR_ENOMEM;

   FD_ZERO(&amp;rfds);
   FD_ZERO(&amp;wfds);
   FD_ZERO(&amp;efds);

   for (i = 0; i &lt; nfds; i++)
   {
      if (readfds &amp;&amp; FD_ISSET(i, readfds))
         event_count++;
      else if (writefds &amp;&amp; FD_ISSET(i, writefds))
         event_count++;
      else if (err_fds &amp;&amp; FD_ISSET(i, err_fds))
         event_count++;
   }

#define ALLOC_EVENTS(count) \
   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
   if (!events) \
   { \
      ret = SCE_NET_ERROR_ENOMEM; \
      goto done; \
   }

   if (event_count)
   {
      ALLOC_EVENTS(event_count)

      for (i = 0, j = 0; i &lt; nfds &amp;&amp; j &lt; event_count; i++)
      {
         SceNetEpollEvent *event = &amp;events[j];

         if (readfds &amp;&amp; FD_ISSET(i, readfds))
            event-&gt;events |= SCE_NET_EPOLLIN;
         if (writefds &amp;&amp; FD_ISSET(i, writefds))
            event-&gt;events |= SCE_NET_EPOLLOUT;

         if (event-&gt;events || (err_fds &amp;&amp; FD_ISSET(i, err_fds)))
         {
            event-&gt;data.fd = i;

            ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
               i, event);
            if (ret &lt; 0)
            {
               switch (ret)
               {
                  case SCE_NET_ERROR_EBADF:
                  case SCE_NET_ERROR_ENOMEM:
                     break;
                  default:
                     ret = SCE_NET_ERROR_EBADF;
                     break;
               }
               goto done;
            }

            j++;
         }
      }

      memset(events, 0, event_count * sizeof(*events));

      /* Keep a copy of the original sets for lookup later. */
      if (readfds)
         memcpy(&amp;rfds, readfds, sizeof(rfds));
      if (writefds)
         memcpy(&amp;wfds, writefds, sizeof(wfds));
      if (err_fds)
         memcpy(&amp;efds, err_fds, sizeof(efds));
   }
   else
   {
      /* Necessary to work with epoll wait. */
      event_count = 1;
      ALLOC_EVENTS(1)
   }

#undef ALLOC_EVENTS

   if (readfds)
      FD_ZERO(readfds);
   if (writefds)
      FD_ZERO(writefds);
   if (err_fds)
      FD_ZERO(err_fds);

   /* Vita's epoll takes a microsecond timeout parameter. */
   if (timeout)
      timeout_us = (int)(timeout-&gt;tv_usec + (timeout-&gt;tv_sec * 1000000));

   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout_us);
   if (ret &lt;= 0)
      goto done;

#define EPOLL_FD_SET(op, in_set, out_set) \
   if ((event-&gt;events &amp; (op)) &amp;&amp; FD_ISSET(event-&gt;data.fd, (in_set))) \
   { \
      FD_SET(event-&gt;data.fd, (out_set)); \
      j++; \
   }

   for (i = 0, j = 0; i &lt; ret; i++)
   {
      SceNetEpollEvent *event = &amp;events[i];

      /* Sanity check */
      if (event-&gt;data.fd &lt; 0 || event-&gt;data.fd &gt;= nfds)
         continue;

      EPOLL_FD_SET(SCE_NET_EPOLLIN,  &amp;rfds, readfds)
      EPOLL_FD_SET(SCE_NET_EPOLLOUT, &amp;wfds, writefds)
      EPOLL_FD_SET(SCE_NET_EPOLLERR, &amp;efds, err_fds)
   }

   ret = j;

#undef EPOLL_FD_SET

done:
   free(events);
   sceNetEpollDestroy(epoll_fd);

   return ret;
#else
   return select(nfds, readfds, writefds, err_fds, timeout);
#endif
}

#ifdef NETWORK_HAVE_POLL
int socket_poll(struct pollfd *fds, unsigned nfds, int timeout)
{
#if defined(_WIN32)
   return WSAPoll(fds, nfds, timeout);
#elif defined(VITA)
   int i, j;
   int epoll_fd;
   SceNetEpollEvent *events     = NULL;
   int              event_count = (int)nfds;
   int              ret         = -1;

   if (event_count &lt; 0)
      return SCE_NET_ERROR_EINVAL;

   epoll_fd = sceNetEpollCreate("socket_poll", 0);
   if (epoll_fd &lt; 0)
      return SCE_NET_ERROR_ENOMEM;

#define ALLOC_EVENTS(count) \
   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
   if (!events) \
   { \
      ret = SCE_NET_ERROR_ENOMEM; \
      goto done; \
   }

   if (event_count)
   {
      ALLOC_EVENTS(event_count)

      for (i = 0; i &lt; event_count; i++)
      {
         struct pollfd    *fd    = &amp;fds[i];
         SceNetEpollEvent *event = &amp;events[i];

         fd-&gt;revents = 0;

         if (fd-&gt;fd &lt; 0)
            continue;

         event-&gt;events  = fd-&gt;events;
         event-&gt;data.fd = fd-&gt;fd;

         ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
            fd-&gt;fd, event);
         if (ret &lt; 0)
            goto done;
      }

      memset(events, 0, event_count * sizeof(*events));
   }
   else
   {
      /* Necessary to work with epoll wait. */
      event_count = 1;
      ALLOC_EVENTS(1)
   }

#undef ALLOC_EVENTS

   /* Vita's epoll takes a microsecond timeout parameter. */
   if (timeout &gt; 0)
      timeout *= 1000;

   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout);
   if (ret &lt;= 0)
      goto done;

   for (i = 0, j = 0; i &lt; ret; i++)
   {
      unsigned k;
      SceNetEpollEvent *event = &amp;events[i];

      /* Sanity check */
      if (event-&gt;data.fd &lt; 0)
         continue;

      for (k = 0; k &lt; nfds; k++)
      {
         struct pollfd *fd = &amp;fds[k];

         if (fd-&gt;fd == event-&gt;data.fd)
         {
            fd-&gt;revents = event-&gt;events;
            j++;
            break;
         }
      }
   }

   ret = j;

done:
   free(events);
   sceNetEpollDestroy(epoll_fd);

   return ret;
#elif defined(_3DS)
   int i;
   int timeout_quotient;
   int timeout_remainder;
   int ret = -1;

#define TIMEOUT_DIVISOR 100
   if (timeout &lt;= TIMEOUT_DIVISOR)
      return poll(fds, nfds, timeout);

   timeout_quotient = timeout / TIMEOUT_DIVISOR;
   for (i = 0; i &lt; timeout_quotient; i++)
   {
      ret = poll(fds, nfds, TIMEOUT_DIVISOR);
      /* Success or error. */
      if (ret)
         return ret;
   }

   timeout_remainder = timeout % TIMEOUT_DIVISOR;
   if (timeout_remainder)
      ret = poll(fds, nfds, timeout_remainder);

   return ret;
#undef TIMEOUT_DIVISOR

#elif defined(GEKKO)
   return net_poll(fds, nfds, timeout);
#else
   return poll(fds, nfds, timeout);
#endif
}
#endif

bool socket_wait(int fd, bool *rd, bool *wr, int timeout)
{
#ifdef NETWORK_HAVE_POLL
   struct pollfd fds = {0};

   NET_POLL_FD(fd, &amp;fds);

   if (rd &amp;&amp; *rd)
   {
      NET_POLL_EVENT(POLLIN, &amp;fds);
      *rd = false;
   }
   if (wr &amp;&amp; *wr)
   {
      NET_POLL_EVENT(POLLOUT, &amp;fds);
      *wr = false;
   }

   if (socket_poll(&amp;fds, 1, timeout) &lt; 0)
      return false;

   if (rd &amp;&amp; NET_POLL_HAS_EVENT(POLLIN, &amp;fds))
      *rd = true;
   if (wr &amp;&amp; NET_POLL_HAS_EVENT(POLLOUT, &amp;fds))
      *wr = true;

   return !NET_POLL_HAS_EVENT((POLLERR | POLLNVAL), &amp;fds);
#else
   fd_set rfd, wfd, efd;
   struct timeval tv, *ptv = NULL;

   FD_ZERO(&amp;rfd);
   FD_ZERO(&amp;wfd);
   FD_ZERO(&amp;efd);

   if (rd &amp;&amp; *rd)
   {
      FD_SET(fd, &amp;rfd);
      *rd = false;
   }
   if (wr &amp;&amp; *wr)
   {
      FD_SET(fd, &amp;wfd);
      *wr = false;
   }
   FD_SET(fd, &amp;efd);

   if (timeout &gt;= 0)
   {
      tv.tv_sec  = (unsigned)timeout / 1000;
      tv.tv_usec = ((unsigned)timeout % 1000) * 1000;
      ptv = &amp;tv;
   }

   if (socket_select(fd + 1, &amp;rfd, &amp;wfd, &amp;efd, ptv) &lt; 0)
      return false;

   if (rd &amp;&amp; FD_ISSET(fd, &amp;rfd))
      *rd = true;
   if (wr &amp;&amp; FD_ISSET(fd, &amp;wfd))
      *wr = true;

   return !FD_ISSET(fd, &amp;efd);
#endif
}

bool socket_send_all_blocking(int fd, const void *data_, size_t len,
      bool no_signal)
{
   const uint8_t *data = (const uint8_t*)data_;
   int           flags = no_signal ? MSG_NOSIGNAL : 0;

   while (len)
   {
      ssize_t ret = send(fd, (const char*)data, len, flags);

      if (!ret)
         continue;

      if (ret &lt; 0)
      {
         if (!isagain((int)ret))
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

bool socket_send_all_blocking_with_timeout(int fd,
      const void *data_, size_t len,
      int timeout, bool no_signal)
{
   const uint8_t *data    = (const uint8_t*)data_;
   int           flags    = no_signal ? MSG_NOSIGNAL : 0;
   retro_time_t  deadline = cpu_features_get_time_usec();

   if (timeout &gt; 0)
      deadline += (retro_time_t)timeout * 1000;
   else
      deadline += 5000000;

   while (len)
   {
      ssize_t ret = send(fd, (const char*)data, len, flags);

      if (!ret)
         continue;

      if (ret &lt; 0)
      {
         int _timeout;
         bool ready = true;

         if (!isagain((int)ret))
            return false;

         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);
         if (_timeout &lt;= 0)
            return false;

         if (!socket_wait(fd, NULL, &amp;ready, _timeout) || !ready)
            return false;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return true;
}

ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t len,
      bool no_signal)
{
   const uint8_t *data = (const uint8_t*)data_;
   int           flags = no_signal ? MSG_NOSIGNAL : 0;

   while (len)
   {
      ssize_t ret = send(fd, (const char*)data, len, flags);

      if (!ret)
         break;

      if (ret &lt; 0)
      {
         if (isagain((int)ret))
            break;

         return -1;
      }
      else
      {
         data += ret;
         len  -= ret;
      }
   }

   return (ssize_t)((size_t)data - (size_t)data_);
}

bool socket_bind(int fd, void *data)
{
   struct addrinfo *addr = (struct addrinfo*)data;

   {
      int on = 1;

      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
         (char*)&amp;on, sizeof(on));
   }

   return !bind(fd, addr-&gt;ai_addr, addr-&gt;ai_addrlen);
}

int socket_connect(int fd, void *data)
{
   struct addrinfo *addr = (struct addrinfo*)data;

#ifdef WIIU
   {
      int op = 1;

      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &amp;op, sizeof(op));

      if (addr-&gt;ai_socktype == SOCK_STREAM)
      {
         int recvsz = WIIU_RCVBUF;
         int sendsz = WIIU_SNDBUF;

         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &amp;op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &amp;op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &amp;recvsz, sizeof(recvsz));
         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &amp;sendsz, sizeof(sendsz));
      }
   }
#endif

   return connect(fd, addr-&gt;ai_addr, addr-&gt;ai_addrlen);
}

bool socket_connect_with_timeout(int fd, void *data, int timeout)
{
   int res;
   struct addrinfo *addr = (struct addrinfo*)data;

   if (!socket_nonblock(fd))
      return false;

#ifdef WIIU
   {
      int op = 1;

      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &amp;op, sizeof(op));

      if (addr-&gt;ai_socktype == SOCK_STREAM)
      {
         int recvsz = WIIU_RCVBUF;
         int sendsz = WIIU_SNDBUF;

         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &amp;op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &amp;op, sizeof(op));
         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &amp;recvsz, sizeof(recvsz));
         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &amp;sendsz, sizeof(sendsz));
      }
   }
#endif

   res = connect(fd, addr-&gt;ai_addr, addr-&gt;ai_addrlen);
   if (res)
   {
      bool ready = true;

      if (!isinprogress(res) &amp;&amp; !isagain(res))
         return false;

      if (timeout &lt;= 0)
         timeout = 5000;

      if (!socket_wait(fd, NULL, &amp;ready, timeout) || !ready)
         return false;
   }

#if defined(GEKKO)
   /* libogc does not have getsockopt implemented */
   res = connect(fd, addr-&gt;ai_addr, addr-&gt;ai_addrlen);
   if (res &lt; 0 &amp;&amp; -res != EISCONN)
      return false;
#elif defined(_3DS)
   /* libctru getsockopt does not return expected value */
   if ((connect(fd, addr-&gt;ai_addr, addr-&gt;ai_addrlen) &lt; 0) &amp;&amp; errno != EISCONN)
      return false;
#elif defined(WIIU)
   /* On WiiU, getsockopt() returns -1 and sets lastsocketerr() (Wii's
    * equivalent to errno) to 16. */
   if ((connect(fd, addr-&gt;ai_addr, addr-&gt;ai_addrlen) == -1)
         &amp;&amp; socketlasterr() != SO_EISCONN)
      return false;
#else
   {
      int       err = -1;
      socklen_t errsz = sizeof(err);

      getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&amp;err, &amp;errsz);
      if (err)
         return false;
   }
#endif

   return true;
}

int socket_create(
      const char *name,
      enum socket_domain   domain_type,
      enum socket_type     socket_type,
      enum socket_protocol protocol_type)
{
   int domain   = 0;
   int type     = 0;
   int protocol = 0;

   switch (domain_type)
   {
      case SOCKET_DOMAIN_INET:
         domain = AF_INET;
         break;
      default:
         break;
   }

   switch (socket_type)
   {
      case SOCKET_TYPE_DATAGRAM:
         type = SOCK_DGRAM;
         break;
      case SOCKET_TYPE_STREAM:
         type = SOCK_STREAM;
         break;
      case SOCKET_TYPE_SEQPACKET:
      default:
         /* TODO/FIXME - implement */
         break;
   }

   switch (protocol_type)
   {
      case SOCKET_PROTOCOL_TCP:
         protocol = IPPROTO_TCP;
         break;
      case SOCKET_PROTOCOL_UDP:
         protocol = IPPROTO_UDP;
         break;
      case SOCKET_PROTOCOL_NONE:
      default:
         break;
   }

#ifdef VITA
   return sceNetSocket(name, domain, type, protocol);
#else
   return socket(domain, type, protocol);
#endif
}

void socket_set_target(void *data, socket_target_t *in_addr)
{
   struct sockaddr_in *out_target = (struct sockaddr_in*)data;

#ifdef GEKKO
   out_target-&gt;sin_len          = 8;
#endif
   switch (in_addr-&gt;domain)
   {
      case SOCKET_DOMAIN_INET:
         out_target-&gt;sin_family = AF_INET;
         break;
      default:
         out_target-&gt;sin_family = 0;
         break;
   }
   out_target-&gt;sin_port         = htons(in_addr-&gt;port);
   inet_pton(AF_INET, in_addr-&gt;server, &amp;out_target-&gt;sin_addr);
}</pre>
<h2>./include/libretro-common/net/net_socket_ssl_bear.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;net/net_socket_ssl.h&gt;
#include &lt;net/net_socket.h&gt;
#include &lt;encodings/base64.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;string/stdstring.h&gt;

#include "../../deps/bearssl-0.6/inc/bearssl.h"

struct ssl_state
{
   int fd;
   br_ssl_client_context sc;
   br_x509_minimal_context xc;
   uint8_t iobuf[BR_SSL_BUFSIZE_BIDI];
};

/* TODO/FIXME - static global variables */
static br_x509_trust_anchor TAs[500] = {};
static size_t TAs_NUM = 0;

static uint8_t* current_vdn;
static size_t current_vdn_size;

static uint8_t* blobdup(const void * src, size_t len)
{
   uint8_t *ret = (uint8_t*)malloc(len);
   memcpy(ret, src, len);
   return ret;
}
static void vdn_append(void* dest_ctx, const void * src, size_t len)
{
   current_vdn = (uint8_t*)realloc(current_vdn, current_vdn_size + len);
   memcpy(current_vdn + current_vdn_size, src, len);
   current_vdn_size += len;
}

static bool append_cert_x509(void* x509, size_t len)
{
   br_x509_pkey* pk;
   br_x509_decoder_context dc;
   br_x509_trust_anchor* ta = &amp;TAs[TAs_NUM];

   current_vdn              = NULL;
   current_vdn_size         = 0;

   br_x509_decoder_init(&amp;dc, vdn_append, NULL);
   br_x509_decoder_push(&amp;dc, x509, len);
   pk                       = br_x509_decoder_get_pkey(&amp;dc);
   if (!pk || !br_x509_decoder_isCA(&amp;dc))
      return false;

   ta-&gt;dn.len               = current_vdn_size;
   ta-&gt;dn.data              = current_vdn;
   ta-&gt;flags                = BR_X509_TA_CA;

   switch (pk-&gt;key_type)
   {
      case BR_KEYTYPE_RSA:
         ta-&gt;pkey.key_type     = BR_KEYTYPE_RSA;
         ta-&gt;pkey.key.rsa.nlen = pk-&gt;key.rsa.nlen;
         ta-&gt;pkey.key.rsa.n    = blobdup(pk-&gt;key.rsa.n, pk-&gt;key.rsa.nlen);
         ta-&gt;pkey.key.rsa.elen = pk-&gt;key.rsa.elen;
         ta-&gt;pkey.key.rsa.e    = blobdup(pk-&gt;key.rsa.e, pk-&gt;key.rsa.elen);
         break;
      case BR_KEYTYPE_EC:
         ta-&gt;pkey.key_type     = BR_KEYTYPE_EC;
         ta-&gt;pkey.key.ec.curve = pk-&gt;key.ec.curve;
         ta-&gt;pkey.key.ec.qlen  = pk-&gt;key.ec.qlen;
         ta-&gt;pkey.key.ec.q     = blobdup(pk-&gt;key.ec.q, pk-&gt;key.ec.qlen);
         break;
      default:
         return false;
   }

   TAs_NUM++;
   return true;
}

static char* delete_linebreaks(char* in)
{
   char* iter_in;
   char* iter_out;
   while (*in == '\n')
      in++;

   iter_in = in;

   while (*iter_in != '\n' &amp;&amp; *iter_in != '\0')
      iter_in++;
   iter_out = iter_in;
   while (*iter_in != '\0')
   {
      while (*iter_in == '\n')
         iter_in++;
      *iter_out++ = *iter_in++;
   }

   return in;
}

/* this rearranges its input, it's easier to implement
 * that way and caller doesn't need it anymore anyways */
static void append_certs_pem_x509(char * certs_pem)
{
   void * cert_bin;
   int cert_bin_len;
   char *cert     = certs_pem;
   char *cert_end = certs_pem;

   for (;;)
   {
      cert      = strstr(cert_end, "-----BEGIN CERTIFICATE-----");
      if (!cert)
         break;
      cert     += STRLEN_CONST("-----BEGIN CERTIFICATE-----");
      cert_end  = strstr(cert, "-----END CERTIFICATE-----");

      *cert_end = '\0';
      cert      = delete_linebreaks(cert);

      cert_bin  = unbase64(cert, cert_end-cert, &amp;cert_bin_len);
      append_cert_x509(cert_bin, cert_bin_len);
      free(cert_bin);

      cert_end++; /* skip the NUL we just added */
   }
}

/* TODO: not thread safe, rthreads doesn't provide any
 * statically allocatable mutex/etc */
static void initialize(void)
{
   void* certs_pem;
   if (TAs_NUM)
      return;
   /* filestream_read_file appends a NUL */
   filestream_read_file("/etc/ssl/certs/ca-certificates.crt", &amp;certs_pem, NULL);
   append_certs_pem_x509((char*)certs_pem);
   free(certs_pem);
}

void* ssl_socket_init(int fd, const char *domain)
{
   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));

   initialize();

   br_ssl_client_init_full(&amp;state-&gt;sc, &amp;state-&gt;xc, TAs, TAs_NUM);
   br_ssl_engine_set_buffer(&amp;state-&gt;sc.eng,
         state-&gt;iobuf, sizeof(state-&gt;iobuf), true);
   br_ssl_client_reset(&amp;state-&gt;sc, domain, false);

   state-&gt;fd = fd;
   return state;
}

static bool process_inner(struct ssl_state *state, bool blocking)
{
   bool dummy;
   size_t buflen;
   ssize_t bytes;
   uint8_t *buf = br_ssl_engine_sendrec_buf(&amp;state-&gt;sc.eng, &amp;buflen);

   if (buflen)
   {
      if (blocking)
         bytes = (socket_send_all_blocking(state-&gt;fd, buf, buflen, true)
               ? buflen
               : -1);
      else
         bytes = socket_send_all_nonblocking(state-&gt;fd, buf, buflen, true);

      if (bytes &gt; 0)
         br_ssl_engine_sendrec_ack(&amp;state-&gt;sc.eng, bytes);
      if (bytes &lt; 0)
         return false;
      /* if we did something, return immediately so we
       * don't try to read if Bear still wants to send */
      return true;
   }

   buf = br_ssl_engine_recvrec_buf(&amp;state-&gt;sc.eng, &amp;buflen);
   if (buflen)
   {
      /* if the socket is blocking, socket_receive_all_nonblocking blocks,
       * but only to read at least 1 byte which is exactly what we want */
      bytes = socket_receive_all_nonblocking(state-&gt;fd, &amp;dummy, buf, buflen);
      if (bytes &gt; 0)
         br_ssl_engine_recvrec_ack(&amp;state-&gt;sc.eng, bytes);
      if (bytes &lt; 0)
         return false;
   }

   return true;
}

int ssl_socket_connect(void *state_data,
      void *data, bool timeout_enable, bool nonblock)
{
   struct ssl_state *state = (struct ssl_state*)state_data;
   unsigned bearstate;

   if (timeout_enable)
   {
      if (!socket_connect_with_timeout(state-&gt;fd, data, 5000))
         return -1;
      /* socket_connect_with_timeout makes the socket non-blocking. */
      if (!socket_set_block(state-&gt;fd, true))
         return -1;
   }
   else
   {
      if (socket_connect(state-&gt;fd, data))
         return -1;
   }

   for (;;)
   {
      if (!process_inner(state, true))
         return -1;

      bearstate = br_ssl_engine_current_state(&amp;state-&gt;sc.eng);
      if (bearstate &amp; BR_SSL_SENDAPP)
         break; /* handshake done */
      if (bearstate &amp; BR_SSL_CLOSED)
         return -1; /* failed */
   }

   return 1;
}

ssize_t ssl_socket_receive_all_nonblocking(void *state_data,
      bool *err, void *data_, size_t len)
{
   size_t __len;
   uint8_t *bear_data;
   struct ssl_state *state = (struct ssl_state*)state_data;
   socket_set_block(state-&gt;fd, false);
   if (!process_inner(state, false))
   {
      *err = true;
      return -1;
   }
   bear_data = br_ssl_engine_recvapp_buf(&amp;state-&gt;sc.eng, &amp;__len);
   if (__len &gt; len)
      __len = len;
   memcpy(data_, bear_data, __len);
   if (__len)
      br_ssl_engine_recvapp_ack(&amp;state-&gt;sc.eng, __len);
   return __len;
}

int ssl_socket_receive_all_blocking(void *state_data,
      void *data_, size_t len)
{
   size_t __len;
   struct ssl_state *state = (struct ssl_state*)state_data;
   uint8_t           *data = (uint8_t*)data_;
   uint8_t *         bear_data;

   socket_set_block(state-&gt;fd, true);

   for (;;)
   {
      bear_data = br_ssl_engine_recvapp_buf(&amp;state-&gt;sc.eng, &amp;__len);
      if (__len &gt; len)
         __len = len;
      memcpy(data, bear_data, __len);
      if (__len)
         br_ssl_engine_recvapp_ack(&amp;state-&gt;sc.eng, __len);
      data += __len;
      len -= __len;

      if (len)
         process_inner(state, true);
      else
         break;
   }
   return 1;
}

int ssl_socket_send_all_blocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   size_t __len;
   struct ssl_state *state = (struct ssl_state*)state_data;
   const     uint8_t *data = (const uint8_t*)data_;
   uint8_t *         bear_data;

   socket_set_block(state-&gt;fd, true);

   for (;;)
   {
      bear_data = br_ssl_engine_sendapp_buf(&amp;state-&gt;sc.eng, &amp;__len);
      if (__len &gt; len)
         __len = len;
      memcpy(bear_data, data_, __len);
      if (__len)
         br_ssl_engine_sendapp_ack(&amp;state-&gt;sc.eng, __len);
      data += __len;
      len  -= __len;

      if (len)
         process_inner(state, true);
      else
         break;
   }

   br_ssl_engine_flush(&amp;state-&gt;sc.eng, false);
   process_inner(state, false);
   return 1;
}

ssize_t ssl_socket_send_all_nonblocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   size_t __len;
   uint8_t *bear_data;
   struct ssl_state *state = (struct ssl_state*)state_data;

   socket_set_block(state-&gt;fd, false);
   bear_data = br_ssl_engine_sendapp_buf(&amp;state-&gt;sc.eng, &amp;__len);
   if (__len &gt; len)
      __len = len;
   memcpy(bear_data, data_, __len);
   if (__len)
   {
      br_ssl_engine_sendapp_ack(&amp;state-&gt;sc.eng, __len);
      br_ssl_engine_flush(&amp;state-&gt;sc.eng, false);
   }
   if (!process_inner(state, false))
      return -1;
   return __len;
}

void ssl_socket_close(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;

   br_ssl_engine_close(&amp;state-&gt;sc.eng);
   process_inner(state, false); /* send close notification */
   socket_close(state-&gt;fd);     /* but immediately close socket
                                   and don't worry about recipient
                                   getting our message */
}

void ssl_socket_free(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;
   /* BearSSL does zero allocations of its own,
    * so other than this struct, there is nothing to free */
   free(state);
}</pre>
<h2>./include/libretro-common/net/net_socket_ssl_mbed.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_socket.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;string.h&gt;
#include &lt;net/net_compat.h&gt;
#include &lt;net/net_socket.h&gt;
#include &lt;net/net_socket_ssl.h&gt;

#ifdef _3DS
#include &lt;3ds/types.h&gt;
#include &lt;3ds/services/ps.h&gt;
#endif

#if defined(HAVE_BUILTINMBEDTLS)
#include "../../deps/mbedtls/mbedtls/config.h"
#include "../../deps/mbedtls/mbedtls/certs.h"
#include "../../deps/mbedtls/mbedtls/debug.h"
#include "../../deps/mbedtls/mbedtls/platform.h"
#include "../../deps/mbedtls/mbedtls/net_sockets.h"
#include "../../deps/mbedtls/mbedtls/ssl.h"
#include "../../deps/mbedtls/mbedtls/ctr_drbg.h"
#include "../../deps/mbedtls/mbedtls/entropy.h"
#else
#include &lt;mbedtls/version.h&gt;
#if MBEDTLS_VERSION_MAJOR &lt; 3
#include &lt;mbedtls/config.h&gt;
#include &lt;mbedtls/certs.h&gt;
#else
#include &lt;mbedtls/build_info.h&gt;
#endif
#include &lt;mbedtls/debug.h&gt;
#include &lt;mbedtls/platform.h&gt;
#include &lt;mbedtls/net_sockets.h&gt;
#include &lt;mbedtls/ssl.h&gt;
#include &lt;mbedtls/ctr_drbg.h&gt;
#include &lt;mbedtls/entropy.h&gt;
#endif

/* Not part of the mbedtls upstream source */
#include "cacert.h"

#define DEBUG_LEVEL 0

struct ssl_state
{
   mbedtls_net_context net_ctx;
   mbedtls_ssl_context ctx;
   mbedtls_entropy_context entropy;
   mbedtls_ctr_drbg_context ctr_drbg;
   mbedtls_ssl_config conf;
#if defined(MBEDTLS_X509_CRT_PARSE_C)
   mbedtls_x509_crt ca;
#endif
  const char *domain;
};

static void ssl_debug(void *ctx, int level,
      const char *file, int line,
      const char *str)
{
   fprintf((FILE*)ctx, "%s:%04d: %s", file, line, str);
   fflush((FILE*)ctx);
}

#ifdef _3DS
int ctr_entropy_func(void *data, unsigned char *s, size_t len)
{
   (void)data;
   PS_GenerateRandomBytes(s, len);
   return 0;
}
#endif

void* ssl_socket_init(int fd, const char *domain)
{
   static const char *pers = "libretro";
   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));

   state-&gt;domain           = domain;

#if defined(MBEDTLS_DEBUG_C)
   mbedtls_debug_set_threshold(DEBUG_LEVEL);
#endif

   mbedtls_net_init(&amp;state-&gt;net_ctx);
   mbedtls_ssl_init(&amp;state-&gt;ctx);
   mbedtls_ssl_config_init(&amp;state-&gt;conf);
#if defined(MBEDTLS_X509_CRT_PARSE_C)
   mbedtls_x509_crt_init(&amp;state-&gt;ca);
#endif
   mbedtls_ctr_drbg_init(&amp;state-&gt;ctr_drbg);
   mbedtls_entropy_init(&amp;state-&gt;entropy);

   state-&gt;net_ctx.fd = fd;

   if (mbedtls_ctr_drbg_seed(&amp;state-&gt;ctr_drbg,
#ifdef _3DS
      ctr_entropy_func,
#else
      mbedtls_entropy_func,
#endif
      &amp;state-&gt;entropy, (const unsigned char*)pers, strlen(pers)) != 0)
      goto error;

#if defined(MBEDTLS_X509_CRT_PARSE_C)
   if (mbedtls_x509_crt_parse(&amp;state-&gt;ca, (const unsigned char*)cacert_pem, sizeof(cacert_pem) / sizeof(cacert_pem[0])) &lt; 0)
      goto error;
#endif

   return state;

error:
   if (state)
      free(state);
   return NULL;
}

int ssl_socket_connect(void *state_data,
      void *data, bool timeout_enable, bool nonblock)
{
   int ret, flags;
   struct ssl_state *state = (struct ssl_state*)state_data;

   if (timeout_enable)
   {
      if (!socket_connect_with_timeout(state-&gt;net_ctx.fd, data, 5000))
         return -1;
      /* socket_connect_with_timeout makes the socket non-blocking. */
      if (!socket_set_block(state-&gt;net_ctx.fd, true))
         return -1;
   }
   else
   {
      if (socket_connect(state-&gt;net_ctx.fd, data))
         return -1;
   }

   if (mbedtls_ssl_config_defaults(&amp;state-&gt;conf,
               MBEDTLS_SSL_IS_CLIENT,
               MBEDTLS_SSL_TRANSPORT_STREAM,
               MBEDTLS_SSL_PRESET_DEFAULT) != 0)
      return -1;

   mbedtls_ssl_conf_authmode(&amp;state-&gt;conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
   mbedtls_ssl_conf_ca_chain(&amp;state-&gt;conf, &amp;state-&gt;ca, NULL);
   mbedtls_ssl_conf_rng(&amp;state-&gt;conf, mbedtls_ctr_drbg_random, &amp;state-&gt;ctr_drbg);
   mbedtls_ssl_conf_dbg(&amp;state-&gt;conf, ssl_debug, stderr);

   if (mbedtls_ssl_setup(&amp;state-&gt;ctx, &amp;state-&gt;conf) != 0)
      return -1;

#if defined(MBEDTLS_X509_CRT_PARSE_C)
   if (mbedtls_ssl_set_hostname(&amp;state-&gt;ctx, state-&gt;domain) != 0)
      return -1;
#endif

   mbedtls_ssl_set_bio(&amp;state-&gt;ctx, &amp;state-&gt;net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL);

   while ((ret = mbedtls_ssl_handshake(&amp;state-&gt;ctx)) != 0)
   {
      if (ret != MBEDTLS_ERR_SSL_WANT_READ &amp;&amp; ret != MBEDTLS_ERR_SSL_WANT_WRITE)
         return -1;
   }

   if ((flags = mbedtls_ssl_get_verify_result(&amp;state-&gt;ctx)) != 0)
   {
      char vrfy_buf[512];
      mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
   }

   return state-&gt;net_ctx.fd;
}

ssize_t ssl_socket_receive_all_nonblocking(void *state_data,
      bool *err, void *data_, size_t len)
{
   ssize_t ret;
   struct ssl_state *state = (struct ssl_state*)state_data;
   unsigned char     *data = (unsigned char*)data_;
   size_t       total_read = 0;
   int      max_iterations = 8;  /* Limit iterations to prevent infinite loops */

   mbedtls_net_set_nonblock(&amp;state-&gt;net_ctx);

   /* Keep reading while we get data without blocking, up to max iterations
    * This allows us to read multiple TLS records (16KB each) in one call */
   while (len &gt; 0 &amp;&amp; max_iterations-- &gt; 0)
   {
      ret = mbedtls_ssl_read(&amp;state-&gt;ctx, data, len);

      if (ret &gt; 0)
      {
         total_read += ret;
         data += ret;
         len -= ret;

         /* If we read less than requested, there's likely no more data available
          * But check if there's buffered data we can read without blocking */
         if ((size_t)ret &lt; len)
         {
            size_t bytes_avail = mbedtls_ssl_get_bytes_avail(&amp;state-&gt;ctx);
            if (bytes_avail == 0)

               break;  /* No more buffered data, don't risk blocking */
         }
         /* Continue looping to read more records */
      }
      else if (ret == 0)
      {
         /* Socket closed */
         if (total_read &gt; 0)
            return total_read;  /* Return what we got before close */
         *err = true;
         return -1;
      }
      else if (isagain((int)ret) || ret == MBEDTLS_ERR_SSL_WANT_READ)
      {
         /* Would block - return what we have so far */
         if (total_read &gt; 0)
            return total_read;
         return 0;  /* No data available yet */
      }
      else
      {
         /* Error */
         if (total_read &gt; 0)
            return total_read;  /* Return what we got before error */
         *err = true;
         return -1;
      }
   }

   return total_read;
}

int ssl_socket_receive_all_blocking(void *state_data,
      void *data_, size_t len)
{
   struct ssl_state *state = (struct ssl_state*)state_data;
   const uint8_t     *data = (const uint8_t*)data_;

   mbedtls_net_set_block(&amp;state-&gt;net_ctx);

   for (;;)
   {
      /* mbedtls_ssl_read wants non-const data but it only reads it,
       * so this cast is safe */
      int ret = mbedtls_ssl_read(&amp;state-&gt;ctx, (unsigned char*)data, len);

      if (     ret == MBEDTLS_ERR_SSL_WANT_READ
            || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
         continue;

      if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
         break;

      if (ret == 0)
         break; /* normal EOF */

      if (ret &lt; 0)
         return -1;
   }

   return 1;
}

int ssl_socket_send_all_blocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   int ret;
   struct ssl_state *state = (struct ssl_state*)state_data;
   const     uint8_t *data = (const uint8_t*)data_;

   mbedtls_net_set_block(&amp;state-&gt;net_ctx);

   while (len)
   {
      ret = mbedtls_ssl_write(&amp;state-&gt;ctx, data, len);

      if (!ret)
         continue;

      if (ret &lt; 0)
      {
         if (  ret != MBEDTLS_ERR_SSL_WANT_READ &amp;&amp;
              ret != MBEDTLS_ERR_SSL_WANT_WRITE)
            return false;
      }
      else
      {
          data += ret;
          len  -= ret;
      }
   }

   return true;
}

ssize_t ssl_socket_send_all_nonblocking(void *state_data,
      const void *data_, size_t len, bool no_signal)
{
   int ret;
   ssize_t __len = len;
   struct ssl_state *state = (struct ssl_state*)state_data;
   const uint8_t     *data = (const uint8_t*)data_;
   mbedtls_net_set_nonblock(&amp;state-&gt;net_ctx);
   ret = mbedtls_ssl_write(&amp;state-&gt;ctx, data, len);
   if (ret &lt;= 0)
      return -1;
   return __len;
}

void ssl_socket_close(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;

   mbedtls_ssl_close_notify(&amp;state-&gt;ctx);

   socket_close(state-&gt;net_ctx.fd);
}

void ssl_socket_free(void *state_data)
{
   struct ssl_state *state = (struct ssl_state*)state_data;

   if (!state)
      return;

   mbedtls_ssl_free(&amp;state-&gt;ctx);
   mbedtls_ssl_config_free(&amp;state-&gt;conf);
   mbedtls_ctr_drbg_free(&amp;state-&gt;ctr_drbg);
   mbedtls_entropy_free(&amp;state-&gt;entropy);
#if defined(MBEDTLS_X509_CRT_PARSE_C)
   mbedtls_x509_crt_free(&amp;state-&gt;ca);
#endif

   free(state);
}</pre>
<h2>./include/libretro-common/playlists/label_sanitization.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (label_sanitization.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;playlists/label_sanitization.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;string.h&gt;

#define DISC_STRINGS_LENGTH   5
#define REGION_STRINGS_LENGTH 20

const char *disc_strings[DISC_STRINGS_LENGTH] = {
   "(CD",
   "(Disc",
   "(Disk",
   "(Side",
   "(Tape"
};

/*
 * We'll use the standard No-Intro regions for now.
 */
const char *region_strings[REGION_STRINGS_LENGTH] = {
   "(Australia)", /* Don’t use with Europe */
   "(Brazil)",
   "(Canada)",    /* Don’t use with USA */
   "(China)",
   "(France)",
   "(Germany)",
   "(Hong Kong)",
   "(Italy)",
   "(Japan)",
   "(Korea)",
   "(Netherlands)",
   "(Spain)",
   "(Sweden)",
   "(USA)",       /* Includes Canada */
   "(World)",
   "(Europe)",    /* Includes Australia */
   "(Asia)",
   "(Japan, USA)",
   "(Japan, Europe)",
   "(USA, Europe)"
};

/**
 * label_sanitize:
 *
 * NOTE: Does not work with nested blocks.
 **/
void label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*))
{
   bool copy = true;
   int rindex = 0;
   int lindex = 0;
   char new_label[PATH_MAX_LENGTH];

   for (; lindex &lt; PATH_MAX_LENGTH &amp;&amp; label[lindex] != '\0'; lindex++)
   {
      if (copy)
      {
         /* check for the start of the range */
         if ((*left)(&amp;label[lindex]))
            copy                = false;
         else
         {
            const bool whitespace = label[lindex] == ' ' &amp;&amp; (rindex == 0 || new_label[rindex - 1] == ' ');

            /* Simplify consecutive whitespaces */
            if (!whitespace)
               new_label[rindex++] = label[lindex];
         }
      }
      else if ((*right)(&amp;label[lindex]))
         copy = true;
   }

   /* Trim trailing whitespace */
   if (rindex &gt; 0 &amp;&amp; new_label[rindex - 1] == ' ')
      new_label[rindex - 1] = '\0';
   else
      new_label[rindex] = '\0';

   strlcpy(label, new_label, PATH_MAX_LENGTH);
}

static bool left_parens(char *left)
{
   return left[0] == '(';
}

static bool right_parens(char *right)
{
   return right[0] == ')';
}

static bool left_brackets(char *left)
{
   return left[0] == '[';
}

static bool right_brackets(char *right)
{
   return right[0] == ']';
}

static bool left_parens_or_brackets(char *left)
{
   return left[0] == '(' || left[0] == '[';
}

static bool right_parens_or_brackets(char *right)
{
   return right[0] == ')' || right[0] == ']';
}

static bool left_exclusion(char *left,
      const char **strings, const size_t strings_count)
{
   unsigned i;
   char exclusion_string[32];
   char comparison_string[32];

   strlcpy(exclusion_string, left, sizeof(exclusion_string));
   string_to_upper(exclusion_string);

   for (i = 0; i &lt; (unsigned)strings_count; i++)
   {
      strlcpy(comparison_string, strings[i], sizeof(comparison_string));
      string_to_upper(comparison_string);

      if (string_starts_with(exclusion_string,
               comparison_string))
         return true;
   }

   return false;
}

static bool left_parens_or_brackets_excluding_region(char *left)
{
   return left_parens_or_brackets(left)
      &amp;&amp; !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH);
}

static bool left_parens_or_brackets_excluding_disc(char *left)
{
   return left_parens_or_brackets(left)
      &amp;&amp; !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
}

static bool left_parens_or_brackets_excluding_region_or_disc(char *left)
{
   return left_parens_or_brackets(left)
      &amp;&amp; !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH)
      &amp;&amp; !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
}

void label_remove_parens(char *label)
{
   label_sanitize(label, left_parens, right_parens);
}

void label_remove_brackets(char *label)
{
   label_sanitize(label, left_brackets, right_brackets);
}

void label_remove_parens_and_brackets(char *label)
{
   label_sanitize(label, left_parens_or_brackets,
         right_parens_or_brackets);
}

void label_keep_region(char *label)
{
   label_sanitize(label, left_parens_or_brackets_excluding_region,
         right_parens_or_brackets);
}

void label_keep_disc(char *label)
{
   label_sanitize(label, left_parens_or_brackets_excluding_disc,
         right_parens_or_brackets);
}

void label_keep_region_and_disc(char *label)
{
   label_sanitize(label, left_parens_or_brackets_excluding_region_or_disc,
         right_parens_or_brackets);
}</pre>
<h2>./include/libretro-common/queues/fifo_queue.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (fifo_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_common_api.h&gt;
#include &lt;retro_inline.h&gt;
#include &lt;boolean.h&gt;

#include &lt;queues/fifo_queue.h&gt;

static bool fifo_initialize_internal(fifo_buffer_t *buf, size_t len)
{
   uint8_t *buffer    = (uint8_t*)calloc(1, len + 1);

   if (!buffer)
      return false;

   buf-&gt;buffer        = buffer;
   buf-&gt;size          = len + 1;
   buf-&gt;first         = 0;
   buf-&gt;end           = 0;

   return true;
}

bool fifo_initialize(fifo_buffer_t *buf, size_t len)
{
   return (buf &amp;&amp; fifo_initialize_internal(buf, len));
}

void fifo_free(fifo_buffer_t *buffer)
{
   if (!buffer)
      return;

   free(buffer-&gt;buffer);
   free(buffer);
}

bool fifo_deinitialize(fifo_buffer_t *buffer)
{
   if (!buffer)
      return false;

   if (buffer-&gt;buffer)
      free(buffer-&gt;buffer);
   buffer-&gt;buffer = NULL;
   buffer-&gt;size   = 0;
   buffer-&gt;first  = 0;
   buffer-&gt;end    = 0;

   return true;
}

fifo_buffer_t *fifo_new(size_t len)
{
   fifo_buffer_t *buf = (fifo_buffer_t*)malloc(sizeof(*buf));

   if (!buf)
      return NULL;

   if (!fifo_initialize_internal(buf, len))
   {
      free(buf);
      return NULL;
   }

   return buf;
}

void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len)
{
   size_t first_write = len;
   size_t rest_write  = 0;

   if (buffer-&gt;end + len &gt; buffer-&gt;size)
   {
      first_write = buffer-&gt;size - buffer-&gt;end;
      rest_write  = len - first_write;
   }

   memcpy(buffer-&gt;buffer + buffer-&gt;end, in_buf, first_write);
   if (rest_write &gt; 0)
      memcpy(buffer-&gt;buffer, (const uint8_t*)in_buf + first_write, rest_write);

   buffer-&gt;end = (buffer-&gt;end + len) % buffer-&gt;size;
}

void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t len)
{
   size_t first_read = len;
   size_t rest_read  = 0;

   if (buffer-&gt;first + len &gt; buffer-&gt;size)
   {
      first_read = buffer-&gt;size - buffer-&gt;first;
      rest_read  = len - first_read;
   }

   memcpy(in_buf, (const uint8_t*)buffer-&gt;buffer + buffer-&gt;first, first_read);
   if (rest_read &gt; 0)
      memcpy((uint8_t*)in_buf + first_read, buffer-&gt;buffer, rest_read);

   buffer-&gt;first = (buffer-&gt;first + len) % buffer-&gt;size;
}</pre>
<h2>./include/libretro-common/queues/generic_queue.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (generic_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;boolean.h&gt;
#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;queues/generic_queue.h&gt;

struct generic_queue_item_t
{
   void *value;
   struct generic_queue_item_t *previous;
   struct generic_queue_item_t *next;
};

struct generic_queue
{
   struct generic_queue_item_t *first_item;
   struct generic_queue_item_t *last_item;
   size_t length;
};

struct generic_queue_iterator
{
   generic_queue_t *queue;
   struct generic_queue_item_t *item;
   bool forward;
};

generic_queue_t *generic_queue_new(void)
{
   return (generic_queue_t *)calloc(1, sizeof(generic_queue_t));
}

void generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value))
{
   struct generic_queue_item_t *next_item;

   if (!queue)
      return;

   while (queue-&gt;first_item)
   {
      if (free_value)
         free_value(queue-&gt;first_item-&gt;value);

      next_item = queue-&gt;first_item-&gt;next;
      free(queue-&gt;first_item);
      queue-&gt;first_item = next_item;
   }

   free(queue);
}

void generic_queue_push(generic_queue_t *queue, void *value)
{
   struct generic_queue_item_t *new_item;

   new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t));
   new_item-&gt;value = value;
   new_item-&gt;previous = queue-&gt;last_item;
   new_item-&gt;next = NULL;

   queue-&gt;last_item = new_item;
   queue-&gt;length++;

   if (!queue-&gt;first_item)
      queue-&gt;first_item = new_item;
   else
      new_item-&gt;previous-&gt;next = new_item;
}

void *generic_queue_pop(generic_queue_t *queue)
{
   void *value;
   struct generic_queue_item_t *item;

   if (!queue || !queue-&gt;last_item)
      return NULL;

   item = queue-&gt;last_item;
   queue-&gt;last_item = queue-&gt;last_item-&gt;previous;
   queue-&gt;length--;

   if (queue-&gt;length == 0)
      queue-&gt;first_item = NULL;

   value = item-&gt;value;
   free(item);

   return value;
}

void *generic_queue_peek(generic_queue_t *queue)
{
   if (!queue || !queue-&gt;last_item)
      return NULL;

   return queue-&gt;last_item-&gt;value;
}

void *generic_queue_peek_first(generic_queue_t *queue)
{
   if (!queue || !queue-&gt;first_item)
      return NULL;

   return queue-&gt;first_item-&gt;value;
}

void generic_queue_shift(generic_queue_t *queue, void *value)
{
   struct generic_queue_item_t *new_item;

   if (!queue)
      return;

   new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t));
   new_item-&gt;value = value;
   new_item-&gt;previous = NULL;
   new_item-&gt;next = queue-&gt;first_item;

   queue-&gt;first_item = new_item;
   queue-&gt;length++;

   if (!queue-&gt;last_item)
      queue-&gt;last_item = new_item;
   else
      new_item-&gt;next-&gt;previous = new_item;
}

void *generic_queue_unshift(generic_queue_t *queue)
{
   void *value;
   struct generic_queue_item_t *item;

   if (!queue || !queue-&gt;first_item)
      return NULL;

   item = queue-&gt;first_item;
   queue-&gt;first_item = queue-&gt;first_item-&gt;next;
   queue-&gt;length--;

   if (queue-&gt;length == 0)
      queue-&gt;last_item = NULL;

   value = item-&gt;value;
   free(item);

   return value;
}

size_t generic_queue_length(generic_queue_t *queue)
{
   if (queue)
      return queue-&gt;length;

   return 0;
}

void *generic_queue_remove(generic_queue_t *queue, void *value)
{
   struct generic_queue_item_t *item;

   if (!queue)
      return NULL;

   for (item = queue-&gt;first_item; item; item = item-&gt;next)
   {
      if (item-&gt;value == value)
      {
         if (item-&gt;previous)
            item-&gt;previous-&gt;next = item-&gt;next;
         else
            queue-&gt;first_item = item-&gt;next;

         if (item-&gt;next)
            item-&gt;next-&gt;previous = item-&gt;previous;
         else
            queue-&gt;last_item = item-&gt;previous;

         free(item);
         queue-&gt;length--;

         return value;
      }
   }

   return NULL;
}

generic_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward)
{
   if (queue &amp;&amp; queue-&gt;first_item)
   {
      generic_queue_iterator_t *iterator;

      iterator = (generic_queue_iterator_t *)malloc(sizeof(generic_queue_iterator_t));
      iterator-&gt;queue = queue;
      iterator-&gt;item = forward ? queue-&gt;first_item : queue-&gt;last_item;
      iterator-&gt;forward = forward;

      return iterator;
   }

   return NULL;
}

generic_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator)
{
   if (iterator)
   {
      struct generic_queue_item_t *item;

      item = iterator-&gt;forward ? iterator-&gt;item-&gt;next : iterator-&gt;item-&gt;previous;
      if (item)
      {
         iterator-&gt;item = item;
         return iterator;
      } else
      {
         free(iterator);
         return NULL;
      }
   }

   return NULL;
}

void *generic_queue_iterator_value(generic_queue_iterator_t *iterator)
{
   if (iterator)
      return iterator-&gt;item-&gt;value;

   return NULL;
}

generic_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator)
{
   struct generic_queue_item_t *item;

   if (!iterator)
      return NULL;

   item = iterator-&gt;forward ? iterator-&gt;queue-&gt;first_item : iterator-&gt;queue-&gt;last_item;
   while (item)
   {
      if (iterator-&gt;item == item)
      {
         if (iterator-&gt;queue-&gt;first_item == item)
            iterator-&gt;queue-&gt;first_item = item-&gt;next;
         else
            item-&gt;previous-&gt;next = item-&gt;next;

         if (iterator-&gt;queue-&gt;last_item == item)
            iterator-&gt;queue-&gt;last_item = item-&gt;previous;
         else
            item-&gt;next-&gt;previous = item-&gt;previous;

         iterator-&gt;queue-&gt;length--;

         iterator-&gt;item = iterator-&gt;forward ? item-&gt;next : item-&gt;previous;
         free(item);
         if (iterator-&gt;item)
            return iterator;
         free(iterator);
         return NULL;
      }

      item = iterator-&gt;forward ? item-&gt;next : item-&gt;previous;
   }

   return iterator;
}

void generic_queue_iterator_free(generic_queue_iterator_t *iterator)
{
   if (iterator)
      free(iterator);
}</pre>
<h2>./include/libretro-common/queues/message_queue.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (message_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;boolean.h&gt;
#include &lt;queues/message_queue.h&gt;
#include &lt;compat/strl.h&gt;
#include &lt;compat/posix_string.h&gt;

bool msg_queue_initialize(msg_queue_t *queue, size_t len)
{
   struct queue_elem **elems = NULL;

   if (!queue)
      return false;

   if (!(elems = (struct queue_elem**)
            calloc(len + 1, sizeof(struct queue_elem*))))
      return false;

   queue-&gt;tmp_msg            = NULL;
   queue-&gt;elems              = elems;
   queue-&gt;ptr                = 1;
   queue-&gt;size               = len + 1;

   return true;
}

/**
 * msg_queue_new:
 * @len              : maximum size of message
 *
 * Creates a message queue with maximum size different messages.
 *
 * Returns: NULL if allocation error, pointer to a message queue
 * if successful. Has to be freed manually.
 **/
msg_queue_t *msg_queue_new(size_t len)
{
   msg_queue_t *queue = (msg_queue_t*)malloc(sizeof(*queue));

   if (!msg_queue_initialize(queue, len))
   {
      if (queue)
         free(queue);
      return NULL;
   }

   return queue;
}

/**
 * msg_queue_free:
 * @queue             : pointer to queue object
 *
 * Frees message queue..
 **/
void msg_queue_free(msg_queue_t *queue)
{
   if (!queue)
      return;
   msg_queue_clear(queue);
   free(queue-&gt;elems);
   free(queue);
}

bool msg_queue_deinitialize(msg_queue_t *queue)
{
   if (!queue)
      return false;
   msg_queue_clear(queue);
   free(queue-&gt;elems);
   queue-&gt;elems   = NULL;
   queue-&gt;tmp_msg = NULL;
   queue-&gt;ptr     = 0;
   queue-&gt;size    = 0;
   return true;
}

/**
 * msg_queue_push:
 * @queue             : pointer to queue object
 * @msg               : message to add to the queue
 * @prio              : priority level of the message
 * @duration          : how many times the message can be pulled
 *                      before it vanishes (E.g. show a message for
 *                      3 seconds @ 60fps = 180 duration).
 *
 * Push a new message onto the queue.
 **/
void msg_queue_push(msg_queue_t *queue, const char *msg,
      unsigned prio, unsigned duration,
      char *title,
      enum message_queue_icon icon, enum message_queue_category category)
{
   size_t tmp_ptr = 0;
   struct queue_elem *new_elem = NULL;

   if (!queue || queue-&gt;ptr &gt;= queue-&gt;size)
      return;

   if (!(new_elem = (struct queue_elem*)malloc(sizeof(struct queue_elem))))
      return;

   new_elem-&gt;duration            = duration;
   new_elem-&gt;prio                = prio;
   new_elem-&gt;msg                 = msg   ? strdup(msg)   : NULL;
   new_elem-&gt;title               = title ? strdup(title) : NULL;
   new_elem-&gt;icon                = icon;
   new_elem-&gt;category            = category;

   queue-&gt;elems[queue-&gt;ptr]      = new_elem;

   tmp_ptr                       = queue-&gt;ptr++;

   while (tmp_ptr &gt; 1)
   {
      struct queue_elem *parent  = queue-&gt;elems[tmp_ptr &gt;&gt; 1];
      struct queue_elem *child   = queue-&gt;elems[tmp_ptr];

      if (child-&gt;prio &lt;= parent-&gt;prio)
         break;

      queue-&gt;elems[tmp_ptr &gt;&gt; 1] = child;
      queue-&gt;elems[tmp_ptr]      = parent;

      tmp_ptr &gt;&gt;= 1;
   }
}

/**
 * msg_queue_clear:
 * @queue             : pointer to queue object
 *
 * Clears out everything in the queue.
 **/
void msg_queue_clear(msg_queue_t *queue)
{
   size_t i;

   if (!queue)
      return;

   for (i = 1; i &lt; queue-&gt;ptr; i++)
   {
      if (queue-&gt;elems[i])
      {
         free(queue-&gt;elems[i]-&gt;msg);
         free(queue-&gt;elems[i]-&gt;title);
         free(queue-&gt;elems[i]);
         queue-&gt;elems[i] = NULL;
      }
   }
   queue-&gt;ptr     = 1;
   free(queue-&gt;tmp_msg);
   queue-&gt;tmp_msg = NULL;
}

/**
 * msg_queue_pull:
 * @queue             : pointer to queue object
 *
 * Pulls highest priority message in queue.
 *
 * Returns: NULL if no message in queue, otherwise a string
 * containing the message.
 **/
const char *msg_queue_pull(msg_queue_t *queue)
{
   struct queue_elem *front  = NULL, *last = NULL;
   size_t tmp_ptr = 1;

   /* Nothing in queue. */
   if (!queue || queue-&gt;ptr == 1)
      return NULL;

   front = (struct queue_elem*)queue-&gt;elems[1];
   front-&gt;duration--;
   if (front-&gt;duration &gt; 0)
      return front-&gt;msg;

   free(queue-&gt;tmp_msg);
   queue-&gt;tmp_msg = front-&gt;msg;
   front-&gt;msg = NULL;

   last  = (struct queue_elem*)queue-&gt;elems[--queue-&gt;ptr];
   queue-&gt;elems[1] = last;
   free(front-&gt;title);
   free(front);

   for (;;)
   {
      struct queue_elem *parent = NULL;
      struct queue_elem *child  = NULL;
      size_t switch_index       = tmp_ptr;
      bool left                 = (tmp_ptr * 2 &lt;= queue-&gt;ptr)
         &amp;&amp; (queue-&gt;elems[tmp_ptr] &lt; queue-&gt;elems[tmp_ptr * 2]);
      bool right                = (tmp_ptr * 2 + 1 &lt;= queue-&gt;ptr)
         &amp;&amp; (queue-&gt;elems[tmp_ptr] &lt; queue-&gt;elems[tmp_ptr * 2 + 1]);

      if (!left &amp;&amp; !right)
         break;

      if (left &amp;&amp; !right)
         switch_index &lt;&lt;= 1;
      else if (right &amp;&amp; !left)
         switch_index += switch_index + 1;
      else
      {
         if (queue-&gt;elems[tmp_ptr * 2]
               &gt;= queue-&gt;elems[tmp_ptr * 2 + 1])
            switch_index &lt;&lt;= 1;
         else
            switch_index += switch_index + 1;
      }

      parent = (struct queue_elem*)queue-&gt;elems[tmp_ptr];
      child  = (struct queue_elem*)queue-&gt;elems[switch_index];
      queue-&gt;elems[tmp_ptr]      = child;
      queue-&gt;elems[switch_index] = parent;
      tmp_ptr                    = switch_index;
   }

   return queue-&gt;tmp_msg;
}

/**
 * msg_queue_extract:
 * @queue             : pointer to queue object
 * @queue_entry       : pointer to external queue entry struct
 *
 * Removes highest priority message from queue, copying
 * contents into queue_entry struct.
 *
 * Returns: false if no messages in queue, otherwise true
 **/
bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry)
{
   struct queue_elem *front  = NULL, *last = NULL;
   size_t tmp_ptr = 1;

   /* Ensure arguments are valid and queue is not
    * empty */
   if (!queue || queue-&gt;ptr == 1 || !queue_entry)
      return false;

   front = (struct queue_elem*)queue-&gt;elems[1];
   last  = (struct queue_elem*)queue-&gt;elems[--queue-&gt;ptr];
   queue-&gt;elems[1] = last;

   /* Copy element parameters */
   queue_entry-&gt;duration = front-&gt;duration;
   queue_entry-&gt;prio     = front-&gt;prio;
   queue_entry-&gt;icon     = front-&gt;icon;
   queue_entry-&gt;category = front-&gt;category;
   queue_entry-&gt;msg[0]   = '\0';
   queue_entry-&gt;title[0] = '\0';

   if (front-&gt;msg)
      strlcpy(queue_entry-&gt;msg, front-&gt;msg, sizeof(queue_entry-&gt;msg));

   if (front-&gt;title)
      strlcpy(queue_entry-&gt;title, front-&gt;title, sizeof(queue_entry-&gt;title));

   /* Delete element */
   free(front-&gt;msg);
   free(front-&gt;title);
   free(front);

   for (;;)
   {
      struct queue_elem *parent = NULL;
      struct queue_elem *child  = NULL;
      size_t switch_index       = tmp_ptr;
      bool left                 = (tmp_ptr * 2 &lt;= queue-&gt;ptr)
         &amp;&amp; (queue-&gt;elems[tmp_ptr] &lt; queue-&gt;elems[tmp_ptr * 2]);
      bool right                = (tmp_ptr * 2 + 1 &lt;= queue-&gt;ptr)
         &amp;&amp; (queue-&gt;elems[tmp_ptr] &lt; queue-&gt;elems[tmp_ptr * 2 + 1]);

      if (!left &amp;&amp; !right)
         break;

      if (left &amp;&amp; !right)
         switch_index &lt;&lt;= 1;
      else if (right &amp;&amp; !left)
         switch_index += switch_index + 1;
      else
      {
         if (queue-&gt;elems[tmp_ptr * 2]
               &gt;= queue-&gt;elems[tmp_ptr * 2 + 1])
            switch_index &lt;&lt;= 1;
         else
            switch_index += switch_index + 1;
      }

      parent = (struct queue_elem*)queue-&gt;elems[tmp_ptr];
      child  = (struct queue_elem*)queue-&gt;elems[switch_index];
      queue-&gt;elems[tmp_ptr]      = child;
      queue-&gt;elems[switch_index] = parent;
      tmp_ptr                    = switch_index;
   }

   return true;
}

/**
 * msg_queue_size:
 * @queue             : pointer to queue object
 *
 * Fetches number of messages in queue.
 *
 * Returns: Number of messages in queue.
 **/
size_t msg_queue_size(msg_queue_t *queue)
{
   if (!queue || queue-&gt;ptr &lt;= 1)
      return 0;

   return queue-&gt;ptr - 1;
}</pre>
<h2>./include/libretro-common/queues/task_queue.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (task_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdarg.h&gt;

#include &lt;queues/task_queue.h&gt;

#include &lt;features/features_cpu.h&gt;

#if defined(HAVE_GCD) &amp;&amp; !defined(HAVE_THREADS)
#error "gcd uses threads, what are you doing"
#endif

#ifdef HAVE_THREADS
#include &lt;rthreads/rthreads.h&gt;
#endif
#if defined(EMSCRIPTEN) || defined(_3DS)
#include &lt;retro_timers.h&gt;
#endif
#ifdef HAVE_GCD
#include &lt;dispatch/dispatch.h&gt;
#endif

typedef struct
{
   retro_task_t *front;
   retro_task_t *back;
} task_queue_t;

struct retro_task_impl
{
   retro_task_queue_msg_t msg_push;
   void (*push_running)(retro_task_t *);
   void (*cancel)(void *);
   void (*reset)(void);
   void (*wait)(retro_task_condition_fn_t, void *);
   void (*gather)(void);
   bool (*find)(retro_task_finder_t, void*);
   void (*retrieve)(task_retriever_data_t *data);
   void (*init)(void);
   void (*deinit)(void);
};

/* TODO/FIXME - static globals */
static retro_task_queue_msg_t msg_push_bak  = NULL;
static task_queue_t tasks_running           = {NULL, NULL};
static task_queue_t tasks_finished          = {NULL, NULL};

static struct retro_task_impl *impl_current = NULL;
static bool task_threaded_enable            = false;

#ifdef HAVE_THREADS
static uintptr_t main_thread_id             = 0;
static slock_t *running_lock                = NULL;
static slock_t *finished_lock               = NULL;
static slock_t *property_lock               = NULL;
static slock_t *queue_lock                  = NULL;
static scond_t *worker_cond                 = NULL;
static sthread_t *worker_thread             = NULL;
static bool worker_continue                 = true;
/* use running_lock when touching it */
#endif

#ifdef HAVE_GCD
static unsigned gcd_queue_count             = 0;
#endif

static void task_queue_msg_push(retro_task_t *task,
      unsigned prio, unsigned duration,
      bool flush, const char *fmt, ...)
{
   char buf[1024];
   va_list ap;

   buf[0] = '\0';

   va_start(ap, fmt);
   vsnprintf(buf, sizeof(buf), fmt, ap);
   va_end(ap);

   if (impl_current-&gt;msg_push)
      impl_current-&gt;msg_push(task, buf, prio, duration, flush);
}

static void task_queue_push_progress(retro_task_t *task)
{
#ifdef HAVE_THREADS
   /* msg_push callback interacts directly with the task properties (particularly title).
    * make sure another thread doesn't modify them while rendering
    */
   slock_lock(property_lock);
#endif

   if (task-&gt;title &amp;&amp; (!((task-&gt;flags &amp; RETRO_TASK_FLG_MUTE) &gt; 0)))
   {
      if ((task-&gt;flags &amp; RETRO_TASK_FLG_FINISHED) &gt; 0)
      {
         if (task-&gt;error)
            task_queue_msg_push(task, 1, 60, true, "%s: %s",
               "Task failed", task-&gt;title);
         else
            task_queue_msg_push(task, 1, 60, false, "100%%: %s", task-&gt;title);
      }
      else
      {
         if (task-&gt;progress &gt;= 0 &amp;&amp; task-&gt;progress &lt;= 100)
            task_queue_msg_push(task, 1, 60, true, "%i%%: %s",
                  task-&gt;progress, task-&gt;title);
         else
            task_queue_msg_push(task, 1, 60, false, "%s...", task-&gt;title);
      }

      if (task-&gt;progress_cb)
         task-&gt;progress_cb(task);
   }

#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

static void task_queue_put(task_queue_t *queue, retro_task_t *task)
{
   task-&gt;next                   = NULL;

   if (queue-&gt;front)
   {
      /* Make sure to insert in order - the queue is
       * sorted by 'when' so items that aren't scheduled
       * to run immediately are at the back of the queue.
       * Items with the same 'when' are inserted after
       * all the other items with the same 'when'.
       * This primarily affects items with a 'when' of 0.
       */
      if (queue-&gt;back)
      {
         if (queue-&gt;back-&gt;when &gt; task-&gt;when)
         {
            retro_task_t** prev = &amp;queue-&gt;front;
            while (*prev &amp;&amp; (*prev)-&gt;when &lt;= task-&gt;when)
               prev             = &amp;((*prev)-&gt;next);

            task-&gt;next          = *prev;
            *prev               = task;
            return;
         }

         queue-&gt;back-&gt;next      = task;
      }
   }
   else
      queue-&gt;front              = task;

   queue-&gt;back                  = task;
}

static retro_task_t *task_queue_get(task_queue_t *queue)
{
   retro_task_t *task = queue-&gt;front;

   if (task)
   {
      queue-&gt;front = task-&gt;next;
      task-&gt;next   = NULL;
   }

   return task;
}

static void retro_task_internal_gather(void)
{
   retro_task_t *task = NULL;
   while ((task = task_queue_get(&amp;tasks_finished)))
   {
      task_queue_push_progress(task);

      if (task-&gt;callback)
         task-&gt;callback(task, task-&gt;task_data, task-&gt;user_data, task-&gt;error);

      if (task-&gt;cleanup)
          task-&gt;cleanup(task);

      if (task-&gt;error)
         free(task-&gt;error);

      if (task-&gt;title)
         free(task-&gt;title);

      free(task);
   }
}

static void retro_task_regular_push_running(retro_task_t *task)
{
   task_queue_put(&amp;tasks_running, task);
}

static void retro_task_regular_cancel(void *task)
{
   retro_task_t *t = (retro_task_t*)task;
   t-&gt;flags       |= RETRO_TASK_FLG_CANCELLED;
}

static void retro_task_regular_gather(void)
{
   retro_task_t *task  = NULL;
   retro_task_t *queue = NULL;
   retro_task_t *next  = NULL;

   while ((task = task_queue_get(&amp;tasks_running)))
   {
      task-&gt;next = queue;
      queue = task;
   }

   for (task = queue; task; task = next)
   {
      next = task-&gt;next;

      if (!task-&gt;when || task-&gt;when &lt; cpu_features_get_time_usec())
      {
         task-&gt;handler(task);

         task_queue_push_progress(task);
      }

      if ((task-&gt;flags &amp; RETRO_TASK_FLG_FINISHED) &gt; 0)
         task_queue_put(&amp;tasks_finished, task);
      else
         task_queue_put(&amp;tasks_running, task);
   }

   retro_task_internal_gather();
}

static void retro_task_regular_wait(retro_task_condition_fn_t cond, void* data)
{
   while ((tasks_running.front &amp;&amp; !tasks_running.front-&gt;when) &amp;&amp; (!cond || cond(data)))
      retro_task_regular_gather();
}

static void retro_task_regular_reset(void)
{
   retro_task_t *task = tasks_running.front;

   for (; task; task = task-&gt;next)
      task-&gt;flags |= RETRO_TASK_FLG_CANCELLED;
}

static void retro_task_regular_init(void) { }
static void retro_task_regular_deinit(void) { }

static bool retro_task_regular_find(retro_task_finder_t func, void *user_data)
{
   retro_task_t *task = tasks_running.front;

   for (; task; task = task-&gt;next)
   {
      if (func(task, user_data))
         return true;
   }

   return false;
}

static void retro_task_regular_retrieve(task_retriever_data_t *data)
{
   retro_task_t *task          = NULL;
   task_retriever_info_t *tail = NULL;

   /* Parse all running tasks and handle matching handlers */
   for (task = tasks_running.front; task != NULL; task = task-&gt;next)
   {
      task_retriever_info_t *info = NULL;
      if (task-&gt;handler != data-&gt;handler)
         continue;

      /* Create new link */
      info       = (task_retriever_info_t*)
         malloc(sizeof(task_retriever_info_t));
      info-&gt;data = malloc(data-&gt;element_size);
      info-&gt;next = NULL;

      /* Call retriever function and fill info-specific data */
      if (!data-&gt;func(task, info-&gt;data))
      {
         free(info-&gt;data);
         free(info);
         continue;
      }

      /* Add link to list */
      if (data-&gt;list)
      {
         if (tail)
         {
            tail-&gt;next = info;
            tail       = tail-&gt;next;
         }
         else
            tail       = info;
      }
      else
      {
         data-&gt;list    = info;
         tail          = data-&gt;list;
      }
   }
}

static struct retro_task_impl impl_regular = {
   NULL,
   retro_task_regular_push_running,
   retro_task_regular_cancel,
   retro_task_regular_reset,
   retro_task_regular_wait,
   retro_task_regular_gather,
   retro_task_regular_find,
   retro_task_regular_retrieve,
   retro_task_regular_init,
   retro_task_regular_deinit
};

#ifdef HAVE_THREADS

/* 'queue_lock' must be held for the duration of this function */
static void task_queue_remove(task_queue_t *queue, retro_task_t *task)
{
   retro_task_t     *t = NULL;
   retro_task_t *front = queue-&gt;front;

   /* Remove first element if needed */
   if (task == front)
   {
      queue-&gt;front     = task-&gt;next;
      if (queue-&gt;back == task) /* if only element, also update back */
         queue-&gt;back   = NULL;
      task-&gt;next       = NULL;
      return;
   }

   /* Parse queue */
   t = front;

   while (t &amp;&amp; t-&gt;next)
   {
      /* Remove task and update queue */
      if (t-&gt;next == task)
      {
         t-&gt;next    = task-&gt;next;
         task-&gt;next = NULL;

         /* When removing the tail of the queue, update the tail pointer */
         if (queue-&gt;back == task)
         {
            if (queue-&gt;back == task)
               queue-&gt;back = t;
         }
         break;
      }

      /* Update iterator */
      t = t-&gt;next;
   }
}

static void retro_task_threaded_push_running(retro_task_t *task)
{
   slock_lock(running_lock);
   slock_lock(queue_lock);
   task_queue_put(&amp;tasks_running, task);
   scond_signal(worker_cond);
   slock_unlock(queue_lock);
   slock_unlock(running_lock);
}

static void retro_task_threaded_cancel(void *task)
{
   retro_task_t *t;

   slock_lock(running_lock);

   for (t = tasks_running.front; t; t = t-&gt;next)
   {
      if (t == task)
      {
        t-&gt;flags |= RETRO_TASK_FLG_CANCELLED;
        break;
      }
   }

   slock_unlock(running_lock);
}

static void retro_task_threaded_gather(void)
{
   retro_task_t *task = NULL;

   slock_lock(running_lock);
   for (task = tasks_running.front; task; task = task-&gt;next)
      task_queue_push_progress(task);
   slock_unlock(running_lock);

   slock_lock(finished_lock);
   retro_task_internal_gather();
   slock_unlock(finished_lock);
}

static void retro_task_threaded_wait(retro_task_condition_fn_t cond, void* data)
{
   bool wait = false;

   do
   {
      retro_task_threaded_gather();

      slock_lock(running_lock);
      wait = (tasks_running.front &amp;&amp; !tasks_running.front-&gt;when);
      slock_unlock(running_lock);

      if (!wait)
      {
         slock_lock(finished_lock);
         wait = (tasks_finished.front &amp;&amp; !tasks_finished.front-&gt;when);
         slock_unlock(finished_lock);
      }
   } while (wait &amp;&amp; (!cond || cond(data)));
}

static void retro_task_threaded_reset(void)
{
   retro_task_t *task = NULL;

   slock_lock(running_lock);
   for (task = tasks_running.front; task; task = task-&gt;next)
      task-&gt;flags |= RETRO_TASK_FLG_CANCELLED;
   slock_unlock(running_lock);
}

static bool retro_task_threaded_find(
      retro_task_finder_t func, void *user_data)
{
   retro_task_t *task = NULL;
   bool ret = false;

   slock_lock(running_lock);
   for (task = tasks_running.front; task; task = task-&gt;next)
   {
      if (func(task, user_data))
      {
         ret = true;
         break;
      }
   }
   slock_unlock(running_lock);

   return ret;
}

static void retro_task_threaded_retrieve(task_retriever_data_t *data)
{
   /* Protect access to running tasks */
   slock_lock(running_lock);
   /* Call regular retrieve function */
   retro_task_regular_retrieve(data);
   /* Release access to running tasks */
   slock_unlock(running_lock);
}

static void threaded_worker(void *userdata)
{
   for (;;)
   {
      retro_task_t *task  = NULL;
      bool       finished = false;

      slock_lock(running_lock);

      if (!worker_continue)
      {
         slock_unlock(running_lock);
         break; /* should we keep running until all tasks finished? */
      }

      /* Get first task to run */
      if (!(task = tasks_running.front))
      {
         scond_wait(worker_cond, running_lock);
         slock_unlock(running_lock);
         continue;
      }

      if (task-&gt;when)
      {
         retro_time_t now   = cpu_features_get_time_usec();
         retro_time_t delay = task-&gt;when - now - 500; /* allow half a millisecond for context switching */
         if (delay &gt; 0)
         {
            scond_wait_timeout(worker_cond, running_lock, delay);
            slock_unlock(running_lock);
            continue;
         }
      }

      slock_unlock(running_lock);
      task-&gt;handler(task);
#if defined(EMSCRIPTEN) || defined(_3DS)
      /* Workaround emscripten pthread bug where not parking the
         thread will prevent other important stuff from
         happening. Maybe due to lack of signals implementation in
         emscripten's pthreads?  */
      retro_sleep(1);
#endif

      slock_lock(property_lock);
      finished = ((task-&gt;flags &amp; RETRO_TASK_FLG_FINISHED) &gt; 0) ? true : false;
      slock_unlock(property_lock);

      /* Update queue */
      if (!finished)
      {
         /* Move the task to the back of the queue */
         /* mimics retro_task_threaded_push_running,
          * but also includes a task_queue_remove */
         slock_lock(running_lock);
         slock_lock(queue_lock);

         /* do nothing if only item in queue */
         if (task-&gt;next)
         {
            task_queue_remove(&amp;tasks_running, task);
            task_queue_put(&amp;tasks_running, task);
            scond_signal(worker_cond);
         }
         slock_unlock(queue_lock);
         slock_unlock(running_lock);
      }
      else
      {
         /* Remove task from running queue */
         slock_lock(running_lock);
         slock_lock(queue_lock);
         task_queue_remove(&amp;tasks_running, task);
         slock_unlock(queue_lock);
         slock_unlock(running_lock);

         /* Add task to finished queue */
         slock_lock(finished_lock);
         task_queue_put(&amp;tasks_finished, task);
         slock_unlock(finished_lock);
      }
   }
}

static void retro_task_threaded_init(void)
{
   running_lock    = slock_new();
   finished_lock   = slock_new();
   property_lock   = slock_new();
   queue_lock      = slock_new();
   worker_cond     = scond_new();

   slock_lock(running_lock);
   worker_continue = true;
   slock_unlock(running_lock);

   worker_thread   = sthread_create(threaded_worker, NULL);
}

static void retro_task_threaded_deinit(void)
{
   slock_lock(running_lock);
   worker_continue = false;
   scond_signal(worker_cond);
   slock_unlock(running_lock);

   sthread_join(worker_thread);

   scond_free(worker_cond);
   slock_free(running_lock);
   slock_free(finished_lock);
   slock_free(property_lock);
   slock_free(queue_lock);

   worker_thread   = NULL;
   worker_cond     = NULL;
   running_lock    = NULL;
   finished_lock   = NULL;
   property_lock   = NULL;
   queue_lock      = NULL;
}

static struct retro_task_impl impl_threaded = {
   NULL,
   retro_task_threaded_push_running,
   retro_task_threaded_cancel,
   retro_task_threaded_reset,
   retro_task_threaded_wait,
   retro_task_threaded_gather,
   retro_task_threaded_find,
   retro_task_threaded_retrieve,
   retro_task_threaded_init,
   retro_task_threaded_deinit
};
#endif

#ifdef HAVE_GCD

static void gcd_worker(retro_task_t *task)
{
   bool       finished = false;
   slock_lock(running_lock);

   if (!worker_continue)
   {
      gcd_queue_count--;
      if (!gcd_queue_count)
         scond_signal(worker_cond);
      slock_unlock(running_lock);
      return;
   }

   if (task-&gt;when)
   {
      retro_time_t now   = cpu_features_get_time_usec();
      retro_time_t delay = task-&gt;when - now - 500;
      if (delay &gt; 0)
      {
         dispatch_time_t after = dispatch_time(DISPATCH_TIME_NOW, delay);
         dispatch_after(after, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                        ^{ gcd_worker(task); });
         slock_unlock(running_lock);
         return;
      }
   }

   slock_unlock(running_lock);

   task-&gt;handler(task);

   slock_lock(property_lock);
   finished = ((task-&gt;flags &amp; RETRO_TASK_FLG_FINISHED) &gt; 0) ? true : false;
   slock_unlock(property_lock);

   if (!finished)
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                     ^{ gcd_worker(task); });
   else
   {
      /* Remove task from running queue */
      slock_lock(running_lock);
      slock_lock(queue_lock);
      gcd_queue_count--;
      if (!gcd_queue_count)
         scond_signal(worker_cond);
      task_queue_remove(&amp;tasks_running, task);
      slock_unlock(queue_lock);
      slock_unlock(running_lock);

      /* Add task to finished queue */
      slock_lock(finished_lock);
      task_queue_put(&amp;tasks_finished, task);
      slock_unlock(finished_lock);
   }
}

static void retro_task_gcd_push_running(retro_task_t *task)
{
   slock_lock(running_lock);
   slock_lock(queue_lock);
   task_queue_put(&amp;tasks_running, task);
   gcd_queue_count++;
   dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                  ^{ gcd_worker(task); });
   slock_unlock(queue_lock);
   slock_unlock(running_lock);
}

static void retro_task_gcd_wait(retro_task_condition_fn_t cond, void* data)
{
   bool wait = false;

   do
   {
      retro_task_t *task = NULL;
      retro_task_threaded_gather();

      slock_lock(running_lock);
      wait = false;
      /* can't just look at the first task like threaded, they're not sorted by when */
      for (task = tasks_running.front; !wait &amp;&amp; task; task = task-&gt;next)
         wait |= !task-&gt;when;
      slock_unlock(running_lock);

      if (!wait)
      {
         slock_lock(finished_lock);
         for (task = tasks_finished.front; !wait &amp;&amp; task; task = task-&gt;next)
            wait |= !task-&gt;when;
         slock_unlock(finished_lock);
      }
   } while (wait &amp;&amp; (!cond || cond(data)));
}

static void retro_task_gcd_init(void)
{
   retro_task_t *task = NULL;

   running_lock    = slock_new();
   finished_lock   = slock_new();
   property_lock   = slock_new();
   queue_lock      = slock_new();
   worker_cond     = scond_new();

   slock_lock(running_lock);
   worker_continue = true;
   for (task = tasks_running.front; task; task = task-&gt;next)
   {
      gcd_queue_count++;
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
                     ^{ gcd_worker(task); });
   };
   slock_unlock(running_lock);
}

static void retro_task_gcd_deinit(void)
{
   slock_lock(running_lock);
   worker_continue = false;
   if (gcd_queue_count)
      scond_wait(worker_cond, running_lock);
   slock_unlock(running_lock);

   scond_free(worker_cond);
   slock_free(running_lock);
   slock_free(finished_lock);
   slock_free(property_lock);
   slock_free(queue_lock);

   worker_cond     = NULL;
   running_lock    = NULL;
   finished_lock   = NULL;
   property_lock   = NULL;
   queue_lock      = NULL;
}

static struct retro_task_impl impl_gcd = {
   NULL,
   retro_task_gcd_push_running,
   retro_task_threaded_cancel,
   retro_task_threaded_reset,
   retro_task_gcd_wait,
   retro_task_threaded_gather,
   retro_task_threaded_find,
   retro_task_threaded_retrieve,
   retro_task_gcd_init,
   retro_task_gcd_deinit
};
#endif

/* Deinitializes the task system.
 * This deinitializes the task system.
 * The tasks that are running at
 * the moment will stay on hold */
void task_queue_deinit(void)
{
   if (impl_current)
      impl_current-&gt;deinit();
   impl_current = NULL;
}

void task_queue_init(bool threaded, retro_task_queue_msg_t msg_push)
{
   impl_current   = &amp;impl_regular;
#ifdef HAVE_THREADS
   main_thread_id = sthread_get_current_thread_id();
   if (threaded)
   {
      task_threaded_enable = true;
#ifdef HAVE_GCD
      impl_current         = &amp;impl_gcd;
#else
      impl_current         = &amp;impl_threaded;
#endif
   }
#endif

   msg_push_bak            = msg_push;

   impl_current-&gt;msg_push  = msg_push;
   impl_current-&gt;init();
}

void task_queue_set_threaded(void)
{
   task_threaded_enable = true;
}

void task_queue_unset_threaded(void)
{
   task_threaded_enable = false;
}

bool task_queue_is_threaded(void)
{
   return task_threaded_enable;
}

bool task_queue_find(task_finder_data_t *find_data)
{
   return impl_current-&gt;find(find_data-&gt;func, find_data-&gt;userdata);
}

void task_queue_retrieve(task_retriever_data_t *data)
{
   impl_current-&gt;retrieve(data);
}

void task_queue_check(void)
{
#ifdef HAVE_THREADS
   bool current_threaded = (impl_current != &amp;impl_regular);
   bool want_threaded    = task_threaded_enable;

   if (want_threaded != current_threaded)
      task_queue_deinit();

   if (!impl_current)
      task_queue_init(want_threaded, msg_push_bak);
#endif

   impl_current-&gt;gather();
}

bool task_queue_push(retro_task_t *task)
{
   /* Ignore this task if a related one is already running */
   if (task-&gt;type == TASK_TYPE_BLOCKING)
   {
      retro_task_t *running = NULL;
      bool            found = false;

#ifdef HAVE_THREADS
      slock_lock(queue_lock);
#endif
      running = tasks_running.front;

      for (; running; running = running-&gt;next)
      {
         if (running-&gt;type == TASK_TYPE_BLOCKING)
         {
            found = true;
            break;
         }
      }

#ifdef HAVE_THREADS
      slock_unlock(queue_lock);
#endif

      /* skip this task, user must try again later */
      if (found)
         return false;
   }

   /* The lack of NULL checks in the following functions
    * is proposital to ensure correct control flow by the users. */
   impl_current-&gt;push_running(task);

   return true;
}

void task_queue_wait(retro_task_condition_fn_t cond, void* data)
{
   impl_current-&gt;wait(cond, data);
}

void task_queue_reset(void)
{
   impl_current-&gt;reset();
}

/**
 * Signals a task to end without waiting for
 * it to complete. */
void task_queue_cancel_task(void *task)
{
   impl_current-&gt;cancel(task);
}

void *task_queue_retriever_info_next(task_retriever_info_t **link)
{
   /* Grab data and move to next link */
   if (*link)
   {
      *link = (*link)-&gt;next;
      return (*link)-&gt;data;
   }
   return NULL;
}

void task_queue_retriever_info_free(task_retriever_info_t *list)
{
   task_retriever_info_t *info;

   /* Free links including retriever-specific data */
   while (list)
   {
      info = list-&gt;next;
      free(list-&gt;data);
      free(list);
      list = info;
   }
}

bool task_is_on_main_thread(void)
{
#ifdef HAVE_THREADS
   return sthread_get_current_thread_id() == main_thread_id;
#else
   return true;
#endif
}

void task_set_error(retro_task_t *task, char *err)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   task-&gt;error = err;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void task_set_progress(retro_task_t *task, int8_t progress)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   task-&gt;progress = progress;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void task_set_title(retro_task_t *task, char *title)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   task-&gt;title = title;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void task_set_data(retro_task_t *task, void *data)
{
#ifdef HAVE_THREADS
   slock_lock(running_lock);
#endif
   task-&gt;task_data = data;
#ifdef HAVE_THREADS
   slock_unlock(running_lock);
#endif
}

void task_free_title(retro_task_t *task)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   if (task-&gt;title)
      free(task-&gt;title);
   task-&gt;title = NULL;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

void* task_get_data(retro_task_t *task)
{
   void *data = NULL;

#ifdef HAVE_THREADS
   slock_lock(running_lock);
#endif
   data = task-&gt;task_data;
#ifdef HAVE_THREADS
   slock_unlock(running_lock);
#endif

   return data;
}

void task_set_flags(retro_task_t *task, uint8_t flags, bool set)
{
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   if (set)
      task-&gt;flags |=  (flags);
   else
      task-&gt;flags &amp;= ~(flags);
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
}

uint8_t task_get_flags(retro_task_t *task)
{
   uint8_t _flags = 0;
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   _flags = task-&gt;flags;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
   return _flags;
}

char* task_get_error(retro_task_t *task)
{
   char *s = NULL;
#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   s = task-&gt;error;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif
   return s;
}

int8_t task_get_progress(retro_task_t *task)
{
   int8_t progress = 0;

#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   progress = task-&gt;progress;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif

   return progress;
}

char* task_get_title(retro_task_t *task)
{
   char *title = NULL;

#ifdef HAVE_THREADS
   slock_lock(property_lock);
#endif
   title = task-&gt;title;
#ifdef HAVE_THREADS
   slock_unlock(property_lock);
#endif

   return title;
}

retro_task_t *task_init(void)
{
   /* TODO/FIXME - static local global */
   static uint32_t task_count = 0;
   retro_task_t *task         = (retro_task_t*)malloc(sizeof(*task));

   if (!task)
      return NULL;

   task-&gt;handler           = NULL;
   task-&gt;callback          = NULL;
   task-&gt;cleanup           = NULL;
   task-&gt;flags             = 0;
   task-&gt;task_data         = NULL;
   task-&gt;user_data         = NULL;
   task-&gt;state             = NULL;
   task-&gt;error             = NULL;
   task-&gt;progress          = 0;
   task-&gt;progress_cb       = NULL;
   task-&gt;title             = NULL;
   task-&gt;type              = TASK_TYPE_NONE;
   task-&gt;style             = TASK_STYLE_NONE;
   task-&gt;ident             = task_count++;
   task-&gt;frontend_userdata = NULL;
   task-&gt;next              = NULL;
   task-&gt;when              = 0;

   return task;
}</pre>
<h2>./include/libretro-common/rthreads/ctr_pthread.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gx_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _CTR_PTHREAD_WRAP_CTR_
#define _CTR_PTHREAD_WRAP_CTR_

#include &lt;3ds/thread.h&gt;
#include &lt;3ds/synchronization.h&gt;
#include &lt;3ds/svc.h&gt;
#include &lt;3ds/services/apt.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;time.h&gt;
#include &lt;errno.h&gt;
#include &lt;retro_inline.h&gt;

#define STACKSIZE (32 * 1024)

#ifndef PTHREAD_SCOPE_PROCESS
/* An earlier version of devkitARM does not define the pthread types. Can remove in r54+. */

typedef Thread     pthread_t;
typedef LightLock  pthread_mutex_t;
typedef void*      pthread_mutexattr_t;
typedef int        pthread_attr_t;
typedef uint32_t   pthread_cond_t;
typedef int        pthread_condattr_t;
#endif

#ifndef USE_CTRULIB_2
/* Backported CondVar API from libctru 2.0, and under its license:
   https://github.com/devkitPro/libctru
   Slightly modified for compatibility with older libctru. */

typedef s32 CondVar;

static INLINE Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value)
{
   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, 0);
}

static INLINE Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns)
{
   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, timeout_ns);
}

static INLINE void __dmb(void)
{
	__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
}

static INLINE void CondVar_BeginWait(CondVar* cv, LightLock* lock)
{
	s32 val;
	do
		val = __ldrex(cv) - 1;
	while (__strex(cv, val));
	LightLock_Unlock(lock);
}

static INLINE bool CondVar_EndWait(CondVar* cv, s32 num_threads)
{
	bool hasWaiters;
	s32 val;

	do {
		val = __ldrex(cv);
		hasWaiters = val &lt; 0;
		if (hasWaiters)
		{
			if (num_threads &lt; 0)
				val = 0;
			else if (val &lt;= -num_threads)
				val += num_threads;
			else
				val = 0;
		}
	} while (__strex(cv, val));

	return hasWaiters;
}

static INLINE void CondVar_Init(CondVar* cv)
{
	*cv = 0;
}

static INLINE void CondVar_Wait(CondVar* cv, LightLock* lock)
{
	CondVar_BeginWait(cv, lock);
	syncArbitrateAddress(cv, ARBITRATION_WAIT_IF_LESS_THAN, 0);
	LightLock_Lock(lock);
}

static INLINE int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns)
{
	CondVar_BeginWait(cv, lock);

	bool timedOut = false;
	Result rc = syncArbitrateAddressWithTimeout(cv, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, timeout_ns);
	if (R_DESCRIPTION(rc) == RD_TIMEOUT)
	{
		timedOut = CondVar_EndWait(cv, 1);
		__dmb();
	}

	LightLock_Lock(lock);
	return timedOut;
}

static INLINE void CondVar_WakeUp(CondVar* cv, s32 num_threads)
{
	__dmb();
	if (CondVar_EndWait(cv, num_threads))
		syncArbitrateAddress(cv, ARBITRATION_SIGNAL, num_threads);
	else
		__dmb();
}

static INLINE void CondVar_Signal(CondVar* cv)
{
	CondVar_WakeUp(cv, 1);
}

static INLINE void CondVar_Broadcast(CondVar* cv)
{
	CondVar_WakeUp(cv, ARBITRATION_SIGNAL_ALL);
}
/* End libctru 2.0 backport */
#endif

/* libctru threads return void but pthreads return void pointer */
static bool mutex_inited = false;
static LightLock safe_double_thread_launch;
static void *(*start_routine_jump)(void*);

static void ctr_thread_launcher(void* data)
{
	void *(*start_routine_jump_safe)(void*) = start_routine_jump;
	LightLock_Unlock(&amp;safe_double_thread_launch);
	start_routine_jump_safe(data);
}

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   s32 prio = 0;
   Thread new_ctr_thread;
   int procnum = -2; /* use default cpu */
   bool isNew3DS;

   APT_CheckNew3DS(&amp;isNew3DS);

   if (isNew3DS)
      procnum = 2;

   if (!mutex_inited)
   {
      LightLock_Init(&amp;safe_double_thread_launch);
      mutex_inited = true;
   }

   /* Must wait if attempting to launch 2 threads at once to prevent corruption of function pointer*/
   while (LightLock_TryLock(&amp;safe_double_thread_launch) != 0);

   svcGetThreadPriority(&amp;prio, CUR_THREAD_HANDLE);

   start_routine_jump = start_routine;
   new_ctr_thread     = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, procnum, false);

   if (!new_ctr_thread)
   {
      LightLock_Unlock(&amp;safe_double_thread_launch);
      return EAGAIN;
   }

   *thread = (pthread_t)new_ctr_thread;
   return 0;
}

static INLINE pthread_t pthread_self(void)
{
   return (pthread_t)threadGetCurrent();
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   LightLock_Init((LightLock *)mutex);
   return 0;
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
   /*Nothing to destroy*/
   return 0;
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
   LightLock_Lock((LightLock *)mutex);
   return 0;
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
   LightLock_Unlock((LightLock *)mutex);
   return 0;
}

static INLINE void pthread_exit(void *retval)
{
   /*Yes the pointer to int cast is not ideal*/
   /*threadExit((int)retval);*/
   (void)retval;

   threadExit(0);
}

static INLINE int pthread_detach(pthread_t thread)
{
   threadDetach((Thread)thread);
   return 0;
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
   /*retval is ignored*/
   if (threadJoin((Thread)thread, INT64_MAX))
      return -1;

   threadFree((Thread)thread);

   return 0;
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
   return LightLock_TryLock((LightLock *)mutex);
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
   CondVar_Wait((CondVar *)cond, (LightLock *)mutex);
   return 0;
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
   /* Missing clock_gettime*/
   struct timespec now;
   struct timeval tm;
   int retval = 0;

   do
   {
      s64 timeout;
      gettimeofday(&amp;tm, NULL);
      now.tv_sec  = tm.tv_sec;
      now.tv_nsec = tm.tv_usec * 1000;

      if ((timeout = (abstime-&gt;tv_sec - now.tv_sec) * 1000000000 +
(abstime-&gt;tv_nsec - now.tv_nsec)) &lt; 0)
      {
         retval = ETIMEDOUT;
         break;
      }

      if (!CondVar_WaitTimeout((CondVar *)cond, (LightLock *)mutex, timeout))
         break;
   } while (1);

   return retval;
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
   CondVar_Init((CondVar *)cond);
   return 0;
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
   CondVar_Signal((CondVar *)cond);
   return 0;
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   CondVar_Broadcast((CondVar *)cond);
   return 0;
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
   /*Nothing to destroy*/
   return 0;
}

static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
{
	if (threadGetHandle((Thread)t1) == threadGetHandle((Thread)t2))
		return 1;
	return 0;
}

#endif</pre>
<h2>./include/libretro-common/rthreads/gx_pthread.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (gx_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _GX_PTHREAD_WRAP_GX_
#define _GX_PTHREAD_WRAP_GX_

#include &lt;ogcsys.h&gt;
#include &lt;gccore.h&gt;
#include &lt;ogc/cond.h&gt;
#include &lt;retro_inline.h&gt;

#ifndef OSThread
#define OSThread lwp_t
#endif

#ifndef OSCond
#define OSCond lwpq_t
#endif

#ifndef OSThreadQueue
#define OSThreadQueue lwpq_t
#endif

#ifndef OSInitMutex
#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
#endif

#ifndef OSLockMutex
#define OSLockMutex(mutex) LWP_MutexLock(mutex)
#endif

#ifndef OSUnlockMutex
#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
#endif

#ifndef OSTryLockMutex
#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)
#endif

#ifndef OSInitCond
#define OSInitCond(cond) LWP_CondInit(cond)
#endif

#ifndef OSWaitCond
#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)
#endif

#ifndef OSInitThreadQueue
#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
#endif

#ifndef OSSleepThread
#define OSSleepThread(queue) LWP_ThreadSleep(queue)
#endif

#ifndef OSJoinThread
#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)
#endif

#ifndef OSCreateThread
#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)
#endif

#define STACKSIZE (8 * 1024)

typedef OSThread pthread_t;
typedef mutex_t pthread_mutex_t;
typedef OSCond pthread_cond_t;

#if defined(GX_PTHREAD_LEGACY)
typedef void* pthread_mutexattr_t;
typedef int pthread_attr_t;
typedef OSCond pthread_condattr_t;
#endif

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   *thread = 0;
   return OSCreateThread(thread, start_routine, 0 /* unused */, arg,
         0, STACKSIZE, 64, 0 /* unused */);
}

static INLINE pthread_t pthread_self(void)
{
   /* zero 20-mar-2016: untested */
   return LWP_GetSelf();
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   return OSInitMutex(mutex);
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
   return LWP_MutexDestroy(*mutex);
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
   return OSLockMutex(*mutex);
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
   return OSUnlockMutex(*mutex);
}

static INLINE void pthread_exit(void *retval)
{
   /* FIXME: No LWP equivalent for this? */
   (void)retval;
}

static INLINE int pthread_detach(pthread_t thread)
{
   /* FIXME: pthread_detach equivalent missing? */
   (void)thread;
   return 0;
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
   return OSJoinThread(thread, retval);
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
   return OSTryLockMutex(*mutex);
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
   return OSWaitCond(*cond, *mutex);
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
   return LWP_CondTimedWait(*cond, *mutex, abstime);
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
   return OSInitCond(cond);
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
   return LWP_CondSignal(*cond);
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   return LWP_CondBroadcast(*cond);
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
   return LWP_CondDestroy(*cond);
}

#endif</pre>
<h2>./include/libretro-common/rthreads/psp_pthread.h</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (psp_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* FIXME: unfinished on PSP, mutexes and condition variables basically a stub. */
#ifndef _PSP_PTHREAD_WRAP__
#define _PSP_PTHREAD_WRAP__

#ifdef VITA
#include &lt;psp2/kernel/threadmgr.h&gt;
#include &lt;sys/time.h&gt;
#else
#include &lt;pspkernel.h&gt;
#include &lt;pspthreadman.h&gt;
#include &lt;pspthreadman_kernel.h&gt;
#endif
#include &lt;stdio.h&gt;
#include &lt;retro_inline.h&gt;

#define STACKSIZE (8 * 1024)

typedef SceUID pthread_t;
typedef SceUID pthread_mutex_t;
typedef void* pthread_mutexattr_t;
typedef int pthread_attr_t;

typedef struct
{
	SceUID mutex;
	SceUID sema;
	int waiting;
} pthread_cond_t;

typedef SceUID pthread_condattr_t;

/* Use pointer values to create unique names for threads/mutexes */
char name_buffer[256];

typedef void* (*sthreadEntry)(void *argp);

typedef struct
{
   void* arg;
   sthreadEntry start_routine;
} sthread_args_struct;

static int psp_thread_wrap(SceSize args, void *argp)
{
   sthread_args_struct* sthread_args = (sthread_args_struct*)argp;

   return (int)sthread_args-&gt;start_routine(sthread_args-&gt;arg);
}

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) thread);

#ifdef VITA
   *thread = sceKernelCreateThread(name_buffer, psp_thread_wrap,
         0x10000100, 0x10000, 0, 0, NULL);
#else
   *thread = sceKernelCreateThread(name_buffer,
         psp_thread_wrap, 0x20, STACKSIZE, 0, NULL);
#endif

   sthread_args_struct sthread_args;
   sthread_args.arg = arg;
   sthread_args.start_routine = start_routine;

   return sceKernelStartThread(*thread, sizeof(sthread_args), &amp;sthread_args);
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) mutex);

#ifdef VITA
   *mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);
	 if (*mutex&lt;0)
	 		return *mutex;
	 return 0;
#else
   return *mutex = sceKernelCreateSema(name_buffer, 0, 1, 1, NULL);
#endif
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
#ifdef VITA
   return sceKernelDeleteMutex(*mutex);
#else
   return sceKernelDeleteSema(*mutex);
#endif
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
#ifdef VITA
	 int ret = sceKernelLockMutex(*mutex, 1, 0);
	 return ret;

#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
#ifdef VITA
	int ret = sceKernelUnlockMutex(*mutex, 1);
	return ret;
#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
#ifdef VITA
   int res = sceKernelWaitThreadEnd(thread, 0, 0);
   if (res &lt; 0)
      return res;
   return sceKernelDeleteThread(thread);
#else
   SceUInt timeout = (SceUInt)-1;
   sceKernelWaitThreadEnd(thread, &amp;timeout);
   exit_status = sceKernelGetThreadExitStatus(thread);
   sceKernelDeleteThread(thread);
   return exit_status;
#endif
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
#ifdef VITA
   return sceKernelTryLockMutex(*mutex, 1 /* not sure about this last param */);
#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
#ifdef VITA
   int ret = pthread_mutex_lock(&amp;cond-&gt;mutex);
   if (ret &lt; 0)
      return ret;
   ++cond-&gt;waiting;
   pthread_mutex_unlock(mutex);
   pthread_mutex_unlock(&amp;cond-&gt;mutex);

   ret = sceKernelWaitSema(cond-&gt;sema, 1, 0);
   if (ret &lt; 0)
      sceClibPrintf("Premature wakeup: %08X", ret);
   pthread_mutex_lock(mutex);
   return ret;
#else
   /* FIXME: stub */
   sceKernelDelayThread(10000);
   return 1;
#endif
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
#ifdef VITA
   int ret = pthread_mutex_lock(&amp;cond-&gt;mutex);
   if (ret &lt; 0)
      return ret;
   ++cond-&gt;waiting;
   pthread_mutex_unlock(mutex);
   pthread_mutex_unlock(&amp;cond-&gt;mutex);

   SceUInt timeout = 0;

   timeout  = abstime-&gt;tv_sec;
   timeout += abstime-&gt;tv_nsec / 1.0e6;

   ret = sceKernelWaitSema(cond-&gt;sema, 1, &amp;timeout);
   if (ret &lt; 0)
      sceClibPrintf("Premature wakeup: %08X", ret);
   pthread_mutex_lock(mutex);
   return ret;

#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
#ifdef VITA

   pthread_mutex_init(&amp;cond-&gt;mutex,NULL);

   if (cond-&gt;mutex&lt;0)
      return cond-&gt;mutex;

   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) cond);
   cond-&gt;sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);

   if (cond-&gt;sema &lt; 0)
   {
      pthread_mutex_destroy(&amp;cond-&gt;mutex);
      return cond-&gt;sema;
   }

   cond-&gt;waiting = 0;

   return 0;

#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
#ifdef VITA
	pthread_mutex_lock(&amp;cond-&gt;mutex);
	if (cond-&gt;waiting)
   {
		--cond-&gt;waiting;
		sceKernelSignalSema(cond-&gt;sema, 1);
	}
	pthread_mutex_unlock(&amp;cond-&gt;mutex);
	return 0;
#else
   /* FIXME: stub */
   return 1;
#endif
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   /* FIXME: stub */
   return 1;
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
#ifdef VITA
   int ret = sceKernelDeleteSema(cond-&gt;sema);
   if (ret &lt; 0)
    return ret;

   return sceKernelDeleteMutex(cond-&gt;mutex);
#else
  /* FIXME: stub */
  return 1;
#endif
}

static INLINE int pthread_detach(pthread_t thread)
{
   return 0;
}

static INLINE void pthread_exit(void *retval)
{
#ifdef VITA
   sceKernelExitDeleteThread(sceKernelGetThreadId());
#endif
}

static INLINE pthread_t pthread_self(void)
{
   /* zero 20-mar-2016: untested */
   return sceKernelGetThreadId();
}

static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
{
	 return t1 == t2;
}

#endif /* _PSP_PTHREAD_WRAP__ */</pre>
<h2>./include/libretro-common/rthreads/rthreads.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rthreads.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef __unix__
#ifndef __sun__
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309
#endif
#endif
#endif

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;boolean.h&gt;
#include &lt;rthreads/rthreads.h&gt;

/* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32. Maybe only supported in MSVC&gt;=2005  */

#if defined(_WIN32) &amp;&amp; !defined(RETRO_WIN32_USE_PTHREADS)
#define USE_WIN32_THREADS
#ifdef _XBOX
#include &lt;xtl.h&gt;
#else
#define WIN32_LEAN_AND_MEAN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */
#endif
#include &lt;windows.h&gt;
#include &lt;mmsystem.h&gt;
#endif
#elif defined(GEKKO)
#include &lt;ogc/lwp_watchdog.h&gt;
#include "gx_pthread.h"
#elif defined(_3DS)
#include "ctr_pthread.h"
#else
#include &lt;pthread.h&gt;
#include &lt;time.h&gt;
#endif

#if defined(VITA) || defined(BSD) || defined(ORBIS) || defined(__mips__) || defined(_3DS)
#include &lt;sys/time.h&gt;
#endif

#if defined(PS2)
#include &lt;ps2sdkapi.h&gt;
#endif

#ifdef __MACH__
#include &lt;mach/clock.h&gt;
#include &lt;mach/mach.h&gt;
#endif

struct thread_data
{
   void (*func)(void*);
   void *userdata;
};

struct sthread
{
#ifdef USE_WIN32_THREADS
   HANDLE thread;
   DWORD id;
#else
   pthread_t id;
#endif
};

struct slock
{
#ifdef USE_WIN32_THREADS
   CRITICAL_SECTION lock;
#else
   pthread_mutex_t lock;
#endif
};

#ifdef USE_WIN32_THREADS
/* The syntax we'll use is mind-bending unless we use a struct. Plus, we might want to store more info later */
/* This will be used as a linked list immplementing a queue of waiting threads */
struct queue_entry
{
   struct queue_entry *next;
};
#endif

struct scond
{
#ifdef USE_WIN32_THREADS
   /* With this implementation of scond, we don't have any way of waking
    * (or even identifying) specific threads
    * But we need to wake them in the order indicated by the queue.
    * This potato token will get get passed around every waiter.
    * The bearer can test whether he's next, and hold onto the potato if he is.
    * When he's done he can then put it back into play to progress
    * the queue further */
   HANDLE hot_potato;

   /* The primary signalled event. Hot potatoes are passed until this is set. */
   HANDLE event;

   /* the head of the queue; NULL if queue is empty */
   struct queue_entry *head;

   /* equivalent to the queue length */
   int waiters;

   /* how many waiters in the queue have been conceptually wakened by signals
    * (even if we haven't managed to actually wake them yet) */
   int wakens;

   /* used to control access to this scond, in case the user fails */
   CRITICAL_SECTION cs;

#else
   pthread_cond_t cond;
#endif
};

#ifdef USE_WIN32_THREADS
static DWORD CALLBACK thread_wrap(void *data_)
#else
static void *thread_wrap(void *data_)
#endif
{
   struct thread_data *data = (struct thread_data*)data_;
   if (!data)
	   return 0;
   data-&gt;func(data-&gt;userdata);
   free(data);
   return 0;
}

sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
{
	return sthread_create_with_priority(thread_func, userdata, 0);
}

/* TODO/FIXME - this needs to be implemented for Switch/3DS */
#if !defined(SWITCH) &amp;&amp; !defined(USE_WIN32_THREADS) &amp;&amp; !defined(_3DS) &amp;&amp; !defined(GEKKO) &amp;&amp; !defined(__HAIKU__) &amp;&amp; !defined(EMSCRIPTEN)
#define HAVE_THREAD_ATTR
#endif

sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority)
{
#ifdef HAVE_THREAD_ATTR
   pthread_attr_t thread_attr;
   bool thread_attr_needed  = false;
#endif
   bool thread_created      = false;
   struct thread_data *data = NULL;
   sthread_t *thread        = (sthread_t*)malloc(sizeof(*thread));

   if (!thread)
      return NULL;

   if (!(data = (struct thread_data*)malloc(sizeof(*data))))
   {
      free(thread);
      return NULL;
   }

   data-&gt;func               = thread_func;
   data-&gt;userdata           = userdata;

   thread-&gt;id               = 0;
#ifdef USE_WIN32_THREADS
   thread-&gt;thread           = CreateThread(NULL, 0, thread_wrap,
         data, 0, &amp;thread-&gt;id);
   thread_created           = !!thread-&gt;thread;
#else
#ifdef HAVE_THREAD_ATTR
   pthread_attr_init(&amp;thread_attr);

   if ((thread_priority &gt;= 1) &amp;&amp; (thread_priority &lt;= 100))
   {
      struct sched_param sp;
      memset(&amp;sp, 0, sizeof(struct sched_param));
      sp.sched_priority = thread_priority;
      pthread_attr_setschedpolicy(&amp;thread_attr, SCHED_RR);
      pthread_attr_setschedparam(&amp;thread_attr, &amp;sp);

      thread_attr_needed = true;
   }

#if defined(VITA)
   pthread_attr_setstacksize(&amp;thread_attr , 0x10000 );
   thread_attr_needed = true;
#elif defined(__APPLE__)
   /* Default stack size on Apple is 512Kb;
    * for PS2 disc scanning and other reasons, we'd like 2MB. */
   pthread_attr_setstacksize(&amp;thread_attr , 0x200000 );
   thread_attr_needed = true;
#endif

   if (thread_attr_needed)
      thread_created = pthread_create(&amp;thread-&gt;id, &amp;thread_attr, thread_wrap, data) == 0;
   else
      thread_created = pthread_create(&amp;thread-&gt;id, NULL, thread_wrap, data) == 0;

   pthread_attr_destroy(&amp;thread_attr);
#else
   thread_created    = pthread_create(&amp;thread-&gt;id, NULL, thread_wrap, data) == 0;
#endif

#endif

   if (thread_created)
      return thread;
   free(data);
   free(thread);
   return NULL;
}

int sthread_detach(sthread_t *thread)
{
#ifdef USE_WIN32_THREADS
   CloseHandle(thread-&gt;thread);
   free(thread);
   return 0;
#else
   int ret = pthread_detach(thread-&gt;id);
   free(thread);
   return ret;
#endif
}

void sthread_join(sthread_t *thread)
{
   if (!thread)
      return;
#ifdef USE_WIN32_THREADS
   WaitForSingleObject(thread-&gt;thread, INFINITE);
   CloseHandle(thread-&gt;thread);
#else
   pthread_join(thread-&gt;id, NULL);
#endif
   free(thread);
}

#if !defined(GEKKO)
bool sthread_isself(sthread_t *thread)
{
#ifdef USE_WIN32_THREADS
   return thread ? GetCurrentThreadId() == thread-&gt;id        : false;
#else
   return thread ? pthread_equal(pthread_self(), thread-&gt;id) : false;
#endif
}
#endif

slock_t *slock_new(void)
{
   slock_t      *lock = (slock_t*)calloc(1, sizeof(*lock));
   if (!lock)
      return NULL;
#ifdef USE_WIN32_THREADS
   InitializeCriticalSection(&amp;lock-&gt;lock);
#else
   if (pthread_mutex_init(&amp;lock-&gt;lock, NULL) != 0)
   {
      free(lock);
      return NULL;
   }
#endif
   return lock;
}

void slock_free(slock_t *lock)
{
   if (!lock)
      return;

#ifdef USE_WIN32_THREADS
   DeleteCriticalSection(&amp;lock-&gt;lock);
#else
   pthread_mutex_destroy(&amp;lock-&gt;lock);
#endif
   free(lock);
}

void slock_lock(slock_t *lock)
{
   if (!lock)
      return;
#ifdef USE_WIN32_THREADS
   EnterCriticalSection(&amp;lock-&gt;lock);
#else
   pthread_mutex_lock(&amp;lock-&gt;lock);
#endif
}

bool slock_try_lock(slock_t *lock)
{
#ifdef USE_WIN32_THREADS
   return lock &amp;&amp; TryEnterCriticalSection(&amp;lock-&gt;lock);
#else
   return lock &amp;&amp; (pthread_mutex_trylock(&amp;lock-&gt;lock) == 0);
#endif
}

void slock_unlock(slock_t *lock)
{
   if (!lock)
      return;
#ifdef USE_WIN32_THREADS
   LeaveCriticalSection(&amp;lock-&gt;lock);
#else
   pthread_mutex_unlock(&amp;lock-&gt;lock);
#endif
}

scond_t *scond_new(void)
{
   scond_t      *cond = (scond_t*)calloc(1, sizeof(*cond));

   if (!cond)
      return NULL;

#ifdef USE_WIN32_THREADS
   /* This is very complex because recreating condition variable semantics
    * with Win32 parts is not easy.
    *
    * The main problem is that a condition variable can't be used to
    * "pre-wake" a thread (it will get wakened only after it's waited).
    *
    * Whereas a win32 event can pre-wake a thread (the event will be set
    * in advance, so a 'waiter' won't even have to wait on it).
    *
    * Keep in mind a condition variable can apparently pre-wake a thread,
    * insofar as spurious wakeups are always possible,
    * but nobody will be expecting this and it does not need to be simulated.
    *
    * Moreover, we won't be doing this, because it counts as a spurious wakeup
    * -- someone else with a genuine claim must get wakened, in any case.
    *
    * Therefore we choose to wake only one of the correct waiting threads.
    * So at the very least, we need to do something clever. But there's
    * bigger problems.
    * We don't even have a straightforward way in win32 to satisfy
    * pthread_cond_wait's atomicity requirement. The bulk of this
    * algorithm is solving that.
    *
    * Note: We might could simplify this using vista+ condition variables,
    * but we wanted an XP compatible solution. */
   if (!(cond-&gt;event = CreateEvent(NULL, FALSE, FALSE, NULL)))
   {
      free(cond);
      return NULL;
   }
   if (!(cond-&gt;hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL)))
   {
      CloseHandle(cond-&gt;event);
      free(cond);
      return NULL;
   }

   InitializeCriticalSection(&amp;cond-&gt;cs);
#else
   if (pthread_cond_init(&amp;cond-&gt;cond, NULL) != 0)
   {
      free(cond);
      return NULL;
   }
#endif

   return cond;
}

void scond_free(scond_t *cond)
{
   if (!cond)
      return;

#ifdef USE_WIN32_THREADS
   CloseHandle(cond-&gt;event);
   CloseHandle(cond-&gt;hot_potato);
   DeleteCriticalSection(&amp;cond-&gt;cs);
#else
   pthread_cond_destroy(&amp;cond-&gt;cond);
#endif
   free(cond);
}

#ifdef USE_WIN32_THREADS
static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds)
{
   struct queue_entry myentry;
   struct queue_entry **ptr;

#if _WIN32_WINNT &gt;= 0x0500 || defined(_XBOX)
   static LARGE_INTEGER performanceCounterFrequency;
   LARGE_INTEGER tsBegin;
   static bool first_init  = true;
#else
   static bool beginPeriod = false;
   DWORD tsBegin;
#endif
   DWORD waitResult;
   DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head,
                                             we don't do the hot potato stuff,
                                             so this timeout needs presetting. */

   /* Reminder: `lock` is held before this is called. */
   /* however, someone else may have called scond_signal without the lock. soo... */
   EnterCriticalSection(&amp;cond-&gt;cs);

   /* since this library is meant for realtime game software
    * I have no problem setting this to 1 and forgetting about it. */
#if _WIN32_WINNT &gt;= 0x0500 || defined(_XBOX)
   if (first_init)
   {
      performanceCounterFrequency.QuadPart = 0;
      first_init = false;
   }

   if (performanceCounterFrequency.QuadPart == 0)
      QueryPerformanceFrequency(&amp;performanceCounterFrequency);
#else
   if (!beginPeriod)
   {
      beginPeriod = true;
      timeBeginPeriod(1);
   }
#endif

   /* Now we can take a good timestamp for use in faking the timeout ourselves. */
   /* But don't bother unless we need to (to save a little time) */
   if (dwMilliseconds != INFINITE)
#if _WIN32_WINNT &gt;= 0x0500 || defined(_XBOX)
      QueryPerformanceCounter(&amp;tsBegin);
#else
      tsBegin = timeGetTime();
#endif

   /* add ourselves to a queue of waiting threads */
   ptr = &amp;cond-&gt;head;

   /* walk to the end of the linked list */
   while (*ptr)
      ptr       = &amp;((*ptr)-&gt;next);

   *ptr         = &amp;myentry;
   myentry.next = NULL;

   cond-&gt;waiters++;

   /* now the conceptual lock release and condition block are supposed to be atomic.
    * we can't do that in Windows, but we can simulate the effects by using
    * the queue, by the following analysis:
    * What happens if they aren't atomic?
    *
    * 1. a signaller can rush in and signal, expecting a waiter to get it;
    * but the waiter wouldn't, because he isn't blocked yet.
    * Solution: Win32 events make this easy. The event will sit there enabled
    *
    * 2. a signaller can rush in and signal, and then turn right around and wait.
    * Solution: the signaller will get queued behind the waiter, who's
    * enqueued before he releases the mutex. */

   /* It's my turn if I'm the head of the queue.
    * Check to see if it's my turn. */
   while (cond-&gt;head != &amp;myentry)
   {
      /* It isn't my turn: */
      DWORD timeout = INFINITE;

      /* As long as someone is even going to be able to wake up
       * when they receive the potato, keep it going round. */
      if (cond-&gt;wakens &gt; 0)
         SetEvent(cond-&gt;hot_potato);

      /* Assess the remaining timeout time */
      if (dwMilliseconds != INFINITE)
      {
#if _WIN32_WINNT &gt;= 0x0500 || defined(_XBOX)
         LARGE_INTEGER now;
         LONGLONG elapsed;

         QueryPerformanceCounter(&amp;now);
         elapsed  = now.QuadPart - tsBegin.QuadPart;
         elapsed *= 1000;
         elapsed /= performanceCounterFrequency.QuadPart;
#else
         DWORD now     = timeGetTime();
         DWORD elapsed = now - tsBegin;
#endif

         /* Try one last time with a zero timeout (keeps the code simpler) */
         if (elapsed &gt; dwMilliseconds)
            elapsed = dwMilliseconds;

         timeout = dwMilliseconds - elapsed;
      }

      /* Let someone else go */
      LeaveCriticalSection(&amp;lock-&gt;lock);
      LeaveCriticalSection(&amp;cond-&gt;cs);

      /* Wait a while to catch the hot potato..
       * someone else should get a chance to go */
      /* After all, it isn't my turn (and it must be someone else's) */
      Sleep(0);
      waitResult = WaitForSingleObject(cond-&gt;hot_potato, timeout);

      /* I should come out of here with the main lock taken */
      EnterCriticalSection(&amp;lock-&gt;lock);
      EnterCriticalSection(&amp;cond-&gt;cs);

      if (waitResult == WAIT_TIMEOUT)
      {
         /* Out of time! Now, let's think about this. I do have the potato now--
          * maybe it's my turn, and I have the event?
          * If that's the case, I could proceed right now without aborting
          * due to timeout.
          *
          * However.. I DID wait a real long time. The caller was willing
          * to wait that long.
          *
          * I choose to give him one last chance with a zero timeout
          * in the next step
          */
         if (cond-&gt;head == &amp;myentry)
         {
            dwFinalTimeout = 0;
            break;
         }
         else
         {
            /* It's not our turn and we're out of time. Give up.
             * Remove ourself from the queue and bail. */
            struct queue_entry *curr = cond-&gt;head;

            while (curr-&gt;next != &amp;myentry)
               curr = curr-&gt;next;
            curr-&gt;next = myentry.next;
            cond-&gt;waiters--;
            LeaveCriticalSection(&amp;cond-&gt;cs);
            return false;
         }
      }

   }

   /* It's my turn now -- and I hold the potato */

   /* I still have the main lock, in any case */
   /* I need to release it so that someone can set the event */
   LeaveCriticalSection(&amp;lock-&gt;lock);
   LeaveCriticalSection(&amp;cond-&gt;cs);

   /* Wait for someone to actually signal this condition */
   /* We're the only waiter waiting on the event right now -- everyone else
    * is waiting on something different */
   waitResult = WaitForSingleObject(cond-&gt;event, dwFinalTimeout);

   /* Take the main lock so we can do work. Nobody else waits on this lock
    * for very long, so even though it's GO TIME we won't have to wait long */
   EnterCriticalSection(&amp;lock-&gt;lock);
   EnterCriticalSection(&amp;cond-&gt;cs);

   /* Remove ourselves from the queue */
   cond-&gt;head = myentry.next;
   cond-&gt;waiters--;

   if (waitResult == WAIT_TIMEOUT)
   {
      /* Oops! ran out of time in the final wait. Just bail. */
      LeaveCriticalSection(&amp;cond-&gt;cs);
      return false;
   }

   /* If any other wakenings are pending, go ahead and set it up  */
   /* There may actually be no waiters. That's OK. The first waiter will come in,
    * find it's his turn, and immediately get the signaled event */
   cond-&gt;wakens--;
   if (cond-&gt;wakens &gt; 0)
   {
      SetEvent(cond-&gt;event);

      /* Progress the queue: Put the hot potato back into play. It'll be
       * tossed around until next in line gets it */
      SetEvent(cond-&gt;hot_potato);
   }

   LeaveCriticalSection(&amp;cond-&gt;cs);
   return true;
}
#endif

void scond_wait(scond_t *cond, slock_t *lock)
{
#ifdef USE_WIN32_THREADS
   _scond_wait_win32(cond, lock, INFINITE);
#else
   pthread_cond_wait(&amp;cond-&gt;cond, &amp;lock-&gt;lock);
#endif
}

int scond_broadcast(scond_t *cond)
{
#ifdef USE_WIN32_THREADS
   /* Remember, we currently have mutex */
   if (cond-&gt;waiters != 0)
   {
      /* Awaken everything which is currently queued up */
      if (cond-&gt;wakens == 0)
         SetEvent(cond-&gt;event);
      cond-&gt;wakens = cond-&gt;waiters;

      /* Since there is now at least one pending waken, the potato must be in play */
      SetEvent(cond-&gt;hot_potato);
   }
   return 0;
#else
   return pthread_cond_broadcast(&amp;cond-&gt;cond);
#endif
}

void scond_signal(scond_t *cond)
{
#ifdef USE_WIN32_THREADS

   /* Unfortunately, pthread_cond_signal does not require that the
    * lock be held in advance */
   /* To avoid stomping on the condvar from other threads, we need
    * to control access to it with this */
   EnterCriticalSection(&amp;cond-&gt;cs);

   /* remember: we currently have mutex */
   if (cond-&gt;waiters == 0)
   {
      LeaveCriticalSection(&amp;cond-&gt;cs);
      return;
   }

   /* wake up the next thing in the queue */
   if (cond-&gt;wakens == 0)
      SetEvent(cond-&gt;event);

   cond-&gt;wakens++;

   /* The data structure is done being modified.. I think we can leave the CS now.
    * This would prevent some other thread from receiving the hot potato and then
    * immediately stalling for the critical section.
    * But remember, we were trying to replicate a semantic where this entire
    * scond_signal call was controlled (by the user) by a lock.
    * So in case there's trouble with this, we can move it after SetEvent() */
   LeaveCriticalSection(&amp;cond-&gt;cs);

   /* Since there is now at least one pending waken, the potato must be in play */
   SetEvent(cond-&gt;hot_potato);

#else
   pthread_cond_signal(&amp;cond-&gt;cond);
#endif
}

bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
{
#ifdef USE_WIN32_THREADS
   /* How to convert a microsecond (us) timeout to millisecond (ms)?
    *
    * Someone asking for a 0 timeout clearly wants immediate timeout.
    * Someone asking for a 1 timeout clearly wants an actual timeout
    * of the minimum length */
   /* The implementation of a 0 timeout here with pthreads is sketchy.
    * It isn't clear what happens if pthread_cond_timedwait is called with NOW.
    * Moreover, it is possible that this thread gets preempted after the
    * clock_gettime but before the pthread_cond_timedwait.
    * In order to help smoke out problems caused by this strange usage,
    * let's treat a 0 timeout as always timing out.
    */
   if (timeout_us == 0)
      return false;
   else if (timeout_us &lt; 1000)
      return _scond_wait_win32(cond, lock, 1);
   /* Someone asking for 1000 or 1001 timeout shouldn't
    * accidentally get 2ms. */
   return _scond_wait_win32(cond, lock, timeout_us / 1000);
#else
   int64_t seconds, remainder;
   struct timespec now;
#ifdef __MACH__
   /* OSX doesn't have clock_gettime. */
   clock_serv_t cclock;
   mach_timespec_t mts;
   host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &amp;cclock);
   clock_get_time(cclock, &amp;mts);
   mach_port_deallocate(mach_task_self(), cclock);
   now.tv_sec = mts.tv_sec;
   now.tv_nsec = mts.tv_nsec;
#elif !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
   sys_time_sec_t s;
   sys_time_nsec_t n;
   sys_time_get_current_time(&amp;s, &amp;n);
   now.tv_sec            = s;
   now.tv_nsec           = n;
#elif defined(PS2)
   int tickms            = ps2_clock();
   now.tv_sec            = tickms / 1000;
   now.tv_nsec           = tickms * 1000;
#elif !defined(DINGUX_BETA) &amp;&amp; (defined(__mips__) || defined(VITA) || defined(_3DS))
   struct timeval tm;
   gettimeofday(&amp;tm, NULL);
   now.tv_sec            = tm.tv_sec;
   now.tv_nsec           = tm.tv_usec * 1000;
#elif defined(RETRO_WIN32_USE_PTHREADS)
   _ftime64_s(&amp;now);
#elif defined(GEKKO)
   /* Avoid gettimeofday due to it being reported to be broken */
   const uint64_t tickms = gettime() / TB_TIMER_CLOCK;
   now.tv_sec            = tickms / 1000;
   now.tv_nsec           = tickms * 1000;
#else
   clock_gettime(CLOCK_REALTIME, &amp;now);
#endif

   seconds              = timeout_us / INT64_C(1000000);
   remainder            = timeout_us % INT64_C(1000000);

   now.tv_sec          += seconds;
   now.tv_nsec         += remainder * INT64_C(1000);

   if (now.tv_nsec &gt; 1000000000)
   {
      now.tv_nsec      -= 1000000000;
      now.tv_sec       += 1;
   }

   return (pthread_cond_timedwait(&amp;cond-&gt;cond, &amp;lock-&gt;lock, &amp;now) == 0);
#endif
}

#ifdef HAVE_THREAD_STORAGE
bool sthread_tls_create(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
   return (*tls = TlsAlloc()) != TLS_OUT_OF_INDEXES;
#else
   return pthread_key_create((pthread_key_t*)tls, NULL) == 0;
#endif
}

bool sthread_tls_delete(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
   return TlsFree(*tls) != 0;
#else
   /* TODO/FIXME - broken for UCRT */
   return pthread_key_delete(*tls) == 0;
#endif
}

void *sthread_tls_get(sthread_tls_t *tls)
{
#ifdef USE_WIN32_THREADS
   return TlsGetValue(*tls);
#else
   /* TODO/FIXME - broken for UCRT */
   return pthread_getspecific(*tls);
#endif
}

bool sthread_tls_set(sthread_tls_t *tls, const void *data)
{
#ifdef USE_WIN32_THREADS
   return TlsSetValue(*tls, (void*)data) != 0;
#else
   /* TODO/FIXME - broken for UCRT */
   return pthread_setspecific(*tls, data) == 0;
#endif
}
#endif

uintptr_t sthread_get_thread_id(sthread_t *thread)
{
   if (thread)
      return (uintptr_t)thread-&gt;id;
   return 0;
}

uintptr_t sthread_get_current_thread_id(void)
{
#ifdef USE_WIN32_THREADS
   return (uintptr_t)GetCurrentThreadId();
#else
   return (uintptr_t)pthread_self();
#endif
}</pre>
<h2>./include/libretro-common/rthreads/tpool.c</h2>
<pre>/*
 * Copyright (c) 2010-2020 The RetroArch team
 * Copyright (c) 2017 John Schember &lt;john@nachtimwald.com&gt;
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (tpool.c).
 * ---------------------------------------------------------------------------------------
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE
 */

#include &lt;stdlib.h&gt;
#include &lt;boolean.h&gt;

#include &lt;rthreads/rthreads.h&gt;
#include &lt;rthreads/tpool.h&gt;

/* Work object which will sit in a queue
 * waiting for the pool to process it.
 *
 * It is a singly linked list acting as a FIFO queue. */
struct tpool_work
{
   thread_func_t      func;  /* Function to be called. */
   void              *arg;   /* Data to be passed to func. */
   struct tpool_work *next;  /* Next work item in the queue. */
};
typedef struct tpool_work tpool_work_t;

struct tpool
{
   tpool_work_t    *work_first;   /* First work item in the work queue. */
   tpool_work_t    *work_last;    /* Last work item in the work queue. */
   slock_t         *work_mutex;   /* Mutex protecting inserting and removing work from the work queue. */
   scond_t         *work_cond;    /* Conditional to signal when there is work to process. */
   scond_t         *working_cond; /* Conditional to signal when there is no work processing.
                                       This will also signal when there are no threads running. */
   size_t           working_cnt;  /* The number of threads processing work (Not waiting for work). */
   size_t           thread_cnt;   /* Total number of threads within the pool. */
   bool             stop;         /* Marker to tell the work threads to exit. */
};

static tpool_work_t *tpool_work_create(thread_func_t func, void *arg)
{
   tpool_work_t *work;

   if (!func)
      return NULL;

   work       = (tpool_work_t*)calloc(1, sizeof(*work));
   work-&gt;func = func;
   work-&gt;arg  = arg;
   work-&gt;next = NULL;
   return work;
}

static void tpool_work_destroy(tpool_work_t *work)
{
   if (work)
      free(work);
}

/* Pull the first work item out of the queue. */
static tpool_work_t *tpool_work_get(tpool_t *tp)
{
   tpool_work_t *work;

   if (!tp)
      return NULL;

   work = tp-&gt;work_first;
   if (!work)
      return NULL;

   if (!work-&gt;next)
   {
      tp-&gt;work_first = NULL;
      tp-&gt;work_last  = NULL;
   }
   else
      tp-&gt;work_first = work-&gt;next;

   return work;
}

static void tpool_worker(void *arg)
{
   tpool_work_t *work = NULL;
   tpool_t      *tp   = (tpool_t*)arg;

   for (;;)
   {
      slock_lock(tp-&gt;work_mutex);
      /* Keep running until told to stop. */
      if (tp-&gt;stop)
         break;

      /* If there is no work in the queue wait in the conditional until
       * there is work to take. */
      if (!tp-&gt;work_first)
         scond_wait(tp-&gt;work_cond, tp-&gt;work_mutex);

      /* Try to pull work from the queue. */
      work = tpool_work_get(tp);
      tp-&gt;working_cnt++;
      slock_unlock(tp-&gt;work_mutex);

      /* Call the work function and let it process.
       *
       * work can legitimately be NULL. Since multiple threads from the pool
       * will wake when there is work, a thread might not get any work. 1
       * piece of work and 2 threads, both will wake but with 1 only work 1
       * will get the work and the other won't.
       *
       * working_cnt has been increment and work could be NULL. While it's
       * not true there is work processing the thread is considered working
       * because it's not waiting in the conditional. Pedantic but...
       */
      if (work)
      {
         work-&gt;func(work-&gt;arg);
         tpool_work_destroy(work);
      }

      slock_lock(tp-&gt;work_mutex);
      tp-&gt;working_cnt--;
      /* Since we're in a lock no work can be added or removed form the queue.
       * Also, the working_cnt can't be changed (except the thread holding the lock).
       * At this point if there isn't any work processing and if there is no work
       * signal this is the case. */
      if (!tp-&gt;stop &amp;&amp; tp-&gt;working_cnt == 0 &amp;&amp; !tp-&gt;work_first)
         scond_signal(tp-&gt;working_cond);
      slock_unlock(tp-&gt;work_mutex);
   }

   tp-&gt;thread_cnt--;
   if (tp-&gt;thread_cnt == 0)
      scond_signal(tp-&gt;working_cond);
   slock_unlock(tp-&gt;work_mutex);
}

tpool_t *tpool_create(size_t num)
{
   tpool_t   *tp;
   sthread_t *thread;
   size_t     i;

   if (num == 0)
      num = 2;

   tp               = (tpool_t*)calloc(1, sizeof(*tp));
   tp-&gt;thread_cnt   = num;

   tp-&gt;work_mutex   = slock_new();
   tp-&gt;work_cond    = scond_new();
   tp-&gt;working_cond = scond_new();

   tp-&gt;work_first   = NULL;
   tp-&gt;work_last    = NULL;

   /* Create the requested number of thread and detach them. */
   for (i = 0; i &lt; num; i++)
   {
      thread = sthread_create(tpool_worker, tp);
      sthread_detach(thread);
   }

   return tp;
}

void tpool_destroy(tpool_t *tp)
{
   tpool_work_t *work;
   tpool_work_t *work2;

   if (!tp)
      return;

   /* Take all work out of the queue and destroy it. */
   slock_lock(tp-&gt;work_mutex);
   work = tp-&gt;work_first;
   while (work)
   {
      work2 = work-&gt;next;
      tpool_work_destroy(work);
      work = work2;
   }

   /* Tell the worker threads to stop. */
   tp-&gt;stop = true;
   scond_broadcast(tp-&gt;work_cond);
   slock_unlock(tp-&gt;work_mutex);

   /* Wait for all threads to stop. */
   tpool_wait(tp);

   slock_free(tp-&gt;work_mutex);
   scond_free(tp-&gt;work_cond);
   scond_free(tp-&gt;working_cond);

   free(tp);
}

bool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg)
{
   tpool_work_t *work;

   if (!tp)
      return false;

   work = tpool_work_create(func, arg);
   if (!work)
      return false;

   slock_lock(tp-&gt;work_mutex);
   if (!tp-&gt;work_first)
   {
      tp-&gt;work_first      = work;
      tp-&gt;work_last       = tp-&gt;work_first;
   }
   else
   {
      tp-&gt;work_last-&gt;next = work;
      tp-&gt;work_last       = work;
   }

   scond_broadcast(tp-&gt;work_cond);
   slock_unlock(tp-&gt;work_mutex);

   return true;
}

void tpool_wait(tpool_t *tp)
{
   if (!tp)
      return;

   slock_lock(tp-&gt;work_mutex);

   for (;;)
   {
      /* working_cond is dual use. It signals when we're not stopping but the
       * working_cnt is 0 indicating there isn't any work processing. If we
       * are stopping it will trigger when there aren't any threads running. */
      if ((!tp-&gt;stop &amp;&amp; tp-&gt;working_cnt != 0) || (tp-&gt;stop &amp;&amp; tp-&gt;thread_cnt != 0))
         scond_wait(tp-&gt;working_cond, tp-&gt;work_mutex);
      else
         break;
   }

   slock_unlock(tp-&gt;work_mutex);
}</pre>
<h2>./include/libretro-common/rthreads/wiiu_pthread.h</h2>
<pre>/* Copyright  (C) 2010-2016 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (wiiu_pthread.h).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef _WIIU_PTHREAD_WRAP_WIIU_
#define _WIIU_PTHREAD_WRAP_WIIU_

#include &lt;retro_inline.h&gt;
#include &lt;wiiu/os/condition.h&gt;
#include &lt;wiiu/os/thread.h&gt;
#include &lt;wiiu/os/mutex.h&gt;
#include &lt;malloc.h&gt;
#define STACKSIZE (8 * 1024)

typedef OSThread* pthread_t;
typedef OSMutex* pthread_mutex_t;
typedef void* pthread_mutexattr_t;
typedef int pthread_attr_t;
typedef OSCondition* pthread_cond_t;
typedef OSCondition* pthread_condattr_t;

static INLINE int pthread_create(pthread_t *thread,
      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
{
   OSThread *t = memalign(8, sizeof(OSThread));
   void *stack = memalign(32, STACKSIZE);
   bool ret = OSCreateThread(t, (OSThreadEntryPointFn)start_routine, 
      (uint32_t)arg, NULL, (void*)(((uint32_t)stack)+STACKSIZE), STACKSIZE, 8, OS_THREAD_ATTRIB_AFFINITY_ANY);
   if(ret == true)
   {
      OSResumeThread(t);
      *thread = t;
   }
   else
      *thread = NULL;
   return (ret == true) ? 0 : -1;
}

static INLINE pthread_t pthread_self(void)
{
   return OSGetCurrentThread();
}

static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
      const pthread_mutexattr_t *attr)
{
   OSMutex *m = malloc(sizeof(OSMutex));
   OSInitMutex(m);
   *mutex = m;
   return 0;
}

static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
   if(*mutex)
      free(*mutex);
   *mutex = NULL;
   return 0;
}

static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
{
   OSLockMutex(*mutex);
   return 0;
}

static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
   OSUnlockMutex(*mutex);
   return 0;
}

static INLINE void pthread_exit(void *retval)
{
   (void)retval;
   OSExitThread(0);
}

static INLINE int pthread_detach(pthread_t thread)
{
   OSDetachThread(thread);
   return 0;
}

static INLINE int pthread_join(pthread_t thread, void **retval)
{
   (void)retval;
   bool ret = OSJoinThread(thread, NULL);
   if(ret == true)
   {
      free(thread-&gt;stackEnd);
      free(thread);
   }
   return (ret == true) ? 0 : -1;
}

static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
   return OSTryLockMutex(*mutex);
}

static INLINE int pthread_cond_wait(pthread_cond_t *cond,
      pthread_mutex_t *mutex)
{
   OSWaitCond(*cond, *mutex);
   return 0;
}

static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
      pthread_mutex_t *mutex, const struct timespec *abstime)
{
   //FIXME: actual timeout needed
   (void)abstime;
   return pthread_cond_wait(cond, mutex);
}

static INLINE int pthread_cond_init(pthread_cond_t *cond,
      const pthread_condattr_t *attr)
{
   OSCondition *c = malloc(sizeof(OSCondition));
   OSInitCond(c);
   *cond = c;
   return 0;
}

static INLINE int pthread_cond_signal(pthread_cond_t *cond)
{
   OSSignalCond(*cond);
   return 0;
}

static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
{
   //FIXME: no OS equivalent
   (void)cond;
   return 0;
}

static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
{
   if(*cond)
      free(*cond);
   *cond = NULL;
   return 0;
}

extern int pthread_equal(pthread_t t1, pthread_t t2);

#endif</pre>
<h2>./include/libretro-common/rthreads/xenon_sdl_threads.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (xenon_sdl_threads.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;) */

#include "SDL_thread.h"
#include "SDL_mutex.h"
#include &lt;stdlib.h&gt;
#include &lt;boolean.h&gt;

SDL_cond *SDL_CreateCond(void)
{
   bool *sleeping = calloc(1, sizeof(*sleeping));
   return (SDL_cond*)sleeping;
}

void SDL_DestroyCond(SDL_cond *sleeping)
{
   free(sleeping);
}

int SDL_CondWait(SDL_cond *cond, SDL_mutex *lock)
{
   (void)lock;
   volatile bool *sleeping = (volatile bool*)cond;

   SDL_mutexV(lock);
   *sleeping = true;
   while (*sleeping); /* Yeah, we all love busyloops don't we? ._. */
   SDL_mutexP(lock);

   return 0;
}

int SDL_CondSignal(SDL_cond *cond)
{
   *(volatile bool*)cond = false;
   return 0;
}</pre>
<h2>./include/libretro-common/samples/compat/fnmatch/compat_fnmatch_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (compat_fnmatch_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;assert.h&gt;
#include &lt;stddef.h&gt;

#include &lt;compat/fnmatch.h&gt;

int main(void)
{
   assert(rl_fnmatch("TEST", "TEST", 0) == 0);
   assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
   assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
   assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0);
   assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0);
   assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0);
   assert(rl_fnmatch("TEST*", "TEST", 0) == 0);
   assert(rl_fnmatch("TEST**", "TEST", 0) == 0);
   assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0);
   assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0);
   assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0);
   assert(rl_fnmatch("TE**ST", "TEST", 0) == 0);
   assert(rl_fnmatch("TE**ST", "TExST", 0) == 0);
   assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0);
   assert(rl_fnmatch("*.*", "test.jpg", 0) == 0);
   assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0);
   assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0);
   assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0);
   assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH);
   assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH);
}</pre>
<h2>./include/libretro-common/samples/compat/fnmatch/Makefile</h2>
<pre>TARGET := compat_fnmatch_test

LIBRETRO_COMM_DIR := ../../..

SOURCES := \
	compat_fnmatch_test.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_fnmatch.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/compat/snprintf/Makefile</h2>
<pre>TARGET := snprintf

CORE_DIR          := .
LIBRETRO_COMM_DIR := ../../..

SOURCES_C := 	\
	$(CORE_DIR)/snprintf_test.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c

OBJS := $(SOURCES_C:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/compat/snprintf/snprintf_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (snprintf_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;

#include &lt;compat/strl.h&gt;

int main(int argc, char *argv[])
{
   char s[128];
   char *variable      = "test1";
   char *variable2     = "test2";
   char *variable3     = "test3";
   char *variable4     = "test4";
   char *variable5     = "test5";
   char *variable6     = "test6";
   int ret             = snprintf(s,
         sizeof(s), "%s%s%s%s%s%s%s%s%s%s%s", variable,
         " : ", variable2,
         " : ", variable3,
         " : ", variable4,
         " : ", variable5,
         " : ", variable6
         );

   fprintf(stderr, "[%d], %s\n", ret, s);

   return 0;
}</pre>
<h2>./include/libretro-common/samples/compat/strl/Makefile</h2>
<pre>TARGET := strl

CORE_DIR          := .
LIBRETRO_COMM_DIR := ../../..

SOURCES_C := 	\
	$(CORE_DIR)/strl_test.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c

OBJS := $(SOURCES_C:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/compat/strl/strl_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (strl_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;

#include &lt;compat/strl.h&gt;

int main(int argc, char *argv[])
{
   char s[128];
   char *variable      = "test1";
   char *variable2     = "test2";
   char *variable3     = "test3";
   char *variable4     = "test4";
   char *variable5     = "test5";
   char *variable6     = "test6";
   int ret             = strlcpy(s, variable, sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable2,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable3,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable4,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable5,sizeof(s));
   ret                 = strlcat(s, " : ",    sizeof(s));
   ret                 = strlcat(s, variable6,sizeof(s));

   fprintf(stderr, "[%d], %s\n", ret, s);

   return 0;
}</pre>
<h2>./include/libretro-common/samples/core_options/example_categories/conversion_scripts/core_option_regex.py</h2>
<pre>import re

# 0: full struct; 1: up to &amp; including first []; 2: content between first {}
p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*'
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'=\s*'  # =
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};')  # captures full struct, it's beginning and it's content
# 0: type name[]; 1: type; 2: name
p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*'
                         r'(option_cats[a-z_]{0,8}|option_defs([a-z_]{0,8}))\s*\[]')
# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
p_option = re.compile(r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\"|'  # key start; group 1
                      r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|'
                      r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|'
                      r'[a-zA-Z0-9_]+\s*\".*?\")\s*'  # key end
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\")\s*'  # description; group 2
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # group 3
                      r'(?:NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')+)'
                      r'(?:'  # defs only start
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # key/value pairs start; group 4
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option key
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*)'  # key/value pairs end
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:'  # defaults start
                      r'(?:NULL|\".*?\")\s*'  # default value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*'  # defaults end
                      r')?'  # defs only end
                      r'},')  # closing braces
# analyse option group 3
p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                    r',\s*'  # comma
                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*')
# analyse option group 4
p_key_value = re.compile(r'{\s*'  # opening braces
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option key; 1
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r',\s*'  # comma
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option value; 2
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'}\s*'  # closing braces
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r',?\s*'  # comma
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*')

p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")')</pre>
<h2>./include/libretro-common/samples/core_options/example_categories/conversion_scripts/v1_to_v2_converter.py</h2>
<pre>#!/usr/bin/env python3

"""Core options v1 to v2 converter

Just copy 'libretro_core_options.h' &amp; 'libretro_core_options_intl.h' into the same folder as this script
and run it! The original files will be preserved as *.v1
"""
import core_option_regex as cor
import os
import sys

if os.name == 'nt':
    joiner = '\\'
else:
    joiner = '/'
dir_path = os.path.dirname(os.path.realpath(__file__))
h_filename = joiner.join((dir_path, 'libretro_core_options.h'))
intl_filename = joiner.join((dir_path, 'libretro_core_options_intl.h'))


def create_v2_code_file(struct_text, file_name):
    def replace_option(option_match):
        _offset = option_match.start(0)

        if option_match.group(3):
            res = option_match.group(0)[:option_match.end(2) - _offset] + ',\n      NULL' + \
                  option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \
                  'NULL,\n      NULL,\n      ' + option_match.group(0)[option_match.end(3) - _offset:]
        else:
            return option_match.group(0)

        return res

    comment_v1 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 1.3\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    comment_v2 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 2.0\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 2.0: Add support for core options v2 interface\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    p_intl = cor.re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {'
                            r'((?:.|[\r\n])*?)};')
    p_set = cor.re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)'
                           r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif')
    new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\n' \
              '      bool *categories_supported)\n' \
              '{\n' \
              '   unsigned version  = 0;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '   unsigned language = 0;\n' \
              '#endif\n' \
              '\n' \
              '   if (!environ_cb || !categories_supported)\n' \
              '      return;\n' \
              '\n' \
              '   *categories_supported = false;\n' \
              '\n' \
              '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &amp;version))\n' \
              '      version = 0;\n' \
              '\n' \
              '   if (version &gt;= 2)\n' \
              '   {\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      struct retro_core_options_v2_intl core_options_intl;\n' \
              '\n' \
              '      core_options_intl.us    = &amp;options_us;\n' \
              '      core_options_intl.local = NULL;\n' \
              '\n' \
              '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;\n' \
              '          (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH))\n' \
              '         core_options_intl.local = options_intl[language];\n' \
              '\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n' \
              '            &amp;core_options_intl);\n' \
              '#else\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n' \
              '            &amp;options_us);\n' \
              '#endif\n' \
              '   }\n' \
              '   else\n' \
              '   {\n' \
              '      size_t i, j;\n' \
              '      size_t option_index              = 0;\n' \
              '      size_t num_options               = 0;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_us         = NULL;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      size_t num_options_intl          = 0;\n' \
              '      struct retro_core_option_v2_definition\n' \
              '            *option_defs_intl          = NULL;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_intl       = NULL;\n' \
              '      struct retro_core_options_intl\n' \
              '            core_options_v1_intl;\n' \
              '#endif\n' \
              '      struct retro_variable *variables = NULL;\n' \
              '      char **values_buf                = NULL;\n' \
              '\n' \
              '      /* Determine total number of options */\n' \
              '      while (true)\n' \
              '      {\n' \
              '         if (option_defs_us[num_options].key)\n' \
              '            num_options++;\n' \
              '         else\n' \
              '            break;\n' \
              '      }\n' \
              '\n' \
              '      if (version &gt;= 1)\n' \
              '      {\n' \
              '         /* Allocate US array */\n' \
              '         option_v1_defs_us = (struct retro_core_option_definition *)\n' \
              '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i &lt; num_options; i++)\n' \
              '         {\n' \
              '            struct retro_core_option_v2_definition *option_def_us = &amp;option_defs_us[i];\n' \
              '            struct retro_core_option_value *option_values         = option_def_us-&gt;values;\n' \
              '            struct retro_core_option_definition *option_v1_def_us = &amp;option_v1_defs_us[i];\n' \
              '            struct retro_core_option_value *option_v1_values      = option_v1_def_us-&gt;values;\n' \
              '\n' \
              '            option_v1_def_us-&gt;key           = option_def_us-&gt;key;\n' \
              '            option_v1_def_us-&gt;desc          = option_def_us-&gt;desc;\n' \
              '            option_v1_def_us-&gt;info          = option_def_us-&gt;info;\n' \
              '            option_v1_def_us-&gt;default_value = option_def_us-&gt;default_value;\n' \
              '\n' \
              '            /* Values must be copied individually... */\n' \
              '            while (option_values-&gt;value)\n' \
              '            {\n' \
              '               option_v1_values-&gt;value = option_values-&gt;value;\n' \
              '               option_v1_values-&gt;label = option_values-&gt;label;\n' \
              '\n' \
              '               option_values++;\n' \
              '               option_v1_values++;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;\n' \
              '             (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH) &amp;&amp;\n' \
              '             options_intl[language])\n' \
              '            option_defs_intl = options_intl[language]-&gt;definitions;\n' \
              '\n' \
              '         if (option_defs_intl)\n' \
              '         {\n' \
              '            /* Determine number of intl options */\n' \
              '            while (true)\n' \
              '            {\n' \
              '               if (option_defs_intl[num_options_intl].key)\n' \
              '                  num_options_intl++;\n' \
              '               else\n' \
              '                  break;\n' \
              '            }\n' \
              '\n' \
              '            /* Allocate intl array */\n' \
              '            option_v1_defs_intl = (struct retro_core_option_definition *)\n' \
              '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '            /* Copy parameters from option_defs_intl array */\n' \
              '            for (i = 0; i &lt; num_options_intl; i++)\n' \
              '            {\n' \
              '               struct retro_core_option_v2_definition *option_def_intl = &amp;option_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_values           = option_def_intl-&gt;values;\n' \
              '               struct retro_core_option_definition *option_v1_def_intl = &amp;option_v1_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl-&gt;values;\n' \
              '\n' \
              '               option_v1_def_intl-&gt;key           = option_def_intl-&gt;key;\n' \
              '               option_v1_def_intl-&gt;desc          = option_def_intl-&gt;desc;\n' \
              '               option_v1_def_intl-&gt;info          = option_def_intl-&gt;info;\n' \
              '               option_v1_def_intl-&gt;default_value = option_def_intl-&gt;default_value;\n' \
              '\n' \
              '               /* Values must be copied individually... */\n' \
              '               while (option_values-&gt;value)\n' \
              '               {\n' \
              '                  option_v1_values-&gt;value = option_values-&gt;value;\n' \
              '                  option_v1_values-&gt;label = option_values-&gt;label;\n' \
              '\n' \
              '                  option_values++;\n' \
              '                  option_v1_values++;\n' \
              '               }\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         core_options_v1_intl.us    = option_v1_defs_us;\n' \
              '         core_options_v1_intl.local = option_v1_defs_intl;\n' \
              '\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &amp;core_options_v1_intl);\n' \
              '#else\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\n' \
              '#endif\n' \
              '      }\n' \
              '      else\n' \
              '      {\n' \
              '         /* Allocate arrays */\n' \
              '         variables  = (struct retro_variable *)calloc(num_options + 1,\n' \
              '               sizeof(struct retro_variable));\n' \
              '         values_buf = (char **)calloc(num_options, sizeof(char *));\n' \
              '\n' \
              '         if (!variables || !values_buf)\n' \
              '            goto error;\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i &lt; num_options; i++)\n' \
              '         {\n' \
              '            const char *key                        = option_defs_us[i].key;\n' \
              '            const char *desc                       = option_defs_us[i].desc;\n' \
              '            const char *default_value              = option_defs_us[i].default_value;\n' \
              '            struct retro_core_option_value *values = option_defs_us[i].values;\n' \
              '            size_t buf_len                         = 3;\n' \
              '            size_t default_index                   = 0;\n' \
              '\n' \
              '            values_buf[i] = NULL;\n' \
              '\n' \
              '            if (desc)\n' \
              '            {\n' \
              '               size_t num_values = 0;\n' \
              '\n' \
              '               /* Determine number of values */\n' \
              '               while (true)\n' \
              '               {\n' \
              '                  if (values[num_values].value)\n' \
              '                  {\n' \
              '                     /* Check if this is the default value */\n' \
              '                     if (default_value)\n' \
              '                        if (strcmp(values[num_values].value, default_value) == 0)\n' \
              '                           default_index = num_values;\n' \
              '\n' \
              '                     buf_len += strlen(values[num_values].value);\n' \
              '                     num_values++;\n' \
              '                  }\n' \
              '                  else\n' \
              '                     break;\n' \
              '               }\n' \
              '\n' \
              '               /* Build values string */\n' \
              '               if (num_values &gt; 0)\n' \
              '               {\n' \
              '                  buf_len += num_values - 1;\n' \
              '                  buf_len += strlen(desc);\n' \
              '\n' \
              '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\n' \
              '                  if (!values_buf[i])\n' \
              '                     goto error;\n' \
              '\n' \
              '                  strcpy(values_buf[i], desc);\n' \
              '                  strcat(values_buf[i], "; ");\n' \
              '\n' \
              '                  /* Default value goes first */\n' \
              '                  strcat(values_buf[i], values[default_index].value);\n' \
              '\n' \
              '                  /* Add remaining values */\n' \
              '                  for (j = 0; j &lt; num_values; j++)\n' \
              '                  {\n' \
              '                     if (j != default_index)\n' \
              '                     {\n' \
              '                        strcat(values_buf[i], "|");\n' \
              '                        strcat(values_buf[i], values[j].value);\n' \
              '                     }\n' \
              '                  }\n' \
              '               }\n' \
              '            }\n' \
              '\n' \
              '            variables[option_index].key   = key;\n' \
              '            variables[option_index].value = values_buf[i];\n' \
              '            option_index++;\n' \
              '         }\n' \
              '\n' \
              '         /* Set variables */\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n' \
              '      }\n' \
              '\n' \
              'error:\n' \
              '      /* Clean up */\n' \
              '\n' \
              '      if (option_v1_defs_us)\n' \
              '      {\n' \
              '         free(option_v1_defs_us);\n' \
              '         option_v1_defs_us = NULL;\n' \
              '      }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      if (option_v1_defs_intl)\n' \
              '      {\n' \
              '         free(option_v1_defs_intl);\n' \
              '         option_v1_defs_intl = NULL;\n' \
              '      }\n' \
              '#endif\n' \
              '\n' \
              '      if (values_buf)\n' \
              '      {\n' \
              '         for (i = 0; i &lt; num_options; i++)\n' \
              '         {\n' \
              '            if (values_buf[i])\n' \
              '            {\n' \
              '               free(values_buf[i]);\n' \
              '               values_buf[i] = NULL;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         free(values_buf);\n' \
              '         values_buf = NULL;\n' \
              '      }\n' \
              '\n' \
              '      if (variables)\n' \
              '      {\n' \
              '         free(variables);\n' \
              '         variables = NULL;\n' \
              '      }\n' \
              '   }\n' \
              '}\n' \
              '\n' \
              '#ifdef __cplusplus\n' \
              '}\n' \
              '#endif'

    struct_groups = cor.p_struct.finditer(struct_text)
    out_text = struct_text

    for construct in struct_groups:
        repl_text = ''
        declaration = construct.group(1)
        struct_match = cor.p_type_name.search(declaration)
        if struct_match:
            struct_type_name = struct_match.group(1, 2)
        else:
            return -1

        if 'retro_core_option_definition' == struct_type_name[0]:
            import shutil
            shutil.copy(file_name, file_name + '.v1')
            new_declaration = f'\nstruct retro_core_option_v2_category option_cats_{struct_match.group(3)}[] = ' \
                              '{\n   { NULL, NULL, NULL },\n' \
                              '};\n\n' \
                              + declaration[:struct_match.start(1)] + \
                              'retro_core_option_v2_definition' \
                              + declaration[struct_match.end(1):]
            offset = construct.start(0)
            repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,
                                               construct.group(0)[:construct.start(2) - offset])
            content = construct.group(2)
            new_content = cor.p_option.sub(replace_option, content)

            repl_text = repl_text + new_content + cor.re.sub(r'{\s*NULL,\s*NULL,\s*NULL,\s*{\{0}},\s*NULL\s*},\s*};',
                                                             '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};'
                                                             '\n\nstruct retro_core_options_v2 options_' +
                                                             struct_match.group(3) + ' = {\n'
                                                             f'   option_cats_{struct_match.group(3)},\n'
                                                             f'   option_defs_{struct_match.group(3)}\n'
                                                             '};',
                                                             construct.group(0)[construct.end(2) - offset:])
            out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text)
        else:
            return -2
    with open(file_name, 'w', encoding='utf-8') as code_file:
        out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)
        intl = p_intl.search(out_text)
        if intl:
            new_intl = out_text[:intl.start(1)] \
                       + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \
                       + out_text[intl.end(1):intl.start(2)] + cor.re.sub(r'option_defs_', '&amp;options_', intl.group(2)) \
                       + out_text[intl.end(2):]
            out_text = p_set.sub(new_set, new_intl)
        else:
            out_text = p_set.sub(new_set, out_text)
        code_file.write(out_text)

    return 1


# --------------------          MAIN          -------------------- #

if __name__ == '__main__':
    try:
        for file in (h_filename, intl_filename):
            if os.path.isfile(file):
                with open(file, 'r+', encoding='utf-8') as h_file:
                    text = h_file.read()
                    test = create_v2_code_file(text, file)
                    if -1 &gt; test:
                        print('Your file looks like it already is v2? (' + file + ')')
                        continue
                    if 0 &gt; test:
                        print('An error occurred! Please make sure to use the complete v1 struct! (' + file + ')')
                        continue
            else:
                print(file + ' not found.')
    except EnvironmentError:
        print('Something went wrong with reading or writing files!')
        sys.exit(1)</pre>
<h2>./include/libretro-common/samples/core_options/example_categories/libretro_core_options.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;libretro.h&gt;
#include &lt;retro_inline.h&gt;

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_v2_category option_cats_us[] = {
   {
      "video",                     /* key (category name) */
      "Video",                     /* category description (label) */
      "Configure display options." /* category sublabel */
   },
   {
      "hacks",
      "Advanced",
      "Options affecting low-level emulation performance and accuracy."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      NULL,                                       /* 'categorised' description (used instead of
                                                   * 'description' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * description is always used */
      "Specify which region the system is from.", /* sublabel */
      NULL,                                       /* 'categorised' sublabel (used instead of
                                                   * 'sublabel' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * sublabel is always used */
      NULL,                                       /* category key (must match an entry in
                                                   * option_cats_us; if NULL or empty,
                                                   * option is uncategorised */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video &gt; Scale",   /* description: here a 'Video &gt;' prefix is used to
                          * signify a category on frontends without explicit
                          * category support */
      "Scale",           /* 'categorised' description: will be displayed inside
                          * the 'Video' submenu */
      "Set internal video scale factor.",
      NULL,
      "video",           /* category key */
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   {
      "mycore_overclock",
      "Advanced &gt; Reduce Slowdown",
      "Reduce Slowdown",
      "Enabling 'Advanced &gt; Reduce Slowdown' will reduce accuracy.", /* sublabel */
      "Enabling 'Reduce Slowdown' will reduce accuracy.",            /* 'categorised' sublabel:
                               * will be displayed inside the 'Advanced' submenu; note that
                               * 'Advanced &gt; Reduce Slowdown' is replaced with 'Reduce Slowdown' */
      "hacks",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_us = {
   option_cats_us,
   option_defs_us
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {
   &amp;options_us, /* RETRO_LANGUAGE_ENGLISH */
   NULL,        /* RETRO_LANGUAGE_JAPANESE */
   &amp;options_fr, /* RETRO_LANGUAGE_FRENCH */
   NULL,        /* RETRO_LANGUAGE_SPANISH */
   NULL,        /* RETRO_LANGUAGE_GERMAN */
   NULL,        /* RETRO_LANGUAGE_ITALIAN */
   NULL,        /* RETRO_LANGUAGE_DUTCH */
   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   NULL,        /* RETRO_LANGUAGE_RUSSIAN */
   NULL,        /* RETRO_LANGUAGE_KOREAN */
   NULL,        /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   NULL,        /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   NULL,        /* RETRO_LANGUAGE_ESPERANTO */
   NULL,        /* RETRO_LANGUAGE_POLISH */
   NULL,        /* RETRO_LANGUAGE_VIETNAMESE */
   NULL,        /* RETRO_LANGUAGE_ARABIC */
   NULL,        /* RETRO_LANGUAGE_GREEK */
   NULL,        /* RETRO_LANGUAGE_TURKISH */
   NULL,        /* RETRO_LANGUAGE_SLOVAK */
   NULL,        /* RETRO_LANGUAGE_PERSIAN */
   NULL,        /* RETRO_LANGUAGE_HEBREW */
   NULL,        /* RETRO_LANGUAGE_ASTURIAN */
   NULL,        /* RETRO_LANGUAGE_FINNISH */
   NULL,        /* RETRO_LANGUAGE_INDONESIAN */
   NULL,        /* RETRO_LANGUAGE_SWEDISH */
   NULL,        /* RETRO_LANGUAGE_UKRAINIAN */
   NULL,        /* RETRO_LANGUAGE_CZECH */
   NULL,        /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   NULL,        /* RETRO_LANGUAGE_CATALAN */
   NULL,        /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   NULL,        /* RETRO_LANGUAGE_HUNGARIAN */
   NULL,        /* RETRO_LANGUAGE_BELARUSIAN */
   NULL,        /* RETRO_LANGUAGE_GALICIAN */
   NULL,        /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * &gt; We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
      bool *categories_supported)
{
   unsigned version  = 0;
#ifndef HAVE_NO_LANGEXTRA
   unsigned language = 0;
#endif

   if (!environ_cb || !categories_supported)
      return;

   *categories_supported = false;

   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &amp;version))
      version = 0;

   if (version &gt;= 2)
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_v2_intl core_options_intl;

      core_options_intl.us    = &amp;options_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;
          (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = options_intl[language];

      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
            &amp;core_options_intl);
#else
      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
            &amp;options_us);
#endif
   }
   else
   {
      size_t i, j;
      size_t option_index              = 0;
      size_t num_options               = 0;
      struct retro_core_option_definition
            *option_v1_defs_us         = NULL;
#ifndef HAVE_NO_LANGEXTRA
      size_t num_options_intl          = 0;
      struct retro_core_option_v2_definition
            *option_defs_intl          = NULL;
      struct retro_core_option_definition
            *option_v1_defs_intl       = NULL;
      struct retro_core_options_intl
            core_options_v1_intl;
#endif
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine total number of options */
      while (true)
      {
         if (option_defs_us[num_options].key)
            num_options++;
         else
            break;
      }

      if (version &gt;= 1)
      {
         /* Allocate US array */
         option_v1_defs_us = (struct retro_core_option_definition *)
               calloc(num_options + 1, sizeof(struct retro_core_option_definition));

         /* Copy parameters from option_defs_us array */
         for (i = 0; i &lt; num_options; i++)
         {
            struct retro_core_option_v2_definition *option_def_us = &amp;option_defs_us[i];
            struct retro_core_option_value *option_values         = option_def_us-&gt;values;
            struct retro_core_option_definition *option_v1_def_us = &amp;option_v1_defs_us[i];
            struct retro_core_option_value *option_v1_values      = option_v1_def_us-&gt;values;

            option_v1_def_us-&gt;key           = option_def_us-&gt;key;
            option_v1_def_us-&gt;desc          = option_def_us-&gt;desc;
            option_v1_def_us-&gt;info          = option_def_us-&gt;info;
            option_v1_def_us-&gt;default_value = option_def_us-&gt;default_value;

            /* Values must be copied individually... */
            while (option_values-&gt;value)
            {
               option_v1_values-&gt;value = option_values-&gt;value;
               option_v1_values-&gt;label = option_values-&gt;label;

               option_values++;
               option_v1_values++;
            }
         }

#ifndef HAVE_NO_LANGEXTRA
         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;
             (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH) &amp;&amp;
             options_intl[language])
            option_defs_intl = options_intl[language]-&gt;definitions;

         if (option_defs_intl)
         {
            /* Determine number of intl options */
            while (true)
            {
               if (option_defs_intl[num_options_intl].key)
                  num_options_intl++;
               else
                  break;
            }

            /* Allocate intl array */
            option_v1_defs_intl = (struct retro_core_option_definition *)
                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));

            /* Copy parameters from option_defs_intl array */
            for (i = 0; i &lt; num_options_intl; i++)
            {
               struct retro_core_option_v2_definition *option_def_intl = &amp;option_defs_intl[i];
               struct retro_core_option_value *option_values           = option_def_intl-&gt;values;
               struct retro_core_option_definition *option_v1_def_intl = &amp;option_v1_defs_intl[i];
               struct retro_core_option_value *option_v1_values        = option_v1_def_intl-&gt;values;

               option_v1_def_intl-&gt;key           = option_def_intl-&gt;key;
               option_v1_def_intl-&gt;desc          = option_def_intl-&gt;desc;
               option_v1_def_intl-&gt;info          = option_def_intl-&gt;info;
               option_v1_def_intl-&gt;default_value = option_def_intl-&gt;default_value;

               /* Values must be copied individually... */
               while (option_values-&gt;value)
               {
                  option_v1_values-&gt;value = option_values-&gt;value;
                  option_v1_values-&gt;label = option_values-&gt;label;

                  option_values++;
                  option_v1_values++;
               }
            }
         }

         core_options_v1_intl.us    = option_v1_defs_us;
         core_options_v1_intl.local = option_v1_defs_intl;

         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &amp;core_options_v1_intl);
#else
         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);
#endif
      }
      else
      {
         /* Allocate arrays */
         variables  = (struct retro_variable *)calloc(num_options + 1,
               sizeof(struct retro_variable));
         values_buf = (char **)calloc(num_options, sizeof(char *));

         if (!variables || !values_buf)
            goto error;

         /* Copy parameters from option_defs_us array */
         for (i = 0; i &lt; num_options; i++)
         {
            const char *key                        = option_defs_us[i].key;
            const char *desc                       = option_defs_us[i].desc;
            const char *default_value              = option_defs_us[i].default_value;
            struct retro_core_option_value *values = option_defs_us[i].values;
            size_t buf_len                         = 3;
            size_t default_index                   = 0;

            values_buf[i] = NULL;

            if (desc)
            {
               size_t num_values = 0;

               /* Determine number of values */
               while (true)
               {
                  if (values[num_values].value)
                  {
                     /* Check if this is the default value */
                     if (default_value)
                        if (strcmp(values[num_values].value, default_value) == 0)
                           default_index = num_values;

                     buf_len += strlen(values[num_values].value);
                     num_values++;
                  }
                  else
                     break;
               }

               /* Build values string */
               if (num_values &gt; 0)
               {
                  buf_len += num_values - 1;
                  buf_len += strlen(desc);

                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));
                  if (!values_buf[i])
                     goto error;

                  strcpy(values_buf[i], desc);
                  strcat(values_buf[i], "; ");

                  /* Default value goes first */
                  strcat(values_buf[i], values[default_index].value);

                  /* Add remaining values */
                  for (j = 0; j &lt; num_values; j++)
                  {
                     if (j != default_index)
                     {
                        strcat(values_buf[i], "|");
                        strcat(values_buf[i], values[j].value);
                     }
                  }
               }
            }

            variables[option_index].key   = key;
            variables[option_index].value = values_buf[i];
            option_index++;
         }

         /* Set variables */
         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
      }

error:
      /* Clean up */

      if (option_v1_defs_us)
      {
         free(option_v1_defs_us);
         option_v1_defs_us = NULL;
      }

#ifndef HAVE_NO_LANGEXTRA
      if (option_v1_defs_intl)
      {
         free(option_v1_defs_intl);
         option_v1_defs_intl = NULL;
      }
#endif

      if (values_buf)
      {
         for (i = 0; i &lt; num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_categories/libretro_core_options_intl.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) &amp;&amp; (_MSC_VER &gt;= 1500 &amp;&amp; _MSC_VER &lt; 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include &lt;libretro.h&gt;

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

struct retro_core_option_v2_category option_cats_fr[] = {
   {
      "video",                              /* key must match option_cats_us entry */
      "Vidéo",                              /* translated category description */
      "Configurez les options d'affichage." /* translated category sublabel */
   },
   {
      "hacks",
      "Avancée",
      "Options affectant les performances et la précision de l'émulation de bas niveau."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_fr[] = {
   {
      "mycore_region",                             /* key must match option_defs_us entry */
      "Région de la console",                      /* translated description */
      NULL,
      "Spécifiez la région d'origine du système.", /* translated sublabel */
      NULL,
      NULL,                                        /* category key is taken from option_defs_us
                                                    * -&gt; can set to NULL here */
      {
         { "auto",   "Auto" },                     /* value must match option_defs_us entry   */
         { "ntsc-j", "Japon" },                    /* &gt; only value_label should be translated */
         { "ntsc-u", "Amérique" },
         { "pal",    "L'Europe" },
         { NULL, NULL },
      },
      NULL                                         /* default_value is taken from option_defs_us
                                                    * -&gt; can set to NULL here */
   },
   {
      "mycore_video_scale",
      "Vidéo &gt; Échelle", /* translated description */
      "Échelle",         /* translated 'categorised' description */
      "Définir le facteur d'échelle vidéo interne.",
      NULL,
      NULL,
      {
         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */
      },
      NULL
   },
   {
      "mycore_overclock",
      "Avancé &gt; Réduire le ralentissement",
      "Réduire le ralentissement",
      "L'activation de « Avancé &gt; Réduire le ralentissement » réduira la précision.", /* translated sublabel */
      "L'activation de « Réduire le ralentissement » réduira la précision.",          /* translated 'categorised'
                                                                                       * sublabel */
      NULL,
      {
         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */
      },
      NULL
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_fr = {
   option_cats_fr,
   option_defs_fr
};

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_default/libretro_core_options.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;libretro.h&gt;
#include &lt;retro_inline.h&gt;

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      "Specify which region the system is from.", /* sublabel */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video Scale",
      "Set internal video scale factor.",
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   {
      "mycore_overclock",
      "Reduce Slowdown",
      "Enable CPU overclock (unsafe).",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, {{0}}, NULL },
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_JAPANESE */
   NULL,           /* RETRO_LANGUAGE_FRENCH */
   NULL,           /* RETRO_LANGUAGE_SPANISH */
   NULL,           /* RETRO_LANGUAGE_GERMAN */
   NULL,           /* RETRO_LANGUAGE_ITALIAN */
   NULL,           /* RETRO_LANGUAGE_DUTCH */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
   NULL,           /* RETRO_LANGUAGE_KOREAN */
   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
   NULL,           /* RETRO_LANGUAGE_POLISH */
   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
   NULL,           /* RETRO_LANGUAGE_ARABIC */
   NULL,           /* RETRO_LANGUAGE_GREEK */
   NULL,           /* RETRO_LANGUAGE_TURKISH */
   NULL,           /* RETRO_LANGUAGE_SLOVAK */
   NULL,           /* RETRO_LANGUAGE_PERSIAN */
   NULL,           /* RETRO_LANGUAGE_HEBREW */
   NULL,           /* RETRO_LANGUAGE_ASTURIAN */
   NULL,           /* RETRO_LANGUAGE_FINNISH */
   NULL,           /* RETRO_LANGUAGE_INDONESIAN */
   NULL,           /* RETRO_LANGUAGE_SWEDISH */
   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
   NULL,           /* RETRO_LANGUAGE_CZECH */
   NULL,           /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   NULL,           /* RETRO_LANGUAGE_CATALAN */
   NULL,           /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_HUNGARIAN */
   NULL,           /* RETRO_LANGUAGE_BELARUSIAN */
   NULL,           /* RETRO_LANGUAGE_GALICIAN */
   NULL,           /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * &gt; We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
{
   unsigned version = 0;

   if (!environ_cb)
      return;

   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &amp;version) &amp;&amp; (version &gt;= 1))
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_intl core_options_intl;
      unsigned language = 0;

      core_options_intl.us    = option_defs_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;
          (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = option_defs_intl[language];

      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &amp;core_options_intl);
#else
      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &amp;option_defs_us);
#endif
   }
   else
   {
      size_t i;
      size_t num_options               = 0;
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine number of options */
      for (;;)
      {
         if (!option_defs_us[num_options].key)
            break;
         num_options++;
      }

      /* Allocate arrays */
      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
      values_buf = (char **)calloc(num_options, sizeof(char *));

      if (!variables || !values_buf)
         goto error;

      /* Copy parameters from option_defs_us array */
      for (i = 0; i &lt; num_options; i++)
      {
         const char *key                        = option_defs_us[i].key;
         const char *desc                       = option_defs_us[i].desc;
         const char *default_value              = option_defs_us[i].default_value;
         struct retro_core_option_value *values = option_defs_us[i].values;
         size_t buf_len                         = 3;
         size_t default_index                   = 0;

         values_buf[i] = NULL;

         if (desc)
         {
            size_t num_values = 0;

            /* Determine number of values */
            for (;;)
            {
               if (!values[num_values].value)
                  break;

               /* Check if this is the default value */
               if (default_value)
                  if (strcmp(values[num_values].value, default_value) == 0)
                     default_index = num_values;

               buf_len += strlen(values[num_values].value);
               num_values++;
            }

            /* Build values string */
            if (num_values &gt; 0)
            {
               size_t j;

               buf_len += num_values - 1;
               buf_len += strlen(desc);

               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
               if (!values_buf[i])
                  goto error;

               strcpy(values_buf[i], desc);
               strcat(values_buf[i], "; ");

               /* Default value goes first */
               strcat(values_buf[i], values[default_index].value);

               /* Add remaining values */
               for (j = 0; j &lt; num_values; j++)
               {
                  if (j != default_index)
                  {
                     strcat(values_buf[i], "|");
                     strcat(values_buf[i], values[j].value);
                  }
               }
            }
         }

         variables[i].key   = key;
         variables[i].value = values_buf[i];
      }

      /* Set variables */
      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);

error:

      /* Clean up */
      if (values_buf)
      {
         for (i = 0; i &lt; num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) &amp;&amp; (_MSC_VER &gt;= 1500 &amp;&amp; _MSC_VER &lt; 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include &lt;libretro.h&gt;

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;libretro.h&gt;
#include &lt;retro_inline.h&gt;

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      "Specify which region the system is from.", /* sublabel */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video Scale",
      "Set internal video scale factor.",
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   /* This 'mycore_show_speedhacks' option will only be shown
    * if the frontend supports core options API v1.
    * It will be hidden on older frontends.
    * See line 227 */
   {
      "mycore_show_speedhacks",
      "Show Unsafe Settings",
      "Enable configuration of emulation speed hacks.",
      {
         { "enabled",  NULL },
         { "disabled", NULL },
         { NULL, NULL},
      },
      "disabled"
   },
   {
      "mycore_overclock",
      "Reduce Slowdown",
      "Enable CPU overclock (unsafe).",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, {{0}}, NULL },
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_JAPANESE */
   NULL,           /* RETRO_LANGUAGE_FRENCH */
   NULL,           /* RETRO_LANGUAGE_SPANISH */
   NULL,           /* RETRO_LANGUAGE_GERMAN */
   NULL,           /* RETRO_LANGUAGE_ITALIAN */
   NULL,           /* RETRO_LANGUAGE_DUTCH */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
   NULL,           /* RETRO_LANGUAGE_KOREAN */
   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
   NULL,           /* RETRO_LANGUAGE_POLISH */
   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
   NULL,           /* RETRO_LANGUAGE_ARABIC */
   NULL,           /* RETRO_LANGUAGE_GREEK */
   NULL,           /* RETRO_LANGUAGE_TURKISH */
   NULL,           /* RETRO_LANGUAGE_SLOVAK */
   NULL,           /* RETRO_LANGUAGE_PERSIAN */
   NULL,           /* RETRO_LANGUAGE_HEBREW */
   NULL,           /* RETRO_LANGUAGE_ASTURIAN */
   NULL,           /* RETRO_LANGUAGE_FINNISH */
   NULL,           /* RETRO_LANGUAGE_INDONESIAN */
   NULL,           /* RETRO_LANGUAGE_SWEDISH */
   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
   NULL,           /* RETRO_LANGUAGE_CZECH */
   NULL,           /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   NULL,           /* RETRO_LANGUAGE_CATALAN */
   NULL,           /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   NULL,           /* RETRO_LANGUAGE_HUNGARIAN */
   NULL,           /* RETRO_LANGUAGE_BELARUSIAN */
   NULL,           /* RETRO_LANGUAGE_GALICIAN */
   NULL,           /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * &gt; We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
{
   unsigned version = 0;

   if (!environ_cb)
      return;

   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &amp;version) &amp;&amp; (version &gt;= 1))
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_intl core_options_intl;
      unsigned language = 0;

      core_options_intl.us    = option_defs_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;
          (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = option_defs_intl[language];

      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &amp;core_options_intl);
#else
      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &amp;option_defs_us);
#endif
   }
   else
   {
      size_t i;
      size_t option_index              = 0;
      size_t num_options               = 0;
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine number of options
       * &gt; Note: We are going to skip a number of irrelevant
       *   core options when building the retro_variable array,
       *   but we'll allocate space for all of them. The difference
       *   in resource usage is negligible, and this allows us to
       *   keep the code 'cleaner' */
      for (;;)
      {
         if (!option_defs_us[num_options].key)
            break;
         num_options++;
      }

      /* Allocate arrays */
      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
      values_buf = (char **)calloc(num_options, sizeof(char *));

      if (!variables || !values_buf)
         goto error;

      /* Copy parameters from option_defs_us array */
      for (i = 0; i &lt; num_options; i++)
      {
         const char *key                        = option_defs_us[i].key;
         const char *desc                       = option_defs_us[i].desc;
         const char *default_value              = option_defs_us[i].default_value;
         struct retro_core_option_value *values = option_defs_us[i].values;
         size_t buf_len                         = 3;
         size_t default_index                   = 0;

         values_buf[i] = NULL;

         /* Skip options that are irrelevant when using the
          * old style core options interface */
         if (strcmp(key, "mycore_show_speedhacks") == 0)
            continue;

         if (desc)
         {
            size_t num_values = 0;

            /* Determine number of values */
            for (;;)
            {
               if (!values[num_values].value)
                  break;

               /* Check if this is the default value */
               if (default_value)
                  if (strcmp(values[num_values].value, default_value) == 0)
                     default_index = num_values;

               buf_len += strlen(values[num_values].value);
               num_values++;
            }

            /* Build values string */
            if (num_values &gt; 0)
            {
               size_t j;

               buf_len += num_values - 1;
               buf_len += strlen(desc);

               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
               if (!values_buf[i])
                  goto error;

               strcpy(values_buf[i], desc);
               strcat(values_buf[i], "; ");

               /* Default value goes first */
               strcat(values_buf[i], values[default_index].value);

               /* Add remaining values */
               for (j = 0; j &lt; num_values; j++)
               {
                  if (j != default_index)
                  {
                     strcat(values_buf[i], "|");
                     strcat(values_buf[i], values[j].value);
                  }
               }
            }
         }

         variables[option_index].key   = key;
         variables[option_index].value = values_buf[i];
         option_index++;
      }

      /* Set variables */
      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);

error:

      /* Clean up */
      if (values_buf)
      {
         for (i = 0; i &lt; num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) &amp;&amp; (_MSC_VER &gt;= 1500 &amp;&amp; _MSC_VER &lt; 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include &lt;libretro.h&gt;

/*
 ********************************
 * VERSION: 1.3
 ********************************
 *
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/libretro_core_options.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;libretro.h&gt;
#include &lt;retro_inline.h&gt;

#ifndef HAVE_NO_LANGEXTRA
#include "libretro_core_options_intl.h"
#endif

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_ENGLISH */

/* Default language:
 * - All other languages must include the same keys and values
 * - Will be used as a fallback in the event that frontend language
 *   is not available
 * - Will be used as a fallback for any missing entries in
 *   frontend language definition */

struct retro_core_option_v2_category option_cats_us[] = {
   {
      "video",                     /* key (category name) */
      "Video",                     /* category description (label) */
      "Configure display options." /* category sublabel */
   },
   {
      "hacks",
      "Advanced",
      "Options affecting low-level emulation performance and accuracy."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_us[] = {
   {
      "mycore_region",                            /* key (option name) */
      "Console Region",                           /* description (label) */
      NULL,                                       /* 'categorised' description (used instead of
                                                   * 'description' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * description is always used */
      "Specify which region the system is from.", /* sublabel */
      NULL,                                       /* 'categorised' sublabel (used instead of
                                                   * 'sublabel' if frontend has category
                                                   * support; if NULL or empty, regular
                                                   * sublabel is always used */
      NULL,                                       /* category key (must match an entry in
                                                   * option_cats_us; if NULL or empty,
                                                   * option is uncategorised */
      {
         { "auto",   "Auto" },                    /* value_1, value_1_label */
         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
         { "ntsc-u", "America" },                 /* value_3, value_3_label */
         { "pal",    "Europe" },                  /* value_4, value_4_label */
         { NULL, NULL },
      },
      "auto"                                      /* default_value */
   },
   {
      "mycore_video_scale",
      "Video &gt; Scale",   /* description: here a 'Video &gt;' prefix is used to
                          * signify a category on frontends without explicit
                          * category support */
      "Scale",           /* 'categorised' description: will be displayed inside
                          * the 'Video' submenu */
      "Set internal video scale factor.",
      NULL,
      "video",           /* category key */
      {
         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
         { "2x", NULL }, /* and can displayed directly, the value_label should */
         { "3x", NULL }, /* be set to NULL                                     */
         { "4x", NULL },
         { NULL, NULL },
      },
      "3x"
   },
   {
      "mycore_overclock",
      "Advanced &gt; Reduce Slowdown",
      "Reduce Slowdown",
      "Enabling 'Advanced &gt; Reduce Slowdown' will reduce accuracy.", /* sublabel */
      "Enabling 'Reduce Slowdown' will reduce accuracy.",            /* 'categorised' sublabel:
                               * will be displayed inside the 'Advanced' submenu; note that
                               * 'Advanced &gt; Reduce Slowdown' is replaced with 'Reduce Slowdown' */
      "hacks",
      {
         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
         { "disabled", NULL }, /* value_label should be set to NULL             */
         { NULL, NULL },
      },
      "disabled"
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_us = {
   option_cats_us,
   option_defs_us
};

/*
 ********************************
 * Language Mapping
 ********************************
*/

#ifndef HAVE_NO_LANGEXTRA
struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {
   &amp;options_us,      /* RETRO_LANGUAGE_ENGLISH */
   &amp;options_ja,      /* RETRO_LANGUAGE_JAPANESE */
   &amp;options_fr,      /* RETRO_LANGUAGE_FRENCH */
   &amp;options_es,      /* RETRO_LANGUAGE_SPANISH */
   &amp;options_de,      /* RETRO_LANGUAGE_GERMAN */
   &amp;options_it,      /* RETRO_LANGUAGE_ITALIAN */
   &amp;options_nl,      /* RETRO_LANGUAGE_DUTCH */
   &amp;options_pt_br,   /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
   &amp;options_pt_pt,   /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
   &amp;options_ru,      /* RETRO_LANGUAGE_RUSSIAN */
   &amp;options_ko,      /* RETRO_LANGUAGE_KOREAN */
   &amp;options_cht,     /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
   &amp;options_chs,     /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
   &amp;options_eo,      /* RETRO_LANGUAGE_ESPERANTO */
   &amp;options_pl,      /* RETRO_LANGUAGE_POLISH */
   &amp;options_vn,      /* RETRO_LANGUAGE_VIETNAMESE */
   &amp;options_ar,      /* RETRO_LANGUAGE_ARABIC */
   &amp;options_el,      /* RETRO_LANGUAGE_GREEK */
   &amp;options_tr,      /* RETRO_LANGUAGE_TURKISH */
   &amp;options_sk,      /* RETRO_LANGUAGE_SLOVAK */
   &amp;options_fa,      /* RETRO_LANGUAGE_PERSIAN */
   &amp;options_he,      /* RETRO_LANGUAGE_HEBREW */
   &amp;options_ast,     /* RETRO_LANGUAGE_ASTURIAN */
   &amp;options_fi,      /* RETRO_LANGUAGE_FINNISH */
   &amp;options_id,      /* RETRO_LANGUAGE_INDONESIAN */
   &amp;options_sv,      /* RETRO_LANGUAGE_SWEDISH */
   &amp;options_uk,      /* RETRO_LANGUAGE_UKRAINIAN */
   &amp;options_cs,      /* RETRO_LANGUAGE_CZECH */
   &amp;options_val,     /* RETRO_LANGUAGE_CATALAN_VALENCIA */
   &amp;options_ca,      /* RETRO_LANGUAGE_CATALAN */
   &amp;options_en,      /* RETRO_LANGUAGE_BRITISH_ENGLISH */
   &amp;options_hu,      /* RETRO_LANGUAGE_HUNGARIAN */
   &amp;options_be,      /* RETRO_LANGUAGE_BELARUSIAN */
   &amp;options_gl,      /* RETRO_LANGUAGE_GALICIAN */
   &amp;options_no,      /* RETRO_LANGUAGE_NORWEGIAN */
};
#endif

/*
 ********************************
 * Functions
 ********************************
*/

/* Handles configuration/setting of core options.
 * Should be called as early as possible - ideally inside
 * retro_set_environment(), and no later than retro_load_game()
 * &gt; We place the function body in the header to avoid the
 *   necessity of adding more .c files (i.e. want this to
 *   be as painless as possible for core devs)
 */

static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
      bool *categories_supported)
{
   unsigned version  = 0;
#ifndef HAVE_NO_LANGEXTRA
   unsigned language = 0;
#endif

   if (!environ_cb || !categories_supported)
      return;

   *categories_supported = false;

   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &amp;version))
      version = 0;

   if (version &gt;= 2)
   {
#ifndef HAVE_NO_LANGEXTRA
      struct retro_core_options_v2_intl core_options_intl;

      core_options_intl.us    = &amp;options_us;
      core_options_intl.local = NULL;

      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;
          (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH))
         core_options_intl.local = options_intl[language];

      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
            &amp;core_options_intl);
#else
      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
            &amp;options_us);
#endif
   }
   else
   {
      size_t i, j;
      size_t option_index              = 0;
      size_t num_options               = 0;
      struct retro_core_option_definition
            *option_v1_defs_us         = NULL;
#ifndef HAVE_NO_LANGEXTRA
      size_t num_options_intl          = 0;
      struct retro_core_option_v2_definition
            *option_defs_intl          = NULL;
      struct retro_core_option_definition
            *option_v1_defs_intl       = NULL;
      struct retro_core_options_intl
            core_options_v1_intl;
#endif
      struct retro_variable *variables = NULL;
      char **values_buf                = NULL;

      /* Determine total number of options */
      while (true)
      {
         if (option_defs_us[num_options].key)
            num_options++;
         else
            break;
      }

      if (version &gt;= 1)
      {
         /* Allocate US array */
         option_v1_defs_us = (struct retro_core_option_definition *)
               calloc(num_options + 1, sizeof(struct retro_core_option_definition));

         /* Copy parameters from option_defs_us array */
         for (i = 0; i &lt; num_options; i++)
         {
            struct retro_core_option_v2_definition *option_def_us = &amp;option_defs_us[i];
            struct retro_core_option_value *option_values         = option_def_us-&gt;values;
            struct retro_core_option_definition *option_v1_def_us = &amp;option_v1_defs_us[i];
            struct retro_core_option_value *option_v1_values      = option_v1_def_us-&gt;values;

            option_v1_def_us-&gt;key           = option_def_us-&gt;key;
            option_v1_def_us-&gt;desc          = option_def_us-&gt;desc;
            option_v1_def_us-&gt;info          = option_def_us-&gt;info;
            option_v1_def_us-&gt;default_value = option_def_us-&gt;default_value;

            /* Values must be copied individually... */
            while (option_values-&gt;value)
            {
               option_v1_values-&gt;value = option_values-&gt;value;
               option_v1_values-&gt;label = option_values-&gt;label;

               option_values++;
               option_v1_values++;
            }
         }

#ifndef HAVE_NO_LANGEXTRA
         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;
             (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH) &amp;&amp;
             options_intl[language])
            option_defs_intl = options_intl[language]-&gt;definitions;

         if (option_defs_intl)
         {
            /* Determine number of intl options */
            while (true)
            {
               if (option_defs_intl[num_options_intl].key)
                  num_options_intl++;
               else
                  break;
            }

            /* Allocate intl array */
            option_v1_defs_intl = (struct retro_core_option_definition *)
                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));

            /* Copy parameters from option_defs_intl array */
            for (i = 0; i &lt; num_options_intl; i++)
            {
               struct retro_core_option_v2_definition *option_def_intl = &amp;option_defs_intl[i];
               struct retro_core_option_value *option_values           = option_def_intl-&gt;values;
               struct retro_core_option_definition *option_v1_def_intl = &amp;option_v1_defs_intl[i];
               struct retro_core_option_value *option_v1_values        = option_v1_def_intl-&gt;values;

               option_v1_def_intl-&gt;key           = option_def_intl-&gt;key;
               option_v1_def_intl-&gt;desc          = option_def_intl-&gt;desc;
               option_v1_def_intl-&gt;info          = option_def_intl-&gt;info;
               option_v1_def_intl-&gt;default_value = option_def_intl-&gt;default_value;

               /* Values must be copied individually... */
               while (option_values-&gt;value)
               {
                  option_v1_values-&gt;value = option_values-&gt;value;
                  option_v1_values-&gt;label = option_values-&gt;label;

                  option_values++;
                  option_v1_values++;
               }
            }
         }

         core_options_v1_intl.us    = option_v1_defs_us;
         core_options_v1_intl.local = option_v1_defs_intl;

         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &amp;core_options_v1_intl);
#else
         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);
#endif
      }
      else
      {
         /* Allocate arrays */
         variables  = (struct retro_variable *)calloc(num_options + 1,
               sizeof(struct retro_variable));
         values_buf = (char **)calloc(num_options, sizeof(char *));

         if (!variables || !values_buf)
            goto error;

         /* Copy parameters from option_defs_us array */
         for (i = 0; i &lt; num_options; i++)
         {
            const char *key                        = option_defs_us[i].key;
            const char *desc                       = option_defs_us[i].desc;
            const char *default_value              = option_defs_us[i].default_value;
            struct retro_core_option_value *values = option_defs_us[i].values;
            size_t buf_len                         = 3;
            size_t default_index                   = 0;

            values_buf[i] = NULL;

            if (desc)
            {
               size_t num_values = 0;

               /* Determine number of values */
               while (true)
               {
                  if (values[num_values].value)
                  {
                     /* Check if this is the default value */
                     if (default_value)
                        if (strcmp(values[num_values].value, default_value) == 0)
                           default_index = num_values;

                     buf_len += strlen(values[num_values].value);
                     num_values++;
                  }
                  else
                     break;
               }

               /* Build values string */
               if (num_values &gt; 0)
               {
                  buf_len += num_values - 1;
                  buf_len += strlen(desc);

                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));
                  if (!values_buf[i])
                     goto error;

                  strcpy(values_buf[i], desc);
                  strcat(values_buf[i], "; ");

                  /* Default value goes first */
                  strcat(values_buf[i], values[default_index].value);

                  /* Add remaining values */
                  for (j = 0; j &lt; num_values; j++)
                  {
                     if (j != default_index)
                     {
                        strcat(values_buf[i], "|");
                        strcat(values_buf[i], values[j].value);
                     }
                  }
               }
            }

            variables[option_index].key   = key;
            variables[option_index].value = values_buf[i];
            option_index++;
         }

         /* Set variables */
         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
      }

error:
      /* Clean up */

      if (option_v1_defs_us)
      {
         free(option_v1_defs_us);
         option_v1_defs_us = NULL;
      }

#ifndef HAVE_NO_LANGEXTRA
      if (option_v1_defs_intl)
      {
         free(option_v1_defs_intl);
         option_v1_defs_intl = NULL;
      }
#endif

      if (values_buf)
      {
         for (i = 0; i &lt; num_options; i++)
         {
            if (values_buf[i])
            {
               free(values_buf[i]);
               values_buf[i] = NULL;
            }
         }

         free(values_buf);
         values_buf = NULL;
      }

      if (variables)
      {
         free(variables);
         variables = NULL;
      }
   }
}

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h</h2>
<pre>#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
#define LIBRETRO_CORE_OPTIONS_INTL_H__

#if defined(_MSC_VER) &amp;&amp; (_MSC_VER &gt;= 1500 &amp;&amp; _MSC_VER &lt; 1900)
/* https://support.microsoft.com/en-us/kb/980263 */
#pragma execution_character_set("utf-8")
#pragma warning(disable:4566)
#endif

#include &lt;libretro.h&gt;

/*
 ********************************
 * VERSION: 2.0
 ********************************
 *
 * - 2.0: Add support for core options v2 interface
 * - 1.3: Move translations to libretro_core_options_intl.h
 *        - libretro_core_options_intl.h includes BOM and utf-8
 *          fix for MSVC 2010-2013
 *        - Added HAVE_NO_LANGEXTRA flag to disable translations
 *          on platforms/compilers without BOM support
 * - 1.2: Use core options v1 interface when
 *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1
 *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
 * - 1.1: Support generation of core options v0 retro_core_option_value
 *        arrays containing options with a single value
 * - 1.0: First commit
*/

#ifdef __cplusplus
extern "C" {
#endif

/*
 ********************************
 * Core Option Definitions
 ********************************
*/

/* RETRO_LANGUAGE_JAPANESE */

/* RETRO_LANGUAGE_FRENCH */

struct retro_core_option_v2_category option_cats_fr[] = {
   {
      "video",                              /* key must match option_cats_us entry */
      "Vidéo",                              /* translated category description */
      "Configurez les options d'affichage." /* translated category sublabel */
   },
   {
      "hacks",
      "Avancée",
      "Options affectant les performances et la précision de l'émulation de bas niveau."
   },
   { NULL, NULL, NULL },
};

struct retro_core_option_v2_definition option_defs_fr[] = {
   {
      "mycore_region",                             /* key must match option_defs_us entry */
      "Région de la console",                      /* translated description */
      NULL,
      "Spécifiez la région d'origine du système.", /* translated sublabel */
      NULL,
      NULL,                                        /* category key is taken from option_defs_us
                                                    * -&gt; can set to NULL here */
      {
         { "auto",   "Auto" },                     /* value must match option_defs_us entry   */
         { "ntsc-j", "Japon" },                    /* &gt; only value_label should be translated */
         { "ntsc-u", "Amérique" },
         { "pal",    "L'Europe" },
         { NULL, NULL },
      },
      NULL                                         /* default_value is taken from option_defs_us
                                                    * -&gt; can set to NULL here */
   },
   {
      "mycore_video_scale",
      "Vidéo &gt; Échelle", /* translated description */
      "Échelle",         /* translated 'categorised' description */
      "Définir le facteur d'échelle vidéo interne.",
      NULL,
      NULL,
      {
         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */
      },
      NULL
   },
   {
      "mycore_overclock",
      "Avancé &gt; Réduire le ralentissement",
      "Réduire le ralentissement",
      "L'activation de « Avancé &gt; Réduire le ralentissement » réduira la précision.", /* translated sublabel */
      "L'activation de « Réduire le ralentissement » réduira la précision.",          /* translated 'categorised'
                                                                                       * sublabel */
      NULL,
      {
         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */
      },
      NULL
   },
   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

struct retro_core_options_v2 options_fr = {
   option_cats_fr,
   option_defs_fr
};

/* RETRO_LANGUAGE_SPANISH */

/* RETRO_LANGUAGE_GERMAN */

/* RETRO_LANGUAGE_ITALIAN */

/* RETRO_LANGUAGE_DUTCH */

/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */

/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */

/* RETRO_LANGUAGE_RUSSIAN */

/* RETRO_LANGUAGE_KOREAN */

/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */

/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */

/* RETRO_LANGUAGE_ESPERANTO */

/* RETRO_LANGUAGE_POLISH */

/* RETRO_LANGUAGE_VIETNAMESE */

/* RETRO_LANGUAGE_ARABIC */

/* RETRO_LANGUAGE_GREEK */

/* RETRO_LANGUAGE_TURKISH */

/* RETRO_LANGUAGE_SLOVAK */

/* RETRO_LANGUAGE_PERSIAN */

/* RETRO_LANGUAGE_HEBREW */

/* RETRO_LANGUAGE_ASTURIAN */

/* RETRO_LANGUAGE_FINNISH */

#ifdef __cplusplus
}
#endif

#endif</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/crowdin.yml</h2>
<pre>files:
  - source: /intl/_us/*.json
    translation: /intl/_%two_letters_code%/%original_file_name%</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_intl.yml</h2>
<pre># Recreate libretro_core_options_intl.h using translations form Crowdin

name: Crowdin Translation Integration

on:
  push:
    branches:
      - master
    paths:
      - 'intl/*/*'

jobs:
  create_intl_file:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Python
        uses: actions/setup-python@v2
        
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
          fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.

      - name: Create intl file
        shell: bash
        run: |
          python3 intl/crowdin_intl.py '&lt;path/to/libretro_core_options.h directory&gt;'

      - name: Commit files
        run: |
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add &lt;path/to/libretro_core_options_intl.h file&gt;
          git commit -m "Recreate libretro_core_options_intl.h" -a

      - name: GitHub Push
        uses: ad-m/github-push-action@v0.6.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_prep.yml</h2>
<pre># Prepare source for Crowdin sync

name: Crowdin Upload Preparation

on:
  push:
    branches:
      - master
    paths:
      - '&lt;path/to/libretro_core_options.h file&gt;'

jobs:
  prepare_source_file:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Python
        uses: actions/setup-python@v2
        
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
          fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.

      - name: Crowdin Prep
        shell: bash
        run: |
          python3 intl/crowdin_prep.py '&lt;path/to/libretro_core_options.h directory&gt;'
          
      - name: Commit files
        run: |
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add intl/*
          git commit -m "Recreate translation source text files" -a

      - name: GitHub Push
        uses: ad-m/github-push-action@v0.6.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/instructions.txt</h2>
<pre>Place 'crowdin.yml' &amp; the 'intl' and '.github' folder, including content, into the root of the repo.

In '.github/workflows' are two files: 'crowdin_intl.yml' &amp; 'crowdin_prep.yml'
In each of those are place holders, which need to be replaced as follows:

&lt;path/to/libretro_core_options.h directory&gt;
-&gt; replace with the path from the root of the repo to the directory containing
'libretro_core_options.h' (it is assumed that 'libretro_core_options.h' &amp;
'libretro_core_options_intl.h' are in the same directory)

&lt;path/to/libretro_core_options.h file&gt;
-&gt; replace with the full path from the root of the repo to the 'libretro_core_options.h' file

&lt;path/to/libretro_core_options_intl.h file&gt;
-&gt; replace with the full path from the root of the repo to the 'libretro_core_options_intl.h' file


From the root of the repo run (using bash):
python3 intl/core_opt_translation.py '&lt;path/to/libretro_core_options.h directory&gt;'

(If python3 doesn't work, try just python)

Push changes to repo. Once merged, request Crowdin integration.


Crowdin integration:

On the project page, go to the Applications tab. Choose GitHub.
There are two options: connecting a GitHub account, which has write/commit permissions to the repo
or providing a GitHub token, which will unlock these permissions.

Then add a repository, a new interface opens. Pick the repository as well as the branch, which you want to sync.
On the right, Crowdin will display the default name of the repository it will use for creating PRs.
Below, set the sync schedule and then save. With that the synchronisation should be set up.
If there are still problems, you might need to manually modify the configuration (double click on the branch in the lower frame).

Here's what the file paths should look like (the '/' at the start is very important!):

Source files path:
/intl/_us/*.json

Translated files path:
/intl/_%two_letters_code%/%original_file_name%


Once Crowdin successfully creates the PR &amp; it has been merged, the automatically created branch can be deleted on GitHub.</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_option_regex.py</h2>
<pre>import re

# 0: full struct; 1: up to &amp; including first []; 2: content between first {}
p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*'
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'=\s*'  # =
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
                      r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};')  # captures full struct, it's beginning and it's content
# 0: type name[]; 1: type; 2: name
p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*'
                         r'(option_cats([a-z_]{0,8})|option_defs([a-z_]{0,8}))\s*\[]')
# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
p_option = re.compile(r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\"|'  # key start; group 1
                      r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|'
                      r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|'
                      r'[a-zA-Z0-9_]+\s*\".*?\")\s*'  # key end
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(\".*?\")\s*'  # description; group 2
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # group 3
                      r'(?:NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')+)'
                      r'(?:'  # defs only start
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'((?:'  # key/value pairs start; group 4
                      r'{\s*'  # opening braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option key
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:NULL|\".*?\")\s*'  # option value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*)'  # key/value pairs end
                      r'}\s*'  # closing braces
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r'(?:'  # defaults start
                      r'(?:NULL|\".*?\")\s*'  # default value
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r',?\s*'  # comma
                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                      r')*'  # defaults end
                      r')?'  # defs only end
                      r'},')  # closing braces
# analyse option group 3
p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                    r',')
p_info_cat = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")')
# analyse option group 4
p_key_value = re.compile(r'{\s*'  # opening braces
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option key; 1
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r',\s*'  # comma
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'(NULL|\".*?\")\s*'  # option value; 2
                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
                         r'}')

p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")')

p_intl = re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {'
                    r'((?:.|[\r\n])*?)};')
p_set = re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)'
                   r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif')

p_yaml = re.compile(r'"project_id": "[0-9]+".*\s*'
                    r'"api_token": "([a-zA-Z0-9]+)".*\s*'
                    r'"base_path": "\./intl".*\s*'
                    r'"base_url": "https://api\.crowdin\.com".*\s*'
                    r'"preserve_hierarchy": true.*\s*'
                    r'"files": \[\s*'
                    r'\{\s*'
                    r'"source": "/_us/\*\.json",.*\s*'
                    r'"translation": "/_%two_letters_code%/%original_file_name%",.*\s*'
                    r'"skip_untranslated_strings": true.*\s*'
                    r'},\s*'
                    r']')</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_opt_translation.py</h2>
<pre>#!/usr/bin/env python3

"""Core options text extractor

The purpose of this script is to set up &amp; provide functions for automatic generation of 'libretro_core_options_intl.h'
from 'libretro_core_options.h' using translations from Crowdin.

Both v1 and v2 structs are supported. It is, however, recommended to convert v1 files to v2 using the included
'v1_to_v2_converter.py'.

Usage:
python3 path/to/core_opt_translation.py "path/to/where/libretro_core_options.h &amp; libretro_core_options_intl.h/are"

This script will:
1.) create key words for &amp; extract the texts from libretro_core_options.h &amp; save them into intl/_us/core_options.h
2.) do the same for any present translations in libretro_core_options_intl.h, saving those in their respective folder
"""
import core_option_regex as cor
import re
import os
import sys
import json
import urllib.request as req
import shutil

# for uploading translations to Crowdin, the Crowdin 'language id' is required
LANG_CODE_TO_ID = {'_ar': 'ar',
                   '_ast': 'ast',
                   '_chs': 'zh-CN',
                   '_cht': 'zh-TW',
                   '_cs': 'cs',
                   '_cy': 'cy',
                   '_da': 'da',
                   '_de': 'de',
                   '_el': 'el',
                   '_eo': 'eo',
                   '_es': 'es-ES',
                   '_fa': 'fa',
                   '_fi': 'fi',
                   '_fr': 'fr',
                   '_gl': 'gl',
                   '_he': 'he',
                   '_hu': 'hu',
                   '_id': 'id',
                   '_it': 'it',
                   '_ja': 'ja',
                   '_ko': 'ko',
                   '_nl': 'nl',
                   '_pl': 'pl',
                   '_pt_br': 'pt-BR',
                   '_pt_pt': 'pt-PT',
                   '_ru': 'ru',
                   '_sk': 'sk',
                   '_sv': 'sv-SE',
                   '_tr': 'tr',
                   '_uk': 'uk',
                   '_vn': 'vi'}
LANG_CODE_TO_R_LANG = {'_ar': 'RETRO_LANGUAGE_ARABIC',
                       '_ast': 'RETRO_LANGUAGE_ASTURIAN',
                       '_chs': 'RETRO_LANGUAGE_CHINESE_SIMPLIFIED',
                       '_cht': 'RETRO_LANGUAGE_CHINESE_TRADITIONAL',
                       '_cs': 'RETRO_LANGUAGE_CZECH',
                       '_cy': 'RETRO_LANGUAGE_WELSH',
                       '_da': 'RETRO_LANGUAGE_DANISH',
                       '_de': 'RETRO_LANGUAGE_GERMAN',
                       '_el': 'RETRO_LANGUAGE_GREEK',
                       '_eo': 'RETRO_LANGUAGE_ESPERANTO',
                       '_es': 'RETRO_LANGUAGE_SPANISH',
                       '_fa': 'RETRO_LANGUAGE_PERSIAN',
                       '_fi': 'RETRO_LANGUAGE_FINNISH',
                       '_fr': 'RETRO_LANGUAGE_FRENCH',
                       '_gl': 'RETRO_LANGUAGE_GALICIAN',
                       '_he': 'RETRO_LANGUAGE_HEBREW',
                       '_hu': 'RETRO_LANGUAGE_HUNGARIAN',
                       '_id': 'RETRO_LANGUAGE_INDONESIAN',
                       '_it': 'RETRO_LANGUAGE_ITALIAN',
                       '_ja': 'RETRO_LANGUAGE_JAPANESE',
                       '_ko': 'RETRO_LANGUAGE_KOREAN',
                       '_nl': 'RETRO_LANGUAGE_DUTCH',
                       '_pl': 'RETRO_LANGUAGE_POLISH',
                       '_pt_br': 'RETRO_LANGUAGE_PORTUGUESE_BRAZIL',
                       '_pt_pt': 'RETRO_LANGUAGE_PORTUGUESE_PORTUGAL',
                       '_ru': 'RETRO_LANGUAGE_RUSSIAN',
                       '_sk': 'RETRO_LANGUAGE_SLOVAK',
                       '_sv': 'RETRO_LANGUAGE_SWEDISH',
                       '_tr': 'RETRO_LANGUAGE_TURKISH',
                       '_uk': 'RETRO_LANGUAGE_UKRAINIAN',
                       '_us': 'RETRO_LANGUAGE_ENGLISH',
                       '_vn': 'RETRO_LANGUAGE_VIETNAMESE'}

# these are handled by RetroArch directly - no need to include them in core translations
ON_OFFS = {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'}


def remove_special_chars(text: str, char_set=0) -&gt; str:
    """Removes special characters from a text.

    :param text: String to be cleaned.
    :param char_set: 0 -&gt; remove all ASCII special chars except for '_' &amp; 'space';
                     1 -&gt; remove invalid chars from file names
    :return: Clean text.
    """
    command_chars = [chr(unicode) for unicode in tuple(range(0, 32)) + (127,)]
    special_chars = ([chr(unicode) for unicode in tuple(range(33, 48)) + tuple(range(58, 65)) + tuple(range(91, 95))
                      + (96,) + tuple(range(123, 127))],
                     ('\\', '/', ':', '*', '?', '"', '&lt;', '&gt;', '|'))
    res = text
    for cm in command_chars:
        res = res.replace(cm, '_')
    for sp in special_chars[char_set]:
        res = res.replace(sp, '_')
    while res.startswith('_'):
        res = res[1:]
    while res.endswith('_'):
        res = res[:-1]
    return res


def clean_file_name(file_name: str) -&gt; str:
    """Removes characters which might make file_name inappropriate for files on some OS.

    :param file_name: File name to be cleaned.
    :return: The clean file name.
    """
    file_name = remove_special_chars(file_name, 1)
    file_name = re.sub(r'__+', '_', file_name.replace(' ', '_'))
    return file_name


def get_struct_type_name(decl: str) -&gt; tuple:
    """ Returns relevant parts of the struct declaration:
    type, name of the struct and the language appendix, if present.
    :param decl: The struct declaration matched by cor.p_type_name.
    :return: Tuple, e.g.: ('retro_core_option_definition', 'option_defs_us', '_us')
    """
    struct_match = cor.p_type_name.search(decl)
    if struct_match:
        if struct_match.group(3):
            struct_type_name = struct_match.group(1, 2, 3)
            return struct_type_name
        elif struct_match.group(4):
            struct_type_name = struct_match.group(1, 2, 4)
            return struct_type_name
        else:
            struct_type_name = struct_match.group(1, 2)
            return struct_type_name
    else:
        raise ValueError(f'No or incomplete struct declaration: {decl}!\n'
                         'Please make sure all structs are complete, including the type and name declaration.')


def is_viable_non_dupe(text: str, comparison) -&gt; bool:
    """text must be longer than 2 ('""'), not 'NULL' and not in comparison.

    :param text: String to be tested.
    :param comparison: Dictionary or set to search for text in.
    :return: bool
    """
    return 2 &lt; len(text) and text != 'NULL' and text not in comparison


def is_viable_value(text: str) -&gt; bool:
    """text must be longer than 2 ('""'), not 'NULL' and text.lower() not in
    {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'}.

    :param text: String to be tested.
    :return: bool
    """
    return 2 &lt; len(text) and text != 'NULL' and text.lower() not in ON_OFFS


def create_non_dupe(base_name: str, opt_num: int, comparison) -&gt; str:
    """Makes sure base_name is not in comparison, and if it is it's renamed.

    :param base_name: Name to check/make unique.
    :param opt_num: Number of the option base_name belongs to, used in making it unique.
    :param comparison: Dictionary or set to search for base_name in.
    :return: Unique name.
    """
    h = base_name
    if h in comparison:
        n = 0
        h = h + '_O' + str(opt_num)
        h_end = len(h)
        while h in comparison:
            h = h[:h_end] + '_' + str(n)
            n += 1
    return h


def get_texts(text: str) -&gt; dict:
    """Extracts the strings, which are to be translated/are the translations,
    from text and creates macro names for them.

    :param text: The string to be parsed.
    :return: Dictionary of the form { '_&lt;lang&gt;': { 'macro': 'string', ... }, ... }.
    """
    # all structs: group(0) full struct, group(1) beginning, group(2) content
    structs = cor.p_struct.finditer(text)
    hash_n_string = {}
    just_string = {}
    for struct in structs:
        struct_declaration = struct.group(1)
        struct_type_name = get_struct_type_name(struct_declaration)
        if 3 &gt; len(struct_type_name):
            lang = '_us'
        else:
            lang = struct_type_name[2]
        if lang not in just_string:
            hash_n_string[lang] = {}
            just_string[lang] = set()

        is_v2 = False
        pre_name = ''
        p = cor.p_info
        if 'retro_core_option_v2_definition' == struct_type_name[0]:
            is_v2 = True
        elif 'retro_core_option_v2_category' == struct_type_name[0]:
            pre_name = 'CATEGORY_'
            p = cor.p_info_cat

        struct_content = struct.group(2)
        # 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
        struct_options = cor.p_option.finditer(struct_content)
        for opt, option in enumerate(struct_options):
            # group 1: key
            if option.group(1):
                opt_name = pre_name + option.group(1)
                # no special chars allowed in key
                opt_name = remove_special_chars(opt_name).upper().replace(' ', '_')
            else:
                raise ValueError(f'No option name (key) found in struct {struct_type_name[1]} option {opt}!')

            # group 2: description0
            if option.group(2):
                desc0 = option.group(2)
                if is_viable_non_dupe(desc0, just_string[lang]):
                    just_string[lang].add(desc0)
                    m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL'), opt, hash_n_string[lang])
                    hash_n_string[lang][m_h] = desc0
            else:
                raise ValueError(f'No label found in struct {struct_type_name[1]} option {option.group(1)}!')

            # group 3: desc1, info0, info1, category
            if option.group(3):
                infos = option.group(3)
                option_info = p.finditer(infos)
                if is_v2:
                    desc1 = next(option_info).group(1)
                    if is_viable_non_dupe(desc1, just_string[lang]):
                        just_string[lang].add(desc1)
                        m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL_CAT'), opt, hash_n_string[lang])
                        hash_n_string[lang][m_h] = desc1
                    last = None
                    m_h = None
                    for j, info in enumerate(option_info):
                        last = info.group(1)
                        if is_viable_non_dupe(last, just_string[lang]):
                            just_string[lang].add(last)
                            m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,
                                                  hash_n_string[lang])
                            hash_n_string[lang][m_h] = last
                    if last in just_string[lang]:  # category key should not be translated
                        hash_n_string[lang].pop(m_h)
                        just_string[lang].remove(last)
                else:
                    for j, info in enumerate(option_info):
                        gr1 = info.group(1)
                        if is_viable_non_dupe(gr1, just_string[lang]):
                            just_string[lang].add(gr1)
                            m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,
                                                  hash_n_string[lang])
                            hash_n_string[lang][m_h] = gr1
            else:
                raise ValueError(f'Too few arguments in struct {struct_type_name[1]} option {option.group(1)}!')

            # group 4:
            if option.group(4):
                for j, kv_set in enumerate(cor.p_key_value.finditer(option.group(4))):
                    set_key, set_value = kv_set.group(1, 2)
                    if not is_viable_value(set_value):
                        if not is_viable_value(set_key):
                            continue
                        set_value = set_key
                    # re.fullmatch(r'(?:[+-][0-9]+)+', value[1:-1])
                    if set_value not in just_string[lang] and not re.sub(r'[+-]', '', set_value[1:-1]).isdigit():
                        clean_key = set_key.encode('ascii', errors='ignore').decode('unicode-escape')[1:-1]
                        clean_key = remove_special_chars(clean_key).upper().replace(' ', '_')
                        m_h = create_non_dupe(re.sub(r'__+', '_', f"OPTION_VAL_{clean_key}"), opt, hash_n_string[lang])
                        hash_n_string[lang][m_h] = set_value
                        just_string[lang].add(set_value)
    return hash_n_string


def create_msg_hash(intl_dir_path: str, core_name: str, keyword_string_dict: dict) -&gt; dict:
    """Creates '&lt;core_name&gt;.h' files in 'intl/_&lt;lang&gt;/' containing the macro name &amp; string combinations.

    :param intl_dir_path: Path to the intl directory.
    :param core_name: Name of the core, used for naming the files.
    :param keyword_string_dict: Dictionary of the form { '_&lt;lang&gt;': { 'macro': 'string', ... }, ... }.
    :return: Dictionary of the form { '_&lt;lang&gt;': 'path/to/file (./intl/_&lt;lang&gt;/&lt;core_name&gt;.h)', ... }.
    """
    files = {}
    for localisation in keyword_string_dict:
        path = os.path.join(intl_dir_path, localisation)  # intl/_&lt;lang&gt;
        files[localisation] = os.path.join(path, core_name + '.h')  # intl/_&lt;lang&gt;/&lt;core_name&gt;.h
        if not os.path.exists(path):
            os.makedirs(path)
        with open(files[localisation], 'w', encoding='utf-8') as crowdin_file:
            out_text = ''
            for keyword in keyword_string_dict[localisation]:
                out_text = f'{out_text}{keyword} {keyword_string_dict[localisation][keyword]}\n'
            crowdin_file.write(out_text)
    return files


def h2json(file_paths: dict) -&gt; dict:
    """Converts .h files pointed to by file_paths into .jsons.

    :param file_paths: Dictionary of the form { '_&lt;lang&gt;': 'path/to/file (./intl/_&lt;lang&gt;/&lt;core_name&gt;.h)', ... }.
    :return: Dictionary of the form { '_&lt;lang&gt;': 'path/to/file (./intl/_&lt;lang&gt;/&lt;core_name&gt;.json)', ... }.
    """
    jsons = {}
    for file_lang in file_paths:
        jsons[file_lang] = file_paths[file_lang][:-2] + '.json'

        p = cor.p_masked

        with open(file_paths[file_lang], 'r+', encoding='utf-8') as h_file:
            text = h_file.read()
            result = p.finditer(text)
            messages = {}
            for msg in result:
                key, val = msg.group(1, 2)
                if key not in messages:
                    if key and val:
                        # unescape &amp; remove "\n"
                        messages[key] = re.sub(r'"\s*(?:(?:/\*(?:.|[\r\n])*?\*/|//.*[\r\n]+)\s*)*"',
                                               '\\\n', val[1:-1].replace('\\\"', '"'))
                else:
                    print(f"DUPLICATE KEY in {file_paths[file_lang]}: {key}")
            with open(jsons[file_lang], 'w', encoding='utf-8') as json_file:
                json.dump(messages, json_file, indent=2)

    return jsons


def json2h(intl_dir_path: str, json_file_path: str, core_name: str) -&gt; None:
    """Converts .json file in json_file_path into an .h ready to be included in C code.

    :param intl_dir_path: Path to the intl directory.
    :param json_file_path: Base path of translation .json.
    :param core_name: Name of the core, required for naming the files.
    :return: None
    """
    h_filename = os.path.join(json_file_path, core_name + '.h')
    json_filename = os.path.join(json_file_path, core_name + '.json')
    file_lang = os.path.basename(json_file_path).upper()

    if os.path.basename(json_file_path).lower() == '_us':
        print('    skipped')
        return

    p = cor.p_masked

    def update(s_messages, s_template, s_source_messages):
        translation = ''
        template_messages = p.finditer(s_template)
        for tp_msg in template_messages:
            old_key = tp_msg.group(1)
            if old_key in s_messages and s_messages[old_key] != s_source_messages[old_key]:
                tl_msg_val = s_messages[old_key]
                tl_msg_val = tl_msg_val.replace('"', '\\\"').replace('\n', '')  # escape
                translation = ''.join((translation, '#define ', old_key, file_lang, f' "{tl_msg_val}"\n'))

            else:  # Remove English duplicates and non-translatable strings
                translation = ''.join((translation, '#define ', old_key, file_lang, ' NULL\n'))
        return translation

    with open(os.path.join(intl_dir_path, '_us', core_name + '.h'), 'r', encoding='utf-8') as template_file:
        template = template_file.read()
    with open(os.path.join(intl_dir_path, '_us', core_name + '.json'), 'r+', encoding='utf-8') as source_json_file:
        source_messages = json.load(source_json_file)
    with open(json_filename, 'r+', encoding='utf-8') as json_file:
        messages = json.load(json_file)
        new_translation = update(messages, template, source_messages)
    with open(h_filename, 'w', encoding='utf-8') as h_file:
        h_file.seek(0)
        h_file.write(new_translation)
        h_file.truncate()
    return


def get_crowdin_client(dir_path: str) -&gt; str:
    """Makes sure the Crowdin CLI client is present. If it isn't, it is fetched &amp; extracted.

    :return: The path to 'crowdin-cli.jar'.
    """
    jar_name = 'crowdin-cli.jar'
    jar_path = os.path.join(dir_path, jar_name)

    if not os.path.isfile(jar_path):
        print('Downloading crowdin-cli.jar')
        crowdin_cli_file = os.path.join(dir_path, 'crowdin-cli.zip')
        crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/crowdin-cli.zip'
        req.urlretrieve(crowdin_cli_url, crowdin_cli_file)
        import zipfile
        with zipfile.ZipFile(crowdin_cli_file, 'r') as zip_ref:
            jar_dir = zip_ref.namelist()[0]
            for file in zip_ref.namelist():
                if file.endswith(jar_name):
                    jar_file = file
                    break
            zip_ref.extract(jar_file)
            os.rename(jar_file, jar_path)
            os.remove(crowdin_cli_file)
            shutil.rmtree(jar_dir)
    return jar_path


def create_intl_file(intl_file_path: str, intl_dir_path: str, text: str, core_name: str, file_path: str) -&gt; None:
    """Creates 'libretro_core_options_intl.h' from Crowdin translations.

    :param intl_file_path: Path to 'libretro_core_options_intl.h'
    :param intl_dir_path: Path to the intl directory.
    :param text: Content of the 'libretro_core_options.h' being translated.
    :param core_name: Name of the core. Needed to identify the files to pull the translations from.
    :param file_path: Path to the '&lt;core name&gt;_us.h' file, containing the original English texts.
    :return: None
    """
    msg_dict = {}
    lang_up = ''

    def replace_pair(pair_match):
        """Replaces a key-value-pair of an option with the macros corresponding to the language.

        :param pair_match: The re match object representing the key-value-pair block.
        :return: Replacement string.
        """
        offset = pair_match.start(0)
        if pair_match.group(1):  # key
            if pair_match.group(2) in msg_dict:  # value
                val = msg_dict[pair_match.group(2)] + lang_up
            elif pair_match.group(1) in msg_dict:  # use key if value not viable (e.g. NULL)
                val = msg_dict[pair_match.group(1)] + lang_up
            else:
                return pair_match.group(0)
        else:
            return pair_match.group(0)
        res = pair_match.group(0)[:pair_match.start(2) - offset] + val \
            + pair_match.group(0)[pair_match.end(2) - offset:]
        return res

    def replace_info(info_match):
        """Replaces the 'additional strings' of an option with the macros corresponding to the language.

        :param info_match: The re match object representing the 'additional strings' block.
        :return: Replacement string.
        """
        offset = info_match.start(0)
        if info_match.group(1) in msg_dict:
            res = info_match.group(0)[:info_match.start(1) - offset] + \
                  msg_dict[info_match.group(1)] + lang_up + \
                  info_match.group(0)[info_match.end(1) - offset:]
            return res
        else:
            return info_match.group(0)

    def replace_option(option_match):
        """Replaces strings within an option
        '{ "opt_key", "label", "additional strings", ..., { {"key", "value"}, ... }, ... }'
        within a struct with the macros corresponding to the language:
        '{ "opt_key", MACRO_LABEL, MACRO_STRINGS, ..., { {"key", MACRO_VALUE}, ... }, ... }'

        :param option_match: The re match object representing the option.
        :return: Replacement string.
        """
        # label
        offset = option_match.start(0)
        if option_match.group(2):
            res = option_match.group(0)[:option_match.start(2) - offset] + msg_dict[option_match.group(2)] + lang_up
        else:
            return option_match.group(0)
        # additional block
        if option_match.group(3):
            res = res + option_match.group(0)[option_match.end(2) - offset:option_match.start(3) - offset]
            new_info = p.sub(replace_info, option_match.group(3))
            res = res + new_info
        else:
            return res + option_match.group(0)[option_match.end(2) - offset:]
        # key-value-pairs
        if option_match.group(4):
            res = res + option_match.group(0)[option_match.end(3) - offset:option_match.start(4) - offset]
            new_pairs = cor.p_key_value.sub(replace_pair, option_match.group(4))
            res = res + new_pairs + option_match.group(0)[option_match.end(4) - offset:]
        else:
            res = res + option_match.group(0)[option_match.end(3) - offset:]

        return res

    with open(file_path, 'r+', encoding='utf-8') as template:  # intl/_us/&lt;core_name&gt;.h
        masked_msgs = cor.p_masked.finditer(template.read())
        for msg in masked_msgs:
            msg_dict[msg.group(2)] = msg.group(1)

    with open(intl_file_path, 'r', encoding='utf-8') as intl:  # libretro_core_options_intl.h
        in_text = intl.read()
        intl_start = re.search(re.escape('/*\n'
                                         ' ********************************\n'
                                         ' * Core Option Definitions\n'
                                         ' ********************************\n'
                                         '*/\n'), in_text)
        if intl_start:
            out_txt = in_text[:intl_start.end(0)]
        else:
            intl_start = re.search(re.escape('#ifdef __cplusplus\n'
                                             'extern "C" {\n'
                                             '#endif\n'), in_text)
            out_txt = in_text[:intl_start.end(0)]

    for folder in os.listdir(intl_dir_path):  # intl/_*
        if os.path.isdir(os.path.join(intl_dir_path, folder)) and folder.startswith('_')\
                and folder != '_us' and folder != '__pycache__':
            translation_path = os.path.join(intl_dir_path, folder, core_name + '.h')  # &lt;core_name&gt;_&lt;lang&gt;.h
            # all structs: group(0) full struct, group(1) beginning, group(2) content
            struct_groups = cor.p_struct.finditer(text)
            lang_up = folder.upper()
            lang_low = folder.lower()
            out_txt = out_txt + f'/* {LANG_CODE_TO_R_LANG[lang_low]} */\n\n'  # /* RETRO_LANGUAGE_NAME */
            with open(translation_path, 'r+', encoding='utf-8') as f_in:  # &lt;core name&gt;.h
                out_txt = out_txt + f_in.read() + '\n'
            for construct in struct_groups:
                declaration = construct.group(1)
                struct_type_name = get_struct_type_name(declaration)
                if 3 &gt; len(struct_type_name):  # no language specifier
                    new_decl = re.sub(re.escape(struct_type_name[1]), struct_type_name[1] + lang_low, declaration)
                else:
                    new_decl = re.sub(re.escape(struct_type_name[2]), lang_low, declaration)
                    if '_us' != struct_type_name[2]:
                        continue

                p = cor.p_info
                if 'retro_core_option_v2_category' == struct_type_name[0]:
                    p = cor.p_info_cat
                offset_construct = construct.start(0)
                start = construct.end(1) - offset_construct
                end = construct.start(2) - offset_construct
                out_txt = out_txt + new_decl + construct.group(0)[start:end]

                content = construct.group(2)
                new_content = cor.p_option.sub(replace_option, content)

                start = construct.end(2) - offset_construct
                out_txt = out_txt + new_content + construct.group(0)[start:] + '\n'

                if 'retro_core_option_v2_definition' == struct_type_name[0]:
                    out_txt = out_txt + f'struct retro_core_options_v2 options{lang_low}' \
                                        ' = {\n' \
                                        f'   option_cats{lang_low},\n' \
                                        f'   option_defs{lang_low}\n' \
                                        '};\n\n'
        #    shutil.rmtree(JOINER.join((intl_dir_path, folder)))

    with open(intl_file_path, 'w', encoding='utf-8') as intl:
        intl.write(out_txt + '\n#ifdef __cplusplus\n'
                             '}\n#endif\n'
                             '\n#endif')
    return


# --------------------          MAIN          -------------------- #

if __name__ == '__main__':
    #
    try:
        if os.path.isfile(sys.argv[1]):
            _temp = os.path.dirname(sys.argv[1])
        else:
            _temp = sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        TARGET_DIR_PATH = _temp
    except IndexError:
        TARGET_DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)

    DIR_PATH = os.path.dirname(os.path.realpath(__file__))
    H_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')
    INTL_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')

    _core_name = 'core_options'
    try:
        print('Getting texts from libretro_core_options.h')
        with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
            _main_text = _h_file.read()
        _hash_n_str = get_texts(_main_text)
        _files = create_msg_hash(DIR_PATH, _core_name, _hash_n_str)
        _source_jsons = h2json(_files)
    except Exception as e:
        print(e)

    print('Getting texts from libretro_core_options_intl.h')
    with open(INTL_FILE_PATH, 'r+', encoding='utf-8') as _intl_file:
        _intl_text = _intl_file.read()
        _hash_n_str_intl = get_texts(_intl_text)
        _intl_files = create_msg_hash(DIR_PATH, _core_name, _hash_n_str_intl)
        _intl_jsons = h2json(_intl_files)

    print('\nAll done!')</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_intl.py</h2>
<pre>#!/usr/bin/env python3

import core_opt_translation as t


if __name__ == '__main__':
    try:
        if t.os.path.isfile(t.sys.argv[1]):
            _temp = t.os.path.dirname(t.sys.argv[1])
        else:
            _temp = t.sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        TARGET_DIR_PATH = _temp
    except IndexError:
        TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)

    DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))
    H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')
    INTL_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')

    _core_name = 'core_options'
    _core_name = t.clean_file_name(_core_name)

    print('Getting texts from libretro_core_options.h')
    with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
        _main_text = _h_file.read()
    _hash_n_str = t.get_texts(_main_text)
    _files = t.create_msg_hash(DIR_PATH, _core_name, _hash_n_str)

    print('Converting translations *.json to *.h:')
    for _folder in t.os.listdir(DIR_PATH):
        if t.os.path.isdir(t.os.path.join(DIR_PATH, _folder))\
                and _folder.startswith('_')\
                and _folder != '__pycache__':
            print(_folder)
            t.json2h(DIR_PATH, t.os.path.join(DIR_PATH, _folder), _core_name)

    print('Constructing libretro_core_options_intl.h')
    t.create_intl_file(INTL_FILE_PATH, DIR_PATH, _main_text, _core_name, _files['_us'])

    print('\nAll done!')</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_prep.py</h2>
<pre>#!/usr/bin/env python3

import core_opt_translation as t


if __name__ == '__main__':
    _core_name = 'core_options'

    try:
        if t.os.path.isfile(t.sys.argv[1]):
            _temp = t.os.path.dirname(t.sys.argv[1])
        else:
            _temp = t.sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        TARGET_DIR_PATH = _temp
    except IndexError:
        TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)

    DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))
    H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')

    _core_name = t.clean_file_name(_core_name)

    print('Getting texts from libretro_core_options.h')
    with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
        _main_text = _h_file.read()
    _hash_n_str = t.get_texts(_main_text)
    _files = t.create_msg_hash(DIR_PATH, _core_name, _hash_n_str)

    _source_jsons = t.h2json(_files)

    print('\nAll done!')</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/.gitignore</h2>
<pre>__pycache__</pre>
<h2>./include/libretro-common/samples/core_options/example_translation/translation scripts/intl/v1_to_v2_converter.py</h2>
<pre>#!/usr/bin/env python3

"""Core options v1 to v2 converter

Just run this script as follows, to convert 'libretro_core_options.h' &amp; 'Libretro_coreoptions_intl.h' to v2:
python3 "/path/to/v1_to_v2_converter.py" "/path/to/where/libretro_core_options.h &amp; Libretro_coreoptions_intl.h/are"

The original files will be preserved as *.v1
"""
import core_option_regex as cor
import os
import sys


def create_v2_code_file(struct_text, file_name):
    def replace_option(option_match):
        _offset = option_match.start(0)

        if option_match.group(3):
            res = option_match.group(0)[:option_match.end(2) - _offset] + ',\n      NULL' + \
                  option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \
                  'NULL,\n      NULL,\n      ' + option_match.group(0)[option_match.end(3) - _offset:]
        else:
            return option_match.group(0)

        return res

    comment_v1 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 1.3\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    comment_v2 = '/*\n' \
                 ' ********************************\n' \
                 ' * VERSION: 2.0\n' \
                 ' ********************************\n' \
                 ' *\n' \
                 ' * - 2.0: Add support for core options v2 interface\n' \
                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
                 ' *          fix for MSVC 2010-2013\n' \
                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
                 ' *          on platforms/compilers without BOM support\n' \
                 ' * - 1.2: Use core options v1 interface when\n' \
                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is &gt;= 1\n' \
                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
                 ' *        arrays containing options with a single value\n' \
                 ' * - 1.0: First commit\n' \
                 '*/\n'

    p_intl = cor.p_intl
    p_set = cor.p_set
    new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\n' \
              '      bool *categories_supported)\n' \
              '{\n' \
              '   unsigned version  = 0;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '   unsigned language = 0;\n' \
              '#endif\n' \
              '\n' \
              '   if (!environ_cb || !categories_supported)\n' \
              '      return;\n' \
              '\n' \
              '   *categories_supported = false;\n' \
              '\n' \
              '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &amp;version))\n' \
              '      version = 0;\n' \
              '\n' \
              '   if (version &gt;= 2)\n' \
              '   {\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      struct retro_core_options_v2_intl core_options_intl;\n' \
              '\n' \
              '      core_options_intl.us    = &amp;options_us;\n' \
              '      core_options_intl.local = NULL;\n' \
              '\n' \
              '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;\n' \
              '          (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH))\n' \
              '         core_options_intl.local = options_intl[language];\n' \
              '\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n' \
              '            &amp;core_options_intl);\n' \
              '#else\n' \
              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n' \
              '            &amp;options_us);\n' \
              '#endif\n' \
              '   }\n' \
              '   else\n' \
              '   {\n' \
              '      size_t i, j;\n' \
              '      size_t option_index              = 0;\n' \
              '      size_t num_options               = 0;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_us         = NULL;\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      size_t num_options_intl          = 0;\n' \
              '      struct retro_core_option_v2_definition\n' \
              '            *option_defs_intl          = NULL;\n' \
              '      struct retro_core_option_definition\n' \
              '            *option_v1_defs_intl       = NULL;\n' \
              '      struct retro_core_options_intl\n' \
              '            core_options_v1_intl;\n' \
              '#endif\n' \
              '      struct retro_variable *variables = NULL;\n' \
              '      char **values_buf                = NULL;\n' \
              '\n' \
              '      /* Determine total number of options */\n' \
              '      while (true)\n' \
              '      {\n' \
              '         if (option_defs_us[num_options].key)\n' \
              '            num_options++;\n' \
              '         else\n' \
              '            break;\n' \
              '      }\n' \
              '\n' \
              '      if (version &gt;= 1)\n' \
              '      {\n' \
              '         /* Allocate US array */\n' \
              '         option_v1_defs_us = (struct retro_core_option_definition *)\n' \
              '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i &lt; num_options; i++)\n' \
              '         {\n' \
              '            struct retro_core_option_v2_definition *option_def_us = &amp;option_defs_us[i];\n' \
              '            struct retro_core_option_value *option_values         = option_def_us-&gt;values;\n' \
              '            struct retro_core_option_definition *option_v1_def_us = &amp;option_v1_defs_us[i];\n' \
              '            struct retro_core_option_value *option_v1_values      = option_v1_def_us-&gt;values;\n' \
              '\n' \
              '            option_v1_def_us-&gt;key           = option_def_us-&gt;key;\n' \
              '            option_v1_def_us-&gt;desc          = option_def_us-&gt;desc;\n' \
              '            option_v1_def_us-&gt;info          = option_def_us-&gt;info;\n' \
              '            option_v1_def_us-&gt;default_value = option_def_us-&gt;default_value;\n' \
              '\n' \
              '            /* Values must be copied individually... */\n' \
              '            while (option_values-&gt;value)\n' \
              '            {\n' \
              '               option_v1_values-&gt;value = option_values-&gt;value;\n' \
              '               option_v1_values-&gt;label = option_values-&gt;label;\n' \
              '\n' \
              '               option_values++;\n' \
              '               option_v1_values++;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &amp;language) &amp;&amp;\n' \
              '             (language &lt; RETRO_LANGUAGE_LAST) &amp;&amp; (language != RETRO_LANGUAGE_ENGLISH) &amp;&amp;\n' \
              '             options_intl[language])\n' \
              '            option_defs_intl = options_intl[language]-&gt;definitions;\n' \
              '\n' \
              '         if (option_defs_intl)\n' \
              '         {\n' \
              '            /* Determine number of intl options */\n' \
              '            while (true)\n' \
              '            {\n' \
              '               if (option_defs_intl[num_options_intl].key)\n' \
              '                  num_options_intl++;\n' \
              '               else\n' \
              '                  break;\n' \
              '            }\n' \
              '\n' \
              '            /* Allocate intl array */\n' \
              '            option_v1_defs_intl = (struct retro_core_option_definition *)\n' \
              '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\n' \
              '\n' \
              '            /* Copy parameters from option_defs_intl array */\n' \
              '            for (i = 0; i &lt; num_options_intl; i++)\n' \
              '            {\n' \
              '               struct retro_core_option_v2_definition *option_def_intl = &amp;option_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_values           = option_def_intl-&gt;values;\n' \
              '               struct retro_core_option_definition *option_v1_def_intl = &amp;option_v1_defs_intl[i];\n' \
              '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl-&gt;values;\n' \
              '\n' \
              '               option_v1_def_intl-&gt;key           = option_def_intl-&gt;key;\n' \
              '               option_v1_def_intl-&gt;desc          = option_def_intl-&gt;desc;\n' \
              '               option_v1_def_intl-&gt;info          = option_def_intl-&gt;info;\n' \
              '               option_v1_def_intl-&gt;default_value = option_def_intl-&gt;default_value;\n' \
              '\n' \
              '               /* Values must be copied individually... */\n' \
              '               while (option_values-&gt;value)\n' \
              '               {\n' \
              '                  option_v1_values-&gt;value = option_values-&gt;value;\n' \
              '                  option_v1_values-&gt;label = option_values-&gt;label;\n' \
              '\n' \
              '                  option_values++;\n' \
              '                  option_v1_values++;\n' \
              '               }\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         core_options_v1_intl.us    = option_v1_defs_us;\n' \
              '         core_options_v1_intl.local = option_v1_defs_intl;\n' \
              '\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &amp;core_options_v1_intl);\n' \
              '#else\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\n' \
              '#endif\n' \
              '      }\n' \
              '      else\n' \
              '      {\n' \
              '         /* Allocate arrays */\n' \
              '         variables  = (struct retro_variable *)calloc(num_options + 1,\n' \
              '               sizeof(struct retro_variable));\n' \
              '         values_buf = (char **)calloc(num_options, sizeof(char *));\n' \
              '\n' \
              '         if (!variables || !values_buf)\n' \
              '            goto error;\n' \
              '\n' \
              '         /* Copy parameters from option_defs_us array */\n' \
              '         for (i = 0; i &lt; num_options; i++)\n' \
              '         {\n' \
              '            const char *key                        = option_defs_us[i].key;\n' \
              '            const char *desc                       = option_defs_us[i].desc;\n' \
              '            const char *default_value              = option_defs_us[i].default_value;\n' \
              '            struct retro_core_option_value *values = option_defs_us[i].values;\n' \
              '            size_t buf_len                         = 3;\n' \
              '            size_t default_index                   = 0;\n' \
              '\n' \
              '            values_buf[i] = NULL;\n' \
              '\n' \
              '            if (desc)\n' \
              '            {\n' \
              '               size_t num_values = 0;\n' \
              '\n' \
              '               /* Determine number of values */\n' \
              '               while (true)\n' \
              '               {\n' \
              '                  if (values[num_values].value)\n' \
              '                  {\n' \
              '                     /* Check if this is the default value */\n' \
              '                     if (default_value)\n' \
              '                        if (strcmp(values[num_values].value, default_value) == 0)\n' \
              '                           default_index = num_values;\n' \
              '\n' \
              '                     buf_len += strlen(values[num_values].value);\n' \
              '                     num_values++;\n' \
              '                  }\n' \
              '                  else\n' \
              '                     break;\n' \
              '               }\n' \
              '\n' \
              '               /* Build values string */\n' \
              '               if (num_values &gt; 0)\n' \
              '               {\n' \
              '                  buf_len += num_values - 1;\n' \
              '                  buf_len += strlen(desc);\n' \
              '\n' \
              '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\n' \
              '                  if (!values_buf[i])\n' \
              '                     goto error;\n' \
              '\n' \
              '                  strcpy(values_buf[i], desc);\n' \
              '                  strcat(values_buf[i], "; ");\n' \
              '\n' \
              '                  /* Default value goes first */\n' \
              '                  strcat(values_buf[i], values[default_index].value);\n' \
              '\n' \
              '                  /* Add remaining values */\n' \
              '                  for (j = 0; j &lt; num_values; j++)\n' \
              '                  {\n' \
              '                     if (j != default_index)\n' \
              '                     {\n' \
              '                        strcat(values_buf[i], "|");\n' \
              '                        strcat(values_buf[i], values[j].value);\n' \
              '                     }\n' \
              '                  }\n' \
              '               }\n' \
              '            }\n' \
              '\n' \
              '            variables[option_index].key   = key;\n' \
              '            variables[option_index].value = values_buf[i];\n' \
              '            option_index++;\n' \
              '         }\n' \
              '\n' \
              '         /* Set variables */\n' \
              '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n' \
              '      }\n' \
              '\n' \
              'error:\n' \
              '      /* Clean up */\n' \
              '\n' \
              '      if (option_v1_defs_us)\n' \
              '      {\n' \
              '         free(option_v1_defs_us);\n' \
              '         option_v1_defs_us = NULL;\n' \
              '      }\n' \
              '\n' \
              '#ifndef HAVE_NO_LANGEXTRA\n' \
              '      if (option_v1_defs_intl)\n' \
              '      {\n' \
              '         free(option_v1_defs_intl);\n' \
              '         option_v1_defs_intl = NULL;\n' \
              '      }\n' \
              '#endif\n' \
              '\n' \
              '      if (values_buf)\n' \
              '      {\n' \
              '         for (i = 0; i &lt; num_options; i++)\n' \
              '         {\n' \
              '            if (values_buf[i])\n' \
              '            {\n' \
              '               free(values_buf[i]);\n' \
              '               values_buf[i] = NULL;\n' \
              '            }\n' \
              '         }\n' \
              '\n' \
              '         free(values_buf);\n' \
              '         values_buf = NULL;\n' \
              '      }\n' \
              '\n' \
              '      if (variables)\n' \
              '      {\n' \
              '         free(variables);\n' \
              '         variables = NULL;\n' \
              '      }\n' \
              '   }\n' \
              '}\n' \
              '\n' \
              '#ifdef __cplusplus\n' \
              '}\n' \
              '#endif'

    struct_groups = cor.p_struct.finditer(struct_text)
    out_text = struct_text

    for construct in struct_groups:
        repl_text = ''
        declaration = construct.group(1)
        struct_match = cor.p_type_name.search(declaration)
        if struct_match:
            if struct_match.group(3):
                struct_type_name_lang = struct_match.group(1, 2, 3)
                declaration_end = declaration[struct_match.end(1):]
            elif struct_match.group(4):
                struct_type_name_lang = struct_match.group(1, 2, 4)
                declaration_end = declaration[struct_match.end(1):]
            else:
                struct_type_name_lang = sum((struct_match.group(1, 2), ('_us',)), ())
                declaration_end = f'{declaration[struct_match.end(1):struct_match.end(2)]}_us' \
                                  f'{declaration[struct_match.end(2):]}'
        else:
            return -1

        if 'retro_core_option_definition' == struct_type_name_lang[0]:
            import shutil
            shutil.copy(file_name, file_name + '.v1')
            new_declaration = f'\nstruct retro_core_option_v2_category option_cats{struct_type_name_lang[2]}[] = ' \
                              '{\n   { NULL, NULL, NULL },\n' \
                              '};\n\n' \
                              + declaration[:struct_match.start(1)] + \
                              'retro_core_option_v2_definition' \
                              + declaration_end
            offset = construct.start(0)
            repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,
                                               construct.group(0)[:construct.start(2) - offset])
            content = construct.group(2)
            new_content = cor.p_option.sub(replace_option, content)

            repl_text = repl_text + new_content + cor.re.sub(r'{\s*NULL,\s*NULL,\s*NULL,\s*{\{0}},\s*NULL\s*},\s*};',
                                                             '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};'
                                                             '\n\nstruct retro_core_options_v2 options' +
                                                             struct_type_name_lang[2] + ' = {\n'
                                                             f'   option_cats{struct_type_name_lang[2]},\n'
                                                             f'   option_defs{struct_type_name_lang[2]}\n'
                                                             '};',
                                                             construct.group(0)[construct.end(2) - offset:])
            out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text)
        else:
            return -2
    with open(file_name, 'w', encoding='utf-8') as code_file:
        out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)
        intl = p_intl.search(out_text)
        if intl:
            new_intl = out_text[:intl.start(1)] \
                       + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \
                       + out_text[intl.end(1):intl.start(2)] \
                       + '&amp;options_us, /* RETRO_LANGUAGE_ENGLISH */' \
                       '   &amp;options_ja,      /* RETRO_LANGUAGE_JAPANESE */' \
                       '   &amp;options_fr,      /* RETRO_LANGUAGE_FRENCH */' \
                       '   &amp;options_es,      /* RETRO_LANGUAGE_SPANISH */' \
                       '   &amp;options_de,      /* RETRO_LANGUAGE_GERMAN */' \
                       '   &amp;options_it,      /* RETRO_LANGUAGE_ITALIAN */' \
                       '   &amp;options_nl,      /* RETRO_LANGUAGE_DUTCH */' \
                       '   &amp;options_pt_br,   /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */' \
                       '   &amp;options_pt_pt,   /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */' \
                       '   &amp;options_ru,      /* RETRO_LANGUAGE_RUSSIAN */' \
                       '   &amp;options_ko,      /* RETRO_LANGUAGE_KOREAN */' \
                       '   &amp;options_cht,     /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */' \
                       '   &amp;options_chs,     /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */' \
                       '   &amp;options_eo,      /* RETRO_LANGUAGE_ESPERANTO */' \
                       '   &amp;options_pl,      /* RETRO_LANGUAGE_POLISH */' \
                       '   &amp;options_vn,      /* RETRO_LANGUAGE_VIETNAMESE */' \
                       '   &amp;options_ar,      /* RETRO_LANGUAGE_ARABIC */' \
                       '   &amp;options_el,      /* RETRO_LANGUAGE_GREEK */' \
                       '   &amp;options_tr,      /* RETRO_LANGUAGE_TURKISH */' \
                       '   &amp;options_sv,      /* RETRO_LANGUAGE_SLOVAK */' \
                       '   &amp;options_fa,      /* RETRO_LANGUAGE_PERSIAN */' \
                       '   &amp;options_he,      /* RETRO_LANGUAGE_HEBREW */' \
                       '   &amp;options_ast,     /* RETRO_LANGUAGE_ASTURIAN */' \
                       '   &amp;options_fi,      /* RETRO_LANGUAGE_FINNISH */' \
                       + out_text[intl.end(2):]
            out_text = p_set.sub(new_set, new_intl)
        else:
            out_text = p_set.sub(new_set, out_text)
        code_file.write(out_text)

    return 1


# --------------------          MAIN          -------------------- #

if __name__ == '__main__':
    try:
        if os.path.isfile(sys.argv[1]):
            _temp = os.path.dirname(sys.argv[1])
        else:
            _temp = sys.argv[1]
        while _temp.endswith('/') or _temp.endswith('\\'):
            _temp = _temp[:-1]
        DIR_PATH = _temp
    except IndexError:
        DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
        print("No path provided, assuming parent directory:\n" + DIR_PATH)

    H_FILE_PATH = os.path.join(DIR_PATH, 'libretro_core_options.h')
    INTL_FILE_PATH = os.path.join(DIR_PATH, 'libretro_core_options_intl.h')

    for file in (H_FILE_PATH, INTL_FILE_PATH):
        if os.path.isfile(file):
            with open(file, 'r+', encoding='utf-8') as h_file:
                text = h_file.read()
                try:
                    test = create_v2_code_file(text, file)
                except Exception as e:
                    print(e)
                    test = -1
                if -1 &gt; test:
                    print('Your file looks like it already is v2? (' + file + ')')
                    continue
                if 0 &gt; test:
                    print('An error occurred! Please make sure to use the complete v1 struct! (' + file + ')')
                    continue
        else:
            print(file + ' not found.')</pre>
<h2>./include/libretro-common/samples/core_options/README.md</h2>
<pre>## Adding 'enhanced' core options to a core

The basic steps for updating a core to support core options v1 are as follows:

- Copy `example_default/libretro_core_options.h` to the same directory as `libretro.c/.cpp`

- Copy `example_default/libretro_core_options_intl.h` to the same directory as `libretro.c/.cpp`

- Add `#include "libretro_core_options.h"` to `libretro.c/.cpp`

- Replace any existing calls of `RETRO_ENVIRONMENT_SET_VARIABLES` with `libretro_set_core_options(retro_environment_t environ_cb)`  
  (Note: `libretro_set_core_options()` should be called as early as possible - preferably in `retro_set_environment()`  
  and no later than `retro_load_game()`)

- Open `libretro_core_options.h` and replace the contents of the existing `option_defs_us` struct array with all required core option parameters.  

## Adding core option translations

To add a translation, simply:

- Copy the contents of `option_defs_us` *from* `libretro_core_options.h` *to* `libretro_core_options_intl.h` into a new struct array with the appropriate language suffix

- Translate all human-readable strings

- Add the new struct array to the appropriate location in the `option_defs_intl` array inside `libretro_core_options.h`

This is most easily understood by considering the example in `example_translation/`. Here a French translation has been added (`option_defs_fr`), with comments explaining the appropriate formatting requirements.

NOTE: Since translations involve the use of UTF-8 characters, `libretro_core_options_intl.h` must include a BOM marker. *This renders translations incompatible with c89 builds*. When performing a c89 build, the flag `HAVE_NO_LANGEXTRA` *must* be defined (e.g. `-DHAVE_NO_LANGEXTRA`). This will disable all translations.

## Disabling core options on unsupported frontends

Sometimes it is desirable to only show a particular core option if the frontend supports the new core options v1 API. For example:

- The API v1 allows cores to hide options dynamically

- We can therefore create a specific 'toggle display' option to hide or show a number of other options (e.g. advanced settings)

- On frontends that do not support API v1, this 'toggle display' option will have no function - it should therefore be omitted

This can be handled easily by editing the `libretro_set_core_options()` function to ignore certain core name (key) values when generating option variable arrays for old-style frontends. Again, this is most easily understood by considering the example in `example_hide_option/libretro_core_options.h`:

- Here, a `mycore_show_speedhacks` option is added to `option_defs_us`

- On line 227, the following comparison allows the option to be skipped:  
  (Note that another `strcmp()` may be added for each option to be omitted)

```c
if (strcmp(key, "mycore_show_speedhacks") == 0)
	continue;
```

For any cores that require this functionality, `example_hide_option/libretro_core_options.h` should be used as a template in place of `example_default/libretro_core_options.h`

## Adding core option categories

Core options v2 adds a mechanism for assigning categories to options. On supported fontends, options of a particular category will be displayed in a submenu/subsection of the main core options menu. This functionality may be used to reduce visual clutter, or to effectively 'hide' advanced settings without requiring a dedicated 'toggle display' option.

A template for enabling categories via the core options v2 interface is provided in `example_categories`. The usage of this code is identical to that described in the `Adding 'enhanced' core options to a core` section, with one addition: the `libretro_set_core_options()` function here includes an additional argument identifying whether the frontend has option category support (a core may wish to selectively hide or reorganise options based upon this variable).</pre>
<h2>./include/libretro-common/samples/file/config_file/config_file_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdio.h&gt;
#include &lt;ctype.h&gt;
#include &lt;errno.h&gt;

#include &lt;file/config_file.h&gt;

static void test_config_file_parse_contains(
      const char *cfgtext,
      const char *key, const char *val)
{
   char *cfgtext_copy = strdup(cfgtext);
   config_file_t *cfg = config_file_new_from_string(cfgtext_copy, NULL);
   char          *out = NULL;
   bool            ok = false;

   free(cfgtext_copy);

   if (!cfg)
      abort();

   ok = config_get_string(cfg, key, &amp;out);
   if (ok != (bool)val)
      abort();
   if (!val)
      return;

   if (!out)
      out = strdup("");
   if (strcmp(out, val) != 0)
   {
      printf("[FAILED] Key [%s] Doesn't contain val [%s]\n", key, val);
      abort();
   }
   printf("[SUCCESS] Key [%s] contains val [%s]\n", key, val);
   free(out);
}

int main(void)
{
   test_config_file_parse_contains("foo = \"bar\"\n",   "foo", "bar");
   test_config_file_parse_contains("foo = \"bar\"",     "foo", "bar");
   test_config_file_parse_contains("foo = \"bar\"\r\n", "foo", "bar");
   test_config_file_parse_contains("foo = \"bar\"",     "foo", "bar");

   test_config_file_parse_contains("foo = \"\"\n",   "foo", "");
   test_config_file_parse_contains("foo = \"\"",     "foo", "");
   test_config_file_parse_contains("foo = \"\"\r\n", "foo", "");
   test_config_file_parse_contains("foo = \"\"",     "foo", "");

   test_config_file_parse_contains("foo = \"\"\n",   "bar", NULL);
   test_config_file_parse_contains("foo = \"\"",     "bar", NULL);
   test_config_file_parse_contains("foo = \"\"\r\n", "bar", NULL);
   test_config_file_parse_contains("foo = \"\"",     "bar", NULL);
}</pre>
<h2>./include/libretro-common/samples/file/config_file/Makefile</h2>
<pre>TARGET := config_file_test

LIBRETRO_COMM_DIR := ../../..

SOURCES := \
	config_file_test.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/file/file_path.c \
	$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
	$(LIBRETRO_COMM_DIR)/file/config_file.c \
	$(LIBRETRO_COMM_DIR)/lists/string_list.c \
	$(LIBRETRO_COMM_DIR)/string/stdstring.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
	$(LIBRETRO_COMM_DIR)/time/rtime.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/file/nbio/Makefile</h2>
<pre>TARGET := nbio_test

LIBRETRO_COMM_DIR := ../../..

SOURCES := \
	nbio_test.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/file/nbio/nbio_test.c</h2>
<pre>#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#include &lt;file/nbio.h&gt;

static void nbio_write_test(void)
{
   size_t _len;
   bool looped = false;
   void *ptr   = NULL;
   struct nbio_t* write = nbio_open("test.bin", NBIO_WRITE);
   if (!write)
      puts("[ERROR] nbio_open failed (1)");

   nbio_resize(write, 1024*1024);

   ptr = nbio_get_ptr(write, &amp;_len);
   if (_len != 1024*1024)
      puts("[ERROR] wrong size (1)");

   memset(ptr, 0x42, 1024*1024);
   nbio_begin_write(write);

   while (!nbio_iterate(write))
      looped=true;

   if (!looped)
      puts("[SUCCESS] Write finished immediately.");

   nbio_free(write);
}

static void nbio_read_test(void)
{
   size_t _len;
   bool looped = false;
   struct nbio_t* read = nbio_open("test.bin", NBIO_READ);
   void* ptr           = nbio_get_ptr(read, &amp;_len);
   if (!read)
      puts("[ERROR] nbio_open failed (2)");

   if (_len != 1024*1024)
      puts("[ERROR] wrong size (2)");
   if (ptr)
      puts("[SUCCESS] Read pointer is available before iterating.");

   nbio_begin_read(read);

   while (!nbio_iterate(read))
      looped=true;

   if (!looped)
      puts("[SUCCESS] Read finished immediately.");

   ptr = nbio_get_ptr(read, &amp;_len);

   if (_len != 1024*1024)
      puts("[ERROR] wrong size (3)");
   if (*(char*)ptr != 0x42 || memcmp(ptr, (char*)ptr+1, 1024*1024-1))
      puts("[ERROR] wrong data");

   nbio_free(read);
}

int main(void)
{
   nbio_write_test();
   nbio_read_test();
}</pre>
<h2>./include/libretro-common/samples/formats/png/Makefile</h2>
<pre>TARGET := rpng

CORE_DIR          := .
LIBRETRO_PNG_DIR  := ../../../formats/png
LIBRETRO_COMM_DIR := ../../..

HAVE_IMLIB2=0

LDFLAGS +=  -lz

ifeq ($(HAVE_IMLIB2),1)
CFLAGS += -DHAVE_IMLIB2
LDFLAGS += -lImlib2
endif

SOURCES_C := 	\
	$(CORE_DIR)/rpng_test.c \
	$(LIBRETRO_PNG_DIR)/rpng.c \
	$(LIBRETRO_PNG_DIR)/rpng_encode.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/string/stdstring.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \
	$(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \
	$(LIBRETRO_COMM_DIR)/file/archive_file.c \
	$(LIBRETRO_COMM_DIR)/file/archive_file_zlib.c \
	$(LIBRETRO_COMM_DIR)/file/file_path.c \
	$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
	$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
	$(LIBRETRO_COMM_DIR)/lists/string_list.c

OBJS := $(SOURCES_C:.c=.o)

CFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB -DRPNG_TEST -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/formats/png/rpng_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rpng_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;
#ifdef HAVE_IMLIB2
#include &lt;Imlib2.h&gt;
#endif

#include &lt;file/nbio.h&gt;
#include &lt;formats/rpng.h&gt;
#include &lt;formats/image.h&gt;

static bool rpng_load_image_argb(const char *path, uint32_t **data,
      unsigned *width, unsigned *height)
{
   int retval;
   size_t file_len;
   bool              ret = true;
   rpng_t          *rpng = NULL;
   void             *ptr = NULL;
   struct nbio_t* handle = (struct nbio_t*)nbio_open(path, NBIO_READ);

   if (!handle)
      goto end;

   nbio_begin_read(handle);

   while (!nbio_iterate(handle));

   ptr = nbio_get_ptr(handle, &amp;file_len);

   if (!ptr)
   {
      ret = false;
      goto end;
   }

   rpng = rpng_alloc();

   if (!rpng)
   {
      ret = false;
      goto end;
   }

   if (!rpng_set_buf_ptr(rpng, (uint8_t*)ptr, file_len))
   {
      ret = false;
      goto end;
   }

   if (!rpng_start(rpng))
   {
      ret = false;
      goto end;
   }

   while (rpng_iterate_image(rpng));

   if (!rpng_is_valid(rpng))
   {
      ret = false;
      goto end;
   }

   do
   {
      retval = rpng_process_image(rpng,
            (void**)data, file_len, width, height);
   }while(retval == IMAGE_PROCESS_NEXT);

   if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)
      ret = false;

end:
   if (handle)
      nbio_free(handle);
   if (rpng)
      rpng_free(rpng);
   rpng = NULL;
   if (!ret)
      free(*data);
   return ret;
}

static int test_rpng(const char *in_path)
{
#ifdef HAVE_IMLIB2
   Imlib_Image img;
   const uint32_t *imlib_data = NULL;
#endif
   const uint32_t test_data[] = {
      0xff000000 | 0x50, 0xff000000 | 0x80,
      0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0x50, 0xff000000 | 0x80,
      0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
   };
   uint32_t *data = NULL;
   unsigned width = 0;
   unsigned height = 0;

   if (!rpng_save_image_argb("/tmp/test.png", test_data, 4, 4, 16))
      return 1;

   if (!rpng_load_image_argb(in_path, &amp;data, &amp;width, &amp;height))
      return 2;

   fprintf(stderr, "Path: %s.\n", in_path);
   fprintf(stderr, "Got image: %u x %u.\n", width, height);

#if 0
   fprintf(stderr, "\nRPNG:\n");
   for (unsigned h = 0; h &lt; height; h++)
   {
      unsigned w;
      for (w = 0; w &lt; width; w++)
         fprintf(stderr, "[%08x] ", data[h * width + w]);
      fprintf(stderr, "\n");
   }
#endif

#ifdef HAVE_IMLIB2
   /* Validate with imlib2 as well. */
   img = imlib_load_image(in_path);
   if (!img)
      return 4;

   imlib_context_set_image(img);

   width      = imlib_image_get_width();
   height     = imlib_image_get_width();
   imlib_data = imlib_image_get_data_for_reading_only();

#if 0
   fprintf(stderr, "\nImlib:\n");
   for (unsigned h = 0; h &lt; height; h++)
   {
      for (unsigned w = 0; w &lt; width; w++)
         fprintf(stderr, "[%08x] ", imlib_data[h * width + w]);
      fprintf(stderr, "\n");
   }
#endif

   if (memcmp(imlib_data, data, width * height * sizeof(uint32_t)) != 0)
   {
      fprintf(stderr, "Imlib and RPNG differs!\n");
      return 5;
   }
   else
      fprintf(stderr, "Imlib and RPNG are equivalent!\n");

   imlib_free_image();
#endif
   free(data);

   return 0;
}

int main(int argc, char *argv[])
{
   const char *in_path = "/tmp/test.png";

   if (argc &gt; 2)
   {
      fprintf(stderr, "Usage: %s &lt;png file&gt;\n", argv[0]);
      return 1;
   }

   if (argc == 2)
      in_path = argv[1];

   fprintf(stderr, "Doing tests...\n");

   if (test_rpng(in_path) != 0)
   {
      fprintf(stderr, "Test failed.\n");
      return -1;
   }

   return 0;
}</pre>
<h2>./include/libretro-common/samples/formats/xml/Makefile</h2>
<pre>TARGET := rxml

LIBRETRO_XML_DIR  := ../../../formats/xml
LIBRETRO_COMM_DIR := ../../../
LIBRETRO_DEPS_DIR := ../../../../deps

SOURCES := \
	rxml_test.c \
	$(LIBRETRO_XML_DIR)/rxml.c \
	$(LIBRETRO_DEPS_DIR)/yxml/yxml.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c

OBJS := $(SOURCES:.c=.o)

CFLAGS += -DRXML_TEST -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/formats/xml/rxml_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rxml_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;formats/rxml.h&gt;
#include &lt;stdio.h&gt;

static void print_siblings(struct rxml_node *node, unsigned level)
{
   fprintf(stderr, "\n%*sName: %s\n", level * 4, "", node-&gt;name);
   if (node-&gt;data)
      fprintf(stderr, "%*sData: %s\n", level * 4, "", node-&gt;data);

   for (const struct rxml_attrib_node *attrib =
         node-&gt;attrib; attrib; attrib = attrib-&gt;next)
      fprintf(stderr, "%*s  Attrib: %s = %s\n", level * 4, "",
            attrib-&gt;attrib, attrib-&gt;value);

   if (node-&gt;children)
      print_siblings(node-&gt;children, level + 1);

   if (node-&gt;next)
      print_siblings(node-&gt;next, level);
}

static void rxml_log_document(const char *path)
{
   rxml_document_t *doc = rxml_load_document(path);
   if (!doc)
   {
      fprintf(stderr, "rxml: Failed to load document: %s\n", path);
      return;
   }

   print_siblings(rxml_root_node(doc), 0);
   rxml_free_document(doc);
}

int main(int argc, char *argv[])
{
   if (argc != 2)
   {
      fprintf(stderr, "Usage: %s &lt;path&gt;\n", argv[0]);
      return 1;
   }

   rxml_log_document(argv[1]);
}</pre>
<h2>./include/libretro-common/samples/net/http_test</h2>
<pre>ELF&gt;@@pH@8	@@@@@@88@8@@@-- ..`.`08  . .` .`TT@T@DDPtdh$h$@h$@QtdRtd..`.`/lib64/ld-linux-x86-64.so.2GNU GNUKEs?W7&gt;~_f75@#X*C QG18"kwlibc.so.6socketstrcpy__strdupconnectsignalselectreallocmemchrinet_ptonstrtolcallocstrlensendgetaddrinfostrstr__errno_locationbindrecvmemcpystrtoulsetsockoptmallocstrcasecmp__ctype_b_locclose__ctype_toupper_loc__ctype_tolower_locfreeaddrinfofcntlmemmovestrcmp__libc_start_mainsnprintffree__gmon_start__GLIBC_2.14GLIBC_2.2.5GLIBC_2.3Rui	]ii
i/`/`0` 0`(0`00`80`@0`H0`P0`X0`	`0`
h0`p0`x0`
0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`0`1` 1`!1`"1`# 1`$HH]$ HtH5R$ %T$ @%R$ h%J$ h%B$ h%:$ h%2$ h%*$ h%"$ h%$ hp%$ h`%
$ h	P%$ h
@%# h0%# h %# h
%# h%# h%# h%# h%# h%# h%# h%# h%# h%# hp%# h`%# hP%# h@%z# h0%r# h %j# h%b# h%Z# h%R# h %J# h!USH(HD$HD$##@.HfHT$Ht$0$@1*HT$Ht$HHtԿG$@H11H$tHt$1H
H¿a$@1HH
1H([]f.1I^HHPTIP#@H"@H
@! D?1`UH-81`HHvHt]81`f]@f.81`UH81`HHHH?HHtHt]81`]fD=! uUHn]! @.`H?uHtUH]zf.ATUSHHIlHHމuA$[]A\ff.ATU(SHHI]̉11@p JEHL
uxH11fD0q\5Ht+ u0%zr8200q\5HuID$d#@HuHID$I$L[]A\HLE1L[]A\ÿHt1HtKHG:wHHr%HHHGH:wHs@1f.Ht;HG8t2USHHHoG P}:tHHkH[]Ð1DHUHDPu1H[]H}Hs
vHkC }/t1DHtSHHHtH[@f.HGÐf.ATUSH HD$w HHH|$HD$Ht$
H|$ApEx}t	trHt$#@D$|$tsK Pt@H|$1#@HD$HD$s|$uHT$Ht$D$'	1H H[]A\fHSHt$p|$rHt$l#@T|$VHt$x#@8|$H7Ht$K P'bDHt$u#@|$NHt$#@|$2Ht$u#@|$0
(@@@	H@
H@H@H@ HHC(H1bH H[]A\fDHtøfHAWAVAUATIUSHH
H4$uuG&lt;&lt;H$HtID$HHtA|$	ttHEA|$H[]A\A]A^A_I\$ID$H9HI\$H9sAD$
AD$AD$H[]A\A]A^A_fID$HEDHWHO HG
HHD$H)HW(?HHxIID$ M|$HPI9NEl$M|$A~gfD#@HGHx	
1kI|$(AD$AD$IwI)LM9El$Mt$A\I|$(L
N4?^HIFID$(I9tA
A|$^#@H#@Hl	tAD$	I|$(?YA|$	AD$GAD$&lt;HG
HD$IT$IL$ Ht$A&lt;$H)IT$(HHIT$ ID$HJH9@AD$	&lt;AD$&lt;t;&lt;ID$H9HH)AD$AD$IT$&lt;IT$IT$uI\$M|$HI\$L)H&lt;Ml$(H
K|=LHIK|=1I|$IvIH)I|$I|$(HeMMl$AD$!It$I|$(AD$It$ID$(AD$	H4I|$(It$ ID$(AGID$(HxAD$	
1jID$ID$(LID$AA,HuA|$
"A|$	iIt$I|$(1AD$VID$(1f.H)I\$ID$H4I|$(IIt$ M|$ID$(I|$(AD$It$ID$(ID$DHtGøÐHtCtHtHGHHG(fD
u
G-ȃcvHtH1fD1DHtSH?xH[@f.G
uG-ȃcBt@f.= tÐH
 Hff.@f.ff{f.AVAU1ATUISAιIH@H\$H$HD$HHQEAtZMtbͺ#@H1nLHHLxYIEHtPPpxH@[]A\A]A^DMD$uD$fD$yfSHHH1OH~	[txH[fDC8u1[f.HtEATAUHSH@HH)t 1HHDH[1]A\@[]A\øS1߾1[+f.f.Ht{AUATAUSHHHEAA@fDHH)t8DHHDHxH1[]A\A]Ð+8u@H[]A\A]øf.USHAHHL$D$UHuH[]fUSHHt)AHH$HD$SHsH[]1@t	1@ƃtEDUSHHH&gt;|UfC1HuHSfH[]aHtTHHtnHN6HW@@7tcLfHqH@@rt3HH)I9uHH€&gt;HtH)@H&lt;u@HH1fATUHSHI~IH&lt;HL)ȺI9HFL=[L]A\DATUISDI$tCHLHHHHtDX uI9t[HUL]A\@[]A\USHHH\H9tZCHfDHCH9t/HHBf% ufH[]f.HCHBf% HHPf% Ht?@f.HtHtHH1f.HtHtHH1f.USHHHt$JHHHJHuHH[]ÐUSHHHt$HHHJHuHH[]ÐUSHHHtOHDZHt uHrHHˈ
uH]HEHH[]{fAWAVAUATUSHH(HHT$HHI1H|$HD$HI@HL$HH&lt;LHuH~LH+T$HH|(HHD$H9fDMHHI)LLHt$HLLHD$ILHjHIuHHHD$H([]A\A]A^A_H(H[]A\A]A^A_*f.HSHt
?tmH[HSHt
?tH[HSHt?u
H[D;tHH[ÐAWAVAAUATL% UH- SIIL)HHHt 1LLDAHH9uH[]A\A]A^A_Ðf.HHhttp:// HTTP/1.1
Host: :%iConnection: close
GET /HTTP/1.Content-Length: Transfer-Encoding: chunked%huhttp://buildbot.libretro.com/nightly/win-x86/latest/mednafen_psx_libretro.dll.zip%.9lu / %.9lu        
http://www.wikipedia.org/%.*s
;1Hx	XX8xP(hHx8Ph((hP8`8xHHxx8x@(Hx(	p	zRx+zRx$`0FJw?;*3$",DH4BAC jAB&lt;tX
BAF 
ABAW
ABA(S&lt;pOAG eAAJ Z
AAD"FU,DD:BAA D@
 DABJ2 DAB|KBB B(D0A8GPT
8A0A(B BBBA~8A0A(B BBBLP$&lt;KT("FRt8@804T_XPHD@BBD A(D0Qp
0A(A BBBF$dFAW
HQ
GM&lt;PGDD g
CBEAFB )Ag0(T GBD A(J0~
(C ABBBT(F ABB$tXGAAW0fFA$MAAI0AA;$?AAJ lAA,`;BAD mDB4Lp]BAD ~
HBIAAB,AAG J
AAK#NN#NN$0?AAG pDA$$H?AAG pDA,L`gAAG Q
DAA\|BBB B(A0A8G`
8A0A(B BBBDD8D0A(B BBB`DS`DS`/DN
FV$&lt;pAAD@CADdHeBBE B(H0H8M@r8A0A(B BBBp@p@@
T#@.`.`o@0@@
s0`0`@0@0	o@oo@ .`@@@@@@&amp;@6@F@V@f@v@@@@@@@@@
@
@&amp;
@6
@F
@V
@f
@v
@
@
@
@
@
@
@GCC: (GNU) 6.1.1 20160802GCC: (GNU) 6.2.1 201608308@T@t@@@0@@@	0@
`@@@

@T#@`#@h$@&amp;@.`.`.` .`/`0`(1`81`#.`0
@2
0@E
p@[81`j.`
@.`
@491` 
@]C
P@g-@u.`.` .`.`h$@0`
@
P#@+=Uo (1`s
`@
@G
 @g
"@/81`T#@
` @?
@F=QOe
@P
@"
@
0 @#
@;
@"

@-
P@:Ym(1`z 01`
P@M`#@
"@7K
"@e[o
@
p@@1`
p@s
@+
`@
 @#
 @?
p"@81`
`@K
@S8
@?J

@O
 @4\
 @)l~
p@
@@:
@
@
P!@
@
@
P@.C81`O
0@g
@;u
@
V@
 @init.cnet_http_test.ccrtstuff.c__JCR_LIST__deregister_tm_clones__do_global_dtors_auxcompleted.6916__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entrynet_http.cnet_http_send_str.part.0net_compat.cinited.4619net_socket.ccompat_strl.cstdstring.cstring_trim_whitespace_left.part.0string_trim_whitespace_right.part.1__FRAME_END____JCR_END____init_array_end_DYNAMIC__init_array_start__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE_freeaddrinfo_retro__libc_csu_fini__ctype_toupper_loc@@GLIBC_2.3free@@GLIBC_2.2.5recv@@GLIBC_2.2.5strcasecmp@@GLIBC_2.2.5__errno_location@@GLIBC_2.2.5strcpy@@GLIBC_2.2.5network_deinitsocket_bindsetsockopt@@GLIBC_2.2.5string_ucwordsfcntl@@GLIBC_2.2.5string_trim_whitespace_edatastrlen@@GLIBC_2.2.5string_to_uppersocket_receive_all_nonblockingsend@@GLIBC_2.2.5snprintf@@GLIBC_2.2.5socket_receive_all_blockingnet_http_connection_freeclose@@GLIBC_2.2.5getaddrinfo_retrostring_is_equal_noncasestrlcat_retro__net_http_delete__strdup@@GLIBC_2.2.5socket_initmemchr@@GLIBC_2.2.5socket_close__libc_start_main@@GLIBC_2.2.5calloc@@GLIBC_2.2.5__data_startstrcmp@@GLIBC_2.2.5signal@@GLIBC_2.2.5__gmon_start__strtol@@GLIBC_2.2.5__dso_handlememcpy@@GLIBC_2.14socket_connect_IO_stdin_usedinet_pton@@GLIBC_2.2.5string_trim_whitespace_rightselect@@GLIBC_2.2.5__libc_csu_initmalloc@@GLIBC_2.2.5net_http_updatenet_http_connection_doneinet_htonssocket_selectstring_is_equalstring_to_lowerrealloc@@GLIBC_2.2.5string_trim_whitespace_left__bss_startnet_http_datanet_http_connection_iteratesocket_set_targetmainnetwork_initsocket_nonblockbind@@GLIBC_2.2.5socket_send_all_blockingmemmove@@GLIBC_2.2.5net_http_newnet_http_errorinet_ptrtonstring_replace_substringstring_is_emptystrtoul@@GLIBC_2.2.5net_http_fdnet_http_statusconnect@@GLIBC_2.2.5__TMC_END__net_http_connection_urlsocket_creategetaddrinfo@@GLIBC_2.2.5net_http_connection_newstrstr@@GLIBC_2.2.5strlcpy_retro____ctype_tolower_loc@@GLIBC_2.3__ctype_b_loc@@GLIBC_2.3freeaddrinfo@@GLIBC_2.2.5socket@@GLIBC_2.2.5.symtab.strtab.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.dynamic.got.got.plt.data.bss.comment8@8#T@T 1t@t$Do@N@xV0@0s^o@Jko@@z0@00B`@`0@@0
@
rT#@T#	`#@`#h$@h$&amp;@&amp;.`..`..`. .` ./`/0`0((1`(181`810814hGp1
8	8?0</pre>
<h2>./include/libretro-common/samples/net/Makefile</h2>
<pre>TARGETS  = http_test http_parse_test net_ifinfo

LIBRETRO_COMM_DIR := ../..

INCFLAGS = -I$(LIBRETRO_COMM_DIR)/include

ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
   platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
   platform = osx
	arch = intel
ifeq ($(shell uname -p),powerpc)
	arch = ppc
endif
else ifneq ($(findstring MINGW,$(shell uname -a)),)
   platform = win
endif
endif

ifeq ($(DEBUG),1)
CFLAGS += -O0 -g
else
CFLAGS += -O2
endif
CFLAGS += -Wall -pedantic -std=gnu99

HTTP_TEST_C = \
				  $(LIBRETRO_COMM_DIR)/net/net_http.c \
				  $(LIBRETRO_COMM_DIR)/net/net_compat.c \
				  $(LIBRETRO_COMM_DIR)/net/net_socket.c \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
				  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
				  $(LIBRETRO_COMM_DIR)/string/stdstring.c \
				  net_http_test.c

HTTP_TEST_OBJS := $(HTTP_TEST_C:.c=.o)

HTTP_PARSE_TEST_C = \
				  $(LIBRETRO_COMM_DIR)/net/net_http.c \
				  $(LIBRETRO_COMM_DIR)/net/net_http_parse.c \
				  $(LIBRETRO_COMM_DIR)/net/net_compat.c \
				  $(LIBRETRO_COMM_DIR)/net/net_socket.c \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
				  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
				  $(LIBRETRO_COMM_DIR)/string/stdstring.c \
				  net_http_parse_test.c

HTTP_PARSE_TEST_OBJS := $(HTTP_PARSE_TEST_C:.c=.o)

NET_IFINFO_C = \
					$(LIBRETRO_COMM_DIR)/net/net_ifinfo.c \
					net_ifinfo_test.c

ifeq ($(platform), win)
CFLAGS += -liphlpapi -lws2_32
endif

NET_IFINFO_OBJS := $(NET_IFINFO_C:.c=.o)

.PHONY: all clean

all: $(TARGETS)

%.o: %.c
	$(CC) $(INCFLAGS) $&lt; -c $(CFLAGS) -o $@

http_parse_test: $(HTTP_PARSE_TEST_OBJS)
	$(CC) $(INCFLAGS) $(HTTP_PARSE_TEST_OBJS) $(CFLAGS) -o $@

http_test: $(HTTP_TEST_OBJS)
	$(CC) $(INCFLAGS) $(HTTP_TEST_OBJS) $(CFLAGS) -o $@

net_ifinfo: $(NET_IFINFO_OBJS)
	$(CC) $(INCFLAGS) $(NET_IFINFO_OBJS) $(CFLAGS) -o $@

clean:
	rm -rf $(TARGETS) $(HTTP_TEST_OBJS) $(HTTP_PARSE_TEST_OBJS) $(NET_IFINFO_OBJS)</pre>
<h2>./include/libretro-common/samples/net/net_http_parse_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http_parse_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;compat/strcasestr.h&gt;

int main(int argc, char *argv[])
{
   char link[1024];
   char name[1024];
   const char *line  = "&lt;a href=\"http://www.test.com/somefile.zip\"&gt;Test&lt;/a&gt;\n";

   link[0] = name[0] = '\0';

   string_parse_html_anchor(line, link, name, sizeof(link), sizeof(name));

   printf("link: %s\nname: %s\n", link, name);

   return 1;
}</pre>
<h2>./include/libretro-common/samples/net/net_http_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_http_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;net/net_http.h&gt;
#include &lt;net/net_compat.h&gt;

#ifdef _WIN32
#include &lt;winsock2.h&gt;
#endif

int main(void)
{
   char   *data;
   struct http_t *http1, *http3;
   size_t _len, pos = 0, tot = 0;

   if (!network_init())
      return -1;

   http1 = net_http_new("http://buildbot.libretro.com/nightly/windows/x86_64/latest/mednafen_psx_libretro.dll.zip");

   while (!net_http_update(http1, &amp;pos, &amp;tot))
      printf("%.9lu / %.9lu        \r",pos,tot);

   http3 = net_http_new("http://www.wikipedia.org/");
   while (!net_http_update(http3, NULL, NULL)) {}

   data  = (char*)net_http_data(http3, &amp;_len, false);

   printf("%.*s\n", (int)256, data);

   net_http_delete(http1);
   net_http_delete(http3);

   return 0;
}</pre>
<h2>./include/libretro-common/samples/net/net_ifinfo</h2>
<pre>ELF&gt;@@8@8	@@@@@@88@8@@@ ```h   ` `TT@T@DDPtd		@	@DDQtdRtd``/lib64/ld-linux-x86-64.so.2GNU GNUBJlg-\nt_*M#d B6libc.so.6__strdupreallocprintfcallocgetnameinfofreeifaddrsgetifaddrs__libc_start_mainfree__gmon_start__GLIBC_2.3GLIBC_2.2.5ii
sui	}``` `(`0`8`@`H`	P`
HHm
 HtH5b
 %d
 @%b
 h%Z
 h%R
 h%J
 h%B
 h%:
 h%2
 h%*
 hpUSHHtVHHtG11H}t+@HHE	@HPH01=CH;EHrH1H[]Ãf.1I^HHPTI	@Hp	@H0@	 Do`UH-h`HHvHt]h`f]@f.h`UHh`HHHH?HHtHt]h`]fD=	 uUHn] @`H?uHtUH]zf.HATU1S1HIu*SH{?u:HHC]I;\$Hs+HI$H;?tH{?tfDI&lt;$[L]A\{fDAWAVAUATIUSH(H|$HD$MH\$H1DHHH{Htf?uHE1E1jHT$ ZYDuI&lt;$LH'HtjH{HI$L&lt;(H|$II,$HHEMt$DHp@H\$HH([]A\A]A^A_@H|$LF1fAWAVAAUATL% UH- SIIL)HHHt 1LLDAHH9uH[]A\A]A^A_Ðf.HH%s:%s
;@4D\DttzRxP+zRx$FJw?;*3$",DKAC kDB\tX.BBB B(D0A8G[HWAz
8A0A(B BBBE,uAAN ]
AAADeBBE B(H0H8M@r8A0A(B BBBL @`@@
	@``o@@@
`@@0	o`@ooJ@ `@@@@@@@&amp;@GCC: (GNU) 6.1.1 20160802GCC: (GNU) 6.2.1 201608308@T@t@@@@J@`@	@
@@@
0@	@	@	@@
@``` ```X`h`%`2
@4
 @G
`@]h`l`
@`@`` ``	@%`;
	@K X`]h`E	@dxX` ``	@
@"
p	@e2p`
@+H]h`i
0@unh`
@@.,@init.cnet_ifinfo_test.ccrtstuff.c__JCR_LIST__deregister_tm_clones__do_global_dtors_auxcompleted.6916__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entrynet_ifinfo.c__FRAME_END____JCR_END____init_array_end_DYNAMIC__init_array_start__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_csu_finifree@@GLIBC_2.2.5_edataprintf@@GLIBC_2.2.5getnameinfo@@GLIBC_2.2.5__strdup@@GLIBC_2.2.5__libc_start_main@@GLIBC_2.2.5calloc@@GLIBC_2.2.5__data_start__gmon_start____dso_handle_IO_stdin_usednet_ifinfo_free__libc_csu_initgetifaddrs@@GLIBC_2.3realloc@@GLIBC_2.2.5__bss_startmainfreeifaddrs@@GLIBC_2.3__TMC_END__net_ifinfo_new.symtab.strtab.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.dynamic.got.got.plt.data.bss.comment8@8#T@T 1t@t$Do@N@V@^oJ@Jko`@`0z@0B@@@0@0	@			@		@	D@
@@
``` ` ``XX`Xh`h0h400	</pre>
<h2>./include/libretro-common/samples/net/net_ifinfo_test.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (net_ifinfo_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;net/net_ifinfo.h&gt;

int main(int argc, const char *argv[])
{
   unsigned k              = 0;
   net_ifinfo_t list;

   if (!net_ifinfo_new(&amp;list))
      return -1;

   for (k = 0; k &lt; list.size; k++)
   {
      printf("%s:%s\n", list.entries[k].name, list.entries[k].host);
   }

   net_ifinfo_free(&amp;list);

   return 0;
}</pre>
<h2>./include/libretro-common/samples/net/udp-test.c</h2>
<pre>/* public domain */
/* gcc -o udptest udp-test.c */

/*
   will send "RETROPAD RIGHT" indefinely to player 1
   to send to player 2 change port to 55401 and so on
*/

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;arpa/inet.h&gt;
#include &lt;sys/socket.h&gt;

#define SERVER "127.0.0.1"
#define PORT 55400

void die(char *s)
{
    perror(s);
    exit(1);
}

int main(void)
{
   struct sockaddr_in si_other;
   int s, i, slen=sizeof(si_other);

   if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
      die("socket");

   memset((char *) &amp;si_other, 0, sizeof(si_other));
   si_other.sin_family = AF_INET;
   si_other.sin_port = htons(PORT);

   if (inet_aton(SERVER , &amp;si_other.sin_addr) == 0)
   {
      fprintf(stderr, "inet_aton() failed\n");
      exit(1);
   }

   for (;;)
   {
      char message[10]="128";
      /* send the message */
      if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &amp;si_other, slen)==-1)
         die("sendto()");

      /* sleep for 1 frame (60hz) */
      usleep(16*1000);
   }

   close(s);
   return 0;
}</pre>
<h2>./include/libretro-common/samples/streams/rzip/Makefile</h2>
<pre>TARGET := rzip

LIBRETRO_COMM_DIR := ../../..
LIBRETRO_DEPS_DIR := ../../../../deps

# Attempt to detect target platform
ifeq '$(findstring ;,$(PATH))' ';'
	UNAME := Windows
else
	UNAME := $(shell uname 2&gt;/dev/null || echo Unknown)
	UNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))
	UNAME := $(patsubst MSYS%,MSYS,$(UNAME))
	UNAME := $(patsubst MINGW%,MSYS,$(UNAME))
endif

# Add '.exe' extension on Windows platforms
ifeq ($(UNAME), Windows)
	TARGET := rzip.exe
endif
ifeq ($(UNAME), MSYS)
	TARGET := rzip.exe
endif

SOURCES := \
	rzip.c \
	$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
	$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
	$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
	$(LIBRETRO_COMM_DIR)/file/file_path.c \
	$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
	$(LIBRETRO_COMM_DIR)/string/stdstring.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
	$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/rzip_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/stdin_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
	$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
	$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
	$(LIBRETRO_COMM_DIR)/time/rtime.c

ifneq ($(wildcard $(LIBRETRO_DEPS_DIR)/*),)
	# If we are building from inside the RetroArch
	# directory (i.e. if an 'external' deps directory
	# is available), bake in zlib support
	SOURCES += \
		$(LIBRETRO_DEPS_DIR)/libz/adler32.c \
		$(LIBRETRO_DEPS_DIR)/libz/libz-crc32.c \
		$(LIBRETRO_DEPS_DIR)/libz/deflate.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzclose.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzlib.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzread.c \
		$(LIBRETRO_DEPS_DIR)/libz/gzwrite.c \
		$(LIBRETRO_DEPS_DIR)/libz/inffast.c \
		$(LIBRETRO_DEPS_DIR)/libz/inflate.c \
		$(LIBRETRO_DEPS_DIR)/libz/inftrees.c \
		$(LIBRETRO_DEPS_DIR)/libz/trees.c \
		$(LIBRETRO_DEPS_DIR)/libz/zutil.c
	INCLUDE_DIRS := -I$(LIBRETRO_COMM_DIR)/include/compat/zlib
else
	# If this is a stand-alone libretro-common directory,
	# rely on system zlib library (note: only likely to
	# work on Unix-based platforms...)
	LDFLAGS += -lz
endif

OBJS := $(SOURCES:.c=.o)
INCLUDE_DIRS += -I$(LIBRETRO_COMM_DIR)/include
CFLAGS += -DHAVE_ZLIB -Wall -pedantic -std=gnu99 $(INCLUDE_DIRS)

# Silence "ISO C does not support the 'I64' ms_printf length modifier"
# warnings when using MinGW
ifeq ($(UNAME), Windows)
	CFLAGS += -Wno-format
endif
ifeq ($(UNAME), MSYS)
	CFLAGS += -Wno-format
endif

ifeq ($(DEBUG), 1)
	CFLAGS += -O0 -g -DDEBUG -D_DEBUG
else
	CFLAGS += -O2 -DNDEBUG
endif

all: $(TARGET)

%.o: %.c
	$(CC) -c -o $@ $&lt; $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: clean</pre>
<h2>./include/libretro-common/samples/streams/rzip/rzip.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (config_file_test.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdio.h&gt;
#include &lt;ctype.h&gt;
#include &lt;inttypes.h&gt;
#include &lt;errno.h&gt;
#include &lt;time.h&gt;

#include &lt;string/stdstring.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;streams/interface_stream.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;streams/rzip_stream.h&gt;
#include &lt;retro_miscellaneous.h&gt;

#define FILE_TRANSFER_CHUNK_SIZE 4096

enum rzip_action_type
{
	RZIP_ACTION_QUERY = 0,
	RZIP_ACTION_COMPRESS,
	RZIP_ACTION_EXTRACT
};

static void rand_str(char *dst, size_t len)
{
   char charset[] = "0123456789"
         "abcdefghijklmnopqrstuvwxyz"
         "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

   while (len-- &gt; 0)
   {
      size_t i = (double)rand() / RAND_MAX * (sizeof(charset) - 1);
      *dst++   = charset[i];
   }
   *dst = '\0';
}

int main(int argc, char *argv[])
{
   char in_file_path[PATH_MAX_LENGTH];
   char out_file_path[PATH_MAX_LENGTH];
   enum rzip_action_type action = RZIP_ACTION_QUERY;
   intfstream_t *in_file        = NULL;
   intfstream_t *out_file       = NULL;
   int64_t in_file_size         = 0;
   int64_t in_file_raw_size     = 0;
   int64_t out_file_size        = 0;
   int64_t file_size_diff       = 0;
   int64_t total_data_read      = 0;
   bool in_file_compressed      = false;
   bool valid_args              = false;
   bool in_place                = false;
   int ret                      = 1;

   in_file_path[0]  = '\0';
   out_file_path[0] = '\0';

   /* Parse arguments */
   if ((argc &gt; 1) &amp;&amp; !string_is_empty(argv[1]))
   {
      valid_args = true;

      if (string_is_equal(argv[1], "i"))
         action = RZIP_ACTION_QUERY;
      else if (string_is_equal(argv[1], "a"))
         action = RZIP_ACTION_COMPRESS;
      else if (string_is_equal(argv[1], "x"))
         action = RZIP_ACTION_EXTRACT;
      else
         valid_args = false;
   }

   /* Get input file path */
   if (valid_args &amp;&amp; (argc &gt; 2) &amp;&amp; !string_is_empty(argv[2]))
   {
      strlcpy(in_file_path, argv[2], sizeof(in_file_path));
      path_resolve_realpath(in_file_path, sizeof(in_file_path), true);
      valid_args = valid_args &amp;&amp; !string_is_empty(in_file_path);
   }
   else
      valid_args = false;

   /* Ensure arguments are valid */
   if (!valid_args)
   {
      fprintf(stderr, "Usage:\n");
      fprintf(stderr, "- Query file status: %s i &lt;input file&gt;\n", argv[0]);
      fprintf(stderr, "- Compress file:     %s a &lt;input file&gt; &lt;output file (optional)&gt;\n", argv[0]);
      fprintf(stderr, "- Extract file:      %s x &lt;input file&gt; &lt;output file (optional)&gt;\n", argv[0]);
      fprintf(stderr, "Omitting &lt;output file&gt; will overwrite &lt;input file&gt;\n");
      goto end;
   }

   /* Ensure that input file exists */
   if (!path_is_valid(in_file_path))
   {
      fprintf(stderr, "ERROR: Input file does not exist: %s\n", in_file_path);
      goto end;
   }

   /* Get output file path, if specified */
   if ((argc &gt; 3) &amp;&amp; !string_is_empty(argv[3]))
   {
      strlcpy(out_file_path, argv[3], sizeof(out_file_path));
      path_resolve_realpath(out_file_path, sizeof(out_file_path), true);
   }

   /* If we are compressing/extracting and an
    * output file was not specified, generate a
    * temporary output file path */
   if ((action != RZIP_ACTION_QUERY) &amp;&amp;
       string_is_empty(out_file_path))
   {
      const char *in_file_name = path_basename(in_file_path);
      char in_file_dir[DIR_MAX_LENGTH];

      in_file_dir[0] = '\0';

      fill_pathname_parent_dir(in_file_dir, in_file_path, sizeof(in_file_dir));

      if (string_is_empty(in_file_name))
      {
         fprintf(stderr, "ERROR: Invalid input file: %s\n", in_file_path);
         goto end;
      }

      srand((unsigned int)time(NULL));

      for (;;)
      {
         char tmp_str[10] = {0};

         /* Generate 'random' file name */
         rand_str(tmp_str, sizeof(tmp_str) - 1);
         tmp_str[0] = '.';

         if (!string_is_empty(in_file_dir))
            fill_pathname_join_special(out_file_path, in_file_dir,
                  tmp_str, sizeof(out_file_path));
         else
            strlcpy(out_file_path, tmp_str, sizeof(out_file_path));

         strlcat(out_file_path, ".", sizeof(out_file_path));
         strlcat(out_file_path, in_file_name, sizeof(out_file_path));
         path_resolve_realpath(out_file_path, sizeof(out_file_path), true);

         if (!path_is_valid(out_file_path))
            break;
      }

      in_place = true;
   }

   /* Ensure that input and output files
    * are different */
   if (string_is_equal(in_file_path, out_file_path))
   {
      fprintf(stderr, "ERROR: Input and output are the same file: %s\n", in_file_path);
      goto end;
   }

   /* Get input file size */
   in_file_size = (int64_t)path_get_size(in_file_path);

   if (in_file_size &lt; 1)
   {
      fprintf(stderr, "ERROR: Input file is empty: %s\n", in_file_path);
      goto end;
   }

   /* Open input file
    * &gt; Always use RZIP interface */
   in_file = intfstream_open_rzip_file(
         in_file_path, RETRO_VFS_FILE_ACCESS_READ);

   if (!in_file)
   {
      fprintf(stderr, "ERROR: Failed to open input file: %s\n", in_file_path);
      goto end;
   }

   /* Get input file compression status */
   in_file_compressed = intfstream_is_compressed(in_file);

   /* Get raw (uncompressed) input file size */
   in_file_raw_size   = intfstream_get_size(in_file);

   /* If this is a query operation, just
    * print current state */
   if (action == RZIP_ACTION_QUERY)
   {
      printf("%s: %s\n",
            in_file_compressed ? "File is in RZIP format" : "File is NOT in RZIP format",
            in_file_path);
      printf("   Size on disk:      %" PRIi64 " bytes\n", in_file_size);
      if (in_file_compressed)
         printf("   Uncompressed size: %" PRIi64 " bytes\n", in_file_raw_size);
      goto end;
   }

   /* Check whether file is already in the
    * requested state */
   if ((in_file_compressed  &amp;&amp; (action == RZIP_ACTION_COMPRESS)) ||
       (!in_file_compressed &amp;&amp; (action == RZIP_ACTION_EXTRACT)))
   {
      printf("Input file is %s: %s\n",
            in_file_compressed ?
                  "already in RZIP format - cannot compress" :
                        "not in RZIP format - cannot extract",
            in_file_path);
      goto end;
   }

   /* Check whether output file already exists */
   if (path_is_valid(out_file_path))
   {
      char reply[8];

      reply[0] = '\0';

      printf("WARNING: Output file already exists: %s\n", out_file_path);
      printf("         Overwrite? [Y/n]: ");
      fgets(reply, sizeof(reply), stdin);
      if (reply[0] != 'Y')
         goto end;
   }

   /* Open output file */
   if (in_file_compressed)
      out_file = intfstream_open_file(
            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE,
            RETRO_VFS_FILE_ACCESS_HINT_NONE);
   else
      out_file = intfstream_open_rzip_file(
            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE);

   if (!out_file)
   {
      fprintf(stderr, "ERROR: Failed to open output file: %s\n", out_file_path);
      goto end;
   }

   /* Start file transfer */
   printf("%s file\n", in_file_compressed ? "Extracting" : "Compressing");
   printf("   From: %s\n", in_file_path);
   printf("   To:   %s\n", in_place ? in_file_path : out_file_path);

   for (;;)
   {
      int64_t data_written = 0;
      uint8_t buffer[FILE_TRANSFER_CHUNK_SIZE];
      /* Read a single chunk from input file */
      int64_t data_read    = intfstream_read(
            in_file, buffer, sizeof(buffer));

      if (data_read &lt; 0)
      {
         fprintf(stderr, "ERROR: Failed to read from input file: %s\n", in_file_path);
         goto end;
      }

      total_data_read += data_read;

      /* Check whether we have reached the end of the file */
      if (data_read == 0)
      {
         /* Close files */
         intfstream_flush(out_file);
         intfstream_close(out_file);
         free(out_file);
         out_file = NULL;

         intfstream_close(in_file);
         free(in_file);
         in_file = NULL;

         break;
      }

      /* Write chunk to backup file */
      data_written = intfstream_write(out_file, buffer, data_read);

      if (data_written != data_read)
      {
         fprintf(stderr, "ERROR: Failed to write to output file: %s\n", out_file_path);
         goto end;
      }

      /* Update progress */
      printf("\rProgress: %" PRIi64 " %%", total_data_read * 100 / in_file_raw_size);
      fflush(stdout);
   }
   printf("\rProgress: 100 %%\n");

   /* Display final status 'report' */
   printf("%s complete:\n", in_file_compressed ? "Extraction" : "Compression");

   out_file_size  = (int64_t)path_get_size(out_file_path);
   file_size_diff = (in_file_size &gt; out_file_size) ?
         (in_file_size - out_file_size) :
               (out_file_size - in_file_size);

   printf("   %" PRIi64 " -&gt; %" PRIi64 " bytes [%" PRIi64 " %% %s]\n",
         in_file_size, out_file_size,
               file_size_diff * 100 / in_file_size,
               (out_file_size &gt;= in_file_size) ?
                     "increase" : "decrease");

   /* If this was an in-place operation,
    * replace input file with output file */
   if (in_place)
   {
      filestream_delete(in_file_path);
      if (filestream_rename(out_file_path, in_file_path))
      {
         fprintf(stderr, "ERROR: Failed to rename temporary file\n");
         fprintf(stderr, "   From: %s\n", out_file_path);
         fprintf(stderr, "   To:   %s\n", in_file_path);
         goto end;
      }
   }

   ret = 0;

end:
   if (in_file)
   {
      intfstream_close(in_file);
      free(in_file);
   }

   if (out_file)
   {
      intfstream_close(out_file);
      free(out_file);
   }

   return ret;
}</pre>
<h2>./include/libretro-common/samples/utils/crc32.c</h2>
<pre>/* gcc -O3 -o crc32 crc32.c -lz */

#include &lt;stdio.h&gt;
#include &lt;errno.h&gt;
#include &lt;string.h&gt;

#include &lt;encodings/crc32.h&gt;

int main(int argc, const char* argv[])
{
   if (argc != 2 )
   {
      fprintf( stderr, "Usage: crc32 &lt;filename&gt;\n" );
      return 1;
   }

   FILE *file = fopen(argv[1], "rb");

   if (file)
   {
      uint32_t crc = encoding_crc32(0L, NULL, 0 );

      for (;;)
      {
         uint8_t buffer[16384];

         int numread = fread((void*)buffer, 1, sizeof(buffer), file);

         if (numread &gt; 0)
            crc = encoding_crc32( crc, buffer, numread );
         else
            break;
      }

      fclose(file);

      printf("%08x\n", crc);
      return 0;
   }

   fprintf(stderr, "Error opening input file: %s\n", strerror(errno));
   return 1;
}</pre>
<h2>./include/libretro-common/samples/utils/Makefile</h2>
<pre>compiler    := gcc
extra_flags :=
use_neon    := 0
release	   := release
EXE_EXT	      :=

ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
   platform = win
else ifneq ($(findstring MINGW,$(shell uname -a)),)
   platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
   platform = osx
   arch = intel
ifeq ($(shell uname -p),powerpc)
   arch = ppc
endif
else ifneq ($(findstring win,$(shell uname -a)),)
   platform = win
endif
endif

ifeq ($(compiler),gcc)
extra_rules_gcc := $(shell $(compiler) -dumpmachine)
endif

ifneq (,$(findstring armv7,$(extra_rules_gcc)))
extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon
use_neon := 1
endif

ifneq (,$(findstring hardfloat,$(extra_rules_gcc)))
extra_flags += -mfloat-abi=hard
endif

ifeq (release,$(build))
extra_flags += -O2
endif

ifeq (debug,$(build))
extra_flags += -O0 -g
endif

ldflags :=

EXE_EXT :=
ifeq ($(platform), unix)
else ifeq ($(platform), osx)
compiler := $(CC)
else
EXE_EXT = .exe
endif

PWD_DIR := .
LIBRETRO_COMM_DIR := ../..
CORE_DIR := $(LIBRETRO_COMM_DIR)/utils

CC      := $(compiler)
CXX     := $(subst CC,++,$(compiler))
flags   := -I$(LIBRETRO_COMM_DIR)/include
asflags := $(extra_flags)
LDFLAGS :=
flags   += -std=c99 -DMD5_BUILD_UTILITY -DSHA1_BUILD_UTILITY

ifeq (1,$(use_neon))
ASMFLAGS := -INEON/asm
asflags += -mfpu=neon
endif

DJB2_OBJS := $(CORE_DIR)/djb2.o

MD5_OBJS  := $(CORE_DIR)/md5.o \
				 $(PWD_DIR)/md5_test.o

SHA1_OBJS := $(CORE_DIR)/sha1.o \
				 $(PWD_DIR)/sha1_main.o

CRC32_OBJS := $(PWD_DIR)/crc32.o \
				  $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.o \
				  $(LIBRETRO_COMM_DIR)/compat/compat_strl.o \
				  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.o \
				  $(LIBRETRO_COMM_DIR)/streams/file_stream.o \
				  $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.o \
			     $(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.o

UTILS := djb2$(EXE_EXT) md5$(EXE_EXT) sha1$(EXE_EXT) crc32$(EXE_EXT)

all: $(UTILS)

djb2$(EXE_EXT): $(DJB2_OBJS)

md5$(EXE_EXT): $(MD5_OBJS)

sha1$(EXE_EXT): $(SHA1_OBJS)

crc32$(EXE_EXT): $(CRC32_OBJS)

%.o: %.S
	$(CC) -c -o $@ $(asflags) $(LDFLAGS)  $(ASMFLAGS)  $&lt;

%.o: %.c
	$(CC) -c -o $@ $(flags) $&lt;

$(UTILS):
	$(CC) -o $@ $(ldflags) $(flags) $^

clean:
	rm -f $(CORE_DIR)/*.o
	rm -f $(UTILS)

strip:
	strip -s $(UTILS)</pre>
<h2>./include/libretro-common/samples/utils/md5_test.c</h2>
<pre>/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer &lt;solar at openwall.com&gt;
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there's no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's.  No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible.  Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#include &lt;lrc_hash.h&gt;

int main (int argc, char *argv[])
{
   /* For each command line argument in turn:
    ** filename          -- prints message digest and name of file
    */
   int i;
   MD5_CTX ctx;
   FILE* file;
   size_t numread;
   char buffer[16384];
   unsigned char result[16];

   for (i = 1; i &lt; argc; i++)
   {
      MD5_Init(&amp;ctx);
      file = fopen(argv[i], "rb");

      if (file)
      {
         do
         {
            numread = fread((void*)buffer, 1, sizeof(buffer), file);

            if (numread)
            {
               MD5_Update(&amp;ctx,(void*)buffer, numread);
            }
         }
         while (numread);

         fclose(file);
         MD5_Final(result, &amp;ctx);
         printf("%02x%02x%02x%02x%02x%02x%02x%02x"
			          "%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
			          result[ 0 ], result[ 1 ], result[ 2 ], result[ 3 ],
                result[ 4 ], result[ 5 ], result[ 6 ], result[ 7 ],
                result[ 8 ], result[ 9 ], result[ 10 ], result[ 11 ],
                result[ 12 ], result[ 13 ], result[ 14 ], result[ 15 ],
                argv[i]);
      }
   }

   return 0;
}</pre>
<h2>./include/libretro-common/samples/utils/sha1_main.c</h2>
<pre>/*
 *  sha.cpp
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones &lt;paulej@packetizer.com&gt;
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha.c 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This utility will display the message digest (fingerprint) for
 *      the specified file(s).
 *
 *  Portability Issues:
 *      None.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#ifdef _WIN32
#include &lt;io.h&gt;
#endif
#include &lt;fcntl.h&gt;
#include &lt;string/stdstring.h&gt;
/*#include "sha1.h"*/

/*
 *  Function prototype
 */
void usage(void);

/*
 *  main
 *
 *  Description:
 *      This is the entry point for the program
 *
 *  Parameters:
 *      argc: [in]
 *          This is the count of arguments in the argv array
 *      argv: [in]
 *          This is an array of filenames for which to compute message
 *          digests
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
typedef struct SHA1Context
{
   unsigned Message_Digest[5]; /* Message Digest (output)          */

   unsigned Length_Low;        /* Message length in bits           */
   unsigned Length_High;       /* Message length in bits           */

   unsigned char Message_Block[64]; /* 512-bit message blocks      */
   int Message_Block_Index;    /* Index into message block array   */

   int Computed;               /* Is the digest computed?          */
   int Corrupted;              /* Is the message digest corruped?  */
} SHA1Context;

int main(int argc, char *argv[])
{
   struct SHA1Context sha;         /* SHA-1 context                 */
   FILE        *fp;                /* File pointer for reading files*/
   char        c;                  /* Character read from file      */
   int         i;                  /* Counter                       */
   int         reading_stdin;      /* Are we reading standard in?   */
   int         read_stdin = 0;     /* Have we read stdin?           */

   /*
    *  Check the program arguments and print usage information if -?
    *  or --help is passed as the first argument.
    */
   if (argc &gt; 1 &amp;&amp; (string_is_equal(argv[1],"-?") ||
            string_is_equal(argv[1],"--help")))
   {
      usage();
      return 1;
   }

   /*
    *  For each filename passed in on the command line, calculate the
    *  SHA-1 value and display it.
    */
   for (i = 0; i &lt; argc; i++)
   {
      /*
       *  We start the counter at 0 to guarantee entry into the for
       *  loop. So if 'i' is zero, we will increment it now.  If there
       *  is no argv[1], we will use STDIN below.
       */
      if (i == 0)
         i++;

      if (argc == 1 || string_is_equal(argv[i],"-"))
      {
#ifdef WIN32
         setmode(fileno(stdin), _O_BINARY);
#endif
         fp = stdin;
         reading_stdin = 1;
      }
      else
      {
         if (!(fp = fopen(argv[i],"rb")))
         {
            fprintf(stderr,
                  "sha: unable to open file %s\n",
                  argv[i]);
            return 2;
         }
         reading_stdin = 0;
      }

      /*
       *  We do not want to read STDIN multiple times
       */
      if (reading_stdin)
      {
         if (read_stdin)
            continue;

         read_stdin = 1;
      }

      /*
       *  Reset the SHA-1 context and process input
       */
      SHA1Reset(&amp;sha);

      c = fgetc(fp);
      while(!feof(fp))
      {
         SHA1Input(&amp;sha, &amp;c, 1);
         c = fgetc(fp);
      }

      if (!reading_stdin)
         fclose(fp);

      if (!SHA1Result(&amp;sha))
      {
         fprintf(stderr,
               "sha: could not compute message digest for %s\n",
               reading_stdin?"STDIN":argv[i]);
      }
      else
      {
         printf( "%08X %08X %08X %08X %08X - %s\n",
               sha.Message_Digest[0],
               sha.Message_Digest[1],
               sha.Message_Digest[2],
               sha.Message_Digest[3],
               sha.Message_Digest[4],
               reading_stdin?"STDIN":argv[i]);
      }
   }

   return 0;
}

/*
 *  usage
 *
 *  Description:
 *      This function will display program usage information to the
 *      user.
 *
 *  Parameters:
 *      None.
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void usage(void)
{
   printf("usage: sha &lt;file&gt; [&lt;file&gt; ...]\n");
   printf("\tThis program will display the message digest\n");
   printf("\tfor files using the Secure Hashing Algorithm (SHA-1).\n");
}</pre>
<h2>./include/libretro-common/streams/chd_stream.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (chd_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;boolean.h&gt;

#include &lt;streams/chd_stream.h&gt;
#include &lt;retro_endianness.h&gt;
#include &lt;libchdr/chd.h&gt;
#include &lt;string/stdstring.h&gt;

#define SECTOR_RAW_SIZE 2352
#define SECTOR_SIZE 2048
#define SUBCODE_SIZE 96
#define TRACK_PAD 4

struct chdstream
{
   chd_file *chd;
   /* Loaded hunk */
   uint8_t *hunkmem;
   /* Byte offset where track data starts (after pregap) */
   size_t track_start;
   /* Byte offset where track data ends */
   size_t track_end;
   /* Byte offset of read cursor */
   size_t offset;
   /* Loaded hunk number */
   int32_t hunknum;
   /* Size of frame taken from each hunk */
   uint32_t frame_size;
   /* Offset of data within frame */
   uint32_t frame_offset;
   /* Number of frames per hunk */
   uint32_t frames_per_hunk;
   /* First frame of track in chd */
   uint32_t track_frame;
   /* Should we swap bytes? */
   bool swab;
};

typedef struct metadata
{
   uint32_t frame_offset;
   uint32_t frames;
   uint32_t pad;
   uint32_t extra;
   uint32_t pregap;
   uint32_t postgap;
   uint32_t track;
   char type[64];
   char subtype[32];
   char pgtype[32];
   char pgsub[32];
} metadata_t;

static uint32_t padding_frames(uint32_t frames)
{
   return ((frames + TRACK_PAD - 1) &amp; ~(TRACK_PAD - 1)) - frames;
}

static bool
chdstream_get_meta(chd_file *chd, int idx, metadata_t *md)
{
   char meta[256];
   uint32_t meta_size = 0;
   chd_error err;

   meta[0] = '\0';

   memset(md, 0, sizeof(*md));

   err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, idx, meta,
         sizeof(meta), &amp;meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      sscanf(meta, CDROM_TRACK_METADATA2_FORMAT,
            &amp;md-&gt;track, md-&gt;type,
            md-&gt;subtype, &amp;md-&gt;frames, &amp;md-&gt;pregap,
            md-&gt;pgtype, md-&gt;pgsub,
            &amp;md-&gt;postgap);
      md-&gt;extra = padding_frames(md-&gt;frames);
      return true;
   }

   err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, idx, meta,
         sizeof(meta), &amp;meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      sscanf(meta, CDROM_TRACK_METADATA_FORMAT, &amp;md-&gt;track, md-&gt;type,
             md-&gt;subtype, &amp;md-&gt;frames);
      md-&gt;extra = padding_frames(md-&gt;frames);
      return true;
   }

   err = chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, idx, meta,
         sizeof(meta), &amp;meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      sscanf(meta, GDROM_TRACK_METADATA_FORMAT, &amp;md-&gt;track, md-&gt;type,
             md-&gt;subtype, &amp;md-&gt;frames, &amp;md-&gt;pad, &amp;md-&gt;pregap, md-&gt;pgtype,
             md-&gt;pgsub, &amp;md-&gt;postgap);
      md-&gt;extra = padding_frames(md-&gt;frames);
      return true;
   }

   err = chd_get_metadata(chd, DVD_METADATA_TAG, idx, meta,
         sizeof(meta), &amp;meta_size, NULL, NULL);

   if (err == CHDERR_NONE)
   {
      md-&gt;track = 1;
      strlcpy(md-&gt;type, "DVD", sizeof(md-&gt;type));
      return true;
   }

   return false;
}

static bool
chdstream_find_track_number(chd_file *fd, int32_t track, metadata_t *meta)
{
   uint32_t i;
   uint32_t frame_offset = 0;

   for (i = 0; true; ++i)
   {
      if (!chdstream_get_meta(fd, i, meta))
         return false;

      if (track == (int)meta-&gt;track)
      {
         meta-&gt;frame_offset = frame_offset;
         return true;
      }

      frame_offset += meta-&gt;frames + meta-&gt;extra;
   }
}

static bool
chdstream_find_special_track(chd_file *fd, int32_t track, metadata_t *meta)
{
   int32_t i;
   metadata_t iter;
   int32_t largest_track = 0;
   uint32_t largest_size = 0;

   for (i = 1; true; ++i)
   {
      if (!chdstream_find_track_number(fd, i, &amp;iter))
      {
         if (track == CHDSTREAM_TRACK_LAST &amp;&amp; i &gt; 1)
            return chdstream_find_track_number(fd, i - 1, meta);

         if (track == CHDSTREAM_TRACK_PRIMARY &amp;&amp; largest_track != 0)
            return chdstream_find_track_number(fd, largest_track, meta);

         return false;
      }

      switch (track)
      {
         case CHDSTREAM_TRACK_FIRST_DATA:
            if (strcmp(iter.type, "AUDIO"))
            {
               *meta = iter;
               return true;
            }
            break;
         case CHDSTREAM_TRACK_PRIMARY:
            if (strcmp(iter.type, "AUDIO") &amp;&amp; iter.frames &gt; largest_size)
            {
               largest_size  = iter.frames;
               largest_track = iter.track;
            }
            break;
         default:
            break;
      }
   }
}

static bool
chdstream_find_track(chd_file *fd, int32_t track, metadata_t *meta)
{
   if (track &lt; 0)
      return chdstream_find_special_track(fd, track, meta);
   return chdstream_find_track_number(fd, track, meta);
}

chdstream_t *chdstream_open(const char *path, int32_t track)
{
   metadata_t meta;
   uint32_t pregap         = 0;
   uint8_t *hunkmem        = NULL;
   const chd_header *hd    = NULL;
   chdstream_t *stream     = NULL;
   chd_file *chd           = NULL;
   chd_error err           = chd_open(path, CHD_OPEN_READ, NULL, &amp;chd);

   if (err != CHDERR_NONE)
      return NULL;

   if (!chdstream_find_track(chd, track, &amp;meta))
      goto error;

   stream                  = (chdstream_t*)malloc(sizeof(*stream));
   if (!stream)
      goto error;

   stream-&gt;chd             = NULL;
   stream-&gt;swab            = false;
   stream-&gt;frame_size      = 0;
   stream-&gt;frame_offset    = 0;
   stream-&gt;frames_per_hunk = 0;
   stream-&gt;track_frame     = 0;
   stream-&gt;track_start     = 0;
   stream-&gt;track_end       = 0;
   stream-&gt;offset          = 0;
   stream-&gt;hunkmem         = NULL;
   stream-&gt;hunknum         = -1;

   hd                      = chd_get_header(chd);
   hunkmem                 = (uint8_t*)malloc(hd-&gt;hunkbytes);
   if (!hunkmem)
      goto error;

   stream-&gt;hunkmem         = hunkmem;

   if (string_is_equal(meta.type, "MODE1_RAW"))
      stream-&gt;frame_size   = SECTOR_RAW_SIZE;
   else if (string_is_equal(meta.type, "MODE2_RAW"))
      stream-&gt;frame_size   = SECTOR_RAW_SIZE;
   else if (string_is_equal(meta.type, "MODE1"))
      stream-&gt;frame_size   = SECTOR_SIZE;
   else if (string_is_equal(meta.type, "AUDIO"))
   {
      stream-&gt;frame_size   = SECTOR_RAW_SIZE;
      stream-&gt;swab         = true;
   }
   else if (string_is_equal(meta.type, "DVD"))
   {
      stream-&gt;frame_size   = hd-&gt;unitbytes;
      meta.frames          = hd-&gt;totalhunks;
   }
   else
      stream-&gt;frame_size   = hd-&gt;unitbytes;

   /* Only include pregap data if it was in the track file */
   if (meta.pgtype[0] != 'V')
      pregap               = meta.pregap;

   stream-&gt;chd             = chd;
   stream-&gt;frames_per_hunk = hd-&gt;hunkbytes / hd-&gt;unitbytes;
   stream-&gt;track_frame     = meta.frame_offset;
   stream-&gt;track_start     = (size_t)pregap * stream-&gt;frame_size;
   stream-&gt;track_end       = stream-&gt;track_start +
                             (size_t)meta.frames * stream-&gt;frame_size;

   return stream;

error:
   chdstream_close(stream);

   if (chd)
      chd_close(chd);

   return NULL;
}

void chdstream_close(chdstream_t *stream)
{
   if (!stream)
      return;

   if (stream-&gt;hunkmem)
      free(stream-&gt;hunkmem);
   if (stream-&gt;chd)
      chd_close(stream-&gt;chd);
   free(stream);
}

static bool
chdstream_load_hunk(chdstream_t *stream, uint32_t hunknum)
{
   uint16_t *array;

   if ((int)hunknum == stream-&gt;hunknum)
      return true;

   if (chd_read(stream-&gt;chd, hunknum, stream-&gt;hunkmem) != CHDERR_NONE)
      return false;

   if (stream-&gt;swab)
   {
      uint32_t i;
      uint32_t count = chd_get_header(stream-&gt;chd)-&gt;hunkbytes / 2;
      array          = (uint16_t*)stream-&gt;hunkmem;
      for (i = 0; i &lt; count; ++i)
         array[i] = SWAP16(array[i]);
   }

   stream-&gt;hunknum = hunknum;
   return true;
}

ssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes)
{
   size_t end;
   size_t data_offset   = 0;
   const chd_header *hd = chd_get_header(stream-&gt;chd);
   uint8_t         *out = (uint8_t*)data;

   if (stream-&gt;track_end - stream-&gt;offset &lt; bytes)
      bytes             = stream-&gt;track_end - stream-&gt;offset;

   end                  = stream-&gt;offset + bytes;

   while (stream-&gt;offset &lt; end)
   {
      uint32_t frame_offset = stream-&gt;offset % stream-&gt;frame_size;
      uint32_t amount       = stream-&gt;frame_size - frame_offset;

      if (amount &gt; end - stream-&gt;offset)
         amount = (uint32_t)(end - stream-&gt;offset);

      /* In pregap */
      if (stream-&gt;offset &lt; stream-&gt;track_start)
         memset(out + data_offset, 0, amount);
      else
      {
         uint32_t chd_frame   = (uint32_t)(stream-&gt;track_frame +
            (stream-&gt;offset - stream-&gt;track_start) / stream-&gt;frame_size);
         uint32_t hunk        = chd_frame / stream-&gt;frames_per_hunk;
         uint32_t hunk_offset = (chd_frame % stream-&gt;frames_per_hunk)
            * hd-&gt;unitbytes;

         if (!chdstream_load_hunk(stream, hunk))
            return -1;

         memcpy(out + data_offset,
                stream-&gt;hunkmem + frame_offset
                + hunk_offset + stream-&gt;frame_offset, amount);
      }

      data_offset    += amount;
      stream-&gt;offset += amount;
   }

   return bytes;
}

int chdstream_getc(chdstream_t *stream)
{
   char c = 0;

   if (chdstream_read(stream, &amp;c, sizeof(c) != sizeof(c)))
      return EOF;

   return c;
}

char *chdstream_gets(chdstream_t *stream, char *s, size_t len)
{
   int c;
   size_t _len = 0;
   while (_len &lt; len &amp;&amp; (c = chdstream_getc(stream)) != EOF)
      s[_len++] = c;
   if (_len &lt; len)
      s[_len]   = '\0';
   return s;
}

uint64_t chdstream_tell(chdstream_t *stream)
{
   return stream-&gt;offset;
}

void chdstream_rewind(chdstream_t *stream)
{
   stream-&gt;offset = 0;
}

int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence)
{
   int64_t new_offset;

   switch (whence)
   {
      case SEEK_SET:
         new_offset = offset;
         break;
      case SEEK_CUR:
         new_offset = stream-&gt;offset + offset;
         break;
      case SEEK_END:
         new_offset = stream-&gt;track_end + offset;
         break;
      default:
         return -1;
   }

   if (new_offset &lt; 0)
      return -1;

   if ((size_t)new_offset &gt; stream-&gt;track_end)
      new_offset = stream-&gt;track_end;

   stream-&gt;offset = new_offset;
   return 0;
}

ssize_t chdstream_get_size(chdstream_t *stream)
{
   return stream-&gt;track_end - stream-&gt;track_start;
}

uint32_t chdstream_get_track_start(chdstream_t *stream)
{
   uint32_t i;
   metadata_t meta;
   uint32_t frame_offset = 0;

   for (i = 0; chdstream_get_meta(stream-&gt;chd, i, &amp;meta); ++i)
   {
      if (stream-&gt;track_frame == frame_offset)
         return meta.pregap * stream-&gt;frame_size;

      frame_offset += meta.frames + meta.extra;
   }

   return 0;
}

uint32_t chdstream_get_frame_size(chdstream_t *stream)
{
   return stream-&gt;frame_size;
}

uint32_t chdstream_get_first_track_sector(chdstream_t* stream)
{
   uint32_t i;
   metadata_t meta;
   uint32_t frame_offset = 0;
   uint32_t sector_offset = 0;

   for (i = 0; chdstream_get_meta(stream-&gt;chd, i, &amp;meta); ++i)
   {
      if (stream-&gt;track_frame == frame_offset)
         return sector_offset;

      sector_offset += meta.frames;
      frame_offset += meta.frames + meta.extra;
   }

   return 0;
}</pre>
<h2>./include/libretro-common/streams/file_stream.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (file_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;ctype.h&gt;

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef _MSC_VER
#include &lt;compat/msvc.h&gt;
#endif

#include &lt;retro_miscellaneous.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;streams/file_stream.h&gt;
#define VFS_FRONTEND
#include &lt;vfs/vfs_implementation.h&gt;

#define VFS_ERROR_RETURN_VALUE -1

struct RFILE
{
   struct retro_vfs_file_handle *hfile;
   bool err_flag;
};

static retro_vfs_get_path_t filestream_get_path_cb = NULL;
static retro_vfs_open_t filestream_open_cb         = NULL;
static retro_vfs_close_t filestream_close_cb       = NULL;
static retro_vfs_size_t filestream_size_cb         = NULL;
static retro_vfs_truncate_t filestream_truncate_cb = NULL;
static retro_vfs_tell_t filestream_tell_cb         = NULL;
static retro_vfs_seek_t filestream_seek_cb         = NULL;
static retro_vfs_read_t filestream_read_cb         = NULL;
static retro_vfs_write_t filestream_write_cb       = NULL;
static retro_vfs_flush_t filestream_flush_cb       = NULL;
static retro_vfs_remove_t filestream_remove_cb     = NULL;
static retro_vfs_rename_t filestream_rename_cb     = NULL;

/* VFS Initialization */

void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
   const struct retro_vfs_interface *
      vfs_iface           = vfs_info-&gt;iface;

   filestream_get_path_cb = NULL;
   filestream_open_cb     = NULL;
   filestream_close_cb    = NULL;
   filestream_tell_cb     = NULL;
   filestream_size_cb     = NULL;
   filestream_truncate_cb = NULL;
   filestream_seek_cb     = NULL;
   filestream_read_cb     = NULL;
   filestream_write_cb    = NULL;
   filestream_flush_cb    = NULL;
   filestream_remove_cb   = NULL;
   filestream_rename_cb   = NULL;

   if (
             (vfs_info-&gt;required_interface_version &lt;
             FILESTREAM_REQUIRED_VFS_VERSION)
         || !vfs_iface)
      return;

   filestream_get_path_cb = vfs_iface-&gt;get_path;
   filestream_open_cb     = vfs_iface-&gt;open;
   filestream_close_cb    = vfs_iface-&gt;close;
   filestream_size_cb     = vfs_iface-&gt;size;
   filestream_truncate_cb = vfs_iface-&gt;truncate;
   filestream_tell_cb     = vfs_iface-&gt;tell;
   filestream_seek_cb     = vfs_iface-&gt;seek;
   filestream_read_cb     = vfs_iface-&gt;read;
   filestream_write_cb    = vfs_iface-&gt;write;
   filestream_flush_cb    = vfs_iface-&gt;flush;
   filestream_remove_cb   = vfs_iface-&gt;remove;
   filestream_rename_cb   = vfs_iface-&gt;rename;
}

/* Callback wrappers */
bool filestream_exists(const char *path)
{
   RFILE *dummy           = NULL;

   if (!path || !*path)
      return false;
   if (!(dummy = filestream_open(
         path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return false;

   if (filestream_close(dummy) != 0)
      free(dummy);

   dummy = NULL;
   return true;
}

int64_t filestream_get_size(RFILE *stream)
{
   int64_t output;

   if (filestream_size_cb)
      output = filestream_size_cb(stream-&gt;hfile);
   else
      output = retro_vfs_file_size_impl(
            (libretro_vfs_implementation_file*)stream-&gt;hfile);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream-&gt;err_flag = true;

   return output;
}

int64_t filestream_truncate(RFILE *stream, int64_t length)
{
   int64_t output;

   if (filestream_truncate_cb)
      output = filestream_truncate_cb(stream-&gt;hfile, length);
   else
      output = retro_vfs_file_truncate_impl(
            (libretro_vfs_implementation_file*)stream-&gt;hfile, length);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream-&gt;err_flag = true;

   return output;
}

RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
{
   struct retro_vfs_file_handle  *fp = NULL;
   RFILE* output                     = (RFILE*)malloc(sizeof(RFILE));

   if (!output)
      return NULL;

   if (filestream_open_cb)
      fp = (struct retro_vfs_file_handle*)
         filestream_open_cb(path, mode, hints);
   else
      fp = (struct retro_vfs_file_handle*)
         retro_vfs_file_open_impl(path, mode, hints);

   if (!fp)
   {
      free(output);
      return NULL;
   }

   output-&gt;err_flag = false;
   output-&gt;hfile    = fp;
   return output;
}

char* filestream_gets(RFILE *stream, char *s, size_t len)
{
   int c   = 0;
   char *p = s;
   if (!stream)
      return NULL;

   /* get max bytes or up to a newline */

   for (len--; len &gt; 0; len--)
   {
      if ((c = filestream_getc(stream)) == EOF)
         break;
      *p++ = c;
      if (c == '\n')
         break;
   }
   *p = 0;

   if (p == s &amp;&amp; c == EOF)
      return NULL;
   return (s);
}

int filestream_getc(RFILE *stream)
{
   char c = 0;
   if (stream &amp;&amp; filestream_read(stream, &amp;c, 1) == 1)
      return (int)(unsigned char)c;
   return EOF;
}

int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
{
   char buf[4096];
   char subfmt[64];
   va_list args_copy;
   const char *bufiter  = buf;
   int        ret       = 0;
   int64_t startpos     = filestream_tell(stream);
   int64_t maxlen       = filestream_read(stream, buf, sizeof(buf)-1);

   if (maxlen &lt;= 0)
      return EOF;

   buf[maxlen] = '\0';

   /* Have to copy the input va_list here
    * &gt; Calling va_arg() on 'args' directly would
    *   cause the va_list to have an indeterminate value
    *   in the function calling filestream_vscanf(),
    *   leading to unexpected behaviour */
#ifdef __va_copy
   __va_copy(args_copy, *args);
#else
   va_copy(args_copy, *args);
#endif

   while (*format)
   {
      if (*format == '%')
      {
         int sublen       = 0;
         char* subfmtiter = subfmt;
         bool asterisk    = false;

         *subfmtiter++    = *format++; /* '%' */

         /* %[*][width][length]specifier */

         if (*format == '*')
         {
            asterisk      = true;
            *subfmtiter++ = *format++;
         }

         while (ISDIGIT((unsigned char)*format))
            *subfmtiter++ = *format++; /* width */

         /* length */
         if (*format == 'h' || *format == 'l')
         {
            if (format[1] == format[0])
               *subfmtiter++ = *format++;
            *subfmtiter++    = *format++;
         }
         else if (
               *format == 'j' ||
               *format == 'z' ||
               *format == 't' ||
               *format == 'L')
         {
            *subfmtiter++ = *format++;
         }

         /* specifier - always a single character (except ]) */
         if (*format == '[')
         {
            while (*format != ']')
               *subfmtiter++ = *format++;
            *subfmtiter++    = *format++;
         }
         else
            *subfmtiter++    = *format++;

         *subfmtiter++       = '%';
         *subfmtiter++       = 'n';
         *subfmtiter++       = '\0';

         if (sizeof(void*) != sizeof(long*))
            abort(); /* all pointers must have the same size */

         if (asterisk)
         {
            int v = sscanf(bufiter, subfmt, &amp;sublen);
            if (v == EOF)
               return EOF;
            if (v != 0)
               break;
         }
         else
         {
            int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &amp;sublen);
            if (v == EOF)
               return EOF;
            if (v != 1)
               break;
         }

         ret++;
         bufiter += sublen;
      }
      else if (isspace((unsigned char)*format))
      {
         while (isspace((unsigned char)*bufiter))
            bufiter++;
         format++;
      }
      else
      {
         if (*bufiter != *format)
            break;
         bufiter++;
         format++;
      }
   }

   va_end(args_copy);
   filestream_seek(stream, startpos + (bufiter - buf),
         RETRO_VFS_SEEK_POSITION_START);

   return ret;
}

int filestream_scanf(RFILE *stream, const char* format, ...)
{
   int ret;
   va_list vl;
   va_start(vl, format);
   ret = filestream_vscanf(stream, format, &amp;vl);
   va_end(vl);
   return ret;
}

int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
{
   int64_t output;

   if (filestream_seek_cb)
      output = filestream_seek_cb(stream-&gt;hfile, offset, seek_position);
   else
      output = retro_vfs_file_seek_impl(
            (libretro_vfs_implementation_file*)stream-&gt;hfile,
            offset, seek_position);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream-&gt;err_flag = true;

   return output;
}

int filestream_eof(RFILE *stream)
{
   return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
}

int64_t filestream_tell(RFILE *stream)
{
   int64_t output;

   if (filestream_size_cb)
      output = filestream_tell_cb(stream-&gt;hfile);
   else
      output = retro_vfs_file_tell_impl(
            (libretro_vfs_implementation_file*)stream-&gt;hfile);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream-&gt;err_flag = true;

   return output;
}

void filestream_rewind(RFILE *stream)
{
   if (!stream)
      return;
   filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
   stream-&gt;err_flag = false;
}

int64_t filestream_read(RFILE *stream, void *s, int64_t len)
{
   int64_t output;

   if (filestream_read_cb)
      output = filestream_read_cb(stream-&gt;hfile, s, len);
   else
      output = retro_vfs_file_read_impl(
            (libretro_vfs_implementation_file*)stream-&gt;hfile, s, len);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream-&gt;err_flag = true;

   return output;
}

int filestream_flush(RFILE *stream)
{
   int output;

   if (filestream_flush_cb)
      output = filestream_flush_cb(stream-&gt;hfile);
   else
      output = retro_vfs_file_flush_impl(
            (libretro_vfs_implementation_file*)stream-&gt;hfile);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream-&gt;err_flag = true;

   return output;
}

int filestream_delete(const char *path)
{
   if (filestream_remove_cb)
      return filestream_remove_cb(path);

   return retro_vfs_file_remove_impl(path);
}

int filestream_rename(const char *old_path, const char *new_path)
{
   if (filestream_rename_cb)
      return filestream_rename_cb(old_path, new_path);

   return retro_vfs_file_rename_impl(old_path, new_path);
}

int filestream_copy(const char *src, const char *dst)
{
   char buf[256] = {0};
   int64_t n     = 0;
   int ret       = 0;
   char path_dst[PATH_MAX_LENGTH] = {0};

   RFILE *fp_src = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
   RFILE *fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fp_src || !fp_dst)
      ret = -1;

   if (ret &lt; 0)
      goto close;

   snprintf(path_dst, sizeof(path_dst), "%s", dst);
   path_basedir(path_dst);

   if (!path_is_directory(path_dst))
      path_mkdir(path_dst);

   while ((n = filestream_read(fp_src, buf, sizeof(buf))) &gt; 0 &amp;&amp; ret == 0)
   {
      if (filestream_write(fp_dst, buf, n) != n)
         ret = -1;
   }

close:
   if (fp_src)
      filestream_close(fp_src);
   if (fp_dst)
      filestream_close(fp_dst);
   return ret;
}

int filestream_cmp(const char *src, const char *dst)
{
   int ret           = 0;
   RFILE *fp_src     = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   RFILE *fp_dst     = filestream_open(dst, RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!fp_src || !fp_dst || filestream_get_size(fp_src) != filestream_get_size(fp_dst))
      ret = -1;

   if (ret &gt;= 0)
   {
      char buf_src[256] = {0};
      char buf_dst[256] = {0};
      while ((filestream_read(fp_src, buf_src, sizeof(buf_src))) &gt; 0 &amp;&amp; ret == 0)
      {
         filestream_read(fp_dst, buf_dst, sizeof(buf_dst));
         ret = memcmp(buf_src, buf_dst, sizeof(buf_src));
      }
   }

   if (fp_src)
   {
      filestream_close(fp_src);
      fp_src = NULL;
   }
   if (fp_dst)
   {
      filestream_close(fp_dst);
      fp_dst = NULL;
   }
   return ret;
}

const char* filestream_get_path(RFILE *stream)
{
   if (filestream_get_path_cb)
      return filestream_get_path_cb(stream-&gt;hfile);

   return retro_vfs_file_get_path_impl(
         (libretro_vfs_implementation_file*)stream-&gt;hfile);
}

int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
{
   int64_t output;

   if (filestream_write_cb)
      output = filestream_write_cb(stream-&gt;hfile, s, len);
   else
      output = retro_vfs_file_write_impl(
            (libretro_vfs_implementation_file*)stream-&gt;hfile, s, len);

   if (output == VFS_ERROR_RETURN_VALUE)
      stream-&gt;err_flag = true;

   return output;
}

int filestream_putc(RFILE *stream, int c)
{
   char c_char = (char)c;
   if (!stream)
      return EOF;
   return filestream_write(stream, &amp;c_char, 1) == 1
      ? (int)(unsigned char)c
      : EOF;
}

int filestream_vprintf(RFILE *stream, const char* format, va_list args)
{
   static char buffer[8 * 1024];
   int _len = vsnprintf(buffer, sizeof(buffer),
         format, args);
   if (_len &lt; 0)
      return -1;
   else if (_len == 0)
      return 0;
   return (int)filestream_write(stream, buffer, _len);
}

int filestream_printf(RFILE *stream, const char* format, ...)
{
   va_list vl;
   int ret;
   va_start(vl, format);
   ret = filestream_vprintf(stream, format, vl);
   va_end(vl);
   return ret;
}

int filestream_error(RFILE *stream)
{
   return (stream &amp;&amp; stream-&gt;err_flag);
}

int filestream_close(RFILE *stream)
{
   int output;
   struct retro_vfs_file_handle* fp = stream-&gt;hfile;

   if (filestream_close_cb)
      output = filestream_close_cb(fp);
   else
      output = retro_vfs_file_close_impl(
            (libretro_vfs_implementation_file*)fp);

   if (output == 0)
      free(stream);

   return output;
}

int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
{
   int64_t ret              = 0;
   int64_t content_buf_size = 0;
   void *content_buf        = NULL;
   RFILE *file              = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_READ,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);

   if (!file)
   {
      *buf = NULL;
      return 0;
   }

   if ((content_buf_size = filestream_get_size(file)) &lt; 0)
      goto error;

   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
      goto error;
   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
      goto error;

   if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) &lt;
         0)
      goto error;

   if (filestream_close(file) != 0)
      free(file);

   *buf    = content_buf;

   /* Allow for easy reading of strings to be safe.
    * Will only work with sane character formatting (Unix). */
   ((char*)content_buf)[ret] = '\0';

   if (len)
      *len = ret;

   return 1;

error:
   if (filestream_close(file) != 0)
      free(file);
   if (content_buf)
      free(content_buf);
   if (len)
      *len = -1;
   *buf = NULL;
   return 0;
}

bool filestream_write_file(const char *path, const void *data, int64_t size)
{
   int64_t ret   = 0;
   RFILE *file   = filestream_open(path,
         RETRO_VFS_FILE_ACCESS_WRITE,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!file)
      return false;
   ret = filestream_write(file, data, size);
   if (filestream_close(file) != 0)
      free(file);
   return (ret == size);
}

char *filestream_getline(RFILE *stream)
{
   char *newline_tmp  = NULL;
   size_t cur_size    = 8;
   size_t idx         = 0;
   int in             = 0;
   char *newline      = (char*)malloc(9);

   if (!stream || !newline)
   {
      if (newline)
         free(newline);
      return NULL;
   }

   in = filestream_getc(stream);

   while (in != EOF &amp;&amp; in != '\n')
   {
      if (idx == cur_size)
      {
         cur_size    *= 2;

         if (!(newline_tmp = (char*)realloc(newline, cur_size + 1)))
         {
            free(newline);
            return NULL;
         }

         newline     = newline_tmp;
      }

      newline[idx++] = in;
      in             = filestream_getc(stream);
   }

   newline[idx]      = '\0';
   return newline;
}

libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
{
   return (libretro_vfs_implementation_file*)stream-&gt;hfile;
}</pre>
<h2>./include/libretro-common/streams/file_stream_transforms.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream_transforms.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include &lt;string.h&gt;
#include &lt;stdarg.h&gt;

#include &lt;libretro.h&gt;
#include &lt;streams/file_stream.h&gt;

RFILE* rfopen(const char *path, const char *mode)
{
   RFILE          *output  = NULL;
   unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;
   bool position_to_end    = false;

   if (strstr(mode, "r"))
   {
      retro_mode = RETRO_VFS_FILE_ACCESS_READ;
      if (strstr(mode, "+"))
      {
         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
      }
   }
   else if (strstr(mode, "w"))
   {
      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE;
      if (strstr(mode, "+"))
         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE;
   }
   else if (strstr(mode, "a"))
   {
      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE |
         RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
      position_to_end = true;
      if (strstr(mode, "+"))
      {
         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
      }
   }

   output = filestream_open(path, retro_mode,
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (output &amp;&amp; position_to_end)
      filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END);

   return output;
}

int rfclose(RFILE* stream)
{
   if (!stream)
      return EOF;

   return filestream_close(stream);
}

int64_t rftell(RFILE* stream)
{
   if (!stream)
      return -1;

   return filestream_tell(stream);
}

int64_t rfseek(RFILE* stream, int64_t offset, int origin)
{
   int seek_position = -1;

   if (!stream)
      return -1;

   switch (origin)
   {
      case SEEK_SET:
         seek_position = RETRO_VFS_SEEK_POSITION_START;
         break;
      case SEEK_CUR:
         seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
         break;
      case SEEK_END:
         seek_position = RETRO_VFS_SEEK_POSITION_END;
         break;
   }

   return filestream_seek(stream, offset, seek_position);
}

int64_t rfread(void* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream)
{
   if (!stream || (elem_size == 0) || (elem_count == 0))
      return 0;

   return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
}

char *rfgets(char *s, int maxCount, RFILE* stream)
{
   if (!stream)
      return NULL;
   return filestream_gets(stream, s, maxCount);
}

int rfgetc(RFILE* stream)
{
   if (!stream)
      return EOF;

   return filestream_getc(stream);
}

int64_t rfwrite(void const* buffer,
   size_t elem_size, size_t elem_count, RFILE* stream)
{
   if (!stream || (elem_size == 0) || (elem_count == 0))
      return 0;

   return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);
}

int rfputc(int character, RFILE * stream)
{
   if (!stream)
      return EOF;

   return filestream_putc(stream, character);
}

int64_t rfflush(RFILE * stream)
{
   if (!stream)
      return EOF;

   return filestream_flush(stream);
}

int rfprintf(RFILE * stream, const char * format, ...)
{
   int ret;
   va_list vl;

   if (!stream)
      return -1;

   va_start(vl, format);
   ret = filestream_vprintf(stream, format, vl);
   va_end(vl);
   return ret;
}

int rferror(RFILE* stream)
{
   return filestream_error(stream);
}

int rfeof(RFILE* stream)
{
   return filestream_eof(stream);
}

int rfscanf(RFILE * stream, const char * format, ...)
{
   int ret;
   va_list vl;

   if (!stream)
      return 0;

   va_start(vl, format);
   ret = filestream_vscanf(stream, format, &amp;vl);
   va_end(vl);
   return ret;
}</pre>
<h2>./include/libretro-common/streams/interface_stream.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (interface_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;

#include &lt;streams/interface_stream.h&gt;
#include &lt;streams/file_stream.h&gt;
#include &lt;streams/memory_stream.h&gt;
#ifdef HAVE_CHD
#include &lt;streams/chd_stream.h&gt;
#endif
#if defined(HAVE_ZLIB)
#include &lt;streams/rzip_stream.h&gt;
#endif
#include &lt;encodings/crc32.h&gt;

struct intfstream_internal
{
   struct
   {
      RFILE *fp;
   } file;

   struct
   {
      memstream_t *fp;
      struct
      {
         uint8_t *data;
         uint64_t size;
      } buf;
      bool writable;
   } memory;
#ifdef HAVE_CHD
   struct
   {
      chdstream_t *fp;
      int32_t track;
   } chd;
#endif
#if defined(HAVE_ZLIB)
   struct
   {
      rzipstream_t *fp;
   } rzip;
#endif
   enum intfstream_type type;
};

int64_t intfstream_get_size(intfstream_internal_t *intf)
{
   if (!intf)
      return 0;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_get_size(intf-&gt;file.fp);
      case INTFSTREAM_MEMORY:
         return intf-&gt;memory.buf.size;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
        return chdstream_get_size(intf-&gt;chd.fp);
#else
        break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_get_size(intf-&gt;rzip.fp);
#else
         break;
#endif
   }

   return 0;
}

bool intfstream_resize(intfstream_internal_t *intf, intfstream_info_t *info)
{
   if (!intf || !info)
      return false;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         break;
      case INTFSTREAM_MEMORY:
         intf-&gt;memory.buf.data = info-&gt;memory.buf.data;
         intf-&gt;memory.buf.size = info-&gt;memory.buf.size;

         memstream_set_buffer(intf-&gt;memory.buf.data,
               intf-&gt;memory.buf.size);
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
#endif
         break;
      case INTFSTREAM_RZIP:
         /* Unsupported */
         return false;
   }

   return true;
}

bool intfstream_open(intfstream_internal_t *intf, const char *path,
      unsigned mode, unsigned hints)
{
   if (!intf)
      return false;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         intf-&gt;file.fp = filestream_open(path, mode, hints);
         if (!intf-&gt;file.fp)
            return false;
         break;
      case INTFSTREAM_MEMORY:
         intf-&gt;memory.fp = memstream_open(intf-&gt;memory.writable);
         if (!intf-&gt;memory.fp)
            return false;
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         intf-&gt;chd.fp = chdstream_open(path, intf-&gt;chd.track);
         if (!intf-&gt;chd.fp)
            return false;
         break;
#else
         return false;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         intf-&gt;rzip.fp = rzipstream_open(path, mode);
         if (!intf-&gt;rzip.fp)
            return false;
         break;
#else
         return false;
#endif
   }

   return true;
}

int intfstream_flush(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_flush(intf-&gt;file.fp);
      case INTFSTREAM_MEMORY:
      case INTFSTREAM_CHD:
      case INTFSTREAM_RZIP:
         /* Should we stub this for these interfaces? */
         break;
   }

   return 0;
}

int intfstream_close(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         if (intf-&gt;file.fp)
            return filestream_close(intf-&gt;file.fp);
         return 0;
      case INTFSTREAM_MEMORY:
         if (intf-&gt;memory.fp)
            memstream_close(intf-&gt;memory.fp);
         return 0;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         if (intf-&gt;chd.fp)
            chdstream_close(intf-&gt;chd.fp);
#endif
         return 0;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         if (intf-&gt;rzip.fp)
            return rzipstream_close(intf-&gt;rzip.fp);
#endif
         return 0;
   }

   return -1;
}

void *intfstream_init(intfstream_info_t *info)
{
   intfstream_internal_t *intf = NULL;
   if (!info)
      return NULL;

   if (!(intf = (intfstream_internal_t*)malloc(sizeof(*intf))))
      return NULL;

   intf-&gt;type            = info-&gt;type;
   intf-&gt;file.fp         = NULL;
   intf-&gt;memory.buf.data = NULL;
   intf-&gt;memory.buf.size = 0;
   intf-&gt;memory.fp       = NULL;
   intf-&gt;memory.writable = false;
#ifdef HAVE_CHD
   intf-&gt;chd.track       = 0;
   intf-&gt;chd.fp          = NULL;
#endif
#ifdef HAVE_ZLIB
   intf-&gt;rzip.fp         = NULL;
#endif

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         break;
      case INTFSTREAM_MEMORY:
         intf-&gt;memory.writable = info-&gt;memory.writable;
         if (!intfstream_resize(intf, info))
         {
            free(intf);
            return NULL;
         }
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         intf-&gt;chd.track = info-&gt;chd.track;
         break;
#else
         free(intf);
         return NULL;
#endif
      case INTFSTREAM_RZIP:
         break;
   }

   return intf;
}

int64_t intfstream_seek(
      intfstream_internal_t *intf, int64_t offset, int whence)
{
   if (!intf)
      return -1;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         {
            int seek_position = 0;
            switch (whence)
            {
               case SEEK_SET:
                  seek_position = RETRO_VFS_SEEK_POSITION_START;
                  break;
               case SEEK_CUR:
                  seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
                  break;
               case SEEK_END:
                  seek_position = RETRO_VFS_SEEK_POSITION_END;
                  break;
            }
            return (int64_t)filestream_seek(intf-&gt;file.fp, (int64_t)offset,
                  seek_position);
         }
      case INTFSTREAM_MEMORY:
         return (int64_t)memstream_seek(intf-&gt;memory.fp, offset, whence);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return (int64_t)chdstream_seek(intf-&gt;chd.fp, offset, whence);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
         /* Unsupported */
         break;
   }

   return -1;
}

int64_t intfstream_truncate(intfstream_internal_t *intf, uint64_t len)
{
   if (!intf)
      return 0;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_truncate(intf-&gt;file.fp, len);
      case INTFSTREAM_MEMORY:
         break;
      case INTFSTREAM_CHD:
         break;
      case INTFSTREAM_RZIP:
         break;
   }

   return 0;
}

int64_t intfstream_read(intfstream_internal_t *intf, void *s, uint64_t len)
{
   if (!intf)
      return 0;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_read(intf-&gt;file.fp, s, len);
      case INTFSTREAM_MEMORY:
         return memstream_read(intf-&gt;memory.fp, s, len);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return chdstream_read(intf-&gt;chd.fp, s, len);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_read(intf-&gt;rzip.fp, s, len);
#else
         break;
#endif
   }

   return -1;
}

int64_t intfstream_write(intfstream_internal_t *intf,
      const void *s, uint64_t len)
{
   if (!intf)
      return 0;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_write(intf-&gt;file.fp, s, len);
      case INTFSTREAM_MEMORY:
         return memstream_write(intf-&gt;memory.fp, s, len);
      case INTFSTREAM_CHD:
         return -1;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_write(intf-&gt;rzip.fp, s, len);
#else
         return -1;
#endif
   }

   return 0;
}

int intfstream_printf(intfstream_internal_t *intf,
      const char* format, ...)
{
   int ret;
   va_list vl;

   if (!intf)
      return 0;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         va_start(vl, format);
         ret = filestream_vprintf(intf-&gt;file.fp, format, vl);
         va_end(vl);
         return ret;
      case INTFSTREAM_MEMORY:
         return -1;
      case INTFSTREAM_CHD:
         return -1;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         va_start(vl, format);
         ret = rzipstream_vprintf(intf-&gt;rzip.fp, format, vl);
         va_end(vl);
         return ret;
#else
         return -1;
#endif
   }

   return 0;
}

int64_t intfstream_get_ptr(intfstream_internal_t* intf)
{
   if (!intf)
      return 0;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return -1;
      case INTFSTREAM_MEMORY:
         return memstream_get_ptr(intf-&gt;memory.fp);
      case INTFSTREAM_CHD:
         return -1;
      case INTFSTREAM_RZIP:
         return -1;
   }

   return 0;
}

char *intfstream_gets(intfstream_internal_t *intf,
      char *s, uint64_t len)
{
   if (!intf)
      return NULL;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_gets(intf-&gt;file.fp,
               s, (size_t)len);
      case INTFSTREAM_MEMORY:
         return memstream_gets(intf-&gt;memory.fp,
               s, (size_t)len);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return chdstream_gets(intf-&gt;chd.fp, s, len);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_gets(intf-&gt;rzip.fp, s, (size_t)len);
#else
         break;
#endif
   }

   return NULL;
}

int intfstream_getc(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_getc(intf-&gt;file.fp);
      case INTFSTREAM_MEMORY:
         return memstream_getc(intf-&gt;memory.fp);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return chdstream_getc(intf-&gt;chd.fp);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_getc(intf-&gt;rzip.fp);
#else
         break;
#endif
   }

   return -1;
}

int64_t intfstream_tell(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return (int64_t)filestream_tell(intf-&gt;file.fp);
      case INTFSTREAM_MEMORY:
         return (int64_t)memstream_pos(intf-&gt;memory.fp);
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         return (int64_t)chdstream_tell(intf-&gt;chd.fp);
#else
         break;
#endif
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return (int64_t)rzipstream_tell(intf-&gt;rzip.fp);
#else
         break;
#endif
   }

   return -1;
}

int intfstream_eof(intfstream_internal_t *intf)
{
   if (!intf)
      return -1;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return filestream_eof(intf-&gt;file.fp);
      case INTFSTREAM_MEMORY:
         /* TODO: Add this functionality to
          * memory_stream interface */
         break;
      case INTFSTREAM_CHD:
         /* TODO: Add this functionality to
          * chd_stream interface */
         break;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_eof(intf-&gt;rzip.fp);
#else
         break;
#endif
   }

   return -1;
}

void intfstream_rewind(intfstream_internal_t *intf)
{
   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         filestream_rewind(intf-&gt;file.fp);
         break;
      case INTFSTREAM_MEMORY:
         memstream_rewind(intf-&gt;memory.fp);
         break;
      case INTFSTREAM_CHD:
#ifdef HAVE_CHD
         chdstream_rewind(intf-&gt;chd.fp);
#endif
         break;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         rzipstream_rewind(intf-&gt;rzip.fp);
#endif
         break;
   }
}

void intfstream_putc(intfstream_internal_t *intf, int c)
{
   if (!intf)
      return;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         filestream_putc(intf-&gt;file.fp, c);
         break;
      case INTFSTREAM_MEMORY:
         memstream_putc(intf-&gt;memory.fp, c);
         break;
      case INTFSTREAM_CHD:
         break;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         rzipstream_putc(intf-&gt;rzip.fp, c);
#else
         break;
#endif
   }
}

uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf)
{
   if (intf)
   {
#ifdef HAVE_CHD
      if (intf-&gt;type == INTFSTREAM_CHD)
         return chdstream_get_track_start(intf-&gt;chd.fp);
#endif
   }

   return 0;
}

uint32_t intfstream_get_frame_size(intfstream_internal_t *intf)
{
   if (intf)
   {
#ifdef HAVE_CHD
      if (intf-&gt;type == INTFSTREAM_CHD)
         return chdstream_get_frame_size(intf-&gt;chd.fp);
#endif
   }

   return 0;
}

uint32_t intfstream_get_first_sector(intfstream_internal_t* intf)
{
   if (intf)
   {
#ifdef HAVE_CHD
      if (intf-&gt;type == INTFSTREAM_CHD)
         return chdstream_get_first_track_sector(intf-&gt;chd.fp);
#endif
   }

   return 0;
}

bool intfstream_is_compressed(intfstream_internal_t *intf)
{
   if (!intf)
      return false;

   switch (intf-&gt;type)
   {
      case INTFSTREAM_FILE:
         return false;
      case INTFSTREAM_MEMORY:
         return false;
      case INTFSTREAM_CHD:
         return true;
      case INTFSTREAM_RZIP:
#if defined(HAVE_ZLIB)
         return rzipstream_is_compressed(intf-&gt;rzip.fp);
#else
         break;
#endif
   }

   return false;
}

bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc)
{
   int64_t data_read    = 0;
   uint32_t accumulator = 0;
   uint8_t buffer[4096];

   if (!intf || !crc)
      return false;

   /* Ensure we start at the beginning of the file */
   intfstream_rewind(intf);

   while ((data_read = intfstream_read(intf, buffer, sizeof(buffer))) &gt; 0)
      accumulator = encoding_crc32(accumulator, buffer, (size_t)data_read);

   if (data_read &lt; 0)
      return false;

   *crc = accumulator;

   /* Reset file to the beginning */
   intfstream_rewind(intf);

   return true;
}

intfstream_t* intfstream_open_file(const char *path,
      unsigned mode, unsigned hints)
{
   intfstream_info_t info;
   intfstream_t *fd = NULL;

   info.type        = INTFSTREAM_FILE;
   fd               = (intfstream_t*)intfstream_init(&amp;info);

   if (!fd)
      return NULL;

   if (intfstream_open(fd, path, mode, hints))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}

intfstream_t *intfstream_open_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size)
{
   intfstream_info_t info;
   intfstream_t *fd     = NULL;

   info.type            = INTFSTREAM_MEMORY;
   info.memory.buf.data = (uint8_t*)data;
   info.memory.buf.size = size;
   info.memory.writable = (mode &amp; RETRO_VFS_FILE_ACCESS_WRITE) != 0;

   if (!(fd = (intfstream_t*)intfstream_init(&amp;info)))
      return NULL;

   if (intfstream_open(fd, NULL, mode, hints))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}

intfstream_t *intfstream_open_writable_memory(void *data,
      unsigned mode, unsigned hints, uint64_t size)
{
   return intfstream_open_memory(data, mode | RETRO_VFS_FILE_ACCESS_WRITE, hints, size);
}

intfstream_t *intfstream_open_chd_track(const char *path,
      unsigned mode, unsigned hints, int32_t track)
{
   intfstream_info_t info;
   intfstream_t *fd = NULL;

   info.type        = INTFSTREAM_CHD;
   info.chd.track   = track;

   if (!(fd = (intfstream_t*)intfstream_init(&amp;info)))
      return NULL;

   if (intfstream_open(fd, path, mode, hints))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}

intfstream_t* intfstream_open_rzip_file(const char *path,
      unsigned mode)
{
   intfstream_info_t info;
   intfstream_t *fd = NULL;

   info.type        = INTFSTREAM_RZIP;
   fd               = (intfstream_t*)intfstream_init(&amp;info);

   if (!fd)
      return NULL;

   if (intfstream_open(fd, path, mode, RETRO_VFS_FILE_ACCESS_HINT_NONE))
      return fd;

   intfstream_close(fd);
   free(fd);
   return NULL;
}</pre>
<h2>./include/libretro-common/streams/memory_stream.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (memory_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;streams/memory_stream.h&gt;

/* TODO/FIXME - static globals */
static uint8_t* g_buffer      = NULL;
static uint64_t g_size         = 0;
static uint64_t last_file_size = 0;

struct memstream
{
   uint64_t size;
   uint64_t ptr;
   uint64_t max_ptr;
   uint8_t *buf;
   unsigned writing;
};

void memstream_set_buffer(uint8_t *s, uint64_t len)
{
   g_buffer = s;
   g_size   = len;
}

memstream_t *memstream_open(unsigned writing)
{
   memstream_t *stream;
   if (!g_buffer || !g_size)
      return NULL;

   stream = (memstream_t*)malloc(sizeof(*stream));

   if (!stream)
      return NULL;

   stream-&gt;buf       = g_buffer;
   stream-&gt;size      = g_size;
   stream-&gt;ptr       = 0;
   stream-&gt;max_ptr   = 0;
   stream-&gt;writing   = writing;

   g_buffer          = NULL;
   g_size            = 0;

   return stream;
}

void memstream_close(memstream_t *stream)
{
   if (!stream)
      return;

   last_file_size = stream-&gt;writing ? stream-&gt;max_ptr : stream-&gt;size;
   free(stream);
}

uint64_t memstream_get_ptr(memstream_t *stream)
{
   return stream-&gt;ptr;
}

uint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes)
{
   uint64_t avail = 0;

   if (!stream)
      return 0;

   avail               = stream-&gt;size - stream-&gt;ptr;
   if (bytes &gt; avail)
      bytes            = avail;

   memcpy(data, stream-&gt;buf + stream-&gt;ptr, (size_t)bytes);
   stream-&gt;ptr        += bytes;
   if (stream-&gt;ptr &gt; stream-&gt;max_ptr)
      stream-&gt;max_ptr  = stream-&gt;ptr;
   return bytes;
}

uint64_t memstream_write(memstream_t *stream,
      const void *data, uint64_t bytes)
{
   uint64_t avail = 0;

   if (!stream)
      return 0;

   avail = stream-&gt;size - stream-&gt;ptr;
   if (bytes &gt; avail)
      bytes = avail;

   memcpy(stream-&gt;buf + stream-&gt;ptr, data, (size_t)bytes);
   stream-&gt;ptr += bytes;
   if (stream-&gt;ptr &gt; stream-&gt;max_ptr)
      stream-&gt;max_ptr = stream-&gt;ptr;
   return bytes;
}

int64_t memstream_seek(memstream_t *stream, int64_t offset, int whence)
{
   uint64_t ptr;

   switch (whence)
   {
      case SEEK_SET:
         ptr = offset;
         break;
      case SEEK_CUR:
         ptr = stream-&gt;ptr + offset;
         break;
      case SEEK_END:
         ptr = (stream-&gt;writing ? stream-&gt;max_ptr : stream-&gt;size) + offset;
         break;
      default:
         return -1;
   }

   if (ptr &lt;= stream-&gt;size)
   {
      stream-&gt;ptr = ptr;
      return 0;
   }

   return -1;
}

void memstream_rewind(memstream_t *stream)
{
   memstream_seek(stream, 0L, SEEK_SET);
}

uint64_t memstream_pos(memstream_t *stream) { return stream-&gt;ptr; }
char *memstream_gets(memstream_t *stream, char *s, size_t len) { return NULL; }
uint64_t memstream_get_last_size(void) { return last_file_size; }

int memstream_getc(memstream_t *stream)
{
   int ret = 0;
   if (stream-&gt;ptr &gt;= stream-&gt;size)
      return EOF;
   ret = stream-&gt;buf[stream-&gt;ptr++];

   if (stream-&gt;ptr &gt; stream-&gt;max_ptr)
      stream-&gt;max_ptr = stream-&gt;ptr;

   return ret;
}

void memstream_putc(memstream_t *stream, int c)
{
   if (stream-&gt;ptr &lt; stream-&gt;size)
      stream-&gt;buf[stream-&gt;ptr++] = c;

   if (stream-&gt;ptr &gt; stream-&gt;max_ptr)
      stream-&gt;max_ptr = stream-&gt;ptr;
}</pre>
<h2>./include/libretro-common/streams/network_stream.c</h2>
<pre>/* Copyright  (C) 2022 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (network_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;retro_endianness.h&gt;

#include &lt;streams/network_stream.h&gt;

bool netstream_open(netstream_t *stream, void *buf, size_t len, size_t used)
{
   if (buf)
   {
      /* Pre-allocated buffer must have a non-zero size. */
      if (!len || used &gt; len)
         return false;
   }
   else
   {
      if (len)
      {
         buf = malloc(len);
         if (!buf)
            return false;
      }

      used = 0;
   }

   stream-&gt;buf  = buf;
   stream-&gt;size = len;
   stream-&gt;used = used;
   stream-&gt;pos  = 0;

   return true;
}

void netstream_close(netstream_t *stream, bool dealloc)
{
   if (dealloc)
      free(stream-&gt;buf);
   memset(stream, 0, sizeof(*stream));
}

void netstream_reset(netstream_t *stream)
{
   stream-&gt;pos  = 0;
   stream-&gt;used = 0;
}

bool netstream_truncate(netstream_t *stream, size_t used)
{
   if (used &gt; stream-&gt;size)
      return false;

   stream-&gt;used = used;

   /* If the current stream position is past our new end of stream,
      set the current position to the end of the stream. */
   if (stream-&gt;pos &gt; used)
      stream-&gt;pos = used;

   return true;
}

void netstream_data(netstream_t *stream, void **data, size_t *len)
{
   *data = stream-&gt;buf;
   *len  = stream-&gt;used;
}

bool netstream_eof(netstream_t *stream)
{
   return stream-&gt;pos &gt;= stream-&gt;used;
}

size_t netstream_tell(netstream_t *stream)
{
   return stream-&gt;pos;
}

bool netstream_seek(netstream_t *stream, long offset, int origin)
{
   long pos  = (long)stream-&gt;pos;
   long used = (long)stream-&gt;used;

   switch (origin)
   {
      case NETSTREAM_SEEK_SET:
         pos  = offset;
         break;
      case NETSTREAM_SEEK_CUR:
         pos += offset;
         break;
      case NETSTREAM_SEEK_END:
         pos  = used + offset;
         break;
      default:
         return false;
   }

   if (pos &lt; 0 || pos &gt; used)
      return false;

   stream-&gt;pos = (size_t)pos;

   return true;
}

bool netstream_read(netstream_t *stream, void *data, size_t len)
{
   size_t remaining = stream-&gt;used - stream-&gt;pos;

   if (!data || !remaining || len &gt; remaining)
      return false;

   /* If len is 0, read all remaining bytes. */
   if (!len)
      len = remaining;

   memcpy(data, (uint8_t*)stream-&gt;buf + stream-&gt;pos, len);

   stream-&gt;pos += len;

   return true;
}

/* This one doesn't require any swapping. */
bool netstream_read_byte(netstream_t *stream, uint8_t *data)
{
   return netstream_read(stream, data, sizeof(*data));
}

#define NETSTREAM_READ_TYPE(name, type, swap) \
bool netstream_read_##name(netstream_t *stream, type *data) \
{ \
   if (!netstream_read(stream, data, sizeof(*data))) \
      return false; \
   *data = swap(*data); \
   return true; \
}

NETSTREAM_READ_TYPE(word,  uint16_t, retro_be_to_cpu16)
NETSTREAM_READ_TYPE(dword, uint32_t, retro_be_to_cpu32)
NETSTREAM_READ_TYPE(qword, uint64_t, retro_be_to_cpu64)

#undef NETSTREAM_READ_TYPE

#ifdef __STDC_IEC_559__
#define NETSTREAM_READ_TYPE(name, type, type_alt, swap) \
bool netstream_read_##name(netstream_t *stream, type *data) \
{ \
   type_alt *data_alt = (type_alt*)data; \
   if (!netstream_read(stream, data, sizeof(*data))) \
      return false; \
   *data_alt = swap(*data_alt); \
   return true; \
}

NETSTREAM_READ_TYPE(float,  float,  uint32_t, retro_be_to_cpu32)
NETSTREAM_READ_TYPE(double, double, uint64_t, retro_be_to_cpu64)

#undef NETSTREAM_READ_TYPE
#endif

int netstream_read_string(netstream_t *stream, char *s, size_t len)
{
   char c;
   int ret = 0;

   if (!s || !len)
      return -1;

   for (; --len; ret++)
   {
      if (!netstream_read(stream, &amp;c, sizeof(c)))
         return -1;

      *s++ = c;

      if (!c)
         break;
   }

   if (!len)
   {
      *s = '\0';

      for (;; ret++)
      {
         if (!netstream_read(stream, &amp;c, sizeof(c)))
            return -1;
         if (!c)
            break;
      }
   }

   return ret;
}

bool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len)
{
   if (!len)
      return false;

   if (!netstream_read(stream, s, len))
      return false;

   /* Ensure the string is always null-terminated. */
   s[len - 1] = '\0';

   return true;
}

bool netstream_write(netstream_t *stream, const void *data, size_t len)
{
   size_t remaining = stream-&gt;size - stream-&gt;pos;

   if (!data || !len)
      return false;

   if (len &gt; remaining)
   {
      if (!stream-&gt;size)
      {
         if (stream-&gt;buf)
            free(stream-&gt;buf);
         stream-&gt;buf  = malloc(len);
         if (!stream-&gt;buf)
            return false;
         stream-&gt;size = len;
      }
      else
      {
         size_t _len = stream-&gt;size + (len - remaining);
         void   *buf = realloc(stream-&gt;buf, _len);

         if (!buf)
            return false;

         stream-&gt;buf  = buf;
         stream-&gt;size = _len;
      }
   }

   memcpy((uint8_t*)stream-&gt;buf + stream-&gt;pos, data, len);

   stream-&gt;pos += len;

   if (stream-&gt;pos &gt; stream-&gt;used)
      stream-&gt;used = stream-&gt;pos;

   return true;
}

/* This one doesn't require any swapping. */
bool netstream_write_byte(netstream_t *stream, uint8_t data)
{
   return netstream_write(stream, &amp;data, sizeof(data));
}

#define NETSTREAM_WRITE_TYPE(name, type, swap) \
bool netstream_write_##name(netstream_t *stream, type data) \
{ \
   data = swap(data); \
   return netstream_write(stream, &amp;data, sizeof(data)); \
}

NETSTREAM_WRITE_TYPE(word,  uint16_t, retro_cpu_to_be16)
NETSTREAM_WRITE_TYPE(dword, uint32_t, retro_cpu_to_be32)
NETSTREAM_WRITE_TYPE(qword, uint64_t, retro_cpu_to_be64)

#undef NETSTREAM_WRITE_TYPE

#ifdef __STDC_IEC_559__
#define NETSTREAM_WRITE_TYPE(name, type, type_alt, swap) \
bool netstream_write_##name(netstream_t *stream, type data) \
{ \
   type_alt *data_alt = (type_alt*)&amp;data; \
   *data_alt = swap(*data_alt); \
   return netstream_write(stream, &amp;data, sizeof(data)); \
}

NETSTREAM_WRITE_TYPE(float,  float,  uint32_t, retro_cpu_to_be32)
NETSTREAM_WRITE_TYPE(double, double, uint64_t, retro_cpu_to_be64)

#undef NETSTREAM_WRITE_TYPE
#endif

bool netstream_write_string(netstream_t *stream, const char *s)
{
   if (!s)
      return false;

   return netstream_write(stream, s, strlen(s) + 1);
}

bool netstream_write_fixed_string(netstream_t *stream, const char *s,
      size_t len)
{
   char end = '\0';

   if (!netstream_write(stream, s, len))
      return false;

   /* Ensure the string is always null-terminated. */
   netstream_seek(stream, -1, NETSTREAM_SEEK_CUR);
   netstream_write(stream, &amp;end, sizeof(end));

   return true;
}</pre>
<h2>./include/libretro-common/streams/rzip_stream.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rzip_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;string/stdstring.h&gt;
#include &lt;file/file_path.h&gt;

#include &lt;streams/file_stream.h&gt;
#include &lt;streams/trans_stream.h&gt;

#include &lt;streams/rzip_stream.h&gt;

/* Current RZIP file format version */
#define RZIP_VERSION 1

/* Compression level
 * &gt; zlib default of 6 provides the best
 *   balance between file size and
 *   compression speed */
#define RZIP_COMPRESSION_LEVEL 6

/* Default chunk size: 128kb */
#define RZIP_DEFAULT_CHUNK_SIZE 131072

/* Header sizes (in bytes) */
#define RZIP_HEADER_SIZE 20
#define RZIP_CHUNK_HEADER_SIZE 4

/* Holds all metadata for an RZIP file stream */
struct rzipstream
{
   uint64_t size;
   /* virtual_ptr: Used to track how much
    * uncompressed data has been read */
   uint64_t virtual_ptr;
   RFILE* file;
   const struct trans_stream_backend *deflate_backend;
   void *deflate_stream;
   const struct trans_stream_backend *inflate_backend;
   void *inflate_stream;
   uint8_t *in_buf;
   uint8_t *out_buf;
   uint32_t in_buf_size;
   uint32_t in_buf_ptr;
   uint32_t out_buf_size;
   uint32_t out_buf_ptr;
   uint32_t out_buf_occupancy;
   uint32_t chunk_size;
   bool is_compressed;
   bool is_writing;
};

/* Header Functions */

/* Reads header information from RZIP file
 * &gt; Detects whether file is compressed or
 *   uncompressed data
 * &gt; If compressed, extracts uncompressed
 *   file/chunk sizes */
static bool rzipstream_read_file_header(rzipstream_t *stream)
{
   unsigned i;
   int64_t length;
   uint8_t header_bytes[RZIP_HEADER_SIZE];

   if (!stream)
      return false;

   for (i = 0; i &lt; RZIP_HEADER_SIZE; i++)
      header_bytes[i] = 0;

   /* Attempt to read header bytes */
   if ((length = filestream_read(stream-&gt;file,
        header_bytes, sizeof(header_bytes))) &lt;= 0)
      return false;

   /* If file length is less than header size
    * then assume this is uncompressed data */

   /* Check 'magic numbers' - first 8 bytes
    * of header */
   if (
          (length       &lt; RZIP_HEADER_SIZE)
       || (header_bytes[0] !=           35)  /* # */
       || (header_bytes[1] !=           82)  /* R */
       || (header_bytes[2] !=           90)  /* Z */
       || (header_bytes[3] !=           73)  /* I */
       || (header_bytes[4] !=           80)  /* P */
       || (header_bytes[5] !=          118)  /* v */
       || (header_bytes[6] != RZIP_VERSION)  /* file format version number */
       || (header_bytes[7] !=           35)) /* # */
   {
      /* Reset file to start */
      filestream_seek(stream-&gt;file, 0, SEEK_SET);
      /* Get 'raw' file size */
      stream-&gt;size          = filestream_get_size(stream-&gt;file);
      stream-&gt;is_compressed = false;
      return true;
   }

   /* Get uncompressed chunk size - next 4 bytes */
   if ((stream-&gt;chunk_size = (
                            (uint32_t)header_bytes[11] &lt;&lt; 24)
                         | ((uint32_t)header_bytes[10] &lt;&lt; 16)
                         | ((uint32_t)header_bytes[9]  &lt;&lt;  8)
                         | (uint32_t)header_bytes[8]) == 0)
      return false;

   /* Get total uncompressed data size - next 8 bytes */
   if ((stream-&gt;size = (
                      (uint64_t)header_bytes[19] &lt;&lt; 56)
                   | ((uint64_t)header_bytes[18] &lt;&lt; 48)
                   | ((uint64_t)header_bytes[17] &lt;&lt; 40)
                   | ((uint64_t)header_bytes[16] &lt;&lt; 32)
                   | ((uint64_t)header_bytes[15] &lt;&lt; 24)
                   | ((uint64_t)header_bytes[14] &lt;&lt; 16)
                   | ((uint64_t)header_bytes[13] &lt;&lt;  8)
                   | (uint64_t)header_bytes[12]) == 0)
      return false;

   stream-&gt;is_compressed = true;
   return true;
}

/* Writes header information to RZIP file
 * &gt; ID 'magic numbers' + uncompressed
 *   file/chunk sizes */
static bool rzipstream_write_file_header(rzipstream_t *stream)
{
   unsigned i;
   uint8_t header_bytes[RZIP_HEADER_SIZE];

   if (!stream)
      return false;

   /* Populate header array */
   for (i = 0; i &lt; RZIP_HEADER_SIZE; i++)
      header_bytes[i] = 0;

   /* &gt; 'Magic numbers' - first 8 bytes */
   header_bytes[0]    =        35;    /* # */
   header_bytes[1]    =        82;    /* R */
   header_bytes[2]    =        90;    /* Z */
   header_bytes[3]    =        73;    /* I */
   header_bytes[4]    =        80;    /* P */
   header_bytes[5]    =       118;    /* v */
   header_bytes[6]    = RZIP_VERSION; /* file format version number */
   header_bytes[7]    =        35;    /* # */

   /* &gt; Uncompressed chunk size - next 4 bytes */
   header_bytes[11]   = (stream-&gt;chunk_size &gt;&gt; 24) &amp; 0xFF;
   header_bytes[10]   = (stream-&gt;chunk_size &gt;&gt; 16) &amp; 0xFF;
   header_bytes[9]    = (stream-&gt;chunk_size &gt;&gt;  8) &amp; 0xFF;
   header_bytes[8]    =  stream-&gt;chunk_size        &amp; 0xFF;

   /* &gt; Total uncompressed data size - next 8 bytes */
   header_bytes[19]   = (stream-&gt;size &gt;&gt; 56) &amp; 0xFF;
   header_bytes[18]   = (stream-&gt;size &gt;&gt; 48) &amp; 0xFF;
   header_bytes[17]   = (stream-&gt;size &gt;&gt; 40) &amp; 0xFF;
   header_bytes[16]   = (stream-&gt;size &gt;&gt; 32) &amp; 0xFF;
   header_bytes[15]   = (stream-&gt;size &gt;&gt; 24) &amp; 0xFF;
   header_bytes[14]   = (stream-&gt;size &gt;&gt; 16) &amp; 0xFF;
   header_bytes[13]   = (stream-&gt;size &gt;&gt;  8) &amp; 0xFF;
   header_bytes[12]   =  stream-&gt;size        &amp; 0xFF;

   /* Reset file to start */
   filestream_seek(stream-&gt;file, 0, SEEK_SET);

   /* Write header bytes */
   return (filestream_write(stream-&gt;file,
         header_bytes, sizeof(header_bytes)) == RZIP_HEADER_SIZE);
}

/* Stream Initialisation/De-initialisation */

/* Initialises all members of an rzipstream_t struct,
 * reading config from existing file header if available */
static bool rzipstream_init_stream(
      rzipstream_t *stream, const char *path, bool is_writing)
{
   unsigned file_mode;

   if (!stream)
      return false;

   /* Ensure stream has valid initial values */
   stream-&gt;size              = 0;
   stream-&gt;chunk_size        = RZIP_DEFAULT_CHUNK_SIZE;
   stream-&gt;file              = NULL;
   stream-&gt;deflate_backend   = NULL;
   stream-&gt;deflate_stream    = NULL;
   stream-&gt;inflate_backend   = NULL;
   stream-&gt;inflate_stream    = NULL;
   stream-&gt;in_buf            = NULL;
   stream-&gt;in_buf_size       = 0;
   stream-&gt;in_buf_ptr        = 0;
   stream-&gt;out_buf           = NULL;
   stream-&gt;out_buf_size      = 0;
   stream-&gt;out_buf_ptr       = 0;
   stream-&gt;out_buf_occupancy = 0;

   /* Check whether this is a read or write stream */
   stream-&gt;is_writing = is_writing;
   if (stream-&gt;is_writing)
   {
      /* Written files are always compressed */
      stream-&gt;is_compressed = true;
      file_mode             = RETRO_VFS_FILE_ACCESS_WRITE;
   }
   /* For read files, must get compression status
    * from file itself... */
   else
      file_mode             = RETRO_VFS_FILE_ACCESS_READ;

   /* Open file */
   if (!(stream-&gt;file = filestream_open(
         path, file_mode, RETRO_VFS_FILE_ACCESS_HINT_NONE)))
      return false;

   /* If file is open for writing, output header
    * (Size component cannot be written until
    * file is closed...) */
   if (stream-&gt;is_writing)
   {
      /* Note: could just write zeros here, but
       * still want to identify this as an RZIP
       * file if writing fails partway through */
      if (!rzipstream_write_file_header(stream))
         return false;
   }
   /* If file is open for reading, parse any existing
    * header */
   else if (!rzipstream_read_file_header(stream))
      return false;

   /* Initialise appropriate transform stream
    * and determine associated buffer sizes */
   if (stream-&gt;is_writing)
   {
      /* Compression */
      if (!(stream-&gt;deflate_backend = trans_stream_get_zlib_deflate_backend()))
         return false;

      if (!(stream-&gt;deflate_stream = stream-&gt;deflate_backend-&gt;stream_new()))
         return false;

      /* Set compression level */
      if (!stream-&gt;deflate_backend-&gt;define(
            stream-&gt;deflate_stream, "level", RZIP_COMPRESSION_LEVEL))
         return false;

      /* Buffers
       * &gt; Input: uncompressed
       * &gt; Output: compressed */
      stream-&gt;in_buf_size  = stream-&gt;chunk_size;
      stream-&gt;out_buf_size = stream-&gt;chunk_size * 2;
      /* &gt; Account for minimum zlib overhead
       *   of 11 bytes... */
      stream-&gt;out_buf_size =
            (stream-&gt;out_buf_size &lt; (stream-&gt;in_buf_size + 11)) ?
                  stream-&gt;out_buf_size + 11 :
                  stream-&gt;out_buf_size;

      /* Redundant safety check */
      if (   (stream-&gt;in_buf_size  == 0)
          || (stream-&gt;out_buf_size == 0))
         return false;
   }
   /* When reading, don't need an inflate transform
    * stream (or buffers) if source file is uncompressed */
   else if (stream-&gt;is_compressed)
   {
      /* Decompression */
      if (!(stream-&gt;inflate_backend = trans_stream_get_zlib_inflate_backend()))
         return false;

      if (!(stream-&gt;inflate_stream = stream-&gt;inflate_backend-&gt;stream_new()))
         return false;

      /* Buffers
       * &gt; Input: compressed
       * &gt; Output: uncompressed
       * Note 1: Actual compressed chunk sizes are read
       *         from the file - just allocate a sensible
       *         default to minimise memory reallocations
       * Note 2: If file header is valid, output buffer
       *         should have a size of exactly stream-&gt;chunk_size.
       *         Allocate some additional space, just for
       *         redundant safety... */
      stream-&gt;in_buf_size  = stream-&gt;chunk_size * 2;
      stream-&gt;out_buf_size = stream-&gt;chunk_size + (stream-&gt;chunk_size &gt;&gt; 2);

      /* Redundant safety check */
      if (   (stream-&gt;in_buf_size  == 0)
          || (stream-&gt;out_buf_size == 0))
         return false;
   }

   /* Allocate buffers */
   if (stream-&gt;in_buf_size &gt; 0)
   {
      if (!(stream-&gt;in_buf = (uint8_t *)calloc(stream-&gt;in_buf_size, 1)))
         return false;
   }

   if (stream-&gt;out_buf_size &gt; 0)
   {
      if (!(stream-&gt;out_buf = (uint8_t *)calloc(stream-&gt;out_buf_size, 1)))
         return false;
   }

   return true;
}

/* free()'s all members of an rzipstream_t struct
 * &gt; Also closes associated file, if currently open */
static int rzipstream_free_stream(rzipstream_t *stream)
{
   int ret = 0;

   if (!stream)
      return -1;

   /* Free transform streams */
   if (stream-&gt;deflate_stream &amp;&amp; stream-&gt;deflate_backend)
      stream-&gt;deflate_backend-&gt;stream_free(stream-&gt;deflate_stream);

   stream-&gt;deflate_stream  = NULL;
   stream-&gt;deflate_backend = NULL;

   if (stream-&gt;inflate_stream &amp;&amp; stream-&gt;inflate_backend)
      stream-&gt;inflate_backend-&gt;stream_free(stream-&gt;inflate_stream);

   stream-&gt;inflate_stream  = NULL;
   stream-&gt;inflate_backend = NULL;

   /* Free buffers */
   if (stream-&gt;in_buf)
      free(stream-&gt;in_buf);
   stream-&gt;in_buf = NULL;

   if (stream-&gt;out_buf)
      free(stream-&gt;out_buf);
   stream-&gt;out_buf = NULL;

   /* Close file */
   if (stream-&gt;file)
      ret = filestream_close(stream-&gt;file);
   stream-&gt;file = NULL;

   free(stream);

   return ret;
}

/* File Open */

/* Opens a new or existing RZIP file
 * &gt; Supported 'mode' values are:
 *   - RETRO_VFS_FILE_ACCESS_READ
 *   - RETRO_VFS_FILE_ACCESS_WRITE
 * &gt; When reading, 'path' may reference compressed
 *   or uncompressed data
 * Returns NULL if arguments are invalid, file
 * is invalid or an IO error occurs */
rzipstream_t* rzipstream_open(const char *path, unsigned mode)
{
   rzipstream_t *stream = NULL;

   /* Sanity check
    * &gt; Only RETRO_VFS_FILE_ACCESS_READ and
    *   RETRO_VFS_FILE_ACCESS_WRITE are supported */
   if (string_is_empty(path)
       || (   (mode != RETRO_VFS_FILE_ACCESS_READ)
           &amp;&amp; (mode != RETRO_VFS_FILE_ACCESS_WRITE)))
      return NULL;

   /* If opening in read mode, ensure file exists */
   if (   (mode == RETRO_VFS_FILE_ACCESS_READ)
       &amp;&amp; !path_is_valid(path))
      return NULL;

   /* Allocate stream object */
   if (!(stream = (rzipstream_t*)malloc(sizeof(*stream))))
      return NULL;

   stream-&gt;is_compressed   = false;
   stream-&gt;is_writing      = false;
   stream-&gt;size            = 0;
   stream-&gt;chunk_size      = 0;
   stream-&gt;virtual_ptr     = 0;
   stream-&gt;file            = NULL;
   stream-&gt;deflate_backend = NULL;
   stream-&gt;deflate_stream  = NULL;
   stream-&gt;inflate_backend = NULL;
   stream-&gt;inflate_stream  = NULL;
   stream-&gt;in_buf          = NULL;
   stream-&gt;in_buf_size     = 0;
   stream-&gt;in_buf_ptr      = 0;
   stream-&gt;out_buf         = NULL;
   stream-&gt;out_buf_size    = 0;
   stream-&gt;out_buf_ptr     = 0;
   stream-&gt;out_buf_occupancy = 0;

   /* Initialise stream */
   if (!rzipstream_init_stream(
         stream, path,
         (mode == RETRO_VFS_FILE_ACCESS_WRITE)))
   {
      rzipstream_free_stream(stream);
      return NULL;
   }

   return stream;
}

/* File Read */

/* Reads and decompresses the next chunk of data
 * in the RZIP file */
static bool rzipstream_read_chunk(rzipstream_t *stream)
{
   unsigned i;
   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];
   uint32_t compressed_chunk_size;
   uint32_t inflate_read;
   uint32_t inflate_written;

   if (!stream || !stream-&gt;inflate_backend || !stream-&gt;inflate_stream)
      return false;

   for (i = 0; i &lt; RZIP_CHUNK_HEADER_SIZE; i++)
      chunk_header_bytes[i] = 0;

   /* Attempt to read chunk header bytes */
   if (filestream_read(
         stream-&gt;file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=
         RZIP_CHUNK_HEADER_SIZE)
      return false;

   /* Get size of next compressed chunk */
   compressed_chunk_size = ( (uint32_t)chunk_header_bytes[3]  &lt;&lt; 24)
                           | ((uint32_t)chunk_header_bytes[2] &lt;&lt; 16)
                           | ((uint32_t)chunk_header_bytes[1] &lt;&lt;  8)
                           | (uint32_t)chunk_header_bytes[0];
   if (compressed_chunk_size == 0)
      return false;

   /* Resize input buffer, if required */
   if (compressed_chunk_size &gt; stream-&gt;in_buf_size)
   {
      free(stream-&gt;in_buf);
      stream-&gt;in_buf      = NULL;

      stream-&gt;in_buf_size = compressed_chunk_size;
      stream-&gt;in_buf      = (uint8_t *)calloc(stream-&gt;in_buf_size, 1);
      if (!stream-&gt;in_buf)
         return false;

      /* Note: Uncompressed data size is fixed, and read
       * from the file header - we therefore don't attempt
       * to resize the output buffer (if it's too small, then
       * that's an error condition) */
   }

   /* Read compressed chunk from file */
   if (filestream_read(
         stream-&gt;file, stream-&gt;in_buf, compressed_chunk_size) !=
         compressed_chunk_size)
      return false;

   /* Decompress chunk data */
   stream-&gt;inflate_backend-&gt;set_in(
         stream-&gt;inflate_stream,
         stream-&gt;in_buf, compressed_chunk_size);

   stream-&gt;inflate_backend-&gt;set_out(
         stream-&gt;inflate_stream,
         stream-&gt;out_buf, stream-&gt;out_buf_size);

   /* Note: We have to set 'flush == true' here, otherwise we
    * can't guarantee that the entire chunk will be written
    * to the output buffer - this is inefficient, but not
    * much we can do... */
   if (!stream-&gt;inflate_backend-&gt;trans(
         stream-&gt;inflate_stream, true,
         &amp;inflate_read, &amp;inflate_written, NULL))
      return false;

   /* Error checking */
   if (inflate_read != compressed_chunk_size)
      return false;

   if (   (inflate_written == 0)
       || (inflate_written &gt; stream-&gt;out_buf_size))
      return false;

   /* Record current output buffer occupancy
    * and reset pointer */
   stream-&gt;out_buf_occupancy = inflate_written;
   stream-&gt;out_buf_ptr       = 0;

   return true;
}

/* Reads (a maximum of) 'len' bytes from an RZIP file.
 * Returns actual number of bytes read, or -1 in
 * the event of an error */
int64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len)
{
   int64_t _len      = len;
   uint8_t *data_ptr = (uint8_t *)data;
   int64_t data_read = 0;

   if (!stream || stream-&gt;is_writing || !data)
      return -1;

   /* If we are reading uncompressed data, simply
    * 'pass on' the direct file access request */
   if (!stream-&gt;is_compressed)
      return filestream_read(stream-&gt;file, data, len);

   /* Process input data */
   while (_len &gt; 0)
   {
      int64_t read_size = 0;

      /* Check whether we have reached the end
       * of the file */
      if (stream-&gt;virtual_ptr &gt;= stream-&gt;size)
         return data_read;

      /* If everything in the output buffer has already
       * been read, grab and extract the next chunk
       * from disk */
      if (stream-&gt;out_buf_ptr &gt;= stream-&gt;out_buf_occupancy)
         if (!rzipstream_read_chunk(stream))
            return -1;

      /* Get amount of data to 'read out' this loop
       * &gt; i.e. minimum of remaining output buffer
       *   occupancy and remaining 'read data' size */
      if ((read_size = stream-&gt;out_buf_occupancy - stream-&gt;out_buf_ptr) &gt;
            _len)
         read_size = _len;

      /* Copy as much cached data as possible into
       * the read buffer */
      memcpy(data_ptr, stream-&gt;out_buf + stream-&gt;out_buf_ptr, (size_t)read_size);

      /* Increment pointers and remaining length */
      stream-&gt;out_buf_ptr += read_size;
      data_ptr            += read_size;
      _len                -= read_size;

      stream-&gt;virtual_ptr += read_size;

      data_read           += read_size;
   }

   return data_read;
}

/* Reads next character from an RZIP file.
 * Returns character value, or EOF if no data
 * remains.
 * Note: Always returns EOF if file is open
 * for writing. */
int rzipstream_getc(rzipstream_t *stream)
{
   char c = 0;

   if (!stream || stream-&gt;is_writing)
      return EOF;

   /* Attempt to read a single character */
   if (rzipstream_read(stream, &amp;c, 1) == 1)
      return (int)(unsigned char)c;

   return EOF;
}

/* Reads one line from an RZIP file and stores it
 * in the character array pointed to by 's'.
 * It stops reading when either (len-1) characters
 * are read, the newline character is read, or the
 * end-of-file is reached, whichever comes first.
 * On success, returns 's'. In the event of an error,
 * or if end-of-file is reached and no characters
 * have been read, returns NULL. */
char* rzipstream_gets(rzipstream_t *stream, char *s, size_t len)
{
   size_t str_len;
   int c         = 0;
   char *str_ptr = s;

   if (!stream || stream-&gt;is_writing || (len == 0))
      return NULL;

   /* Read bytes until newline or EOF is reached,
    * or string buffer is full */
   for (str_len = (len - 1); str_len &gt; 0; str_len--)
   {
      /* Get next character */
      c = rzipstream_getc(stream);

      /* Check for newline and EOF */
      if (c == EOF)
         break;

      /* Copy character to string buffer */
      *str_ptr++ = c;

      /* Check for newline and EOF */
      if (c == '\n')
          break;
   }

   /* Add NUL termination */
   *str_ptr = '\0';

   /* Check whether EOF has been reached without
    * reading any characters */
   if ((str_ptr == s) &amp;&amp; (c == EOF))
      return NULL;

   return (s);
}

/* Reads all data from file specified by 'path' and
 * copies it to 'buf'.
 * - 'buf' will be allocated and must be free()'d manually.
 * - Allocated 'buf' size is equal to 'len'.
 * Returns false in the event of an error */
bool rzipstream_read_file(const char *path, void **s, int64_t *len)
{
   int64_t bytes_read       = 0;
   void *content_buf        = NULL;
   int64_t content_buf_size = 0;
   rzipstream_t *stream     = NULL;

   if (!s)
      return false;

   /* Attempt to open file */
   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_READ)))
   {
      *s = NULL;
      return false;
   }

   /* Get file size */
   if ((content_buf_size = rzipstream_get_size(stream)) &lt; 0)
      goto error;

   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
      goto error;

   /* Allocate buffer */
   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
      goto error;

   /* Read file contents */
   if ((bytes_read = rzipstream_read(stream, content_buf, content_buf_size)) &lt;
         0)
      goto error;

   /* Close file */
   rzipstream_close(stream);
   stream = NULL;

   /* Add NUL termination for easy/safe handling of strings.
    * Will only work with sane character formatting (Unix). */
   ((char*)content_buf)[bytes_read] = '\0';

   /* Assign buffer */
   *s = content_buf;

   /* Assign length value, if required */
   if (len)
      *len = bytes_read;

   return true;

error:
   if (stream)
      rzipstream_close(stream);
   stream = NULL;

   if (content_buf)
      free(content_buf);
   content_buf = NULL;

   if (len)
      *len = -1;

   *s = NULL;

   return false;
}

/* File Write */

/* Compresses currently cached data and writes it
 * as the next RZIP file chunk */
static bool rzipstream_write_chunk(rzipstream_t *stream)
{
   unsigned i;
   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];
   uint32_t deflate_read;
   uint32_t deflate_written;

   if (!stream || !stream-&gt;deflate_backend || !stream-&gt;deflate_stream)
      return false;

   for (i = 0; i &lt; RZIP_CHUNK_HEADER_SIZE; i++)
      chunk_header_bytes[i] = 0;

   /* Compress data currently held in input buffer */
   stream-&gt;deflate_backend-&gt;set_in(
         stream-&gt;deflate_stream,
         stream-&gt;in_buf, stream-&gt;in_buf_ptr);

   stream-&gt;deflate_backend-&gt;set_out(
         stream-&gt;deflate_stream,
         stream-&gt;out_buf, stream-&gt;out_buf_size);

   /* Note: We have to set 'flush == true' here, otherwise we
    * can't guarantee that the entire chunk will be written
    * to the output buffer - this is inefficient, but not
    * much we can do... */
   if (!stream-&gt;deflate_backend-&gt;trans(
         stream-&gt;deflate_stream, true,
         &amp;deflate_read, &amp;deflate_written, NULL))
      return false;

   /* Error checking */
   if (deflate_read != stream-&gt;in_buf_ptr)
      return false;

   if (   (deflate_written == 0)
       || (deflate_written &gt; stream-&gt;out_buf_size))
      return false;

   /* Write compressed chunk size to file */
   chunk_header_bytes[3] = (deflate_written &gt;&gt; 24) &amp; 0xFF;
   chunk_header_bytes[2] = (deflate_written &gt;&gt; 16) &amp; 0xFF;
   chunk_header_bytes[1] = (deflate_written &gt;&gt;  8) &amp; 0xFF;
   chunk_header_bytes[0] =  deflate_written        &amp; 0xFF;

   if (filestream_write(
         stream-&gt;file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=
         RZIP_CHUNK_HEADER_SIZE)
      return false;

   /* Write compressed data to file */
   if (filestream_write(
         stream-&gt;file, stream-&gt;out_buf, deflate_written) != deflate_written)
      return false;

   /* Reset input buffer pointer */
   stream-&gt;in_buf_ptr = 0;

   return true;
}

/* Writes 'len' bytes to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len)
{
   int64_t _len = len;
   const uint8_t *data_ptr = (const uint8_t *)data;

   if (!stream || !stream-&gt;is_writing || !data)
      return -1;

   /* Process input data */
   while (_len &gt; 0)
   {
      int64_t cache_size = 0;

      /* If input buffer is full, compress and write to disk */
      if (stream-&gt;in_buf_ptr &gt;= stream-&gt;in_buf_size)
         if (!rzipstream_write_chunk(stream))
            return -1;

      /* Get amount of data to cache during this loop
       * &gt; i.e. minimum of space remaining in input buffer
       *   and remaining 'write data' size */
      if ((cache_size = stream-&gt;in_buf_size - stream-&gt;in_buf_ptr) &gt; _len)
         cache_size = _len;

      /* Copy as much data as possible into
       * the input buffer */
      memcpy(stream-&gt;in_buf + stream-&gt;in_buf_ptr, data_ptr, (size_t)cache_size);

      /* Increment pointers and remaining length */
      stream-&gt;in_buf_ptr  += cache_size;
      data_ptr            += cache_size;
      _len                -= cache_size;

      stream-&gt;size        += cache_size;
      stream-&gt;virtual_ptr += cache_size;
   }

   /* We always write the specified number of bytes
    * (unless rzipstream_write_chunk() fails, in
    * which we register a complete failure...) */
   return len;
}

/* Writes a single character to an RZIP file.
 * Returns character written, or EOF in the event
 * of an error */
int rzipstream_putc(rzipstream_t *stream, int c)
{
   char c_char = (char)c;
   if (   stream &amp;&amp; stream-&gt;is_writing
         &amp;&amp; (rzipstream_write(stream, &amp;c_char, 1) == 1))
      return (int)(unsigned char)c;
   return EOF;
}

/* Writes a variable argument list to an RZIP file.
 * Ugly 'internal' function, required to enable
 * 'printf' support in the higher level 'interface_stream'.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args)
{
   static char buffer[8 * 1024] = {0};
   int _len = vsnprintf(buffer,
         sizeof(buffer), format, args);
   if (_len &lt; 0)
      return -1;
   else if (_len == 0)
      return 0;
   return (int)rzipstream_write(stream, buffer, _len);
}

/* Writes formatted output to an RZIP file.
 * Returns actual number of bytes written, or -1
 * in the event of an error */
int rzipstream_printf(rzipstream_t *stream, const char* format, ...)
{
   va_list vl;
   int ret = 0;

   /* Initialise variable argument list */
   va_start(vl, format);

   /* Write variable argument list to file */
   ret = rzipstream_vprintf(stream, format, vl);

   /* End using variable argument list */
   va_end(vl);

   return ret;
}

/* Writes contents of 'data' buffer to file
 * specified by 'path'.
 * Returns false in the event of an error */
bool rzipstream_write_file(const char *path, const void *data, int64_t len)
{
   int64_t bytes_written = 0;
   rzipstream_t *stream  = NULL;

   if (!data)
      return false;

   /* Attempt to open file */
   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_WRITE)))
      return false;

   /* Write contents of data buffer to file */
   bytes_written = rzipstream_write(stream, data, len);

   /* Close file */
   if (rzipstream_close(stream) == -1)
      return false;

   /* Check that the correct number of bytes
    * were written */
   return (bytes_written == len);
}

/* File Control */

/* Sets file position to the beginning of the
 * specified RZIP file.
 * Note: It is not recommended to rewind a file
 * that is open for writing, since the caller
 * may end up with a file containing junk data
 * at the end (harmless, but a waste of space). */
void rzipstream_rewind(rzipstream_t *stream)
{
   if (!stream)
      return;

   /* Note: rzipstream_rewind() has no way of
    * reporting errors (higher level interface
    * requires a void return type) - so if anything
    * goes wrong, all we can do is print to stderr
    * and bail out... */

   /* If we are handling uncompressed data, simply
    * 'pass on' the direct file access request */
   if (!stream-&gt;is_compressed)
   {
      filestream_rewind(stream-&gt;file);
      return;
   }

   /* If no file access has yet occurred, file is
    * already at the beginning -&gt; do nothing */
   if (stream-&gt;virtual_ptr == 0)
      return;

   /* Check whether we are reading or writing */
   if (stream-&gt;is_writing)
   {
      /* Reset file position to first chunk location */
      filestream_seek(stream-&gt;file, RZIP_HEADER_SIZE, SEEK_SET);
      if (filestream_error(stream-&gt;file))
         return;

      /* Reset pointers */
      stream-&gt;virtual_ptr = 0;
      stream-&gt;in_buf_ptr  = 0;

      /* Reset file size */
      stream-&gt;size        = 0;
   }
   else
   {
      /* Check whether first file chunk is currently
       * buffered in memory */
      if ((stream-&gt;virtual_ptr &lt; stream-&gt;chunk_size) &amp;&amp;
          (stream-&gt;out_buf_ptr &lt; stream-&gt;out_buf_occupancy))
      {
         /* It is: No file access is therefore required
          * &gt; Just reset pointers */
         stream-&gt;virtual_ptr = 0;
         stream-&gt;out_buf_ptr = 0;
      }
      else
      {
         /* It isn't: Have to re-read the first chunk
          * from disk... */

         /* Reset file position to first chunk location */
         filestream_seek(stream-&gt;file, RZIP_HEADER_SIZE, SEEK_SET);
         if (filestream_error(stream-&gt;file))
            return;

         /* Read chunk */
         if (!rzipstream_read_chunk(stream))
            return;

         /* Reset pointers */
         stream-&gt;virtual_ptr = 0;
         stream-&gt;out_buf_ptr = 0;
      }
   }
}

/* File Status */

/* Returns total size (in bytes) of the *uncompressed*
 * data in an RZIP file.
 * (If reading an uncompressed file, this corresponds
 * to the 'physical' file size in bytes)
 * Returns -1 in the event of a error. */
int64_t rzipstream_get_size(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   if (stream-&gt;is_compressed)
      return stream-&gt;size;
   return filestream_get_size(stream-&gt;file);
}

/* Returns EOF when no further *uncompressed* data
 * can be read from an RZIP file. */
int rzipstream_eof(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   if (stream-&gt;is_compressed)
      return (stream-&gt;virtual_ptr &gt;= stream-&gt;size) ?
            EOF : 0;
   return filestream_eof(stream-&gt;file);
}

/* Returns the offset of the current byte of *uncompressed*
 * data relative to the beginning of an RZIP file.
 * Returns -1 in the event of a error. */
int64_t rzipstream_tell(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   if (stream-&gt;is_compressed)
      return (int64_t)stream-&gt;virtual_ptr;
   return filestream_tell(stream-&gt;file);
}

/* Returns true if specified RZIP file contains
 * compressed content */
bool rzipstream_is_compressed(rzipstream_t *stream)
{
   return stream &amp;&amp; stream-&gt;is_compressed;
}

/* File Close */

/* Closes RZIP file. If file is open for writing,
 * flushes any remaining buffered data to disk.
 * Returns -1 in the event of a error. */
int rzipstream_close(rzipstream_t *stream)
{
   if (!stream)
      return -1;

   /* If we are writing, ensure that any
    * remaining uncompressed data is flushed to
    * disk and update file header */
   if (stream-&gt;is_writing)
   {
      if (    ((stream-&gt;in_buf_ptr &gt; 0)
            &amp;&amp; !rzipstream_write_chunk(stream))
            || !rzipstream_write_file_header(stream))
      {
         /* Stream must be free()'d regardless */
         rzipstream_free_stream(stream);
         return -1;
      }
   }

   /* Free stream
    * &gt; This also closes the file */
   return rzipstream_free_stream(stream);
}</pre>
<h2>./include/libretro-common/streams/stdin_stream.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdin_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stddef.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;

#ifdef _WIN32
#ifndef _XBOX
#include &lt;windows.h&gt;
#endif
#include &lt;direct.h&gt;
#else
#include &lt;unistd.h&gt;
#endif

#include &lt;boolean.h&gt;
#include &lt;retro_environment.h&gt;
#include &lt;streams/stdin_stream.h&gt;

#if (defined(_WIN32) &amp;&amp; defined(_XBOX)) || defined(__WINRT__) || !defined(__PSL1GHT__) &amp;&amp; defined(__PS3__)
size_t read_stdin(char *s, size_t len) { return 0; } /* not implemented */
#elif defined(_WIN32)
size_t read_stdin(char *s, size_t len)
{
   DWORD i;
   DWORD has_read = 0;
   DWORD avail    = 0;
   bool echo      = false;
   HANDLE hnd     = GetStdHandle(STD_INPUT_HANDLE);

   if (hnd == INVALID_HANDLE_VALUE)
      return 0;

   /* Check first if we're a pipe
    * (not console). */

   /* If not a pipe, check if we're running in a console. */
   if (!PeekNamedPipe(hnd, NULL, 0, NULL, &amp;avail, NULL))
   {
      INPUT_RECORD recs[256];
      bool has_key   = false;
      DWORD mode     = 0;
      DWORD has_read = 0;

      if (!GetConsoleMode(hnd, &amp;mode))
         return 0;

      if ((mode &amp; (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))
            &amp;&amp; !SetConsoleMode(hnd,
               mode &amp; ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)))
         return 0;

      /* Win32, Y U NO SANE NONBLOCK READ!? */
      if (!PeekConsoleInput(hnd, recs,
               sizeof(recs) / sizeof(recs[0]), &amp;has_read))
         return 0;

      for (i = 0; i &lt; has_read; i++)
      {
         /* Very crude, but should get the job done. */
         if (recs[i].EventType == KEY_EVENT &amp;&amp;
               recs[i].Event.KeyEvent.bKeyDown &amp;&amp;
               (isgraph(recs[i].Event.KeyEvent.wVirtualKeyCode) ||
                recs[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN))
         {
            has_key = true;
            echo    = true;
            avail   = len;
            break;
         }
      }

      if (!has_key)
      {
         FlushConsoleInputBuffer(hnd);
         return 0;
      }
   }

   if (!avail)
      return 0;

   if (avail &gt; len)
      avail = len;

   if (!ReadFile(hnd, s, avail, &amp;has_read, NULL))
      return 0;

   for (i = 0; i &lt; has_read; i++)
      if (s[i] == '\r')
         s[i] = '\n';

   /* Console won't echo for us while in non-line mode,
    * so do it manually ... */
   if (echo)
   {
      HANDLE hnd_out = GetStdHandle(STD_OUTPUT_HANDLE);
      if (hnd_out != INVALID_HANDLE_VALUE)
      {
         DWORD has_written;
         WriteConsole(hnd_out, s, has_read, &amp;has_written, NULL);
      }
   }
   return has_read;
}
#else
size_t read_stdin(char *s, size_t len)
{
   size_t has_read = 0;
   while (len)
   {
      ssize_t ret = read(STDIN_FILENO, s, len);
      if (ret &lt;= 0)
         break;
      s        += ret;
      has_read += ret;
      len      -= ret;
   }
   return has_read;
}
#endif</pre>
<h2>./include/libretro-common/streams/trans_stream.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;streams/trans_stream.h&gt;

/**
 * trans_stream_trans_full:
 * @data                        : (optional) existing stream data, or a target
 *                                for the new stream data to be saved
 * @in                          : input data
 * @in_size                     : input size
 * @s                           : output data
 * @len                         : output size
 * @err                         : (optional) output for error code
 *
 * Perform a full transcoding from a source to a destination.
 */
bool trans_stream_trans_full(
    struct trans_stream_backend *backend, void **data,
    const uint8_t *in, uint32_t in_size,
    uint8_t *s, uint32_t len,
    enum trans_stream_error *err)
{
   void *rdata;
   bool ret;
   uint32_t rd, wn;

   if (data &amp;&amp; *data)
      rdata = *data;
   else
   {
      if (!(rdata = backend-&gt;stream_new()))
      {
         if (err)
            *err = TRANS_STREAM_ERROR_ALLOCATION_FAILURE;
         return false;
      }
   }

   backend-&gt;set_in(rdata, in, in_size);
   backend-&gt;set_out(rdata, s, len);
   ret = backend-&gt;trans(rdata, true, &amp;rd, &amp;wn, err);

   if (data)
      *data = rdata;
   else
      backend-&gt;stream_free(rdata);

   return ret;
}

const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void)
{
#if HAVE_ZLIB
   return &amp;zlib_deflate_backend;
#else
   return NULL;
#endif
}

const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void)
{
#if HAVE_ZLIB
   return &amp;zlib_inflate_backend;
#else
   return NULL;
#endif
}

const struct trans_stream_backend* trans_stream_get_pipe_backend(void)
{
   return &amp;pipe_backend;
}</pre>
<h2>./include/libretro-common/streams/trans_stream_pipe.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream_pipe.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;streams/trans_stream.h&gt;

struct pipe_trans_stream
{
   const uint8_t *in;
   uint8_t *out;
   uint32_t in_size, out_size;
};

static void *pipe_stream_new(void)
{
   struct pipe_trans_stream *stream =
      (struct pipe_trans_stream*)malloc(sizeof(*stream));
   if (!stream)
      return NULL;

   stream-&gt;in                       = NULL;
   stream-&gt;out                      = NULL;
   stream-&gt;in_size                  = 0;
   stream-&gt;out_size                 = 0;

   return stream;
}

static void pipe_stream_free(void *data)
{
   free(data);
}

static void pipe_set_in(void *data, const uint8_t *in, uint32_t in_size)
{
   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;

   if (!p)
      return;

   p-&gt;in                       = in;
   p-&gt;in_size                  = in_size;
}

static void pipe_set_out(void *data, uint8_t *out, uint32_t out_size)
{
   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;

   if (!p)
      return;

   p-&gt;out                      = out;
   p-&gt;out_size                 = out_size;
}

static bool pipe_trans(void *data, bool flush,
   uint32_t *rd, uint32_t *wn, enum trans_stream_error *err)
{
   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;

   if (p-&gt;out_size &lt; p-&gt;in_size)
   {
      memcpy(p-&gt;out, p-&gt;in, p-&gt;out_size);
      *rd     = *wn = p-&gt;out_size;
      p-&gt;in  += p-&gt;out_size;
      p-&gt;out += p-&gt;out_size;
      *err    = TRANS_STREAM_ERROR_BUFFER_FULL;
      return false;
   }

   memcpy(p-&gt;out, p-&gt;in, p-&gt;in_size);
   *rd     = *wn = p-&gt;in_size;
   p-&gt;in  += p-&gt;in_size;
   p-&gt;out += p-&gt;in_size;
   *err    = TRANS_STREAM_ERROR_NONE;
   return true;
}

const struct trans_stream_backend pipe_backend = {
   "pipe",
   &amp;pipe_backend,
   pipe_stream_new,
   pipe_stream_free,
   NULL,
   pipe_set_in,
   pipe_set_out,
   pipe_trans
};</pre>
<h2>./include/libretro-common/streams/trans_stream_zlib.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (trans_stream_zlib.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#include &lt;zlib.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;streams/trans_stream.h&gt;

struct zlib_trans_stream
{
   z_stream z;
   int window_bits;
   int level;
   bool inited;
};

static void *zlib_deflate_stream_new(void)
{
   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
      malloc(sizeof(*ret));
   if (!ret)
      return NULL;
   ret-&gt;inited      = false;
   ret-&gt;level       = 9;
   ret-&gt;window_bits = 15;

   ret-&gt;z.next_in   = NULL;
   ret-&gt;z.avail_in  = 0;
   ret-&gt;z.total_in  = 0;
   ret-&gt;z.next_out  = NULL;
   ret-&gt;z.avail_out = 0;
   ret-&gt;z.total_out = 0;

   ret-&gt;z.msg       = NULL;
   ret-&gt;z.state     = NULL;

   ret-&gt;z.zalloc    = NULL;
   ret-&gt;z.zfree     = NULL;
   ret-&gt;z.opaque    = NULL;

   ret-&gt;z.data_type = 0;
   ret-&gt;z.adler     = 0;
   ret-&gt;z.reserved  = 0;
   return (void *)ret;
}

static void *zlib_inflate_stream_new(void)
{
   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
      malloc(sizeof(*ret));
   if (!ret)
      return NULL;
   ret-&gt;inited      = false;
   ret-&gt;window_bits = MAX_WBITS;

   ret-&gt;z.next_in   = NULL;
   ret-&gt;z.avail_in  = 0;
   ret-&gt;z.total_in  = 0;
   ret-&gt;z.next_out  = NULL;
   ret-&gt;z.avail_out = 0;
   ret-&gt;z.total_out = 0;

   ret-&gt;z.msg       = NULL;
   ret-&gt;z.state     = NULL;

   ret-&gt;z.zalloc    = NULL;
   ret-&gt;z.zfree     = NULL;
   ret-&gt;z.opaque    = NULL;

   ret-&gt;z.data_type = 0;
   ret-&gt;z.adler     = 0;
   ret-&gt;z.reserved  = 0;
   return (void *)ret;
}

static void zlib_deflate_stream_free(void *data)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
   if (!z)
      return;
   if (z-&gt;inited)
      deflateEnd(&amp;z-&gt;z);
   free(z);
}

static void zlib_inflate_stream_free(void *data)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
   if (!z)
      return;
   if (z-&gt;inited)
      inflateEnd(&amp;z-&gt;z);
   if (z)
      free(z);
}

static bool zlib_deflate_define(void *data, const char *prop, uint32_t val)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream*)data;
   if (!data)
      return false;

   if (string_is_equal(prop, "level"))
      z-&gt;level = (int) val;
   else if (string_is_equal(prop, "window_bits"))
      z-&gt;window_bits = (int) val;
   else
      return false;

   return true;
}

static bool zlib_inflate_define(void *data, const char *prop, uint32_t val)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream*)data;
   if (!data)
      return false;

   if (string_is_equal(prop, "window_bits"))
   {
      z-&gt;window_bits = (int) val;
      return true;
   }
   return false;
}

static void zlib_deflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;

   if (!z)
      return;

   z-&gt;z.next_in                = (uint8_t *) in;
   z-&gt;z.avail_in               = in_size;

   if (!z-&gt;inited)
   {
      deflateInit2(&amp;z-&gt;z, z-&gt;level, Z_DEFLATED , z-&gt;window_bits, 8,  Z_DEFAULT_STRATEGY );
      z-&gt;inited = true;
   }
}

static void zlib_inflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;

   if (!z)
      return;

   z-&gt;z.next_in                = (uint8_t *) in;
   z-&gt;z.avail_in               = in_size;
   if (!z-&gt;inited)
   {
      inflateInit2(&amp;z-&gt;z, z-&gt;window_bits);
      z-&gt;inited = true;
   }
}

static void zlib_set_out(void *data, uint8_t *out, uint32_t out_size)
{
   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;

   if (!z)
      return;

   z-&gt;z.next_out               = out;
   z-&gt;z.avail_out              = out_size;
}

static bool zlib_deflate_trans(
   void *data, bool flush,
   uint32_t *rd, uint32_t *wn,
   enum trans_stream_error *err)
{
   int zret                     = 0;
   bool ret                     = false;
   uint32_t pre_avail_in        = 0;
   uint32_t pre_avail_out       = 0;
   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
   z_stream                  *z = &amp;zt-&gt;z;

   if (!zt-&gt;inited)
   {
      deflateInit2(z, zt-&gt;level, Z_DEFLATED , zt-&gt;window_bits, 8,  Z_DEFAULT_STRATEGY );
      zt-&gt;inited = true;
   }

   pre_avail_in  = z-&gt;avail_in;
   pre_avail_out = z-&gt;avail_out;
   zret          = deflate(z, flush ? Z_FINISH : Z_NO_FLUSH);

   if (zret == Z_OK)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_AGAIN;
   }
   else if (zret == Z_STREAM_END)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_NONE;
   }
   else
   {
      if (err)
         *err = TRANS_STREAM_ERROR_OTHER;
      return false;
   }
   ret = true;

   if (z-&gt;avail_out == 0)
   {
      /* Filled buffer, maybe an error */
      if (z-&gt;avail_in != 0)
      {
         ret = false;
         if (err)
            *err = TRANS_STREAM_ERROR_BUFFER_FULL;
      }
   }

   *rd = pre_avail_in - z-&gt;avail_in;
   *wn = pre_avail_out - z-&gt;avail_out;

   if (flush &amp;&amp; zret == Z_STREAM_END)
   {
      deflateEnd(z);
      zt-&gt;inited = false;
   }

   return ret;
}

static bool zlib_inflate_trans(
   void *data, bool flush,
   uint32_t *rd, uint32_t *wn,
   enum trans_stream_error *err)
{
   int zret;
   bool ret                     = false;
   uint32_t pre_avail_in        = 0;
   uint32_t pre_avail_out       = 0;
   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
   z_stream                  *z = &amp;zt-&gt;z;

   if (!zt-&gt;inited)
   {
      inflateInit2(z, zt-&gt;window_bits);
      zt-&gt;inited = true;
   }

   pre_avail_in  = z-&gt;avail_in;
   pre_avail_out = z-&gt;avail_out;
   zret          = inflate(z, flush ? Z_FINISH : Z_NO_FLUSH);

   if (zret == Z_OK)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_AGAIN;
   }
   else if (zret == Z_STREAM_END)
   {
      if (err)
         *err = TRANS_STREAM_ERROR_NONE;
   }
   else
   {
      if (err)
         *err = TRANS_STREAM_ERROR_OTHER;
      return false;
   }
   ret = true;

   if (z-&gt;avail_out == 0)
   {
      /* Filled buffer, maybe an error */
      if (z-&gt;avail_in != 0)
      {
         ret = false;
         if (err)
            *err = TRANS_STREAM_ERROR_BUFFER_FULL;
      }
   }

   *rd = pre_avail_in - z-&gt;avail_in;
   *wn = pre_avail_out - z-&gt;avail_out;

   if (flush &amp;&amp; zret == Z_STREAM_END)
   {
      inflateEnd(z);
      zt-&gt;inited = false;
   }

   return ret;
}

const struct trans_stream_backend zlib_deflate_backend = {
   "zlib_deflate",
   &amp;zlib_inflate_backend,
   zlib_deflate_stream_new,
   zlib_deflate_stream_free,
   zlib_deflate_define,
   zlib_deflate_set_in,
   zlib_set_out,
   zlib_deflate_trans
};

const struct trans_stream_backend zlib_inflate_backend = {
   "zlib_inflate",
   &amp;zlib_deflate_backend,
   zlib_inflate_stream_new,
   zlib_inflate_stream_free,
   zlib_inflate_define,
   zlib_inflate_set_in,
   zlib_set_out,
   zlib_inflate_trans
};</pre>
<h2>./include/libretro-common/string/stdstring.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;stdint.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;

#include &lt;compat/strl.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;encodings/utf.h&gt;

const uint8_t lr_char_props[256] = {
	/*x0   x1   x2   x3   x4   x5   x6   x7   x8   x9   xA   xB   xC   xD   xE   xF */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x                  */
	0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x  !"#$%&amp;'()*+,-./ */
	0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;&lt;=&gt;? */
	0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
	0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
	0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
	0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex                  */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx                  */
};

char *string_to_upper(char *s)
{
   char *cs = (char *)s;
   for ( ; *cs != '\0'; cs++)
      *cs = toupper((unsigned char)*cs);
   return s;
}

char *string_to_lower(char *s)
{
   char *cs = (char *)s;
   for ( ; *cs != '\0'; cs++)
      *cs = tolower((unsigned char)*cs);
   return s;
}

char *string_ucwords(char *s)
{
   char *cs = (char *)s;
   for ( ; *cs != '\0'; cs++)
   {
      if (*cs == ' ')
         *(cs+1) = toupper((unsigned char)*(cs+1));
   }

   s[0] = toupper((unsigned char)s[0]);
   return s;
}

char *string_replace_substring(
      const char *in,          size_t in_len,
      const char *pattern,     size_t pattern_len,
      const char *replacement, size_t replacement_len)
{
   size_t outlen;
   size_t numhits     = 0;
   const char *inat   = NULL;
   const char *inprev = NULL;
   char          *out = NULL;
   char        *outat = NULL;

   /* if either pattern or replacement is NULL,
    * duplicate in and let caller handle it. */
   if (!pattern || !replacement)
      return strdup(in);

   inat            = in;

   while ((inat = strstr(inat, pattern)))
   {
      inat += pattern_len;
      numhits++;
   }

   outlen = in_len - pattern_len * numhits + replacement_len*numhits;

   if (!(out = (char *)malloc(outlen+1)))
      return NULL;

   outat           = out;
   inat            = in;
   inprev          = in;

   while ((inat = strstr(inat, pattern)))
   {
      memcpy(outat, inprev, inat-inprev);
      outat += inat-inprev;
      memcpy(outat, replacement, replacement_len);
      outat += replacement_len;
      inat  += pattern_len;
      inprev = inat;
   }
   strcpy(outat, inprev);

   return out;
}

/**
 * string_trim_whitespace_left:
 *
 * Remove leading whitespaces
 **/
char *string_trim_whitespace_left(char *const s)
{
   if (s &amp;&amp; *s)
   {
      size_t _len    = strlen(s);
      char *current  = s;

      while (*current &amp;&amp; ISSPACE((unsigned char)*current))
      {
         ++current;
         --_len;
      }

      if (s != current)
         memmove(s, current, _len + 1);
   }

   return s;
}

/**
 * string_trim_whitespace_right:
 *
 * Remove trailing whitespaces
 **/
char *string_trim_whitespace_right(char *const s)
{
   if (s &amp;&amp; *s)
   {
      size_t _len    = strlen(s);
      char  *current = s + _len - 1;

      while (current != s &amp;&amp; ISSPACE((unsigned char)*current))
      {
         --current;
         --_len;
      }

      current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
   }

   return s;
}

/**
 * string_trim_whitespace:
 *
 * Remove leading and trailing whitespaces
 **/
char *string_trim_whitespace(char *const s)
{
   string_trim_whitespace_right(s);  /* order matters */
   string_trim_whitespace_left(s);

   return s;
}

/**
 * word_wrap:
 * @s                  : pointer to destination buffer.
 * @len                : size of destination buffer.
 * @src                : pointer to input string.
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : not used, but is necessary to keep
 *                       compatibility with word_wrap_wideglyph().
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by @src to destination buffer
 * specified by @s and @len.
 * This function assumes that all glyphs in the string
 * have an on-screen pixel width similar to that of
 * regular Latin characters - i.e. it will not wrap
 * correctly any text containing so-called 'wide' Unicode
 * characters (e.g. CJK languages, emojis, etc.).
 **/
size_t word_wrap(
      char *s,         size_t len,
      const char *src, size_t src_len,
      int line_width,  int wideglyph_width, unsigned max_lines)
{
   char *last_space    = NULL;
   unsigned counter    = 0;
   unsigned lines      = 1;
   const char *src_end = src + src_len;

   /* Prevent buffer overflow */
   if (len &lt; src_len + 1)
      return 0;

   /* Early return if src string length is less
    * than line width */
   if (src_len &lt; (size_t)line_width)
      return strlcpy(s, src, len);

   while (*src != '\0')
   {
      unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
      counter++;

      if (*src == ' ')
         last_space = s; /* Remember the location of the whitespace */
      else if (*src == '\n')
      {
         /* If newlines embedded in the input,
          * reset the index */
         lines++;
         counter   = 0;

         /* Early return if remaining src string
          * length is less than line width */
         if (src_end - src &lt;= line_width)
            return strlcpy(s, src, len);
     }

      while (char_len--)
         *s++ = *src++;

      if (counter &gt;= (unsigned)line_width)
      {
         counter = 0;

         if (last_space &amp;&amp; (max_lines == 0 || lines &lt; max_lines))
         {
            /* Replace nearest (previous) whitespace
             * with newline character */
            *last_space = '\n';
            lines++;

            src        -= s - last_space - 1;
            s           = last_space + 1;
            last_space  = NULL;

            /* Early return if remaining src string
             * length is less than line width */
            if (src_end - src &lt; line_width)
               return strlcpy(s, src, len);
         }
      }
   }

   *s = '\0';
   return 0;
}

/**
 * word_wrap_wideglyph:
 * @dst                : pointer to destination buffer.
 * @len                : size of destination buffer.
 * @src                : pointer to input string.
 * @line_width         : max number of characters per line.
 * @wideglyph_width    : effective width of 'wide' Unicode glyphs.
 *                       the value here is normalised relative to the
 *                       typical on-screen pixel width of a regular
 *                       Latin character:
 *                       - a regular Latin character is defined to
 *                         have an effective width of 100
 *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
 *                       - e.g. if 'wide' Unicode characters in 'src'
 *                         have an on-screen pixel width twice that of
 *                         regular Latin characters, wideglyph_width
 *                         would be 200
 * @max_lines          : max lines of destination string.
 *                       0 means no limit.
 *
 * Wraps string specified by @src to destination buffer
 * specified by @dst and @len.
 * This function assumes that all glyphs in the string
 * are:
 * - EITHER 'non-wide' Unicode glyphs, with an on-screen
 *   pixel width similar to that of regular Latin characters
 * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
 *   with an on-screen pixel width defined by @wideglyph_width
 * Note that wrapping may occur in inappropriate locations
 * if @src string contains 'wide' Unicode characters whose
 * on-screen pixel width deviates greatly from the set
 * @wideglyph_width value.
 **/
size_t word_wrap_wideglyph(char *s, size_t len,
      const char *src, size_t src_len, int line_width,
      int wideglyph_width, unsigned max_lines)
{
   char *lastspace                   = NULL;
   char *lastwideglyph               = NULL;
   const char *src_end               = src + src_len;
   unsigned lines                    = 1;
   /* 'line_width' means max numbers of characters per line,
    * but this metric is only meaningful when dealing with
    * 'regular' glyphs that have an on-screen pixel width
    * similar to that of regular Latin characters.
    * When handing so-called 'wide' Unicode glyphs, it is
    * necessary to consider the actual on-screen pixel width
    * of each character.
    * In order to do this, we create a distinction between
    * regular Latin 'non-wide' glyphs and 'wide' glyphs, and
    * normalise all values relative to the on-screen pixel
    * width of regular Latin characters:
    * - Regular 'non-wide' glyphs have a normalised width of 100
    * - 'line_width' is therefore normalised to 100 * (width_in_characters)
    * - 'wide' glyphs have a normalised width of
    *   100 * (wide_character_pixel_width / latin_character_pixel_width)
    * - When a character is detected, the position in the current
    *   line is incremented by the regular normalised width of 100
    * - If that character is then determined to be a 'wide'
    *   glyph, the position in the current line is further incremented
    *   by the difference between the normalised 'wide' and 'non-wide'
    *   width values */
   unsigned counter_normalized       = 0;
   int line_width_normalized         = line_width * 100;
   int additional_counter_normalized = wideglyph_width - 100;

   /* Early return if src string length is less
    * than line width */
   if (src_end - src &lt; line_width)
      return strlcpy(s, src, len);

   while (*src != '\0')
   {
      unsigned char_len   = (unsigned)(utf8skip(src, 1) - src);
      counter_normalized += 100;

      /* Prevent buffer overflow */
      if (char_len &gt;= len)
         break;

      if (*src == ' ')
         lastspace          = s; /* Remember the location of the whitespace */
      else if (*src == '\n')
      {
         /* If newlines embedded in the input,
          * reset the index */
         lines++;
         counter_normalized = 0;

         /* Early return if remaining src string
          * length is less than line width */
         if (src_end - src &lt;= line_width)
            return strlcpy(s, src, len);
      }
      else if (char_len &gt;= 3)
      {
         /* Remember the location of the first byte
          * whose length as UTF-8 &gt;= 3*/
         lastwideglyph       = s;
         counter_normalized += additional_counter_normalized;
      }

      len -= char_len;
      while (char_len--)
         *s++ = *src++;

      if (counter_normalized &gt;= (unsigned)line_width_normalized)
      {
         counter_normalized = 0;

         if (max_lines != 0 &amp;&amp; lines &gt;= max_lines)
            continue;
         else if (lastwideglyph &amp;&amp; (!lastspace || lastwideglyph &gt; lastspace))
         {
            /* Insert newline character */
            *lastwideglyph = '\n';
            lines++;
            src           -= s - lastwideglyph;
            s              = lastwideglyph + 1;
            lastwideglyph  = NULL;

            /* Early return if remaining src string
             * length is less than line width */
            if (src_end - src &lt;= line_width)
               return strlcpy(s, src, len);
         }
         else if (lastspace)
         {
            /* Replace nearest (previous) whitespace
             * with newline character */
            *lastspace = '\n';
            lines++;
            src       -= s - lastspace - 1;
            s          = lastspace + 1;
            lastspace  = NULL;

            /* Early return if remaining src string
             * length is less than line width */
            if (src_end - src &lt; line_width)
               return strlcpy(s, src, len);
         }
      }
   }

   *s = '\0';
   return 0;
}

/**
 * string_tokenize:
 *
 * Splits string into tokens separated by @delim
 * &gt; Returned token string must be free()'d
 * &gt; Returns NULL if token is not found
 * &gt; After each call, @str is set to the position after the
 *   last found token
 * &gt; Tokens *include* empty strings
 * Usage example:
 *    char *str      = "1,2,3,4,5,6,7,,,10,";
 *    char **str_ptr = &amp;str;
 *    char *token    = NULL;
 *    while ((token = string_tokenize(str_ptr, ",")))
 *    {
 *        printf("%s\n", token);
 *        free(token);
 *        token = NULL;
 *    }
 **/
char* string_tokenize(char **str, const char *delim)
{
   /* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
   char *str_ptr    = NULL;
   char *delim_ptr  = NULL;
   char *token      = NULL;
   size_t token_len = 0;

   /* Sanity checks */
   if (!str || string_is_empty(delim))
      return NULL;

   /* Note: we don't check string_is_empty() here,
    * empty strings are valid */
   if (!(str_ptr = *str))
      return NULL;

   /* Search for delimiter */
   if ((delim_ptr = strstr(str_ptr, delim)))
      token_len = delim_ptr - str_ptr;
   else
      token_len = strlen(str_ptr);

   /* Allocate token string */
   if (!(token = (char *)malloc((token_len + 1) * sizeof(char))))
      return NULL;

   /* Copy token */
   strlcpy(token, str_ptr, (token_len + 1) * sizeof(char));
   token[token_len] = '\0';

   /* Update input string pointer */
   *str = delim_ptr ? delim_ptr + strlen(delim) : NULL;

   return token;
}

/**
 * string_remove_all_chars:
 * @s                 : input string (must be non-NULL, otherwise UB)
 *
 * Leaf function.
 *
 * Removes every instance of character @c from @s
 **/
void string_remove_all_chars(char *s, char c)
{
   char *read_ptr  = s;
   char *write_ptr = s;

   while (*read_ptr != '\0')
   {
      /* Only write if the character is not the one to remove */
      if (*read_ptr != c)
         *write_ptr++ = *read_ptr;
      read_ptr++;
   }

   *write_ptr = '\0';
}

/**
 * string_replace_all_chars:
 * @s                  : input string (must be non-NULL, otherwise UB)
 * @find               : character to find
 * @replace            : character to replace @find with
 *
 * Replaces every instance of character @find in @s
 * with character @replace
 **/
void string_replace_all_chars(char *s, char find, char replace)
{
   char *str_ptr = s;
   while ((str_ptr = strchr(str_ptr, find)))
      *str_ptr++ = replace;
}

/**
 * string_to_unsigned:
 * @str                : input string
 *
 * Converts string to unsigned integer.
 *
 * @return 0 if string is invalid, otherwise &gt; 0
 **/
unsigned string_to_unsigned(const char *str)
{
   const char *ptr = NULL;

   if (string_is_empty(str))
      return 0;

   for (ptr = str; *ptr != '\0'; ptr++)
   {
      if (!ISDIGIT((unsigned char)*ptr))
         return 0;
   }

   return (unsigned)strtoul(str, NULL, 10);
}

/**
 * string_hex_to_unsigned:
 * @str                : input string (must be non-NULL, otherwise UB)
 *
 * Converts hexadecimal string to unsigned integer.
 * Handles optional leading '0x'.
 *
 * @return 0 if string is invalid, otherwise &gt; 0
 **/
unsigned string_hex_to_unsigned(const char *str)
{
   const char *hex_str = str;
   const char *ptr     = NULL;

   /* Remove leading '0x', if required */
   if (str[0] != '\0' &amp;&amp; str[1] != '\0')
   {
      if (     (str[0] == '0')
           &amp;&amp; ((str[1] == 'x')
           ||  (str[1] == 'X')))
      {
         hex_str = str + 2;
         if (string_is_empty(hex_str))
            return 0;
      }
   }
   else
      return 0;

   /* Check for valid characters */
   for (ptr = hex_str; *ptr != '\0'; ptr++)
   {
      if (!isxdigit((unsigned char)*ptr))
         return 0;
   }

   return (unsigned)strtoul(hex_str, NULL, 16);
}

/**
 * string_count_occurrences_single_character:
 *
 * Leaf function.
 *
 * Get the total number of occurrences of character @c in @str.
 *
 * @return Total number of occurrences of character @c
 */
int string_count_occurrences_single_character(const char *str, char c)
{
   int count = 0;

   for (; *str; str++)
      if (*str == c)
         count++;

   return count;
}

/**
 * string_replace_whitespace_with_single_character:
 *
 * Leaf function.
 *
 * Replaces all spaces with given character @c.
 **/
void string_replace_whitespace_with_single_character(char *s, char c)
{
   for (; *s; s++)
      if (ISSPACE(*s))
         *s = c;
}

/**
 * string_replace_multi_space_with_single_space:
 *
 * Leaf function.
 *
 * Replaces multiple spaces with a single space in a string.
 **/
void string_replace_multi_space_with_single_space(char *s)
{
   char *str_trimmed  = s;
   bool prev_is_space = false;
   bool curr_is_space = false;

   for (; *s; s++)
   {
      curr_is_space  = ISSPACE(*s);
      if (prev_is_space &amp;&amp; curr_is_space)
         continue;
      *str_trimmed++ = *s;
      prev_is_space  = curr_is_space;
   }
   *str_trimmed = '\0';
}

/**
 * string_remove_all_whitespace:
 *
 * Leaf function.
 *
 * Remove all spaces from the given string.
 **/
void string_remove_all_whitespace(char *s, const char *str)
{
   for (; *str; str++)
      if (!ISSPACE(*str))
         *s++ = *str;
   *s = '\0';
}

/**
 * Retrieve the last occurance of the given character in a string.
 */
int string_index_last_occurance(const char *str, char c)
{
   const char *pos = strrchr(str, c);
   if (pos)
      return (int)(pos - str);
   return -1;
}

/**
 * string_find_index_substring_string:
 * @str                : input string (must be non-NULL, otherwise UB)
 * @substr             : substring to find in @str
 *
 * Find the position of substring @substr in string @str.
 **/
int string_find_index_substring_string(const char *str, const char *substr)
{
   const char *pos = strstr(str, substr);
   if (pos)
      return (int)(pos - str);
   return -1;
}

/**
 * string_copy_only_ascii:
 *
 * Leaf function.
 *
 * Strips non-ASCII characters from a string.
 **/
void string_copy_only_ascii(char *s, const char *str)
{
   for (; *str; str++)
      if (*str &gt; 0x1F &amp;&amp; *str &lt; 0x7F)
         *s++ = *str;
   *s = '\0';
}</pre>
<h2>./include/libretro-common/test/hash/test_hash.c</h2>
<pre>/* Copyright  (C) 2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;check.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

#include &lt;lrc_hash.h&gt;

#define SUITE_NAME "hash"

START_TEST (test_sha256)
{
   char output[65];
   sha256_hash(output, (uint8_t*)"abc", 3);
   ck_assert(!strcmp(output,
      "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"));
}
END_TEST

START_TEST (test_sha1)
{
   char output[41];
   char tmpfile[512];
   FILE *fd;
   tmpnam(tmpfile);
   fd = fopen(tmpfile, "wb");
   ck_assert(fd != NULL);
   fwrite("abc", 1, 3, fd);
   fclose(fd);
   sha1_calculate(tmpfile, output);

   ck_assert(!strcmp(output,
      "A9993E364706816ABA3E25717850C26C9CD0D89D"));
}
END_TEST

START_TEST (test_djb2)
{
   ck_assert_uint_eq(djb2_calculate("retroarch"), 0xFADF3BCF);
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_sha256);
   tcase_add_test(tc_core, test_sha1);
   tcase_add_test(tc_core, test_djb2);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}</pre>
<h2>./include/libretro-common/test/lists/test_linked_list.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_linked_list.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;check.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;lists/linked_list.h&gt;

#define SUITE_NAME "Linked List"

static char *_value_1 = "value1";
static char *_value_2 = "value2";
static char *_value_3 = "value3";

START_TEST (test_linked_list_create)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_nonnull(list);
   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_free)
{
   linked_list_t *queue = linked_list_new();
   linked_list_free(queue, NULL);
   linked_list_free(NULL, NULL);
}
END_TEST

static int _free_alloced_value_count;
static void _free_alloced_value(void *value)
{
   _free_alloced_value_count++;
   free(value);
}

START_TEST (test_linked_list_free_with_fn)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, malloc(1));
   linked_list_add(list, malloc(1));
   linked_list_add(list, malloc(1));

   _free_alloced_value_count = 0;
   linked_list_free(list, &amp;_free_alloced_value);

   ck_assert_int_eq(3, _free_alloced_value_count);
}
END_TEST

static void _verify_list(linked_list_t *list, int size, ...)
{
   va_list values_list;
   void **values;
   int i;
   linked_list_iterator_t *iterator;

   values = (void **)malloc(size * sizeof(void *));

   ck_assert_int_eq(linked_list_size(list), size);

   va_start(values_list, size);
   for (i = 0; i &lt; size; i++)
   {
      values[i] = va_arg(values_list, void *);
      ck_assert_ptr_eq(values[i], linked_list_get(list, i));
   }
   va_end(values_list);

   iterator = linked_list_iterator(list, true);
   for (i = 0; i &lt; size; i++)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));
      iterator = linked_list_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   iterator = linked_list_iterator(list, false);
   for (i = size - 1; i &gt;= 0; i--)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));
      iterator = linked_list_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   free(values);
}

START_TEST (test_linked_list_add)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_empty)
{
   linked_list_t *list = linked_list_new();
   linked_list_insert(list, 0, _value_1);

   ck_assert_int_eq(linked_list_size(list), 1);
   ck_assert_ptr_eq(linked_list_get(list, 0), _value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_insert(list, 0, _value_1);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);
   linked_list_insert(list, 1, _value_2);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_insert(list, 2, _value_3);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_invalid)
{
   linked_list_t *list = linked_list_new();
   linked_list_insert(list, 2, _value_1);

   ck_assert_int_eq(linked_list_size(list), 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_insert_null)
{
   linked_list_insert(NULL, 0, _value_1);
}
END_TEST

START_TEST (test_linked_list_get_invalid)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get(list, 2));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_null)
{
   ck_assert_ptr_null(linked_list_get(NULL, 0));
}
END_TEST

START_TEST (test_linked_list_get_first_matching_null)
{
   ck_assert_ptr_null(linked_list_get_first_matching(NULL, NULL, NULL));
}
END_TEST

START_TEST (test_linked_list_get_first_matching_function_null)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_first_matching(list, NULL, NULL));

   linked_list_free(list, NULL);
}

bool _matches_function(void *value, void *state)
{
   ck_assert_ptr_eq(_value_1, state);
   return value == _value_2;
}

START_TEST (test_linked_list_get_first_matching_no_match)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_first_matching(list, &amp;_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_first_matching_with_match)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(_value_2, linked_list_get_first_matching(list, &amp;_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_last_matching_null)
{
   ck_assert_ptr_null(linked_list_get_last_matching(NULL, NULL, NULL));
}
END_TEST

START_TEST (test_linked_list_get_last_matching_function_null)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_last_matching(list, NULL, NULL));

   linked_list_free(list, NULL);
}

START_TEST (test_linked_list_get_last_matching_no_match)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_get_last_matching(list, &amp;_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_get_last_matching_with_match)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(_value_2, linked_list_get_last_matching(list, &amp;_matches_function, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_null)
{
   ck_assert_ptr_null(linked_list_remove_at(NULL, 0));
}
END_TEST

START_TEST (test_linked_list_remove_at_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_at(list, 0));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_invalid)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 3);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 0);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 1);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_at(list, 2);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_at_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   linked_list_remove_at(list, 0);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_null)
{
   ck_assert_ptr_null(linked_list_remove_first(NULL, _value_1));
}
END_TEST

START_TEST (test_linked_list_remove_first_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_first(list, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_first(list, "foo"));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_2), _value_2);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_3), _value_3);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_null)
{
   ck_assert_ptr_null(linked_list_remove_last(NULL, _value_1));
}
END_TEST

START_TEST (test_linked_list_remove_last_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_last(list, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_last(list, "foo"));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_2), _value_2);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_3), _value_3);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_null)
{
   ck_assert_ptr_null(linked_list_remove_all(NULL, _value_1));
}
END_TEST

START_TEST (test_linked_list_remove_all_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_all(list, _value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_all(list, "foo"));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_2), _value_2);

   _verify_list(list, 2, _value_1, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_3), _value_3);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);

   _verify_list(list, 1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

bool _match_value_1(void *value)
{
   return _value_1 == value;
}

bool _no_match(void *value)
{
   return false;
}

START_TEST (test_linked_list_remove_first_matching_null)
{
   ck_assert_ptr_null(linked_list_remove_first_matching(NULL, &amp;_match_value_1));
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_first_matching(list, &amp;_match_value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_first_matching(list, &amp;_no_match));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_first_matching_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_null)
{
   ck_assert_ptr_null(linked_list_remove_last_matching(NULL, &amp;_match_value_1));
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_ptr_null(linked_list_remove_last_matching(list, &amp;_match_value_1));

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_null(linked_list_remove_last_matching(list, &amp;_no_match));

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_last_matching_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &amp;_match_value_1), _value_1);

   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_null)
{
   linked_list_remove_all_matching(NULL, &amp;_match_value_1);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_empty)
{
   linked_list_t *list = linked_list_new();
   linked_list_remove_all_matching(list, &amp;_match_value_1);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_not_found)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_all_matching(list, &amp;_no_match);

   _verify_list(list, 3, _value_1, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_remove_all_matching(list, &amp;_match_value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_3);

   linked_list_remove_all_matching(list, &amp;_match_value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);
   linked_list_add(list, _value_1);

   linked_list_remove_all_matching(list, &amp;_match_value_1);

   _verify_list(list, 2, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_only)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);

   linked_list_remove_all_matching(list, &amp;_match_value_1);

   _verify_list(list, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_remove_all_matching_multiple)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_1);

   linked_list_remove_all_matching(list, &amp;_match_value_1);

   _verify_list(list, 1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_null)
{
   ck_assert_int_eq(linked_list_set_at(NULL, 0, _value_1) == true, 0);
}
END_TEST

START_TEST (test_linked_list_set_at_empty)
{
   linked_list_t *list = linked_list_new();
   ck_assert_int_eq(linked_list_set_at(list, 0, _value_1) == true, 0);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_invalid)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   ck_assert_int_eq(linked_list_set_at(list, 1, _value_2) == true, 0);

   linked_list_free(list, NULL);
}
END_TEST

static char *_replacement_value = "foo";

START_TEST (test_linked_list_set_at_first)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_int_eq(linked_list_set_at(list, 0, _replacement_value) == false, 0);

   _verify_list(list, 3, _replacement_value, _value_2, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_middle)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_int_eq(linked_list_set_at(list, 1, _replacement_value) == false, 0);

   _verify_list(list, 3, _value_1, _replacement_value, _value_3);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_set_at_last)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   ck_assert_int_eq(linked_list_set_at(list, 2, _replacement_value) == false, 0);

   _verify_list(list, 3, _value_1, _value_2, _replacement_value);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_remove_null)
{
   ck_assert_ptr_null(linked_list_iterator_remove(NULL));
}
END_TEST

START_TEST (test_linked_list_iterator_remove_first)
{
   linked_list_t *list;
   linked_list_iterator_t *iterator;

   list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   iterator = linked_list_iterator(list, true);
   iterator = linked_list_iterator_remove(iterator);

   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_2);
   _verify_list(list, 2, _value_2, _value_3);

   linked_list_iterator_free(iterator);
   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_remove_middle)
{
   linked_list_t *list;
   linked_list_iterator_t *iterator;

   list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   iterator = linked_list_iterator(list, true);
   iterator = linked_list_iterator_next(iterator);
   iterator = linked_list_iterator_remove(iterator);

   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_3);
   _verify_list(list, 2, _value_1, _value_3);

   linked_list_iterator_free(iterator);
   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_remove_last)
{
   linked_list_t *list;
   linked_list_iterator_t *iterator;

   list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   iterator = linked_list_iterator(list, true);
   iterator = linked_list_iterator_next(iterator);
   iterator = linked_list_iterator_next(iterator);
   iterator = linked_list_iterator_remove(iterator);

   ck_assert_ptr_null(iterator);
   _verify_list(list, 2, _value_1, _value_2);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_iterator_free_null)
{
   linked_list_iterator_free(NULL);
}
END_TEST

static size_t _foreach_count;
static void _foreach_fn(size_t index, void *value)
{
   _foreach_count++;
}

START_TEST (test_linked_list_foreach_null_list)
{
   linked_list_foreach(NULL, _foreach_fn);
}
END_TEST

START_TEST (test_linked_list_foreach_null_fn)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   linked_list_foreach(list, NULL);

   linked_list_free(list, NULL);
}
END_TEST

START_TEST (test_linked_list_foreach_valid)
{
   linked_list_t *list = linked_list_new();
   linked_list_add(list, _value_1);
   linked_list_add(list, _value_2);
   linked_list_add(list, _value_3);

   _foreach_count = 0;
   linked_list_foreach(list, &amp;_foreach_fn);
   ck_assert_uint_eq(3, _foreach_count);

   linked_list_free(list, NULL);
}

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_linked_list_create);
   tcase_add_test(tc_core, test_linked_list_free);
   tcase_add_test(tc_core, test_linked_list_free_with_fn);
   tcase_add_test(tc_core, test_linked_list_add);
   tcase_add_test(tc_core, test_linked_list_insert_empty);
   tcase_add_test(tc_core, test_linked_list_insert_first);
   tcase_add_test(tc_core, test_linked_list_insert_middle);
   tcase_add_test(tc_core, test_linked_list_insert_last);
   tcase_add_test(tc_core, test_linked_list_insert_invalid);
   tcase_add_test(tc_core, test_linked_list_insert_null);
   tcase_add_test(tc_core, test_linked_list_get_invalid);
   tcase_add_test(tc_core, test_linked_list_get_null);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_null);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_function_null);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_no_match);
   tcase_add_test(tc_core, test_linked_list_get_first_matching_with_match);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_null);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_function_null);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_no_match);
   tcase_add_test(tc_core, test_linked_list_get_last_matching_with_match);
   tcase_add_test(tc_core, test_linked_list_remove_at_null);
   tcase_add_test(tc_core, test_linked_list_remove_at_empty);
   tcase_add_test(tc_core, test_linked_list_remove_at_invalid);
   tcase_add_test(tc_core, test_linked_list_remove_at_first);
   tcase_add_test(tc_core, test_linked_list_remove_at_middle);
   tcase_add_test(tc_core, test_linked_list_remove_at_last);
   tcase_add_test(tc_core, test_linked_list_remove_at_only);
   tcase_add_test(tc_core, test_linked_list_remove_first_null);
   tcase_add_test(tc_core, test_linked_list_remove_first_empty);
   tcase_add_test(tc_core, test_linked_list_remove_first_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_first_first);
   tcase_add_test(tc_core, test_linked_list_remove_first_middle);
   tcase_add_test(tc_core, test_linked_list_remove_first_last);
   tcase_add_test(tc_core, test_linked_list_remove_first_only);
   tcase_add_test(tc_core, test_linked_list_remove_first_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_last_null);
   tcase_add_test(tc_core, test_linked_list_remove_last_empty);
   tcase_add_test(tc_core, test_linked_list_remove_last_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_last_first);
   tcase_add_test(tc_core, test_linked_list_remove_last_middle);
   tcase_add_test(tc_core, test_linked_list_remove_last_last);
   tcase_add_test(tc_core, test_linked_list_remove_last_only);
   tcase_add_test(tc_core, test_linked_list_remove_last_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_all_null);
   tcase_add_test(tc_core, test_linked_list_remove_all_empty);
   tcase_add_test(tc_core, test_linked_list_remove_all_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_all_first);
   tcase_add_test(tc_core, test_linked_list_remove_all_middle);
   tcase_add_test(tc_core, test_linked_list_remove_all_last);
   tcase_add_test(tc_core, test_linked_list_remove_all_only);
   tcase_add_test(tc_core, test_linked_list_remove_all_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_null);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_empty);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_first);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_middle);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_last);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_only);
   tcase_add_test(tc_core, test_linked_list_remove_first_matching_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_null);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_empty);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_first);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_middle);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_last);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_only);
   tcase_add_test(tc_core, test_linked_list_remove_last_matching_multiple);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_null);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_empty);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_not_found);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_first);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_middle);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_last);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_only);
   tcase_add_test(tc_core, test_linked_list_remove_all_matching_multiple);
   tcase_add_test(tc_core, test_linked_list_set_at_null);
   tcase_add_test(tc_core, test_linked_list_set_at_empty);
   tcase_add_test(tc_core, test_linked_list_set_at_invalid);
   tcase_add_test(tc_core, test_linked_list_set_at_first);
   tcase_add_test(tc_core, test_linked_list_set_at_middle);
   tcase_add_test(tc_core, test_linked_list_set_at_last);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_null);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_first);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_middle);
   tcase_add_test(tc_core, test_linked_list_iterator_remove_last);
   tcase_add_test(tc_core, test_linked_list_iterator_free_null);
   tcase_add_test(tc_core, test_linked_list_foreach_null_list);
   tcase_add_test(tc_core, test_linked_list_foreach_null_fn);
   tcase_add_test(tc_core, test_linked_list_foreach_valid);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}</pre>
<h2>./include/libretro-common/test/queues/test_generic_queue.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_generic_queue.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include &lt;check.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stdlib.h&gt;

#include &lt;queues/generic_queue.h&gt;

#define SUITE_NAME "Generic Queue"

static char *_value_1 = "value1";
static char *_value_2 = "value2";
static char *_value_3 = "value3";

START_TEST (test_generic_queue_create)
{
   generic_queue_t *queue = generic_queue_new();
   ck_assert_ptr_nonnull(queue);
   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_free)
{
   generic_queue_t *queue = generic_queue_new();
   generic_queue_free(queue, NULL);
   generic_queue_free(NULL, NULL);
}
END_TEST

START_TEST (test_generic_queue_push_pop)
{
   generic_queue_t *queue;
   char *value;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_pop(queue);
   ck_assert_ptr_eq(value, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_push(queue, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   generic_queue_push(queue, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 2);
   value = (char *) generic_queue_pop(queue);
   ck_assert_ptr_eq(value, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_pop(queue);
   ck_assert_ptr_eq(value, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_peek)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   ck_assert_ptr_null(generic_queue_peek(queue));
   ck_assert_ptr_null(generic_queue_peek_first(queue));

   generic_queue_push(queue, _value_1);
   ck_assert_ptr_eq(_value_1, generic_queue_peek(queue));
   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));

   generic_queue_push(queue, _value_2);
   ck_assert_ptr_eq(_value_2, generic_queue_peek(queue));
   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));

   generic_queue_push(queue, _value_3);
   ck_assert_ptr_eq(_value_3, generic_queue_peek(queue));
   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));

   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_shift_unshift)
{
   generic_queue_t *queue;
   char *value;

   queue = generic_queue_new();
   generic_queue_shift(queue, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_unshift(queue);
   ck_assert_ptr_eq(value, _value_1);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_shift(queue, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   generic_queue_shift(queue, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 2);
   value = (char *) generic_queue_unshift(queue);
   ck_assert_ptr_eq(value, _value_3);
   ck_assert_int_eq(generic_queue_length(queue), 1);
   value = (char *) generic_queue_unshift(queue);
   ck_assert_ptr_eq(value, _value_2);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_free(queue, NULL);
}
END_TEST

START_TEST (test_generic_queue_empty)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   ck_assert_ptr_null(generic_queue_pop(queue));
   ck_assert_ptr_null(generic_queue_unshift(queue));
   generic_queue_free(queue, NULL);
}
END_TEST

void _free_value(void *value)
{
   return;
}

START_TEST (test_generic_queue_iterator)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, true);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_null(iterator);

   iterator = generic_queue_iterator(queue, false);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_nonnull(iterator);
   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);
   iterator = generic_queue_iterator_next(iterator);
   ck_assert_ptr_null(iterator);

   generic_queue_free(queue, &amp;_free_value);
}
END_TEST

START_TEST (test_generic_queue_shift_free)
{
   generic_queue_t *queue;

   queue = generic_queue_new();

   generic_queue_shift(queue, _value_1);
   generic_queue_shift(queue, _value_2);
   generic_queue_shift(queue, _value_3);

   generic_queue_free(queue, &amp;_free_value);
}
END_TEST

START_TEST (test_generic_queue_remove_one)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);

   iterator = generic_queue_iterator(queue, true);
   iterator = generic_queue_iterator_remove(iterator);
   ck_assert_ptr_null(iterator);
   ck_assert_int_eq(generic_queue_length(queue), 0);

   generic_queue_free(queue, NULL);
}
END_TEST

static void _verify_queue_values(generic_queue_t *queue, int count, ...)
{
   va_list values_list;
   void **values;
   int i;
   generic_queue_iterator_t *iterator;

   values = (void **)malloc(count * sizeof(void *));

   ck_assert_int_eq(count, generic_queue_length(queue));

   va_start(values_list, count);
   for (i = 0; i &lt; count; i++)
      values[i] = va_arg(values_list, void *);
   va_end(values_list);

   iterator = generic_queue_iterator(queue, true);
   for (i = 0; i &lt; count; i++)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));
      iterator = generic_queue_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   iterator = generic_queue_iterator(queue, false);
   for (i = count - 1; i &gt;= 0; i--)
   {
      ck_assert_ptr_nonnull(iterator);
      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));
      iterator = generic_queue_iterator_next(iterator);
   }
   ck_assert_ptr_null(iterator);

   free(values);
}

START_TEST (test_generic_queue_iterator_remove_first)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, true);
   iterator = generic_queue_iterator_remove(iterator);
   generic_queue_iterator_free(iterator);

   _verify_queue_values(queue, 2, _value_2, _value_3);

   generic_queue_free(queue, &amp;_free_value);
}
END_TEST

START_TEST (test_generic_queue_iterator_remove_middle)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, true);
   iterator = generic_queue_iterator_next(iterator);
   iterator = generic_queue_iterator_remove(iterator);
   generic_queue_iterator_free(iterator);

   _verify_queue_values(queue, 2, _value_1, _value_3);

   generic_queue_free(queue, &amp;_free_value);
}
END_TEST

START_TEST (test_generic_queue_iterator_remove_last)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   iterator = generic_queue_iterator(queue, false);
   iterator = generic_queue_iterator_remove(iterator);
   generic_queue_iterator_free(iterator);

   _verify_queue_values(queue, 2, _value_1, _value_2);

   generic_queue_free(queue, &amp;_free_value);
}
END_TEST

START_TEST (test_generic_queue_remove_first)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   ck_assert_ptr_eq(generic_queue_remove(queue, _value_1), _value_1);

   _verify_queue_values(queue, 2, _value_2, _value_3);

   generic_queue_free(queue, &amp;_free_value);
}

START_TEST (test_generic_queue_remove_middle)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   ck_assert_ptr_eq(generic_queue_remove(queue, _value_2), _value_2);

   _verify_queue_values(queue, 2, _value_1, _value_3);

   generic_queue_free(queue, &amp;_free_value);
}

START_TEST (test_generic_queue_remove_last)
{
   generic_queue_t *queue;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   generic_queue_push(queue, _value_2);
   generic_queue_push(queue, _value_3);

   ck_assert_ptr_eq(generic_queue_remove(queue, _value_3), _value_3);

   _verify_queue_values(queue, 2, _value_1, _value_2);

   generic_queue_free(queue, &amp;_free_value);
}

START_TEST (test_generic_queue_iterator_free)
{
   generic_queue_t *queue;
   generic_queue_iterator_t *iterator;

   queue = generic_queue_new();
   generic_queue_push(queue, _value_1);
   iterator = generic_queue_iterator(queue, true);

   generic_queue_iterator_free(iterator);
   generic_queue_iterator_free(NULL);

   generic_queue_free(queue, _free_value);
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_generic_queue_create);
   tcase_add_test(tc_core, test_generic_queue_free);
   tcase_add_test(tc_core, test_generic_queue_push_pop);
   tcase_add_test(tc_core, test_generic_queue_peek);
   tcase_add_test(tc_core, test_generic_queue_shift_unshift);
   tcase_add_test(tc_core, test_generic_queue_empty);
   tcase_add_test(tc_core, test_generic_queue_iterator);
   tcase_add_test(tc_core, test_generic_queue_shift_free);
   tcase_add_test(tc_core, test_generic_queue_remove_one);
   tcase_add_test(tc_core, test_generic_queue_iterator_remove_first);
   tcase_add_test(tc_core, test_generic_queue_iterator_remove_middle);
   tcase_add_test(tc_core, test_generic_queue_iterator_remove_last);
   tcase_add_test(tc_core, test_generic_queue_remove_first);
   tcase_add_test(tc_core, test_generic_queue_remove_middle);
   tcase_add_test(tc_core, test_generic_queue_remove_last);
   tcase_add_test(tc_core, test_generic_queue_iterator_free);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
	int num_fail;
	Suite *s = create_suite();
	SRunner *sr = srunner_create(s);
	srunner_run_all(sr, CK_NORMAL);
	num_fail = srunner_ntests_failed(sr);
	srunner_free(sr);
	return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}</pre>
<h2>./include/libretro-common/test/string/test_stdstring.c</h2>
<pre>/* Copyright  (C) 2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;check.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

#include &lt;string/stdstring.h&gt;
#include &lt;encodings/utf.h&gt;

#define SUITE_NAME "stdstring"

START_TEST (test_string_filter)
{
   char test1[] = "foo bar some string";
   char test2[] = "";
   string_remove_all_chars(test1, 's');
   string_remove_all_chars(test2, '0');
   string_remove_all_chars(NULL, 'a');
   ck_assert(!strcmp(test1, "foo bar ome tring"));
   ck_assert(!strcmp(test2, ""));
}
END_TEST

START_TEST (test_string_replace)
{
   char test1[] = "foo bar some string";
   string_replace_all_chars(test1, 's', 'S');
   string_replace_all_chars(NULL, 'a', 'A');
   ck_assert(!strcmp(test1, "foo bar Some String"));
}
END_TEST

START_TEST (test_string_case)
{
   char test1[] = "foo";
   char test2[] = "01foOo[]_";
   ck_assert(!strcmp(string_to_upper(test1), "FOO"));
   ck_assert(!strcmp(string_to_upper(test2), "01FOOO[]_"));
   ck_assert(!strcmp(string_to_lower(test2), "01fooo[]_"));
}
END_TEST

START_TEST (test_string_char_classify)
{
   ck_assert(ISSPACE(' '));
   ck_assert(ISSPACE('\n'));
   ck_assert(ISSPACE('\r'));
   ck_assert(ISSPACE('\t'));
   ck_assert(!ISSPACE('a'));

   ck_assert(ISALPHA('a'));
   ck_assert(ISALPHA('Z'));
   ck_assert(!ISALPHA('5'));

   ck_assert(ISALNUM('a'));
   ck_assert(ISALNUM('Z'));
   ck_assert(ISALNUM('5'));
}
END_TEST

START_TEST (test_string_num_conv)
{
   ck_assert_uint_eq(3, string_to_unsigned("3"));
   ck_assert_uint_eq(2147483647, string_to_unsigned("2147483647"));
   ck_assert_uint_eq(0, string_to_unsigned("foo"));
   ck_assert_uint_eq(0, string_to_unsigned("-1"));
   ck_assert_uint_eq(0, string_to_unsigned(NULL));

   ck_assert_uint_eq(10, string_hex_to_unsigned("0xa"));
   ck_assert_uint_eq(10, string_hex_to_unsigned("a"));
   ck_assert_uint_eq(255, string_hex_to_unsigned("FF"));
   ck_assert_uint_eq(255, string_hex_to_unsigned("0xff"));
   ck_assert_uint_eq(0, string_hex_to_unsigned("0xfzzf"));
   ck_assert_uint_eq(0, string_hex_to_unsigned("0x"));
   ck_assert_uint_eq(0, string_hex_to_unsigned("0xx"));
   ck_assert_uint_eq(0, string_hex_to_unsigned(NULL));
}
END_TEST

START_TEST (test_string_tokenizer)
{
   char *testinput = "@@1@@2@@3@@@@9@@@";
   char **ptr = &amp;testinput;
   char *token = NULL;
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, ""));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "1"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "2"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "3"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, ""));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "9"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token != NULL);
   ck_assert(!strcmp(token, "@"));
   free(token);
   token = string_tokenize(ptr, "@@");
   ck_assert(token == NULL);
}
END_TEST

START_TEST (test_string_replacesubstr)
{
   char *res = string_replace_substring("foobaarhellowooorldtest", "oo", "ooo");
   ck_assert(res != NULL);
   ck_assert(!strcmp(res, "fooobaarhellowoooorldtest"));
   free(res);
}
END_TEST

START_TEST (test_string_trim)
{
   char test1[] = "\t \t\nhey there \n \n";
   char test2[] = "\t \t\nhey there \n \n";
   char test3[] = "\t \t\nhey there \n \n";
   ck_assert(string_trim_whitespace_left(test1) ==  (char*)test1);
   ck_assert(!strcmp(test1, "hey there \n \n"));
   ck_assert(string_trim_whitespace_right(test2) ==  (char*)test2);
   ck_assert(!strcmp(test2, "\t \t\nhey there"));
   ck_assert(string_trim_whitespace(test3) ==  (char*)test3);
   ck_assert(!strcmp(test3, "hey there"));
}
END_TEST

START_TEST (test_string_comparison)
{
   ck_assert(memcmp("foo", "bar", 3)   != 0);
   ck_assert(memcmp("foo2", "foo2", 4) == 0);
   ck_assert(memcmp("foo1", "foo2", 4) != 0);
   ck_assert(memcmp("foo1", "foo2", 3) == 0);
}
END_TEST

START_TEST (test_word_wrap)
{
   const char *testtxt = (
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam nec "
      "enim quis orci euismod efficitur at nec arcu. Vivamus imperdiet est "
      "feugiat massa rhoncus porttitor at vitae ante. Nunc a orci vel ipsum "
      "tempor posuere sed a lacus. Ut erat odio, ultrices vitae iaculis "
      "fringilla, iaculis ut eros.\nSed facilisis viverra lectus et "
      "ullamcorper. Aenean risus ex, ornare eget scelerisque ac, imperdiet eu "
      "ipsum. Morbi pellentesque erat metus, sit amet aliquet libero rutrum "
      "et. Integer non ullamcorper tellus.");
   const char *expected = (
      "Lorem ipsum dolor sit amet, consectetur\n"
      "adipiscing elit. Nam nec enim quis orci\n"
      "euismod efficitur at nec arcu. Vivamus\n"
      "imperdiet est feugiat massa rhoncus\n"
      "porttitor at vitae ante. Nunc a orci\n"
      "vel ipsum tempor posuere sed a lacus.\n"
      "Ut erat odio, ultrices vitae iaculis\n"
      "fringilla, iaculis ut eros.\n"
      "Sed facilisis viverra lectus et\n"
      "ullamcorper. "
      "Aenean risus ex, ornare eget scelerisque ac, imperdiet eu ipsum. Morbi "
      "pellentesque erat metus, sit amet aliquet libero rutrum et. Integer "
      "non ullamcorper tellus.");

   char output[1024];

   word_wrap(output, sizeof(output), testtxt, strlen(testtxt), 40, 100, 10);
   ck_assert(!strcmp(output, expected));
}
END_TEST

START_TEST (test_strlcpy)
{
   char buf1[8];
   ck_assert_uint_eq(3, strlcpy(buf1, "foo", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foo", 4));
   ck_assert_uint_eq(11, strlcpy(buf1, "foo12345678", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foo1234", 8));
}
END_TEST

START_TEST (test_strlcat)
{
   char buf1[8];
   buf1[0] = 'f';
   buf1[1] = '\0';
   ck_assert_uint_eq(10, strlcat(buf1, "ooooooooo", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foooooo\0", 8));
   ck_assert_uint_eq(13, strlcat(buf1, "123456", sizeof(buf1)));
   ck_assert(!memcmp(buf1, "foooooo\0", 8));
}
END_TEST

START_TEST (test_strldup)
{
   char buf1[8] = "foo";
   char *tv1 = strldup(buf1, 16);
   char *tv2 = strldup(buf1, 2);
   ck_assert(tv1 != (char*)buf1);
   ck_assert(tv2 != (char*)buf1);
   ck_assert_uint_eq(strlen(tv2), 1);
   ck_assert(tv2[0] == 'f' &amp;&amp; tv2[1] == 0);
   free(tv1);
   free(tv2);
}
END_TEST

START_TEST (test_utf8_conv_utf32)
{
   uint32_t output[12];
   const char test1[] = "aæ⠻จйγチℝ\xff";
   ck_assert_uint_eq(8, utf8_conv_utf32(output, 12, test1, strlen(test1)));
   ck_assert_uint_eq(97, output[0]);
   ck_assert_uint_eq(230, output[1]);
   ck_assert_uint_eq(10299, output[2]);
   ck_assert_uint_eq(3592, output[3]);
   ck_assert_uint_eq(1081, output[4]);
   ck_assert_uint_eq(947, output[5]);
   ck_assert_uint_eq(12481, output[6]);
   ck_assert_uint_eq(8477, output[7]);
}
END_TEST

START_TEST (test_utf8_util)
{
   const char *test1 = "aæ⠻จ𠀤";
   const char **tptr = &amp;test1;
   char out[64];
   ck_assert_uint_eq(utf8len(test1), 5);
   ck_assert_uint_eq(utf8len(NULL), 0);
   ck_assert(&amp;test1[1 + 2 + 3] == utf8skip(test1, 3));

   ck_assert_uint_eq(97, utf8_walk(tptr));
   ck_assert_uint_eq(230, utf8_walk(tptr));
   ck_assert_uint_eq(10299, utf8_walk(tptr));
   ck_assert_uint_eq(3592, utf8_walk(tptr));
   ck_assert_uint_eq(131108, utf8_walk(tptr));

#if 0
   ck_assert_uint_eq(1, utf8cpy(out, 64, test1, 1));
#endif
}
END_TEST

START_TEST (test_utf16_conv)
{
   const uint16_t test1[] = {0x0061, 0x00e6, 0x283b, 0x0e08, 0xd840, 0xdc24};
   char out[64];
   size_t outlen = sizeof(out);
   ck_assert(utf16_conv_utf8((uint8_t*)out, &amp;outlen, test1, sizeof(test1) / 2));
   ck_assert_uint_eq(outlen, 13);
   ck_assert(!memcmp(out, "aæ⠻จ𠀤", 13));
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_string_comparison);
   tcase_add_test(tc_core, test_string_num_conv);
   tcase_add_test(tc_core, test_string_char_classify);
   tcase_add_test(tc_core, test_string_case);
   tcase_add_test(tc_core, test_string_filter);
   tcase_add_test(tc_core, test_string_replace);
   tcase_add_test(tc_core, test_string_tokenizer);
   tcase_add_test(tc_core, test_string_trim);
   tcase_add_test(tc_core, test_string_replacesubstr);
   tcase_add_test(tc_core, test_word_wrap);
   tcase_add_test(tc_core, test_strlcpy);
   tcase_add_test(tc_core, test_strlcat);
   tcase_add_test(tc_core, test_strldup);
   tcase_add_test(tc_core, test_utf8_conv_utf32);
   tcase_add_test(tc_core, test_utf16_conv);
   tcase_add_test(tc_core, test_utf8_util);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}</pre>
<h2>./include/libretro-common/test/utils/test_utils.c</h2>
<pre>/* Copyright  (C) 2021 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (test_stdstring.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include &lt;check.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

#include &lt;utils/md5.h&gt;
#include &lt;encodings/crc32.h&gt;
#include &lt;streams/file_stream.h&gt;

#define SUITE_NAME "hash"

START_TEST (test_md5)
{
   uint8_t output[16];
   MD5_CTX ctx;
   MD5_Init(&amp;ctx);
   MD5_Final(output, &amp;ctx);
   ck_assert(!memcmp(
      "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e",
      output, 16));
   MD5_Init(&amp;ctx);
   MD5_Update(&amp;ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Final(output, &amp;ctx);
   ck_assert(!memcmp(
      "\x9e\x10\x7d\x9d\x37\x2b\xb6\x82\x6b\xd8\x1d\x35\x42\xa4\x19\xd6",
      output, 16));
   MD5_Init(&amp;ctx);
   MD5_Update(&amp;ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Update(&amp;ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Update(&amp;ctx, "The quick brown fox jumps over the lazy dog", 43);
   MD5_Final(output, &amp;ctx);
   ck_assert(!memcmp(
      "\x4e\x67\xdb\x4a\x7a\x40\x6b\x0c\xfd\xad\xd8\x87\xcd\xe7\x88\x8e",
      output, 16));
}
END_TEST

START_TEST (test_crc32)
{
   char buf1[] = "retroarch";
   char buf2[] = "12345678";
   char buf3[] = "The quick brown fox jumps over the lazy dog";
   uint32_t test1 = encoding_crc32(0, (uint8_t*)buf1, strlen(buf1));
   uint32_t test2 = encoding_crc32(0, (uint8_t*)buf2, strlen(buf2));
   uint32_t test3 = encoding_crc32(0, (uint8_t*)buf3, strlen(buf3));
   ck_assert_uint_eq(0x3cae141a, test1);
   ck_assert_uint_eq(0x9ae0daaf, test2);
   ck_assert_uint_eq(0x414fa339, test3);
}
END_TEST

#define CRC32_BUFFER_SIZE 1048576
#define CRC32_MAX_MB 64

/**
 * Calculate a CRC32 from the first part of the given file.
 * "first part" being the first (CRC32_BUFFER_SIZE * CRC32_MAX_MB)
 * bytes.
 *
 * Returns: the crc32, or 0 if there was an error.
 */
static uint32_t file_crc32(uint32_t crc, const char *path)
{
   unsigned i;
   RFILE *file        = NULL;
   unsigned char *buf = NULL;
   if (!path)
      return 0;

   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))
      return 0;

   if (!(buf = (unsigned char*)malloc(CRC32_BUFFER_SIZE)))
   {
      filestream_close(file);
      return 0;
   }

   for (i = 0; i &lt; CRC32_MAX_MB; i++)
   {
      int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);
      if (nread &lt; 0)		
      {
         free(buf);
         filestream_close(file);
         return 0;
      }

      crc = encoding_crc32(crc, buf, (size_t)nread);
      if (filestream_eof(file))
         break;
   }
   free(buf);
   filestream_close(file);
   return crc;
}

START_TEST (test_crc32_file)
{
   char tmpfile[512];
   FILE *fd;
   tmpnam(tmpfile);
   fd = fopen(tmpfile, "wb");
   ck_assert(fd != NULL);
   fwrite("12345678", 1, 8, fd);
   fclose(fd);

   ck_assert_uint_eq(file_crc32(0, tmpfile), 0x9ae0daaf);
   /* Error checking */
   ck_assert_uint_eq(file_crc32(0, "/this/path/should/not/exist"), 0);
   ck_assert_uint_eq(file_crc32(0, NULL), 0);
}
END_TEST

Suite *create_suite(void)
{
   Suite *s = suite_create(SUITE_NAME);

   TCase *tc_core = tcase_create("Core");
   tcase_add_test(tc_core, test_md5);
   tcase_add_test(tc_core, test_crc32);
   tcase_add_test(tc_core, test_crc32_file);
   suite_add_tcase(s, tc_core);

   return s;
}

int main(void)
{
   int num_fail;
   Suite *s = create_suite();
   SRunner *sr = srunner_create(s);
   srunner_run_all(sr, CK_NORMAL);
   num_fail = srunner_ntests_failed(sr);
   srunner_free(sr);
   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}</pre>
<h2>./include/libretro-common/time/rtime.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
 *
 * ---------------------------------------------------------------------------------------
 * The following license statement only applies to this file (rtime.c).
 * ---------------------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge,
 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef HAVE_THREADS
#include &lt;rthreads/rthreads.h&gt;
#include &lt;stdlib.h&gt;
#endif

#include &lt;string.h&gt;
#include &lt;time/rtime.h&gt;

#ifdef HAVE_THREADS
/* TODO/FIXME - global */
slock_t *rtime_localtime_lock = NULL;
#endif

/* Must be called before using rtime_localtime() */
void rtime_init(void)
{
   rtime_deinit();
#ifdef HAVE_THREADS
   if (!rtime_localtime_lock)
      rtime_localtime_lock = slock_new();
#endif
}

/* Must be called upon program termination */
void rtime_deinit(void)
{
#ifdef HAVE_THREADS
   if (rtime_localtime_lock)
   {
      slock_free(rtime_localtime_lock);
      rtime_localtime_lock = NULL;
   }
#endif
}

/* Thread-safe wrapper for localtime() */
struct tm *rtime_localtime(const time_t *timep, struct tm *result)
{
   struct tm *time_info = NULL;

   /* Lock mutex */
#ifdef HAVE_THREADS
   slock_lock(rtime_localtime_lock);
#endif

   time_info = localtime(timep);
   if (time_info)
      memcpy(result, time_info, sizeof(struct tm));

   /* Unlock mutex */
#ifdef HAVE_THREADS
   slock_unlock(rtime_localtime_lock);
#endif

   return result;
}</pre>
<h2>./include/libretro-common/utils/debugbreak/debugbreak.c</h2>
<pre>#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif

#if _WIN32_WINNT &lt; 0x0501
#error Must target Windows NT 5.0.1 or later for DebugBreakProcess
#endif

#include &lt;Windows.h&gt;

#include &lt;stdio.h&gt;
#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;

/* Compile with this line:

gcc -o debugbreak -mno-cygwin -mthreads debugbreak.c

*/

static char errbuffer[256];

static const char *geterrstr(DWORD errcode)
{
size_t skip = 0;
DWORD chars;
chars = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errcode, 0, errbuffer, sizeof(errbuffer)-1, 0);
errbuffer[sizeof(errbuffer)-1] = 0;
if (chars) {
while (errbuffer[chars-1] == '\r' || errbuffer[chars-1] == '\n') {
errbuffer[--chars] = 0;
}
}
if (chars &amp;&amp; errbuffer[chars-1] == '.') errbuffer[--chars] = 0;
if (chars &gt;= 2 &amp;&amp; errbuffer[0] == '%' &amp;&amp; errbuffer[1] &gt;= '0'
&amp;&amp; errbuffer[1] &lt;= '9')
{
skip = 2;
while (chars &gt; skip &amp;&amp; errbuffer[skip] == ' ') ++skip;
if (chars &gt;= skip+2 &amp;&amp; errbuffer[skip] == 'i'
&amp;&amp; errbuffer[skip+1] == 's')
{
skip += 2;
while (chars &gt; skip &amp;&amp; errbuffer[skip] == ' ') ++skip;
}
}
if (chars &gt; skip &amp;&amp; errbuffer[skip] &gt;= 'A' &amp;&amp; errbuffer[skip] &lt;= 'Z') {
errbuffer[skip] += 'a' - 'A';
}
return errbuffer+skip;
}

int main(int argc, char *argv[])
{
    HANDLE proc;
    unsigned proc_id = 0;
    BOOL break_result;

    if (argc != 2) {
        printf("Usage: debugbreak process_id_number\n");
        return 1;
    }
    proc_id = (unsigned) strtol(argv[1], NULL, 0);
    if (proc_id == 0) {
        printf("Invalid process id %u\n", proc_id);
        return 1;
    }
    proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)proc_id);
    if (proc == NULL) {
        DWORD lastError = GetLastError();
        printf("Failed to open process %u\n", proc_id);
        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
            geterrstr(lastError));
        return 1;
    }
    break_result = DebugBreakProcess(proc);
    if (!break_result) {
        DWORD lastError = GetLastError();
        printf("Failed to debug break process %u\n", proc_id);
        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
            geterrstr(lastError));
        CloseHandle(proc);
        return 1;
    }
    printf("DebugBreak sent successfully to process id %u\n", proc_id);
    CloseHandle(proc);
    return 0;
}

/* END debugbreak.c */</pre>
<h2>./include/libretro-common/utils/djb2.c</h2>
<pre>/* public domain */
/* gcc -O3 -o djb2 djb2.c */

#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;

static uint32_t djb2(const char* str)
{
   const unsigned char* aux = (const unsigned char*)str;
   uint32_t hash = 5381;

   while (*aux)
      hash = (hash &lt;&lt; 5) + hash + *aux++;

   return hash;
}

int main(int argc, const char* argv[])
{
   int i;

   for (i = 1; i &lt; argc; i++)
      printf( "0x%08xU: %s\n", djb2( argv[ i ] ), argv[ i ] );

   return 0;
}</pre>
<h2>./include/libretro-common/utils/md5.c</h2>
<pre>/*
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD5 Message-Digest Algorithm (RFC 1321).
 *
 * Homepage:
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer &lt;solar at openwall.com&gt;
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there's no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's.  No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible.  Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */
#include &lt;lrc_hash.h&gt;

#include &lt;string.h&gt;

/*
 * The basic MD5 functions.
 *
 * F and G are optimized compared to their RFC 1321 definitions for
 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
 * implementation.
 */
#define MD5_F(x, y, z)			((z) ^ ((x) &amp; ((y) ^ (z))))
#define MD5_G(x, y, z)			((y) ^ ((z) &amp; ((x) ^ (y))))
#define MD5_H(x, y, z)			(((x) ^ (y)) ^ (z))
#define MD5_H2(x, y, z)			((x) ^ ((y) ^ (z)))
#define MD5_I(x, y, z)			((y) ^ ((x) | ~(z)))

/*
 * The MD5 transformation for all four rounds.
 */
#define MD5_STEP(f, a, b, c, d, x, t, s) \
	(a) += f((b), (c), (d)) + (x) + (t); \
	(a) = (((a) &lt;&lt; (s)) | (((a) &amp; 0xffffffff) &gt;&gt; (32 - (s)))); \
	(a) += (b);

/*
 * MD5_SET reads 4 input bytes in little-endian byte order and stores them
 * in a properly aligned word in host byte order.
 *
 * The check for little-endian architectures that tolerate unaligned
 * memory accesses is just an optimization.  Nothing will break if it
 * doesn't work.
 */
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define MD5_SET(n) \
	(*(MD5_u32plus *)&amp;ptr[(n) * 4])
#define MD5_GET(n) \
	MD5_SET(n)
#else
#define MD5_SET(n) \
	(ctx-&gt;block[(n)] = \
	(MD5_u32plus)ptr[(n) * 4] | \
	((MD5_u32plus)ptr[(n) * 4 + 1] &lt;&lt; 8) | \
	((MD5_u32plus)ptr[(n) * 4 + 2] &lt;&lt; 16) | \
	((MD5_u32plus)ptr[(n) * 4 + 3] &lt;&lt; 24))
#define MD5_GET(n) \
	(ctx-&gt;block[(n)])
#endif

/*
 * This processes one or more 64-byte data blocks, but does NOT update
 * the bit counters.  There are no alignment requirements.
 */
static const void *MD5_body(MD5_CTX *ctx, const void *data, unsigned long size)
{
	MD5_u32plus saved_a, saved_b, saved_c, saved_d;
	const unsigned char *ptr = (const unsigned char *)data;
	MD5_u32plus a = ctx-&gt;a;
	MD5_u32plus b = ctx-&gt;b;
	MD5_u32plus c = ctx-&gt;c;
	MD5_u32plus d = ctx-&gt;d;

	do {
		saved_a = a;
		saved_b = b;
		saved_c = c;
		saved_d = d;

/* Round 1 */
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(3), 0xc1bdceee, 22)
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(4), 0xf57c0faf, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(5), 0x4787c62a, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(6), 0xa8304613, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(7), 0xfd469501, 22)
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(8), 0x698098d8, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(9), 0x8b44f7af, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(10), 0xffff5bb1, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(11), 0x895cd7be, 22)
		MD5_STEP(MD5_F, a, b, c, d, MD5_SET(12), 0x6b901122, 7)
		MD5_STEP(MD5_F, d, a, b, c, MD5_SET(13), 0xfd987193, 12)
		MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17)
		MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22)

/* Round 2 */
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(0), 0xe9b6c7aa, 20)
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(5), 0xd62f105d, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(10), 0x02441453, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(15), 0xd8a1e681, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(4), 0xe7d3fbc8, 20)
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(9), 0x21e1cde6, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(14), 0xc33707d6, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(3), 0xf4d50d87, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(8), 0x455a14ed, 20)
		MD5_STEP(MD5_G, a, b, c, d, MD5_GET(13), 0xa9e3e905, 5)
		MD5_STEP(MD5_G, d, a, b, c, MD5_GET(2), 0xfcefa3f8, 9)
		MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14)
		MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20)

/* Round 3 */
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(14), 0xfde5380c, 23)
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(1), 0xa4beea44, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(4), 0x4bdecfa9, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(7), 0xf6bb4b60, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(10), 0xbebfbc70, 23)
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(13), 0x289b7ec6, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(0), 0xeaa127fa, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(3), 0xd4ef3085, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(6), 0x04881d05, 23)
		MD5_STEP(MD5_H, a, b, c, d, MD5_GET(9), 0xd9d4d039, 4)
		MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(12), 0xe6db99e5, 11)
		MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16)
		MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23)

/* Round 4 */
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(5), 0xfc93a039, 21)
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(12), 0x655b59c3, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(3), 0x8f0ccc92, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(10), 0xffeff47d, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(1), 0x85845dd1, 21)
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(8), 0x6fa87e4f, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(15), 0xfe2ce6e0, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(6), 0xa3014314, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(13), 0x4e0811a1, 21)
		MD5_STEP(MD5_I, a, b, c, d, MD5_GET(4), 0xf7537e82, 6)
		MD5_STEP(MD5_I, d, a, b, c, MD5_GET(11), 0xbd3af235, 10)
		MD5_STEP(MD5_I, c, d, a, b, MD5_GET(2), 0x2ad7d2bb, 15)
		MD5_STEP(MD5_I, b, c, d, a, MD5_GET(9), 0xeb86d391, 21)

		a += saved_a;
		b += saved_b;
		c += saved_c;
		d += saved_d;

		ptr += 64;
	} while (size -= 64);

	ctx-&gt;a = a;
	ctx-&gt;b = b;
	ctx-&gt;c = c;
	ctx-&gt;d = d;

	return ptr;
}

void MD5_Init(MD5_CTX *ctx)
{
	ctx-&gt;a = 0x67452301;
	ctx-&gt;b = 0xefcdab89;
	ctx-&gt;c = 0x98badcfe;
	ctx-&gt;d = 0x10325476;

	ctx-&gt;lo = 0;
	ctx-&gt;hi = 0;
}

void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
{
	unsigned long used;
	MD5_u32plus saved_lo = ctx-&gt;lo;
	if ((ctx-&gt;lo = (saved_lo + size) &amp; 0x1fffffff) &lt; saved_lo)
		ctx-&gt;hi++;
	ctx-&gt;hi += size &gt;&gt; 29;

	used = saved_lo &amp; 0x3f;

	if (used)
   {
      unsigned long available = 64 - used;

      if (size &lt; available)
      {
         memcpy(&amp;ctx-&gt;buffer[used], data, size);
         return;
      }

      memcpy(&amp;ctx-&gt;buffer[used], data, available);
      data = (const unsigned char *)data + available;
      size -= available;
      MD5_body(ctx, ctx-&gt;buffer, 64);
   }

	if (size &gt;= 64)
   {
      data = MD5_body(ctx, data, size &amp; ~(unsigned long)0x3f);
      size &amp;= 0x3f;
   }

	memcpy(ctx-&gt;buffer, data, size);
}

void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
	unsigned long available;
	unsigned long used = ctx-&gt;lo &amp; 0x3f;

	ctx-&gt;buffer[used++] = 0x80;

	available = 64 - used;

	if (available &lt; 8)
   {
      memset(&amp;ctx-&gt;buffer[used], 0, available);
      MD5_body(ctx, ctx-&gt;buffer, 64);
      used = 0;
      available = 64;
   }

	memset(&amp;ctx-&gt;buffer[used], 0, available - 8);

	ctx-&gt;lo &lt;&lt;= 3;
	ctx-&gt;buffer[56] = ctx-&gt;lo;
	ctx-&gt;buffer[57] = ctx-&gt;lo &gt;&gt; 8;
	ctx-&gt;buffer[58] = ctx-&gt;lo &gt;&gt; 16;
	ctx-&gt;buffer[59] = ctx-&gt;lo &gt;&gt; 24;
	ctx-&gt;buffer[60] = ctx-&gt;hi;
	ctx-&gt;buffer[61] = ctx-&gt;hi &gt;&gt; 8;
	ctx-&gt;buffer[62] = ctx-&gt;hi &gt;&gt; 16;
	ctx-&gt;buffer[63] = ctx-&gt;hi &gt;&gt; 24;

	MD5_body(ctx, ctx-&gt;buffer, 64);

	result[0] = ctx-&gt;a;
	result[1] = ctx-&gt;a &gt;&gt; 8;
	result[2] = ctx-&gt;a &gt;&gt; 16;
	result[3] = ctx-&gt;a &gt;&gt; 24;
	result[4] = ctx-&gt;b;
	result[5] = ctx-&gt;b &gt;&gt; 8;
	result[6] = ctx-&gt;b &gt;&gt; 16;
	result[7] = ctx-&gt;b &gt;&gt; 24;
	result[8] = ctx-&gt;c;
	result[9] = ctx-&gt;c &gt;&gt; 8;
	result[10] = ctx-&gt;c &gt;&gt; 16;
	result[11] = ctx-&gt;c &gt;&gt; 24;
	result[12] = ctx-&gt;d;
	result[13] = ctx-&gt;d &gt;&gt; 8;
	result[14] = ctx-&gt;d &gt;&gt; 16;
	result[15] = ctx-&gt;d &gt;&gt; 24;

	memset(ctx, 0, sizeof(*ctx));
}</pre>
<h2>./include/libretro-common/utils/sha1.c</h2>
<pre>/*
 *  sha1.h
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones &lt;paulej@packetizer.com&gt;
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This class implements the Secure Hashing Standard as defined
 *      in FIPS PUB 180-1 published April 17, 1995.
 *
 *      Many of the variable names in the SHA1Context, especially the
 *      single character names, were used because those were the names
 *      used in the publication.
 *
 *      Please read the file sha1.c for more information.
 *
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#ifdef WIN32
#include &lt;io.h&gt;
#endif
#include &lt;fcntl.h&gt;
#include &lt;string/stdstring.h&gt;

#ifndef _SHA1_H_
#define _SHA1_H_

/*
 *  This structure will hold context information for the hashing
 *  operation
 */
typedef struct SHA1Context
{
   unsigned Message_Digest[5]; /* Message Digest (output)          */

   unsigned Length_Low;        /* Message length in bits           */
   unsigned Length_High;       /* Message length in bits           */

   unsigned char Message_Block[64]; /* 512-bit message blocks      */
   int Message_Block_Index;    /* Index into message block array   */

   int Computed;               /* Is the digest computed?          */
   int Corrupted;              /* Is the message digest corruped?  */
} SHA1Context;

/*
 *  Function Prototypes
 */
void SHA1Reset(SHA1Context *);
int SHA1Result(SHA1Context *);
void SHA1Input( SHA1Context *,
      const unsigned char *,
      unsigned);

#endif

/*
 *  sha1.c
 *
 *  Copyright (C) 1998, 2009
 *  Paul E. Jones &lt;paulej@packetizer.com&gt;
 *  All Rights Reserved
 *
 *****************************************************************************
 *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
 *****************************************************************************
 *
 *  Description:
 *      This file implements the Secure Hashing Standard as defined
 *      in FIPS PUB 180-1 published April 17, 1995.
 *
 *      The Secure Hashing Standard, which uses the Secure Hashing
 *      Algorithm (SHA), produces a 160-bit message digest for a
 *      given data stream.  In theory, it is highly improbable that
 *      two messages will produce the same message digest.  Therefore,
 *      this algorithm can serve as a means of providing a "fingerprint"
 *      for a message.
 *
 *  Portability Issues:
 *      SHA-1 is defined in terms of 32-bit "words".  This code was
 *      written with the expectation that the processor has at least
 *      a 32-bit machine word size.  If the machine word size is larger,
 *      the code should still function properly.  One caveat to that
 *      is that the input functions taking characters and character
 *      arrays assume that only 8 bits of information are stored in each
 *      character.
 *
 *  Caveats:
 *      SHA-1 is designed to work with messages less than 2^64 bits
 *      long. Although SHA-1 allows a message digest to be generated for
 *      messages of any number of bits less than 2^64, this
 *      implementation only works with messages with a length that is a
 *      multiple of the size of an 8-bit character.
 *
 */

/*#include "sha1.h"*/

/*
 *  Define the circular shift macro
 */
#define SHA1CircularShift(bits,word) \
                ((((word) &lt;&lt; (bits)) &amp; 0xFFFFFFFF) | \
                ((word) &gt;&gt; (32-(bits))))

/* Function prototypes */
void SHA1ProcessMessageBlock(SHA1Context *);
void SHA1PadMessage(SHA1Context *);

/*
 *  SHA1Reset
 *
 *  Description:
 *      This function will initialize the SHA1Context in preparation
 *      for computing a new message digest.
 *
 *  Parameters:
 *      context: [in/out]
 *          The context to reset.
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void SHA1Reset(SHA1Context *context)
{
   context-&gt;Length_Low             = 0;
   context-&gt;Length_High            = 0;
   context-&gt;Message_Block_Index    = 0;

   context-&gt;Message_Digest[0]      = 0x67452301;
   context-&gt;Message_Digest[1]      = 0xEFCDAB89;
   context-&gt;Message_Digest[2]      = 0x98BADCFE;
   context-&gt;Message_Digest[3]      = 0x10325476;
   context-&gt;Message_Digest[4]      = 0xC3D2E1F0;

   context-&gt;Computed   = 0;
   context-&gt;Corrupted  = 0;
}

/*
 *  SHA1Result
 *
 *  Description:
 *      This function will return the 160-bit message digest into the
 *      Message_Digest array within the SHA1Context provided
 *
 *  Parameters:
 *      context: [in/out]
 *          The context to use to calculate the SHA-1 hash.
 *
 *  Returns:
 *      1 if successful, 0 if it failed.
 *
 *  Comments:
 *
 */
int SHA1Result(SHA1Context *context)
{
   if (context-&gt;Corrupted)
      return 0;

   if (!context-&gt;Computed)
   {
      SHA1PadMessage(context);
      context-&gt;Computed = 1;
   }

   return 1;
}

/*
 *  SHA1Input
 *
 *  Description:
 *      This function accepts an array of octets as the next portion of
 *      the message.
 *
 *  Parameters:
 *      context: [in/out]
 *          The SHA-1 context to update
 *      message_array: [in]
 *          An array of characters representing the next portion of the
 *          message.
 *      length: [in]
 *          The length of the message in message_array
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void SHA1Input(     SHA1Context         *context,
                    const unsigned char *message_array,
                    unsigned            length)
{
   if (!length)
      return;

   if (context-&gt;Computed || context-&gt;Corrupted)
   {
      context-&gt;Corrupted = 1;
      return;
   }

   while(length-- &amp;&amp; !context-&gt;Corrupted)
   {
      context-&gt;Message_Block[context-&gt;Message_Block_Index++] =
         (*message_array &amp; 0xFF);

      context-&gt;Length_Low += 8;
      /* Force it to 32 bits */
      context-&gt;Length_Low &amp;= 0xFFFFFFFF;
      if (context-&gt;Length_Low == 0)
      {
         context-&gt;Length_High++;
         /* Force it to 32 bits */
         context-&gt;Length_High &amp;= 0xFFFFFFFF;
         /* Message is too long */
         if (context-&gt;Length_High == 0)
            context-&gt;Corrupted = 1;
      }

      if (context-&gt;Message_Block_Index == 64)
         SHA1ProcessMessageBlock(context);

      message_array++;
   }
}

/*
 *  SHA1ProcessMessageBlock
 *
 *  Description:
 *      This function will process the next 512 bits of the message
 *      stored in the Message_Block array.
 *
 *  Parameters:
 *      None.
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *      Many of the variable names in the SHAContext, especially the
 *      single character names, were used because those were the names
 *      used in the publication.
 *
 *
 */
void SHA1ProcessMessageBlock(SHA1Context *context)
{
   const unsigned K[] =            /* Constants defined in SHA-1   */
   {
      0x5A827999,
      0x6ED9EBA1,
      0x8F1BBCDC,
      0xCA62C1D6
   };
   int         t;                  /* Loop counter                 */
   unsigned    temp;               /* Temporary word value         */
   unsigned    W[80];              /* Word sequence                */
   unsigned    A, B, C, D, E;      /* Word buffers                 */

   /*
    *  Initialize the first 16 words in the array W
    */
   for (t = 0; t &lt; 16; t++)
   {
      W[t] = ((unsigned) context-&gt;Message_Block[t * 4]) &lt;&lt; 24;
      W[t] |= ((unsigned) context-&gt;Message_Block[t * 4 + 1]) &lt;&lt; 16;
      W[t] |= ((unsigned) context-&gt;Message_Block[t * 4 + 2]) &lt;&lt; 8;
      W[t] |= ((unsigned) context-&gt;Message_Block[t * 4 + 3]);
   }

   for (t = 16; t &lt; 80; t++)
      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);

   A = context-&gt;Message_Digest[0];
   B = context-&gt;Message_Digest[1];
   C = context-&gt;Message_Digest[2];
   D = context-&gt;Message_Digest[3];
   E = context-&gt;Message_Digest[4];

   for (t = 0; t &lt; 20; t++)
   {
      temp =  SHA1CircularShift(5,A) +
         ((B &amp; C) | ((~B) &amp; D)) + E + W[t] + K[0];
      temp &amp;= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   for (t = 20; t &lt; 40; t++)
   {
      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
      temp &amp;= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   for (t = 40; t &lt; 60; t++)
   {
      temp = SHA1CircularShift(5,A) +
         ((B &amp; C) | (B &amp; D) | (C &amp; D)) + E + W[t] + K[2];
      temp &amp;= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   for (t = 60; t &lt; 80; t++)
   {
      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
      temp &amp;= 0xFFFFFFFF;
      E = D;
      D = C;
      C = SHA1CircularShift(30,B);
      B = A;
      A = temp;
   }

   context-&gt;Message_Digest[0] =
      (context-&gt;Message_Digest[0] + A) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[1] =
      (context-&gt;Message_Digest[1] + B) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[2] =
      (context-&gt;Message_Digest[2] + C) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[3] =
      (context-&gt;Message_Digest[3] + D) &amp; 0xFFFFFFFF;
   context-&gt;Message_Digest[4] =
      (context-&gt;Message_Digest[4] + E) &amp; 0xFFFFFFFF;

   context-&gt;Message_Block_Index = 0;
}

/*
 *  SHA1PadMessage
 *
 *  Description:
 *      According to the standard, the message must be padded to an even
 *      512 bits.  The first padding bit must be a '1'.  The last 64
 *      bits represent the length of the original message.  All bits in
 *      between should be 0.  This function will pad the message
 *      according to those rules by filling the Message_Block array
 *      accordingly.  It will also call SHA1ProcessMessageBlock()
 *      appropriately.  When it returns, it can be assumed that the
 *      message digest has been computed.
 *
 *  Parameters:
 *      context: [in/out]
 *          The context to pad
 *
 *  Returns:
 *      Nothing.
 *
 *  Comments:
 *
 */
void SHA1PadMessage(SHA1Context *context)
{
   /*
    *  Check to see if the current message block is too small to hold
    *  the initial padding bits and length.  If so, we will pad the
    *  block, process it, and then continue padding into a second
    *  block.
    */
   if (context-&gt;Message_Block_Index &gt; 55)
   {
      context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0x80;
      while(context-&gt;Message_Block_Index &lt; 64)
         context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0;

      SHA1ProcessMessageBlock(context);

      while(context-&gt;Message_Block_Index &lt; 56)
         context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0;
   }
   else
   {
      context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0x80;
      while(context-&gt;Message_Block_Index &lt; 56)
         context-&gt;Message_Block[context-&gt;Message_Block_Index++] = 0;
   }

   /*
    *  Store the message length as the last 8 octets
    */
   context-&gt;Message_Block[56] = (context-&gt;Length_High &gt;&gt; 24) &amp; 0xFF;
   context-&gt;Message_Block[57] = (context-&gt;Length_High &gt;&gt; 16) &amp; 0xFF;
   context-&gt;Message_Block[58] = (context-&gt;Length_High &gt;&gt; 8) &amp; 0xFF;
   context-&gt;Message_Block[59] = (context-&gt;Length_High) &amp; 0xFF;
   context-&gt;Message_Block[60] = (context-&gt;Length_Low &gt;&gt; 24) &amp; 0xFF;
   context-&gt;Message_Block[61] = (context-&gt;Length_Low &gt;&gt; 16) &amp; 0xFF;
   context-&gt;Message_Block[62] = (context-&gt;Length_Low &gt;&gt; 8) &amp; 0xFF;
   context-&gt;Message_Block[63] = (context-&gt;Length_Low) &amp; 0xFF;

   SHA1ProcessMessageBlock(context);
}</pre>
<h2>./include/libretro-common/vfs/vfs_implementation.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;errno.h&gt;
#include &lt;sys/types.h&gt;

#include &lt;string/stdstring.h&gt; /* string_is_empty */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#if defined(_WIN32)
#  ifdef _MSC_VER
#    define setmode _setmode
#  endif
#include &lt;sys/stat.h&gt;
#  ifdef _XBOX
#    include &lt;xtl.h&gt;
#    define INVALID_FILE_ATTRIBUTES -1
#  else

#    include &lt;fcntl.h&gt;
#    include &lt;direct.h&gt;
#    include &lt;windows.h&gt;
#  endif
#    include &lt;io.h&gt;
#else
#  if defined(PSP)
#    include &lt;pspiofilemgr.h&gt;
#  endif
#  include &lt;sys/types.h&gt;
#  include &lt;sys/stat.h&gt;
#  if !defined(VITA)
#  include &lt;dirent.h&gt;
#  endif
#  include &lt;unistd.h&gt;
#  if defined(WIIU)
#  include &lt;malloc.h&gt;
#  endif
#endif

#include &lt;fcntl.h&gt;

/* TODO: Some things are duplicated but I'm really afraid of breaking other platforms by touching this */
#if defined(VITA)
#  include &lt;psp2/io/fcntl.h&gt;
#  include &lt;psp2/io/dirent.h&gt;
#  include &lt;psp2/io/stat.h&gt;
#elif !defined(_WIN32)
#  if defined(PSP)
#    include &lt;pspiofilemgr.h&gt;
#  endif
#  include &lt;sys/types.h&gt;
#  include &lt;sys/stat.h&gt;
#  include &lt;dirent.h&gt;
#  include &lt;unistd.h&gt;
#endif

#if defined(__QNX__) || defined(PSP)
#include &lt;unistd.h&gt; /* stat() is defined here */
#endif

#ifdef __APPLE__
#include &lt;CoreFoundation/CoreFoundation.h&gt;
#endif
#ifdef __HAIKU__
#include &lt;kernel/image.h&gt;
#endif
#ifndef __MACH__
#include &lt;compat/strl.h&gt;
#include &lt;compat/posix_string.h&gt;
#endif
#include &lt;compat/strcasestr.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;encodings/utf.h&gt;

#if defined(_WIN32)
#ifndef _XBOX
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &lt;= 1200
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
#endif
#elif defined(VITA)
#define SCE_ERROR_ERRNO_EEXIST 0x80010011
#include &lt;psp2/io/fcntl.h&gt;
#include &lt;psp2/io/dirent.h&gt;
#include &lt;psp2/io/stat.h&gt;
#else
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;unistd.h&gt;
#endif


#if defined(PSP)
#include &lt;pspkernel.h&gt;
#endif

#if defined(__PS3__) || defined(__PSL1GHT__)
#define FS_SUCCEEDED 0
#define FS_TYPE_DIR 1
#ifdef __PSL1GHT__
#include &lt;lv2/sysfs.h&gt;
#ifndef O_RDONLY
#define O_RDONLY SYS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY SYS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT SYS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC SYS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR SYS_O_RDWR
#endif
#else
#include &lt;cell/cell_fs.h&gt;
#ifndef O_RDONLY
#define O_RDONLY CELL_FS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY CELL_FS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT CELL_FS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC CELL_FS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR CELL_FS_O_RDWR
#endif
#ifndef sysFsStat
#define sysFsStat cellFsStat
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsOpendir
#define sysFsOpendir cellFsOpendir
#endif
#ifndef sysFsReaddir
#define sysFsReaddir cellFsReaddir
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsClosedir
#define sysFsClosedir cellFsClosedir
#endif
#endif
#endif

#if defined(VITA)
#define FIO_S_ISDIR SCE_S_ISDIR
#endif

#if defined(__QNX__) || defined(PSP)
#include &lt;unistd.h&gt; /* stat() is defined here */
#endif

/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500 || defined(_XBOX)

#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif

#endif

#if defined(_WIN32)
#if defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1400
#define ATLEAST_VC2005
#endif
#endif

#include &lt;vfs/vfs_implementation.h&gt;
#include &lt;libretro.h&gt;
#if defined(HAVE_MMAP)
#include &lt;memmap.h&gt;
#endif
#include &lt;encodings/utf.h&gt;
#include &lt;compat/fopen_utf8.h&gt;
#include &lt;file/file_path.h&gt;

#ifdef HAVE_CDROM
#include &lt;vfs/vfs_implementation_cdrom.h&gt;
#endif

#if (defined(_POSIX_C_SOURCE) &amp;&amp; (_POSIX_C_SOURCE - 0) &gt;= 200112) || (defined(__POSIX_VISIBLE) &amp;&amp; __POSIX_VISIBLE &gt;= 200112) || (defined(_POSIX_VERSION) &amp;&amp; _POSIX_VERSION &gt;= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) &amp;&amp; _FILE_OFFSET_BITS == 64)
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
#endif

#define RFILE_HINT_UNBUFFERED (1 &lt;&lt; 8)

int64_t retro_vfs_file_seek_internal(
      libretro_vfs_implementation_file *stream,
      int64_t offset, int whence)
{
   int64_t val;

   if (!stream)
      return -1;

   if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
   {
#ifdef HAVE_CDROM
      if (stream-&gt;scheme == VFS_SCHEME_CDROM)
         return retro_vfs_file_seek_cdrom(stream, offset, whence);
#endif
#ifdef ATLEAST_VC2005
      /* VC2005 and up have a special 64-bit fseek */
      return _fseeki64(stream-&gt;fp, offset, whence);
#elif defined(HAVE_64BIT_OFFSETS)
      return fseeko(stream-&gt;fp, (off_t)offset, whence);
#else
      return fseek(stream-&gt;fp, (long)offset, whence);
#endif
   }
#ifdef HAVE_MMAP
   /* Need to check stream-&gt;mapped because this function is
    * called in filestream_open() */
   if (stream-&gt;mapped &amp;&amp; stream-&gt;hints &amp;
         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
   {
      /* fseek() returns error on under/overflow but
       * allows cursor &gt; EOF for
       read-only file descriptors. */
      /* The file position must never be negative. */
      switch (whence)
      {
         case SEEK_SET:
            if (offset &lt; 0)
               return -1;

            stream-&gt;mappos = offset;
            break;

         case SEEK_CUR:
            if (stream-&gt;mappos + offset &lt; 0)
              return -1;

            stream-&gt;mappos += offset;
            break;

         case SEEK_END:
            /* RETRO_VFS_SEEK_POSITION_END states offset should be negative.
             * However, this is impractical because we would be forcing the
             * end of file to always be off by one.
             */
            if (offset &gt; 0 || stream-&gt;mapsize + offset &lt; 0)
               return -1;

            stream-&gt;mappos = stream-&gt;mapsize + offset;
            break;
      }
      return stream-&gt;mappos;
   }
#endif

   if ((val = lseek(stream-&gt;fd, (off_t)offset, whence)) &lt; 0)
      return -1;

   return val;
}

/**
 * retro_vfs_file_open_impl:
 * @path               : path to file
 * @mode               : file mode to use when opening (read/write)
 * @hints              :
 *
 * Opens a file for reading or writing, depending on the requested mode.
 * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
 **/

libretro_vfs_implementation_file *retro_vfs_file_open_impl(
      const char *path, unsigned mode, unsigned hints)
{
   int                                flags = 0;
   const char                     *mode_str = NULL;
   libretro_vfs_implementation_file *stream =
      (libretro_vfs_implementation_file*)
      malloc(sizeof(*stream));

   if (!stream)
      return NULL;

   stream-&gt;fd                     = 0;
   stream-&gt;hints                  = hints;
   stream-&gt;size                   = 0;
   stream-&gt;buf                    = NULL;
   stream-&gt;fp                     = NULL;
#ifdef _WIN32
   stream-&gt;fh                     = 0;
#endif
   stream-&gt;orig_path              = NULL;
   stream-&gt;mappos                 = 0;
   stream-&gt;mapsize                = 0;
   stream-&gt;mapped                 = NULL;
   stream-&gt;scheme                 = VFS_SCHEME_NONE;

#ifdef VFS_FRONTEND
   if (     path
         &amp;&amp; path[0] == 'v'
         &amp;&amp; path[1] == 'f'
         &amp;&amp; path[2] == 's'
         &amp;&amp; path[3] == 'o'
         &amp;&amp; path[4] == 'n'
         &amp;&amp; path[5] == 'l'
         &amp;&amp; path[6] == 'y'
         &amp;&amp; path[7] == ':'
         &amp;&amp; path[8] == '/'
         &amp;&amp; path[9] == '/')
         path             += sizeof("vfsonly://")-1;
#endif

#ifdef HAVE_CDROM
   stream-&gt;cdrom.cue_buf          = NULL;
   stream-&gt;cdrom.cue_len          = 0;
   stream-&gt;cdrom.byte_pos         = 0;
   stream-&gt;cdrom.drive            = 0;
   stream-&gt;cdrom.cur_min          = 0;
   stream-&gt;cdrom.cur_sec          = 0;
   stream-&gt;cdrom.cur_frame        = 0;
   stream-&gt;cdrom.cur_track        = 0;
   stream-&gt;cdrom.cur_lba          = 0;
   stream-&gt;cdrom.last_frame_lba   = 0;
   stream-&gt;cdrom.last_frame[0]    = '\0';
   stream-&gt;cdrom.last_frame_valid = false;

   if (     path
         &amp;&amp; path[0] == 'c'
         &amp;&amp; path[1] == 'd'
         &amp;&amp; path[2] == 'r'
         &amp;&amp; path[3] == 'o'
         &amp;&amp; path[4] == 'm'
         &amp;&amp; path[5] == ':'
         &amp;&amp; path[6] == '/'
         &amp;&amp; path[7] == '/'
         &amp;&amp; path[8] != '\0')
   {
      path             += sizeof("cdrom://")-1;
      stream-&gt;scheme    = VFS_SCHEME_CDROM;
   }
#endif

   if (path)
      stream-&gt;orig_path = strdup(path);

#ifdef HAVE_MMAP
   if (stream-&gt;hints &amp; RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS &amp;&amp; mode == RETRO_VFS_FILE_ACCESS_READ)
      stream-&gt;hints |= RFILE_HINT_UNBUFFERED;
   else
#endif
      stream-&gt;hints &amp;= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;

   switch (mode)
   {
      case RETRO_VFS_FILE_ACCESS_READ:
         mode_str = "rb";

         flags    = O_RDONLY;
#ifdef _WIN32
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_WRITE:
         mode_str = "wb";

         flags    = O_WRONLY | O_CREAT | O_TRUNC;
#if !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_READ_WRITE:
         mode_str = "w+b";
         flags    = O_RDWR | O_CREAT | O_TRUNC;
#if !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
      case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
         mode_str = "r+b";

         flags    = O_RDWR;
#if !defined(_WIN32)
         flags   |= S_IRUSR | S_IWUSR;
#else
         flags   |= O_BINARY;
#endif
         break;

      default:
         goto error;
   }

   if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
   {
      FILE *fp;
#ifdef HAVE_CDROM
      if (stream-&gt;scheme == VFS_SCHEME_CDROM)
      {
         retro_vfs_file_open_cdrom(stream, path, mode, hints);
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
         if (!stream-&gt;fh)
            goto error;
#else
         if (!stream-&gt;fp)
            goto error;
#endif
      }
      else
#endif
      {
         if (!(fp = (FILE*)fopen_utf8(path, mode_str)))
         {
#ifdef IOS
            if (errno == EEXIST)
            {
               retro_vfs_file_remove_impl(path);
               fp = (FILE*)fopen_utf8(path, mode_str);
            }
            if (!fp)
#endif
            goto error;
         }

         stream-&gt;fp  = fp;
      }

      /* Regarding setvbuf:
       *
       * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&amp;apropos=0&amp;sektion=0&amp;manpath=FreeBSD+11.1-RELEASE&amp;arch=default&amp;format=html
       *
       * If the size argument is not zero but buf is NULL,
       * a buffer of the given size will be allocated immediately, and
       * released on close. This is an extension to ANSI C.
       *
       * Since C89 does not support specifying a NULL buffer
       * with a non-zero size, we create and track our own buffer for it.
       */
      /* TODO: this is only useful for a few platforms,
       * find which and add ifdef */
#if defined(_3DS)
      if (stream-&gt;scheme != VFS_SCHEME_CDROM)
      {
         stream-&gt;buf = (char*)calloc(1, 0x10000);
         if (stream-&gt;fp)
            setvbuf(stream-&gt;fp, stream-&gt;buf, _IOFBF, 0x10000);
      }
#elif defined(WIIU)
      if (stream-&gt;scheme != VFS_SCHEME_CDROM)
      {
         const int bufsize = 128 * 1024;
         stream-&gt;buf = (char*)memalign(0x40, bufsize);
         if (stream-&gt;fp)
            setvbuf(stream-&gt;fp, stream-&gt;buf, _IOFBF, bufsize);
         stream-&gt;buf = (char*)calloc(1, 0x4000);
         if (stream-&gt;fp)
            setvbuf(stream-&gt;fp, stream-&gt;buf, _IOFBF, 0x4000);
      }
#endif
   }
   else
   {
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#if defined(LEGACY_WIN32)
      char *path_local    = utf8_to_local_string_alloc(path);
      stream-&gt;fd          = open(path_local, flags, 0);
      if (path_local)
         free(path_local);
#else
      wchar_t * path_wide = utf8_to_utf16_string_alloc(path);
      stream-&gt;fd          = _wopen(path_wide, flags, 0);
      if (path_wide)
         free(path_wide);
#endif
#else
      stream-&gt;fd          = open(path, flags, 0);
#endif

      if (stream-&gt;fd == -1)
         goto error;

#ifdef HAVE_MMAP
      if (stream-&gt;hints &amp; RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
      {
         stream-&gt;mappos  = 0;
         stream-&gt;mapped  = NULL;
         stream-&gt;mapsize = retro_vfs_file_seek_internal(stream, 0, SEEK_END);

         if (stream-&gt;mapsize == (uint64_t)-1)
            goto error;

         retro_vfs_file_seek_internal(stream, 0, SEEK_SET);

         if ((stream-&gt;mapped = (uint8_t*)mmap((void*)0,
               stream-&gt;mapsize, PROT_READ,  MAP_SHARED, stream-&gt;fd, 0)) == MAP_FAILED)
            stream-&gt;hints &amp;= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
      }
#endif
   }
#ifdef HAVE_CDROM
   if (stream-&gt;scheme == VFS_SCHEME_CDROM)
   {
      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
      retro_vfs_file_seek_cdrom(stream, 0, SEEK_END);

      stream-&gt;size = retro_vfs_file_tell_impl(stream);

      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
   }
   else
#endif
   {
      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
      retro_vfs_file_seek_internal(stream, 0, SEEK_END);

      stream-&gt;size = retro_vfs_file_tell_impl(stream);

      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
   }
   return stream;

error:
   retro_vfs_file_close_impl(stream);
   return NULL;
}

int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
{
   if (!stream)
      return -1;

#ifdef HAVE_CDROM
   if (stream-&gt;scheme == VFS_SCHEME_CDROM)
   {
      retro_vfs_file_close_cdrom(stream);
      goto end;
   }
#endif

   if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
   {
      if (stream-&gt;fp)
         fclose(stream-&gt;fp);
   }
   else
   {
#ifdef HAVE_MMAP
      if (stream-&gt;hints &amp; RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
         munmap(stream-&gt;mapped, stream-&gt;mapsize);
#endif
   }

   if (stream-&gt;fd &gt; 0)
      close(stream-&gt;fd);
#ifdef HAVE_CDROM
end:
   if (stream-&gt;cdrom.cue_buf)
      free(stream-&gt;cdrom.cue_buf);
#endif
   if (stream-&gt;buf)
      free(stream-&gt;buf);

   if (stream-&gt;orig_path)
      free(stream-&gt;orig_path);

   free(stream);

   return 0;
}

int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
{
#ifdef HAVE_CDROM
   if (stream-&gt;scheme == VFS_SCHEME_CDROM)
      return retro_vfs_file_error_cdrom(stream);
#endif
   return ferror(stream-&gt;fp);
}

int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
{
   if (stream)
      return stream-&gt;size;
   return 0;
}

int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t len)
{
#ifdef _WIN32
   if (stream &amp;&amp; _chsize(_fileno(stream-&gt;fp), len) == 0)
   {
	   stream-&gt;size = len;
	   return 0;
   }
#elif !defined(VITA) &amp;&amp; !defined(PSP) &amp;&amp; !defined(PS2) &amp;&amp; !defined(ORBIS) &amp;&amp; (!defined(SWITCH) || defined(HAVE_LIBNX))
   if (stream &amp;&amp; ftruncate(fileno(stream-&gt;fp), (off_t)len) == 0)
   {
      stream-&gt;size = len;
      return 0;
   }
#endif
   return -1;
}

int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
{
   int64_t val;

   if (!stream)
      return -1;

   if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
   {
#ifdef HAVE_CDROM
      if (stream-&gt;scheme == VFS_SCHEME_CDROM)
         return retro_vfs_file_tell_cdrom(stream);
#endif
#ifdef ATLEAST_VC2005
      /* VC2005 and up have a special 64-bit ftell */
      return _ftelli64(stream-&gt;fp);
#elif defined(HAVE_64BIT_OFFSETS)
      return ftello(stream-&gt;fp);
#else
      return ftell(stream-&gt;fp);
#endif
   }
#ifdef HAVE_MMAP
   /* Need to check stream-&gt;mapped because this function
    * is called in filestream_open() */
   if (stream-&gt;mapped &amp;&amp; stream-&gt;hints &amp;
         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
      return stream-&gt;mappos;
#endif
   if ((val = lseek(stream-&gt;fd, 0, SEEK_CUR)) &lt; 0)
      return -1;

   return val;
}

int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
      int64_t offset, int seek_position)
{
   return retro_vfs_file_seek_internal(stream, offset, seek_position);
}

int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
      void *s, uint64_t len)
{
   if (!stream || !s)
      return -1;

   if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
   {
#ifdef HAVE_CDROM
      if (stream-&gt;scheme == VFS_SCHEME_CDROM)
         return retro_vfs_file_read_cdrom(stream, s, len);
#endif
      return fread(s, 1, (size_t)len, stream-&gt;fp);
   }
#ifdef HAVE_MMAP
   if (stream-&gt;hints &amp; RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
   {
      if (stream-&gt;mappos &gt; stream-&gt;mapsize)
         return -1;

      if (stream-&gt;mappos + len &gt; stream-&gt;mapsize)
         len = stream-&gt;mapsize - stream-&gt;mappos;

      memcpy(s, &amp;stream-&gt;mapped[stream-&gt;mappos], len);
      stream-&gt;mappos += len;

      return len;
   }
#endif

   return read(stream-&gt;fd, s, (size_t)len);
}

int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
{
   int64_t pos = 0;
   ssize_t ret = -1;

   if (!stream)
      return -1;

   if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
   {
      pos = retro_vfs_file_tell_impl(stream);
      ret = fwrite(s, 1, (size_t)len, stream-&gt;fp);

      if (ret != -1 &amp;&amp; pos + ret &gt; stream-&gt;size)
         stream-&gt;size = pos + ret;

      return ret;
   }
#ifdef HAVE_MMAP
   if (stream-&gt;hints &amp; RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
      return -1;
#endif

   pos = retro_vfs_file_tell_impl(stream);
   ret = write(stream-&gt;fd, s, (size_t)len);

   if (ret != -1 &amp;&amp; pos + ret &gt; stream-&gt;size)
      stream-&gt;size = pos + ret;

   return ret;
}

int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
{
   if (stream &amp;&amp; fflush(stream-&gt;fp) == 0)
      return 0;
   return -1;
}

int retro_vfs_file_remove_impl(const char *path)
{
   if (path &amp;&amp; *path)
   {
      int ret          = -1;
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
      /* Win32 (no Xbox) */
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500
      char *path_local = NULL;
      if ((path_local = utf8_to_local_string_alloc(path)))
      {
         /* We need to check if path is a directory */
         if ((retro_vfs_stat_impl(path, NULL) &amp; RETRO_VFS_STAT_IS_DIRECTORY) != 0)
            ret = _rmdir(path_local);
         else
            ret = remove(path_local);
         free(path_local);
      }
#else
      wchar_t *path_wide = NULL;
      if ((path_wide = utf8_to_utf16_string_alloc(path)))
      {
         /* We need to check if path is a directory */
         if ((retro_vfs_stat_impl(path, NULL) &amp; RETRO_VFS_STAT_IS_DIRECTORY) != 0)
            ret = _wrmdir(path_wide);
         else
            ret = _wremove(path_wide);
         free(path_wide);
      }
#endif
#else
      ret = remove(path);
#endif
      if (ret == 0)
         return 0;
   }
   return -1;
}

int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
{
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
   /* Win32 (no Xbox) */
   int ret                 = -1;
#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500
   char *old_path_local    = NULL;
#else
   wchar_t *old_path_wide  = NULL;
#endif

   if (!old_path || !*old_path || !new_path || !*new_path)
      return -1;

#if defined(_WIN32_WINNT) &amp;&amp; _WIN32_WINNT &lt; 0x0500
   old_path_local = utf8_to_local_string_alloc(old_path);

   if (old_path_local)
   {
      char *new_path_local = utf8_to_local_string_alloc(new_path);

      if (new_path_local)
      {
         if (rename(old_path_local, new_path_local) == 0)
            ret = 0;
         free(new_path_local);
      }

      free(old_path_local);
   }
#else
   old_path_wide = utf8_to_utf16_string_alloc(old_path);

   if (old_path_wide)
   {
      wchar_t *new_path_wide = utf8_to_utf16_string_alloc(new_path);

      if (new_path_wide)
      {
         if (_wrename(old_path_wide, new_path_wide) == 0)
            ret = 0;
         free(new_path_wide);
      }

      free(old_path_wide);
   }
#endif
   return ret;

#else
   /* Every other platform */
   if (!old_path || !*old_path || !new_path || !*new_path)
      return -1;
   return rename(old_path, new_path) == 0 ? 0 : -1;
#endif
}

const char *retro_vfs_file_get_path_impl(
      libretro_vfs_implementation_file *stream)
{
   /* should never happen, do something noisy so caller can be fixed */
   if (!stream)
      abort();
   return stream-&gt;orig_path;
}

int retro_vfs_stat_impl(const char *path, int32_t *size)
{
   int ret                   = RETRO_VFS_STAT_IS_VALID;

   if (!path || !*path)
      return 0;
   {
#if defined(VITA)
      /* Vita / PSP */
      SceIoStat stat_buf;
      int dir_ret;
      char *tmp                 = strdup(path);
      size_t _len               = strlen(tmp);
      if (tmp[_len-1] == '/')
          tmp[_len-1]           = '\0';

      dir_ret                   = sceIoGetstat(tmp, &amp;stat_buf);
      free(tmp);
      if (dir_ret &lt; 0)
         return 0;

      if (size)
         *size                  = (int32_t)stat_buf.st_size;

      if (FIO_S_ISDIR(stat_buf.st_mode))
         ret              |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(__PSL1GHT__) || defined(__PS3__)
      /* Lowlevel Lv2 */
      sysFSStat stat_buf;

      if (sysFsStat(path, &amp;stat_buf) &lt; 0)
         return 0;

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if ((stat_buf.st_mode &amp; S_IFMT) == S_IFDIR)
         ret  |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(_WIN32)
      /* Windows */
      struct _stat stat_buf;
#if defined(LEGACY_WIN32)
      char *path_local          = utf8_to_local_string_alloc(path);
      DWORD file_info           = GetFileAttributes(path_local);

      if (!string_is_empty(path_local))
         _stat(path_local, &amp;stat_buf);

      if (path_local)
         free(path_local);
#else
      wchar_t *path_wide        = utf8_to_utf16_string_alloc(path);
      DWORD file_info           = GetFileAttributesW(path_wide);

      _wstat(path_wide, &amp;stat_buf);

      if (path_wide)
         free(path_wide);
#endif
      if (file_info == INVALID_FILE_ATTRIBUTES)
         return 0;

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if (file_info &amp; FILE_ATTRIBUTE_DIRECTORY)
         ret  |= RETRO_VFS_STAT_IS_DIRECTORY;
#elif defined(GEKKO)
      /* On GEKKO platforms, paths cannot have
       * trailing slashes - we must therefore
       * remove them */
      size_t _len;
      char *path_buf = NULL;
      struct stat stat_buf;

      if (!(path_buf = strdup(path)))
         return 0;

      if ((_len = strlen(path_buf)) &gt; 0)
         if (path_buf[_len - 1] == '/')
             path_buf[_len - 1] = '\0';

      if (stat(path_buf, &amp;stat_buf) &lt; 0)
      {
         free(path_buf);
         return 0;
      }

      free(path_buf);

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if (S_ISDIR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_DIRECTORY;
      if (S_ISCHR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
#else
      /* Every other platform */
      struct stat stat_buf;

      if (stat(path, &amp;stat_buf) &lt; 0)
         return 0;

      if (size)
         *size = (int32_t)stat_buf.st_size;

      if (S_ISDIR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_DIRECTORY;
      if (S_ISCHR(stat_buf.st_mode))
         ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;
#endif
   }
   return ret;
}

#if defined(VITA)
#define path_mkdir_err(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
#define path_mkdir_err(ret) ((ret) == -1)
#else
#define path_mkdir_err(ret) ((ret) &lt; 0 &amp;&amp; errno == EEXIST)
#endif

int retro_vfs_mkdir_impl(const char *dir)
{
#if defined(_WIN32)
#ifdef LEGACY_WIN32
   int ret        = _mkdir(dir);
#else
   wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);
   int       ret  = -1;

   if (dir_w)
   {
      ret = _wmkdir(dir_w);
      free(dir_w);
   }
#endif
#elif defined(IOS)
   int ret = mkdir(dir, 0755);
#elif defined(VITA)
   int ret = sceIoMkdir(dir, 0777);
#elif defined(__QNX__)
   int ret = mkdir(dir, 0777);
#elif defined(GEKKO) || defined(WIIU)
   /* On GEKKO platforms, mkdir() fails if
    * the path has a trailing slash. We must
    * therefore remove it. */
   int ret = -1;
   if (!string_is_empty(dir))
   {
      char *dir_buf = strdup(dir);

      if (dir_buf)
      {
         size_t _len = strlen(dir_buf);

         if (_len &gt; 0)
            if (dir_buf[_len - 1] == '/')
                dir_buf[_len - 1] = '\0';

         ret = mkdir(dir_buf, 0750);

         free(dir_buf);
      }
   }
#else
   int ret = mkdir(dir, 0750);
#endif

   if (path_mkdir_err(ret))
      return -2;
   return ret &lt; 0 ? -1 : 0;
}

#ifdef VFS_FRONTEND
struct retro_vfs_dir_handle
#else
struct libretro_vfs_implementation_dir
#endif
{
   char* orig_path;
#if defined(_WIN32)
#if defined(LEGACY_WIN32)
   WIN32_FIND_DATA entry;
#else
   WIN32_FIND_DATAW entry;
#endif
   HANDLE directory;
   bool next;
   char path[PATH_MAX_LENGTH];
#elif defined(VITA)
   SceUID directory;
   SceIoDirent entry;
#elif defined(__PSL1GHT__) || defined(__PS3__)
   int error;
   int directory;
   sysFSDirent entry;
#else
   DIR *directory;
   const struct dirent *entry;
#endif
};

static bool dirent_check_err(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
   return (rdir-&gt;directory == INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(ORBIS)
   return (rdir-&gt;directory &lt; 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   return (rdir-&gt;error != FS_SUCCEEDED);
#else
   return !(rdir-&gt;directory);
#endif
}

libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
      const char *name, bool include_hidden)
{
#if defined(_WIN32)
   char path_buf[1024];
   size_t _len;
#if defined(LEGACY_WIN32)
   char *path_local   = NULL;
#else
   wchar_t *path_wide = NULL;
#endif
#endif
   libretro_vfs_implementation_dir *rdir;

   /* Reject NULL or empty string paths*/
   if (!name || (*name == 0))
      return NULL;

   /*Allocate RDIR struct. Tidied later with retro_closedir*/
   if (!(rdir = (libretro_vfs_implementation_dir*)
            calloc(1, sizeof(*rdir))))
      return NULL;

   rdir-&gt;orig_path       = strdup(name);

#if defined(_WIN32)
   _len = strlcpy(path_buf, name, sizeof(path_buf));
   /* Non-NT platforms don't like extra slashes in the path */
   if (path_buf[_len - 1] != '\\')
      path_buf [_len++]    = '\\';

   path_buf[_len    ]      = '*';
   path_buf[_len + 1]      = '\0';
#if defined(LEGACY_WIN32)
   path_local              = utf8_to_local_string_alloc(path_buf);
   rdir-&gt;directory         = FindFirstFile(path_local, &amp;rdir-&gt;entry);
   if (path_local)
      free(path_local);
#else
   path_wide               = utf8_to_utf16_string_alloc(path_buf);
   rdir-&gt;directory         = FindFirstFileW(path_wide, &amp;rdir-&gt;entry);
   if (path_wide)
      free(path_wide);
#endif

#elif defined(VITA)
   rdir-&gt;directory       = sceIoDopen(name);
#elif defined(_3DS)
   rdir-&gt;directory       = !string_is_empty(name) ? opendir(name) : NULL;
   rdir-&gt;entry           = NULL;
#elif defined(__PSL1GHT__) || defined(__PS3__)
   rdir-&gt;error           = sysFsOpendir(name, &amp;rdir-&gt;directory);
#else
   rdir-&gt;directory       = opendir(name);
   rdir-&gt;entry           = NULL;
#endif

#ifdef _WIN32
   if (include_hidden)
      rdir-&gt;entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
   else
      rdir-&gt;entry.dwFileAttributes &amp;= ~FILE_ATTRIBUTE_HIDDEN;
#else
   (void)include_hidden;
#endif

   if (rdir-&gt;directory &amp;&amp; !dirent_check_err(rdir))
      return rdir;

   retro_vfs_closedir_impl(rdir);
   return NULL;
}

bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
   if (rdir-&gt;next)
#if defined(LEGACY_WIN32)
      return (FindNextFile(rdir-&gt;directory, &amp;rdir-&gt;entry) != 0);
#else
      return (FindNextFileW(rdir-&gt;directory, &amp;rdir-&gt;entry) != 0);
#endif

   rdir-&gt;next = true;
   return (rdir-&gt;directory != INVALID_HANDLE_VALUE);
#elif defined(VITA)
   return (sceIoDread(rdir-&gt;directory, &amp;rdir-&gt;entry) &gt; 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   uint64_t nread;
   rdir-&gt;error = sysFsReaddir(rdir-&gt;directory, &amp;rdir-&gt;entry, &amp;nread);
   return (nread != 0);
#else
   return ((rdir-&gt;entry = readdir(rdir-&gt;directory)) != NULL);
#endif
}

const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
#if defined(LEGACY_WIN32)
   char *name       = local_to_utf8_string_alloc(rdir-&gt;entry.cFileName);
#else
   char *name       = utf16_to_utf8_string_alloc(rdir-&gt;entry.cFileName);
#endif
   memset(rdir-&gt;entry.cFileName, 0, sizeof(rdir-&gt;entry.cFileName));
   strlcpy((char*)rdir-&gt;entry.cFileName, name, sizeof(rdir-&gt;entry.cFileName));
   if (name)
      free(name);
   return (char*)rdir-&gt;entry.cFileName;
#elif defined(VITA) || defined(__PSL1GHT__) || defined(__PS3__)
   return rdir-&gt;entry.d_name;
#else
   if (!rdir || !rdir-&gt;entry)
      return NULL;
   return rdir-&gt;entry-&gt;d_name;
#endif
}

bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
   const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&amp;rdir-&gt;entry;
   return entry-&gt;dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY;
#elif defined(VITA)
   const SceIoDirent *entry     = (const SceIoDirent*)&amp;rdir-&gt;entry;
   return SCE_S_ISDIR(entry-&gt;d_stat.st_mode);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   sysFSDirent *entry          = (sysFSDirent*)&amp;rdir-&gt;entry;
   return (entry-&gt;d_type == FS_TYPE_DIR);
#else
   struct stat buf;
   char path[PATH_MAX_LENGTH];
#if defined(DT_DIR)
   const struct dirent *entry = (const struct dirent*)rdir-&gt;entry;
   if (entry-&gt;d_type == DT_DIR)
      return true;
   /* This can happen on certain file systems. */
   if (!(entry-&gt;d_type == DT_UNKNOWN || entry-&gt;d_type == DT_LNK))
      return false;
#endif
   /* dirent struct doesn't have d_type, do it the slow way ... */
   fill_pathname_join_special(path, rdir-&gt;orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
   if (stat(path, &amp;buf) &lt; 0)
      return false;
   return S_ISDIR(buf.st_mode);
#endif
}

int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
{
   if (!rdir)
      return -1;

#if defined(_WIN32)
   if (rdir-&gt;directory != INVALID_HANDLE_VALUE)
      FindClose(rdir-&gt;directory);
#elif defined(VITA)
   sceIoDclose(rdir-&gt;directory);
#elif defined(__PSL1GHT__) || defined(__PS3__)
   rdir-&gt;error = sysFsClosedir(rdir-&gt;directory);
#else
   if (rdir-&gt;directory)
      closedir(rdir-&gt;directory);
#endif

   if (rdir-&gt;orig_path)
      free(rdir-&gt;orig_path);
   free(rdir);
   return 0;
}</pre>
<h2>./include/libretro-common/vfs/vfs_implementation_cdrom.c</h2>
<pre>/* Copyright  (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation_cdrom.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include &lt;vfs/vfs_implementation.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;compat/fopen_utf8.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;cdrom/cdrom.h&gt;

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
#include &lt;windows.h&gt;
#endif

/* TODO/FIXME - static global variable */
static cdrom_toc_t vfs_cdrom_toc = {0};

const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
{
   return &amp;vfs_cdrom_toc;
}

int64_t retro_vfs_file_seek_cdrom(
      libretro_vfs_implementation_file *stream,
      int64_t offset, int whence)
{
   const char *ext = path_get_extension(stream-&gt;orig_path);

   if (string_is_equal_noncase(ext, "cue"))
   {
      switch (whence)
      {
         case SEEK_SET:
            stream-&gt;cdrom.byte_pos = offset;
            break;
         case SEEK_CUR:
            stream-&gt;cdrom.byte_pos += offset;
            break;
         case SEEK_END:
            stream-&gt;cdrom.byte_pos  = (stream-&gt;cdrom.cue_len - 1) + offset;
            break;
      }

#ifdef CDROM_DEBUG
      printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n",
            stream-&gt;orig_path,
            offset,
            stream-&gt;cdrom.byte_pos);
      fflush(stdout);
#endif
   }
   else if (string_is_equal_noncase(ext, "bin"))
   {
      int lba               = (offset / 2352);
      unsigned char min     = 0;
      unsigned char sec     = 0;
      unsigned char frame   = 0;
#ifdef CDROM_DEBUG
      const char *seek_type = "SEEK_SET";
#endif

      switch (whence)
      {
         case SEEK_CUR:
            {
               unsigned new_lba;
#ifdef CDROM_DEBUG
               seek_type               = "SEEK_CUR";
#endif
               stream-&gt;cdrom.byte_pos += offset;
               new_lba                 = vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].lba + (stream-&gt;cdrom.byte_pos / 2352);

               cdrom_lba_to_msf(new_lba, &amp;min, &amp;sec, &amp;frame);
            }
            break;
         case SEEK_END:
            {
               ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].audio 
                     ? 0 
                     : (vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].lba_start));
               ssize_t lba_len        = vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].track_size - pregap_lba_len;
#ifdef CDROM_DEBUG
               seek_type              = "SEEK_END";
#endif

               cdrom_lba_to_msf(lba_len + lba, &amp;min, &amp;sec, &amp;frame);
               stream-&gt;cdrom.byte_pos = lba_len * 2352;
            }
            break;
         case SEEK_SET:
         default:
            {
#ifdef CDROM_DEBUG
               seek_type = "SEEK_SET";
#endif
               stream-&gt;cdrom.byte_pos = offset;
               cdrom_lba_to_msf(vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].lba + (stream-&gt;cdrom.byte_pos / 2352), &amp;min, &amp;sec, &amp;frame);
            }
            break;
      }

      stream-&gt;cdrom.cur_min   = min;
      stream-&gt;cdrom.cur_sec   = sec;
      stream-&gt;cdrom.cur_frame = frame;
      stream-&gt;cdrom.cur_lba   = cdrom_msf_to_lba(min, sec, frame);

#ifdef CDROM_DEBUG
      printf(
            "[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n",
            seek_type,
            stream-&gt;orig_path,
            offset,
            stream-&gt;cdrom.byte_pos,
            (unsigned)stream-&gt;cdrom.cur_min,
            (unsigned)stream-&gt;cdrom.cur_sec,
            (unsigned)stream-&gt;cdrom.cur_frame,
            stream-&gt;cdrom.cur_lba);
      fflush(stdout);
#endif
   }
   else
      return -1;

   return 0;
}

void retro_vfs_file_open_cdrom(
      libretro_vfs_implementation_file *stream,
      const char *path, unsigned mode, unsigned hints)
{
#if defined(__linux__) &amp;&amp; !defined(ANDROID)
   char cdrom_path[]       = "/dev/sg1";
   size_t path_len         = strlen(path);
   const char *ext         = path_get_extension(path);

   stream-&gt;cdrom.cur_track = 1;

   if (     !string_is_equal_noncase(ext, "cue") 
         &amp;&amp; !string_is_equal_noncase(ext, "bin"))
      return;

   if (path_len &gt;= STRLEN_CONST("drive1-track01.bin"))
   {
      if (!memcmp(path, "drive", STRLEN_CONST("drive")))
      {
         if (!memcmp(path + 6, "-track", STRLEN_CONST("-track")))
         {
            if (sscanf(path + 12, "%02u", (unsigned*)&amp;stream-&gt;cdrom.cur_track))
            {
#ifdef CDROM_DEBUG
               printf("[CDROM] Opening track %d\n", stream-&gt;cdrom.cur_track);
               fflush(stdout);
#endif
            }
         }
      }
   }

   if (path_len &gt;= STRLEN_CONST("drive1.cue"))
   {
      if (!memcmp(path, "drive", STRLEN_CONST("drive")))
      {
         if (path[5] &gt;= '0' &amp;&amp; path[5] &lt;= '9')
         {
            cdrom_path[7]       = path[5];
            stream-&gt;cdrom.drive = path[5];
            vfs_cdrom_toc.drive = stream-&gt;cdrom.drive;
         }
      }
   }

#ifdef CDROM_DEBUG
   printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
   fflush(stdout);
#endif
   stream-&gt;fp = (FILE*)fopen_utf8(cdrom_path, "r+b");

   if (!stream-&gt;fp)
      return;

   if (string_is_equal_noncase(ext, "cue"))
   {
      if (stream-&gt;cdrom.cue_buf)
      {
         free(stream-&gt;cdrom.cue_buf);
         stream-&gt;cdrom.cue_buf = NULL;
      }

      cdrom_write_cue(stream,
            &amp;stream-&gt;cdrom.cue_buf,
            &amp;stream-&gt;cdrom.cue_len,
            stream-&gt;cdrom.drive,
            &amp;vfs_cdrom_toc.num_tracks,
            &amp;vfs_cdrom_toc);
      cdrom_get_timeouts(stream, &amp;vfs_cdrom_toc.timeouts);

#ifdef CDROM_DEBUG
      if (string_is_empty(stream-&gt;cdrom.cue_buf))
      {
         printf("[CDROM] Error writing cue sheet.\n");
         fflush(stdout);
      }
      else
      {
         printf("[CDROM] CUE Sheet:\n%s\n", stream-&gt;cdrom.cue_buf);
         fflush(stdout);
      }
#endif
   }
#endif
#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
   char cdrom_path[] = "\\\\.\\D:";
   size_t path_len   = strlen(path);
   const char *ext   = path_get_extension(path);

   if (     !string_is_equal_noncase(ext, "cue") 
         &amp;&amp; !string_is_equal_noncase(ext, "bin"))
      return;

   if (path_len &gt;= STRLEN_CONST("d:/drive-track01.bin"))
   {
      if (!memcmp(path + 1, ":/drive-track", STRLEN_CONST(":/drive-track")))
      {
         if (sscanf(path + 14, "%02u", (unsigned*)&amp;stream-&gt;cdrom.cur_track))
         {
#ifdef CDROM_DEBUG
            printf("[CDROM] Opening track %d\n", stream-&gt;cdrom.cur_track);
            fflush(stdout);
#endif
         }
      }
   }

   if (path_len &gt;= STRLEN_CONST("d:/drive.cue"))
   {
      if (!memcmp(path + 1, ":/drive", STRLEN_CONST(":/drive")))
      {
         if ((path[0] &gt;= 'A' &amp;&amp; path[0] &lt;= 'Z') || (path[0] &gt;= 'a' &amp;&amp; path[0] &lt;= 'z'))
         {
            cdrom_path[4]       = path[0];
            stream-&gt;cdrom.drive = path[0];
            vfs_cdrom_toc.drive = stream-&gt;cdrom.drive;
         }
      }
   }

#ifdef CDROM_DEBUG
   printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
   fflush(stdout);
#endif
   stream-&gt;fh = CreateFile(cdrom_path,
         GENERIC_READ | GENERIC_WRITE,
         FILE_SHARE_READ | FILE_SHARE_WRITE,
         NULL,
         OPEN_EXISTING,
         FILE_ATTRIBUTE_NORMAL,
         NULL);

   if (stream-&gt;fh == INVALID_HANDLE_VALUE)
      return;

   if (string_is_equal_noncase(ext, "cue"))
   {
      if (stream-&gt;cdrom.cue_buf)
      {
         free(stream-&gt;cdrom.cue_buf);
         stream-&gt;cdrom.cue_buf = NULL;
      }

      cdrom_write_cue(stream,
            &amp;stream-&gt;cdrom.cue_buf,
            &amp;stream-&gt;cdrom.cue_len,
            stream-&gt;cdrom.drive,
            &amp;vfs_cdrom_toc.num_tracks,
            &amp;vfs_cdrom_toc);
      cdrom_get_timeouts(stream,
            &amp;vfs_cdrom_toc.timeouts);

#ifdef CDROM_DEBUG
      if (string_is_empty(stream-&gt;cdrom.cue_buf))
      {
         printf("[CDROM] Error writing cue sheet.\n");
         fflush(stdout);
      }
      else
      {
         printf("[CDROM] CUE Sheet:\n%s\n", stream-&gt;cdrom.cue_buf);
         fflush(stdout);
      }
#endif
   }
#endif
   if (vfs_cdrom_toc.num_tracks &gt; 1 &amp;&amp; stream-&gt;cdrom.cur_track)
   {
      stream-&gt;cdrom.cur_min   = vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].min;
      stream-&gt;cdrom.cur_sec   = vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].sec;
      stream-&gt;cdrom.cur_frame = vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].frame;
      stream-&gt;cdrom.cur_lba   = cdrom_msf_to_lba(stream-&gt;cdrom.cur_min, stream-&gt;cdrom.cur_sec, stream-&gt;cdrom.cur_frame);
   }
   else
   {
      stream-&gt;cdrom.cur_min   = vfs_cdrom_toc.track[0].min;
      stream-&gt;cdrom.cur_sec   = vfs_cdrom_toc.track[0].sec;
      stream-&gt;cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;
      stream-&gt;cdrom.cur_lba   = cdrom_msf_to_lba(stream-&gt;cdrom.cur_min, stream-&gt;cdrom.cur_sec, stream-&gt;cdrom.cur_frame);
   }
}

int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream)
{
#ifdef CDROM_DEBUG
   printf("[CDROM] Close: Path %s\n", stream-&gt;orig_path);
   fflush(stdout);
#endif

#if defined(_WIN32) &amp;&amp; !defined(_XBOX)
   if (!stream-&gt;fh || !CloseHandle(stream-&gt;fh))
      return -1;
#else
   if (!stream-&gt;fp || fclose(stream-&gt;fp))
      return -1;
#endif

   return 0;
}

int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
{
   const char *ext = NULL;
   if (!stream)
      return -1;

   ext = path_get_extension(stream-&gt;orig_path);

   if (string_is_equal_noncase(ext, "cue"))
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] (cue) Tell: Path %s Position %" PRIu64 "\n", stream-&gt;orig_path, stream-&gt;cdrom.byte_pos);
      fflush(stdout);
#endif
      return stream-&gt;cdrom.byte_pos;
   }
   else if (string_is_equal_noncase(ext, "bin"))
   {
#ifdef CDROM_DEBUG
      printf("[CDROM] (bin) Tell: Path %s Position %" PRId64 "\n", stream-&gt;orig_path, stream-&gt;cdrom.byte_pos);
      fflush(stdout);
#endif
      return stream-&gt;cdrom.byte_pos;
   }

   return -1;
}

int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
      void *s, uint64_t len)
{
   int rv;
   const char *ext = path_get_extension(stream-&gt;orig_path);

   if (string_is_equal_noncase(ext, "cue"))
   {
      if ((int64_t)len &gt;= (int64_t)stream-&gt;cdrom.cue_len 
            - stream-&gt;cdrom.byte_pos)
         len = stream-&gt;cdrom.cue_len - stream-&gt;cdrom.byte_pos - 1;
#ifdef CDROM_DEBUG
      printf(
            "[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n",
            len,
            stream-&gt;cdrom.byte_pos);
      fflush(stdout);
#endif
      memcpy(s, stream-&gt;cdrom.cue_buf + stream-&gt;cdrom.byte_pos, len);
      stream-&gt;cdrom.byte_pos += len;

      return len;
   }
   else if (string_is_equal_noncase(ext, "bin"))
   {
      unsigned char min    = 0;
      unsigned char sec    = 0;
      unsigned char frame  = 0;
      unsigned char rmin   = 0;
      unsigned char rsec   = 0;
      unsigned char rframe = 0;
      size_t skip          = stream-&gt;cdrom.byte_pos % 2352;

      if (stream-&gt;cdrom.byte_pos &gt;= 
            vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].track_bytes)
         return 0;

      if (stream-&gt;cdrom.byte_pos + len &gt; 
            vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].track_bytes)
         len -= (stream-&gt;cdrom.byte_pos + len) 
            - vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].track_bytes;

      cdrom_lba_to_msf(stream-&gt;cdrom.cur_lba, &amp;min, &amp;sec, &amp;frame);
      cdrom_lba_to_msf(stream-&gt;cdrom.cur_lba 
            - vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].lba,
            &amp;rmin, &amp;rsec, &amp;rframe);

#ifdef CDROM_DEBUG
      printf(
            "[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n",
            len,
            stream-&gt;orig_path,
            stream-&gt;cdrom.byte_pos,
            (unsigned)rmin,
            (unsigned)rsec,
            (unsigned)rframe,
            (unsigned)min,
            (unsigned)sec,
            (unsigned)frame,
            stream-&gt;cdrom.cur_lba,
            skip);
      fflush(stdout);
#endif

#if 1
      rv = cdrom_read(stream, &amp;vfs_cdrom_toc.timeouts, min, sec,
            frame, s, (size_t)len, skip);
#else
      rv = cdrom_read_lba(stream, stream-&gt;cdrom.cur_lba, s,
            (size_t)len, skip);
#endif

      if (rv)
      {
#ifdef CDROM_DEBUG
         printf("[CDROM] Failed to read %" PRIu64 " bytes from CD.\n", len);
         fflush(stdout);
#endif
         return 0;
      }

      stream-&gt;cdrom.byte_pos += len;
      stream-&gt;cdrom.cur_lba   = 
         vfs_cdrom_toc.track[stream-&gt;cdrom.cur_track - 1].lba 
         + (stream-&gt;cdrom.byte_pos / 2352);

      cdrom_lba_to_msf(stream-&gt;cdrom.cur_lba,
            &amp;stream-&gt;cdrom.cur_min,
            &amp;stream-&gt;cdrom.cur_sec,
            &amp;stream-&gt;cdrom.cur_frame);

#ifdef CDROM_DEBUG
      printf(
            "[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n",
            len,
            stream-&gt;cdrom.byte_pos,
            (unsigned)stream-&gt;cdrom.cur_min,
            (unsigned)stream-&gt;cdrom.cur_sec,
            (unsigned)stream-&gt;cdrom.cur_frame,
            cdrom_msf_to_lba(
               stream-&gt;cdrom.cur_min,
               stream-&gt;cdrom.cur_sec,
               stream-&gt;cdrom.cur_frame)
            );
      fflush(stdout);
#endif

      return len;
   }

   return 0;
}

int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
{
   return 0;
}

const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(
      const libretro_vfs_implementation_file *stream)
{
   return &amp;stream-&gt;cdrom;
}</pre>
<h2>./include/libretro-common/vfs/vfs_implementation_uwp.cpp</h2>
<pre>/* Copyright  (C) 2018-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation_uwp.cpp).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include &lt;retro_environment.h&gt;

#include &lt;ppl.h&gt;
#include &lt;ppltasks.h&gt;
#include &lt;stdio.h&gt;
#include &lt;wrl.h&gt;
#include &lt;wrl/implements.h&gt;
#include &lt;robuffer.h&gt;
#include &lt;collection.h&gt;
#include &lt;functional&gt;
#include &lt;fileapifromapp.h&gt;
#include &lt;AclAPI.h&gt;
#include &lt;sddl.h&gt;
#include &lt;io.h&gt;
#include &lt;fcntl.h&gt;

#ifdef RARCH_INTERNAL
#ifndef VFS_FRONTEND
#define VFS_FRONTEND
#endif
#endif

#include &lt;vfs/vfs.h&gt;
#include &lt;vfs/vfs_implementation.h&gt;
#include &lt;libretro.h&gt;
#include &lt;encodings/utf.h&gt;
#include &lt;retro_miscellaneous.h&gt;
#include &lt;file/file_path.h&gt;
#include &lt;string/stdstring.h&gt;
#include &lt;retro_environment.h&gt;
#include &lt;uwp/uwp_async.h&gt;
#include &lt;uwp/std_filesystem_compat.h&gt;

namespace
{
   /* UWP deals with paths containing / instead of
    * \ way worse than normal Windows */
   /* and RetroArch may sometimes mix them
    * (e.g. on archive extraction) */
   static void windowsize_path(wchar_t* path)
   {
      if (path)
      {
         while (*path)
         {
            if (*path == '/')
               *path = '\\';
            ++path;
         }
      }
   }
}

#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else
struct libretro_vfs_implementation_file
#endif
{
    int64_t size;
    uint64_t mappos;
    uint64_t mapsize;
    FILE* fp;
    HANDLE fh;
    char* buf;
    char* orig_path;
    uint8_t* mapped;
    int fd;
    unsigned hints;
    enum vfs_scheme scheme;
};

#define RFILE_HINT_UNBUFFERED (1 &lt;&lt; 8)

int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
{
    if (!stream)
        return -1;

    if (stream-&gt;fp)
        fclose(stream-&gt;fp);

    if (stream-&gt;buf != NULL)
    {
        free(stream-&gt;buf);
        stream-&gt;buf = NULL;
    }
    if (stream-&gt;orig_path)
        free(stream-&gt;orig_path);

    free(stream);

    return 0;
}

int retro_vfs_file_error_impl(libretro_vfs_implementation_file* stream)
{
    return ferror(stream-&gt;fp);
}

int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file* stream)
{
    if (stream)
        return stream-&gt;size;
    return 0;
}

int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file* stream, int64_t length)
{
   if (stream &amp;&amp; _chsize(_fileno(stream-&gt;fp), length) == 0)
      return 0;
   return -1;
}

int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
{
    if (!stream)
        return -1;

    if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
        return _ftelli64(stream-&gt;fp);
    if (lseek(stream-&gt;fd, 0, SEEK_CUR) &lt; 0)
        return -1;

    return 0;
}

int64_t retro_vfs_file_seek_internal(
    libretro_vfs_implementation_file* stream,
    int64_t offset, int whence)
{
    if (!stream)
        return -1;

    if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
        return _fseeki64(stream-&gt;fp, offset, whence);
    if (lseek(stream-&gt;fd, (off_t)offset, whence) &lt; 0)
        return -1;

    return 0;
}

int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
    int64_t offset, int seek_position)
{
    return retro_vfs_file_seek_internal(stream, offset, seek_position);
}

int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file* stream,
    void* s, uint64_t len)
{
    if (!stream || (!stream-&gt;fp &amp;&amp; stream-&gt;fh == INVALID_HANDLE_VALUE) || !s)
      return -1;

   if (stream-&gt;fh != INVALID_HANDLE_VALUE)
   {
      DWORD _bytes_read;
      ReadFile(stream-&gt;fh, (char*)s, len, &amp;_bytes_read, NULL);
      return (int64_t)_bytes_read;
   }

    if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
       return fread(s, 1, (size_t)len, stream-&gt;fp);
    return read(stream-&gt;fd, s, (size_t)len);
}


int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file* stream, const void* s, uint64_t len)
{
    if (!stream || (!stream-&gt;fp &amp;&amp; stream-&gt;fh == INVALID_HANDLE_VALUE) || !s)
        return -1;

    if (stream-&gt;fh != INVALID_HANDLE_VALUE)
    {
        DWORD bytes_written;
        WriteFile(stream-&gt;fh, s, len, &amp;bytes_written, NULL);
        return (int64_t)bytes_written;
    }

    if ((stream-&gt;hints &amp; RFILE_HINT_UNBUFFERED) == 0)
        return fwrite(s, 1, (size_t)len, stream-&gt;fp);

    return write(stream-&gt;fd, s, (size_t)len);
}

int retro_vfs_file_flush_impl(libretro_vfs_implementation_file* stream)
{
    if (stream &amp;&amp; fflush(stream-&gt;fp) == 0)
       return 0;
    return -1;
}

int retro_vfs_file_remove_impl(const char *path)
{
   BOOL ret;
   wchar_t *path_wide;

   if (!path || !*path)
      return -1;

   path_wide = utf8_to_utf16_string_alloc(path);
   windowsize_path(path_wide);

   /* Try Win32 first, this should work in AppData */
   ret = DeleteFileFromAppW(path_wide);
   free(path_wide);
   if (ret)
      return 0;

   return -1;
}

libretro_vfs_implementation_file* retro_vfs_file_open_impl(
    const char* path, unsigned mode, unsigned hints)
{
    HANDLE file_handle;
    std::wstring path_wstring;
    DWORD desireAccess;
    DWORD creationDisposition;
    wchar_t                       *path_wide = NULL;
    int                                flags = 0;
    const char                     *mode_str = NULL;
    libretro_vfs_implementation_file* stream =
        (libretro_vfs_implementation_file*)
        malloc(sizeof(*stream));

    if (!stream)
        return NULL;

    stream-&gt;fd        = 0;
    stream-&gt;hints     = hints;
    stream-&gt;size      = 0;
    stream-&gt;buf       = NULL;
    stream-&gt;fp        = NULL;
    stream-&gt;fh        = 0;
    stream-&gt;orig_path = NULL;
    stream-&gt;mappos    = 0;
    stream-&gt;mapsize   = 0;
    stream-&gt;mapped    = NULL;
    stream-&gt;scheme    = VFS_SCHEME_NONE;

#ifdef VFS_FRONTEND
   if (     path
         &amp;&amp; path[0] == 'v'
         &amp;&amp; path[1] == 'f'
         &amp;&amp; path[2] == 's'
         &amp;&amp; path[3] == 'o'
         &amp;&amp; path[4] == 'n'
         &amp;&amp; path[5] == 'l'
         &amp;&amp; path[6] == 'y'
         &amp;&amp; path[7] == ':'
         &amp;&amp; path[8] == '/'
         &amp;&amp; path[9] == '/')
         path             += sizeof("vfsonly://")-1;
#endif

    path_wide    = utf8_to_utf16_string_alloc(path);
    windowsize_path(path_wide);
    path_wstring = path_wide;
    free(path_wide);

    for (;;)
    {
       size_t p = path_wstring.find(L"\\\\");
       if (p == std::wstring::npos)
          break;
       path_wstring.replace(p, 2, L"\\");
    }

    path_wstring      = L"\\\\?\\" + path_wstring;
    stream-&gt;orig_path = strdup(path);

    stream-&gt;hints    &amp;= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;

    switch (mode)
    {
       case RETRO_VFS_FILE_ACCESS_READ:
          mode_str = "rb";
          flags    = O_RDONLY | O_BINARY;
          break;

       case RETRO_VFS_FILE_ACCESS_WRITE:
          mode_str = "wb";
          flags    = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
          break;

       case RETRO_VFS_FILE_ACCESS_READ_WRITE:
          mode_str = "w+b";
          flags    = O_RDWR | O_CREAT | O_TRUNC | O_BINARY;
          break;

       case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
       case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
          mode_str = "r+b";
          flags    = O_RDWR | O_BINARY;
          break;

       default:
          goto error;
    }

    switch (mode)
    {
       case RETRO_VFS_FILE_ACCESS_READ_WRITE:
          desireAccess = GENERIC_READ | GENERIC_WRITE;
          break;
       case RETRO_VFS_FILE_ACCESS_WRITE:
          desireAccess = GENERIC_WRITE;
          break;
       case RETRO_VFS_FILE_ACCESS_READ:
          desireAccess = GENERIC_READ;
          break;
    }
    if (mode == RETRO_VFS_FILE_ACCESS_READ)
        creationDisposition = OPEN_EXISTING;
    else
        creationDisposition = (mode &amp; RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING) != 0
           ? OPEN_ALWAYS
           : CREATE_ALWAYS;

    if ((file_handle = CreateFile2FromAppW(path_wstring.data(), desireAccess,
                FILE_SHARE_READ, creationDisposition, NULL)) == INVALID_HANDLE_VALUE)
       goto error;

    stream-&gt;fh      = file_handle;
    if ((stream-&gt;fd = _open_osfhandle((uint64)stream-&gt;fh, flags)) == -1)
        goto error;

    {
        FILE *fp = _fdopen(stream-&gt;fd, mode_str);

        if (!fp)
            goto error;
        stream-&gt;fp = fp;
    }

    /* Regarding setvbuf:
        *
        * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&amp;apropos=0&amp;sektion=0&amp;manpath=FreeBSD+11.1-RELEASE&amp;arch=default&amp;format=html
        *
        * If the size argument is not zero but buf is NULL,
        * a buffer of the given size will be allocated immediately, and
        * released on close. This is an extension to ANSI C.
        *
        * Since C89 does not support specifying a NULL buffer
        * with a non-zero size, we create and track our own buffer for it.
        */
        /* TODO: this is only useful for a few platforms,
        * find which and add ifdef */
    if (stream-&gt;scheme != VFS_SCHEME_CDROM)
    {
        stream-&gt;buf = (char*)calloc(1, 0x4000);
        if (stream-&gt;fp)
            setvbuf(stream-&gt;fp, stream-&gt;buf, _IOFBF, 0x4000);
    }

    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
    retro_vfs_file_seek_internal(stream, 0, SEEK_END);

    stream-&gt;size = retro_vfs_file_tell_impl(stream);

    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);

    return stream;

error:
    retro_vfs_file_close_impl(stream);
    return NULL;
}

static int uwp_mkdir_impl(std::experimental::filesystem::path dir)
{
    /*I feel like this should create the directory recursively but the existing implementation does not so this update won't
     *I put in the work but I just commented out the stuff you would need */
    WIN32_FILE_ATTRIBUTE_DATA lpFileInfo;
    bool parent_dir_exists = false;

    if (dir.empty())
        return -1;

    /* Check if file attributes can be gotten successfully  */
    if (GetFileAttributesExFromAppW(dir.parent_path().wstring().c_str(), GetFileExInfoStandard, &amp;lpFileInfo))
    {
        /* Check that the files attributes are not null or empty */
        if (lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES &amp;&amp; lpFileInfo.dwFileAttributes != 0)
        {
            if (lpFileInfo.dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY)
                parent_dir_exists = true;
        }
    }
    if (!parent_dir_exists)
    {
        /* Try to create parent dir */
        int success = uwp_mkdir_impl(dir.parent_path());
        if (success != 0 &amp;&amp; success != -2)
            return success;
    }


    /* Try Win32 first, this should work in AppData */
    if (CreateDirectoryFromAppW(dir.wstring().c_str(), NULL))
        return 0;

    if (GetLastError() == ERROR_ALREADY_EXISTS)
        return -2;

    return -1;
}

int retro_vfs_mkdir_impl(const char* dir)
{
    return uwp_mkdir_impl(std::filesystem::path(dir));
}

/* The first run parameter is used to avoid error checking
 * when doing recursion.
 * Unlike the initial implementation, this can move folders
 * even empty ones when you want to move a directory structure.
 *
 * This will fail even if a single file cannot be moved.
 */
static int uwp_move_path(
      std::filesystem::path old_path,
      std::filesystem::path new_path,
      bool firstrun)
{
    if (old_path.empty() || new_path.empty())
        return -1;

    if (firstrun)
    {
        WIN32_FILE_ATTRIBUTE_DATA lpFileInfo, targetfileinfo;
        bool parent_dir_exists = false;

        /* Make sure that parent path exists */
        if (GetFileAttributesExFromAppW(
                 new_path.parent_path().wstring().c_str(),
                 GetFileExInfoStandard, &amp;lpFileInfo))
        {
            /* Check that the files attributes are not null or empty */
            if (     lpFileInfo.dwFileAttributes
                  != INVALID_FILE_ATTRIBUTES
                  &amp;&amp; lpFileInfo.dwFileAttributes != 0)
            {
               /* Parent path doesn't exist, so we gotta create it  */
                if (!(lpFileInfo.dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY))
                    uwp_mkdir_impl(new_path.parent_path());
            }
        }

        /* Make sure that source path exists */
        if (GetFileAttributesExFromAppW(old_path.wstring().c_str(), GetFileExInfoStandard, &amp;lpFileInfo))
        {
            /* Check that the files attributes are not null or empty */
            if (     lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES
                  &amp;&amp; lpFileInfo.dwFileAttributes != 0)
            {
                /* Check if source path is a dir */
                if (lpFileInfo.dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY)
                {
                   int ret;
                   /* create the target dir */
                   CreateDirectoryFromAppW(new_path.wstring().c_str(), NULL);
                   /* Call move function again but with first run disabled in
                    * order to move the folder */
                   if ((ret = uwp_move_path(old_path, new_path, false)) != 0)
                      return ret;
                }
                else
                {
                    /* The file that we want to move exists so we can copy it now
                     * check if target file already exists. */
                   if (GetFileAttributesExFromAppW(
                            new_path.wstring().c_str(),
                            GetFileExInfoStandard,
                            &amp;targetfileinfo))
                    {
                        if (
                                 targetfileinfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES
                              &amp;&amp; targetfileinfo.dwFileAttributes != 0
                              &amp;&amp; (!(targetfileinfo.dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY)))
                        {
                            if (DeleteFileFromAppW(new_path.wstring().c_str()))
                                return -1;
                        }
                    }

                    if (!MoveFileFromAppW(old_path.wstring().c_str(),
                             new_path.wstring().c_str()))
                        return -1;
                    /* Set ACL */
                    uwp_set_acl(new_path.wstring().c_str(), L"S-1-15-2-1");
                }
            }
        }

    }
    else
    {
       HANDLE searchResults;
       WIN32_FIND_DATA findDataResult;
       /* We are bypassing error checking and moving a dir.
        * First we have to get a list of files in the dir. */
       wchar_t* filteredPath = wcsdup(old_path.wstring().c_str());
       wcscat_s(filteredPath, sizeof(L"\\*.*"), L"\\*.*");
       searchResults         = FindFirstFileExFromAppW(
             filteredPath, FindExInfoBasic, &amp;findDataResult,
             FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);

       if (searchResults != INVALID_HANDLE_VALUE)
       {
          bool fail = false;
          do
          {
             if (     wcscmp(findDataResult.cFileName, L".")  != 0
                   &amp;&amp; wcscmp(findDataResult.cFileName, L"..") != 0)
             {
                std::filesystem::path temp_old = old_path;
                std::filesystem::path temp_new = new_path;
                temp_old /= findDataResult.cFileName;
                temp_new /= findDataResult.cFileName;
                if (    findDataResult.dwFileAttributes
                      &amp; FILE_ATTRIBUTE_DIRECTORY)
                {
                   CreateDirectoryFromAppW(temp_new.wstring().c_str(), NULL);
                   if (uwp_move_path(temp_old, temp_new, false) != 0)
                      fail = true;
                }
                else
                {
                   WIN32_FILE_ATTRIBUTE_DATA targetfileinfo;
                   /* The file that we want to move exists so we can copy
                    * it now.
                    * Check if target file already exists. */
                   if (GetFileAttributesExFromAppW(temp_new.wstring().c_str(),
                            GetFileExInfoStandard, &amp;targetfileinfo))
                   {
                      if (
                               (targetfileinfo.dwFileAttributes !=
                                INVALID_FILE_ATTRIBUTES)
                            &amp;&amp; (targetfileinfo.dwFileAttributes != 0)
                            &amp;&amp; (!(targetfileinfo.dwFileAttributes
                                  &amp; FILE_ATTRIBUTE_DIRECTORY)))
                      {
                         if (DeleteFileFromAppW(temp_new.wstring().c_str()))
                            fail = true;
                      }
                   }

                   if (!MoveFileFromAppW(temp_old.wstring().c_str(),
                            temp_new.wstring().c_str()))
                      fail = true;
                   /* Set ACL - this step sucks or at least used to
                    * before I made a whole function
                    * Don't know if we actually "need" to set the ACL
                    * though */
                   uwp_set_acl(temp_new.wstring().c_str(), L"S-1-15-2-1");
                }
             }
          } while (FindNextFile(searchResults, &amp;findDataResult));
          FindClose(searchResults);
          if (fail)
             return -1;
       }
       free(filteredPath);
    }
    return 0;
}

/* C doesn't support default arguments so we wrap it up in a shell to enable
 * us to use default arguments.
 * Default arguments mean that we can do better recursion */
int retro_vfs_file_rename_impl(const char* old_path, const char* new_path)
{
    return uwp_move_path(std::filesystem::path(old_path),
          std::filesystem::path(old_path), true);
}

const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream)
{
   /* Should never happen, do something noisy so caller can be fixed */
   if (!stream)
      abort();
   return stream-&gt;orig_path;
}

int retro_vfs_stat_impl(const char *path, int32_t *size)
{
   wchar_t *path_wide;
   _WIN32_FILE_ATTRIBUTE_DATA attribdata;

   if (!path || !*path)
      return 0;

   path_wide = utf8_to_utf16_string_alloc(path);
   windowsize_path(path_wide);

   /* Try Win32 first, this should work in AppData */
   if (GetFileAttributesExFromAppW(path_wide,
            GetFileExInfoStandard, &amp;attribdata))
   {
       if (attribdata.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
       {
           if (!(attribdata.dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY))
           {
               LARGE_INTEGER sz;
               if (size)
               {
                   sz.HighPart = attribdata.nFileSizeHigh;
                   sz.LowPart = attribdata.nFileSizeLow;
                   *size = sz.QuadPart;
               }
           }
           free(path_wide);
           return (attribdata.dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY)
              ? RETRO_VFS_STAT_IS_VALID | RETRO_VFS_STAT_IS_DIRECTORY
              : RETRO_VFS_STAT_IS_VALID;
       }
   }
   free(path_wide);
   return 0;
}

#ifdef VFS_FRONTEND
struct retro_vfs_dir_handle
#else
struct libretro_vfs_implementation_dir
#endif
{
    char* orig_path;
    WIN32_FIND_DATAW entry;
    HANDLE directory;
    bool next;
    char path[PATH_MAX_LENGTH];
};

libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
    const char* name, bool include_hidden)
{
    size_t _len;
    char path_buf[1024];
    wchar_t* path_wide = NULL;
    libretro_vfs_implementation_dir* rdir;

    /* Reject NULL or empty string paths*/
    if (!name || (*name == 0))
        return NULL;

    /*Allocate RDIR struct. Tidied later with retro_closedir*/
    if (!(rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir))))
        return NULL;

    rdir-&gt;orig_path = strdup(name);

    _len = strlcpy(path_buf, name, sizeof(path_buf));

    /* Non-NT platforms don't like extra slashes in the path */
    if (path_buf[_len - 1] != '\\')
        path_buf[_len++]   = '\\';

    path_buf[_len]         = '*';
    path_buf[_len + 1]     = '\0';

    path_wide              = utf8_to_utf16_string_alloc(path_buf);
    rdir-&gt;directory        = FindFirstFileExFromAppW(
          path_wide, FindExInfoStandard, &amp;rdir-&gt;entry,
          FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);

    if (path_wide)
        free(path_wide);

    if (include_hidden)
        rdir-&gt;entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
    else
        rdir-&gt;entry.dwFileAttributes &amp;= ~FILE_ATTRIBUTE_HIDDEN;

    if (rdir-&gt;directory &amp;&amp; rdir != INVALID_HANDLE_VALUE)
        return rdir;

    retro_vfs_closedir_impl(rdir);
    return NULL;
}

bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
{
    if (rdir-&gt;next)
        return (FindNextFileW(rdir-&gt;directory, &amp;rdir-&gt;entry) != 0);

    rdir-&gt;next = true;
    return (rdir-&gt;directory != INVALID_HANDLE_VALUE);
}

const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir)
{
    char* name = utf16_to_utf8_string_alloc(rdir-&gt;entry.cFileName);
    memset(rdir-&gt;entry.cFileName, 0, sizeof(rdir-&gt;entry.cFileName));
    strlcpy((char*)rdir-&gt;entry.cFileName, name, sizeof(rdir-&gt;entry.cFileName));
    if (name)
        free(name);
    return (char*)rdir-&gt;entry.cFileName;
}

bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir* rdir)
{
    const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&amp;rdir-&gt;entry;
    return entry-&gt;dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY;
}

int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
{
    if (!rdir)
        return -1;

    if (rdir-&gt;directory != INVALID_HANDLE_VALUE)
        FindClose(rdir-&gt;directory);

    if (rdir-&gt;orig_path)
        free(rdir-&gt;orig_path);
    free(rdir);
    return 0;
}

void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString)
{
    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
    EXPLICIT_ACCESSW ExplicitAccess         = { 0 };
    ACL* AccessControlCurrent               = NULL;
    ACL* AccessControlNew                   = NULL;
    SECURITY_INFORMATION SecurityInfo       = DACL_SECURITY_INFORMATION;
    PSID SecurityIdentifier                 = NULL;
    HANDLE original_file                    = CreateFileFromAppW(path,
          GENERIC_READ    | GENERIC_WRITE | WRITE_DAC,
          FILE_SHARE_READ | FILE_SHARE_WRITE,
          NULL, OPEN_EXISTING, 0, NULL);

    if (original_file != INVALID_HANDLE_VALUE)
    {
       if (
             GetSecurityInfo(
                original_file,
                SE_FILE_OBJECT,
                DACL_SECURITY_INFORMATION,
                NULL,
                NULL,
                &amp;AccessControlCurrent,
                NULL,
                &amp;SecurityDescriptor
                ) == ERROR_SUCCESS
          )
       {
          ConvertStringSidToSidW(AccessString, &amp;SecurityIdentifier);
          if (SecurityIdentifier)
          {
             ExplicitAccess.grfAccessPermissions= GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE;
             ExplicitAccess.grfAccessMode       = SET_ACCESS;
             ExplicitAccess.grfInheritance      = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
             ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
             ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
             ExplicitAccess.Trustee.ptstrName   = reinterpret_cast&lt;wchar_t*&gt;(SecurityIdentifier);

             if (
                   SetEntriesInAclW(
                      1,
                      &amp;ExplicitAccess,
                      AccessControlCurrent,
                      &amp;AccessControlNew
                      ) == ERROR_SUCCESS
                )
                SetSecurityInfo(
                      original_file,
                      SE_FILE_OBJECT,
                      SecurityInfo,
                      NULL,
                      NULL,
                      AccessControlNew,
                      NULL
                      );
          }
       }
       if (SecurityDescriptor)
          LocalFree(reinterpret_cast&lt;HLOCAL&gt;(SecurityDescriptor));
       if (AccessControlNew)
          LocalFree(reinterpret_cast&lt;HLOCAL&gt;(AccessControlNew));
       CloseHandle(original_file);
    }
}</pre>
<h2>./include/libretro-common/vulkan/vulkan_symbol_wrapper.c</h2>
<pre>
/* This header is autogenerated by vulkan_loader_generator.py */
#include &lt;vulkan/vulkan_symbol_wrapper.h&gt;

PFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;
PFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;
PFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;
PFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;
PFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;
PFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;
PFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;
PFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;
PFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;
PFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;
PFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;
PFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;
PFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;
PFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;
PFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;
PFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;
PFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;
PFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;
PFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;
PFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;
PFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;
PFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;
PFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;
PFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;
PFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;
PFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;
PFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;
PFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;
PFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;
PFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;
PFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;
PFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;
PFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;
PFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;
PFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;
PFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;
PFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;
PFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;
PFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;
PFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;
PFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;
PFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;
PFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;
PFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;
PFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;
PFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;
PFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;
PFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;
PFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;
PFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;
PFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;
PFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;
PFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;
PFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;
PFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;
PFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;
PFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;
PFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;
PFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;
PFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;
PFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;
PFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;
PFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;
PFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;
PFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;
PFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;
PFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;
PFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;
PFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;
PFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;
PFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;
PFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;
PFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;
PFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;
PFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;
PFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;
PFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;
PFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;
PFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;
PFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;
PFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;
PFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;
PFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;
PFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;
PFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;
PFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;
PFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;
PFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;
PFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;
PFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;
PFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;
PFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;
PFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;
PFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;
PFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;
PFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;
PFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;
PFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;
PFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;
PFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;
PFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;
PFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;
PFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;
PFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;
PFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;
PFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;
PFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;
PFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;
PFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;
PFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;
PFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;
PFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;
PFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;
PFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;
PFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;
PFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;
PFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;
PFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;
PFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;
PFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;
PFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;
PFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;
PFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;
PFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;
PFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;
PFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;
PFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;
PFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;
PFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;
PFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;
PFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;
PFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;
PFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;
PFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;
PFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;
PFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;
PFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;
PFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
PFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;
PFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;
PFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;
PFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;
PFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;
PFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;

PFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;
PFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;

static PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
void vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr)
{
    GetInstanceProcAddr = get_instance_proc_addr;
}

PFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void)
{
    return GetInstanceProcAddr;
}

VkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol)
{
    *ppSymbol = GetInstanceProcAddr(instance, name);
    return *ppSymbol != NULL;
}

VkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol)
{
    *ppSymbol = vkGetDeviceProcAddr(device, name);
    return *ppSymbol != NULL;
}

VkBool32 vulkan_symbol_wrapper_load_global_symbols(void)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkCreateInstance", vkCreateInstance)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceExtensionProperties", vkEnumerateInstanceExtensionProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceLayerProperties", vkEnumerateInstanceLayerProperties)) return VK_FALSE;
    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceVersion", vkEnumerateInstanceVersion);
    return VK_TRUE;
}

VkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyInstance", vkDestroyInstance)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumeratePhysicalDevices", vkEnumeratePhysicalDevices)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFeatures", vkGetPhysicalDeviceFeatures)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFormatProperties", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceImageFormatProperties", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceProperties", vkGetPhysicalDeviceProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceQueueFamilyProperties", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceMemoryProperties", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceProcAddr", vkGetDeviceProcAddr)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDevice", vkCreateDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDevice", vkDestroyDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceExtensionProperties", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceLayerProperties", vkEnumerateDeviceLayerProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceQueue", vkGetDeviceQueue)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueSubmit", vkQueueSubmit)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueWaitIdle", vkQueueWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDeviceWaitIdle", vkDeviceWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateMemory", vkAllocateMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeMemory", vkFreeMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkMapMemory", vkMapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkUnmapMemory", vkUnmapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFlushMappedMemoryRanges", vkFlushMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceMemoryCommitment", vkGetDeviceMemoryCommitment)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBindBufferMemory", vkBindBufferMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBindImageMemory", vkBindImageMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetBufferMemoryRequirements", vkGetBufferMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageMemoryRequirements", vkGetImageMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageSparseMemoryRequirements", vkGetImageSparseMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceSparseImageFormatProperties", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueBindSparse", vkQueueBindSparse)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateFence", vkCreateFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyFence", vkDestroyFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetFences", vkResetFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetFenceStatus", vkGetFenceStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkWaitForFences", vkWaitForFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateSemaphore", vkCreateSemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroySemaphore", vkDestroySemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateEvent", vkCreateEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyEvent", vkDestroyEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetEventStatus", vkGetEventStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkSetEvent", vkSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetEvent", vkResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateQueryPool", vkCreateQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyQueryPool", vkDestroyQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetQueryPoolResults", vkGetQueryPoolResults)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateBuffer", vkCreateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyBuffer", vkDestroyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateBufferView", vkCreateBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyBufferView", vkDestroyBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateImage", vkCreateImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyImage", vkDestroyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageSubresourceLayout", vkGetImageSubresourceLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateImageView", vkCreateImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyImageView", vkDestroyImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateShaderModule", vkCreateShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyShaderModule", vkDestroyShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreatePipelineCache", vkCreatePipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipelineCache", vkDestroyPipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPipelineCacheData", vkGetPipelineCacheData)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkMergePipelineCaches", vkMergePipelineCaches)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateGraphicsPipelines", vkCreateGraphicsPipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateComputePipelines", vkCreateComputePipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipeline", vkDestroyPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreatePipelineLayout", vkCreatePipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipelineLayout", vkDestroyPipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateSampler", vkCreateSampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroySampler", vkDestroySampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDescriptorSetLayout", vkCreateDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDescriptorSetLayout", vkDestroyDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDescriptorPool", vkCreateDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDescriptorPool", vkDestroyDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetDescriptorPool", vkResetDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateDescriptorSets", vkAllocateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeDescriptorSets", vkFreeDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkUpdateDescriptorSets", vkUpdateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateFramebuffer", vkCreateFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyFramebuffer", vkDestroyFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateRenderPass", vkCreateRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyRenderPass", vkDestroyRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetRenderAreaGranularity", vkGetRenderAreaGranularity)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateCommandPool", vkCreateCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyCommandPool", vkDestroyCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetCommandPool", vkResetCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateCommandBuffers", vkAllocateCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeCommandBuffers", vkFreeCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBeginCommandBuffer", vkBeginCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEndCommandBuffer", vkEndCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetCommandBuffer", vkResetCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindPipeline", vkCmdBindPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetViewport", vkCmdSetViewport)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetScissor", vkCmdSetScissor)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetLineWidth", vkCmdSetLineWidth)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetDepthBias", vkCmdSetDepthBias)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetBlendConstants", vkCmdSetBlendConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetDepthBounds", vkCmdSetDepthBounds)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilCompareMask", vkCmdSetStencilCompareMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilWriteMask", vkCmdSetStencilWriteMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilReference", vkCmdSetStencilReference)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindDescriptorSets", vkCmdBindDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindIndexBuffer", vkCmdBindIndexBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindVertexBuffers", vkCmdBindVertexBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDraw", vkCmdDraw)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndexed", vkCmdDrawIndexed)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndirect", vkCmdDrawIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndexedIndirect", vkCmdDrawIndexedIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDispatch", vkCmdDispatch)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDispatchIndirect", vkCmdDispatchIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyBuffer", vkCmdCopyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyImage", vkCmdCopyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBlitImage", vkCmdBlitImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyBufferToImage", vkCmdCopyBufferToImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyImageToBuffer", vkCmdCopyImageToBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdUpdateBuffer", vkCmdUpdateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdFillBuffer", vkCmdFillBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearColorImage", vkCmdClearColorImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearDepthStencilImage", vkCmdClearDepthStencilImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearAttachments", vkCmdClearAttachments)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResolveImage", vkCmdResolveImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetEvent", vkCmdSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResetEvent", vkCmdResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdWaitEvents", vkCmdWaitEvents)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdPipelineBarrier", vkCmdPipelineBarrier)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBeginQuery", vkCmdBeginQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdEndQuery", vkCmdEndQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResetQueryPool", vkCmdResetQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdWriteTimestamp", vkCmdWriteTimestamp)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyQueryPoolResults", vkCmdCopyQueryPoolResults)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdPushConstants", vkCmdPushConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBeginRenderPass", vkCmdBeginRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdNextSubpass", vkCmdNextSubpass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdEndRenderPass", vkCmdEndRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdExecuteCommands", vkCmdExecuteCommands)) return VK_FALSE;
    return VK_TRUE;
}

VkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyInstance", vkDestroyInstance)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumeratePhysicalDevices", vkEnumeratePhysicalDevices)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFeatures", vkGetPhysicalDeviceFeatures)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFormatProperties", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceImageFormatProperties", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceProperties", vkGetPhysicalDeviceProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceQueueFamilyProperties", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceMemoryProperties", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceProcAddr", vkGetDeviceProcAddr)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDevice", vkCreateDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceExtensionProperties", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceLayerProperties", vkEnumerateDeviceLayerProperties)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceSparseImageFormatProperties", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;
    return VK_TRUE;
}

VkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device)
{
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDevice", vkDestroyDevice)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetDeviceQueue", vkGetDeviceQueue)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueSubmit", vkQueueSubmit)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueWaitIdle", vkQueueWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDeviceWaitIdle", vkDeviceWaitIdle)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateMemory", vkAllocateMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeMemory", vkFreeMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkMapMemory", vkMapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkUnmapMemory", vkUnmapMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFlushMappedMemoryRanges", vkFlushMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetDeviceMemoryCommitment", vkGetDeviceMemoryCommitment)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBindBufferMemory", vkBindBufferMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBindImageMemory", vkBindImageMemory)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetBufferMemoryRequirements", vkGetBufferMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageMemoryRequirements", vkGetImageMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageSparseMemoryRequirements", vkGetImageSparseMemoryRequirements)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueBindSparse", vkQueueBindSparse)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateFence", vkCreateFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyFence", vkDestroyFence)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetFences", vkResetFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetFenceStatus", vkGetFenceStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkWaitForFences", vkWaitForFences)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateSemaphore", vkCreateSemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroySemaphore", vkDestroySemaphore)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateEvent", vkCreateEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyEvent", vkDestroyEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetEventStatus", vkGetEventStatus)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkSetEvent", vkSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetEvent", vkResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateQueryPool", vkCreateQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyQueryPool", vkDestroyQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetQueryPoolResults", vkGetQueryPoolResults)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateBuffer", vkCreateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyBuffer", vkDestroyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateBufferView", vkCreateBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyBufferView", vkDestroyBufferView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateImage", vkCreateImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyImage", vkDestroyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageSubresourceLayout", vkGetImageSubresourceLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateImageView", vkCreateImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyImageView", vkDestroyImageView)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateShaderModule", vkCreateShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyShaderModule", vkDestroyShaderModule)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreatePipelineCache", vkCreatePipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipelineCache", vkDestroyPipelineCache)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetPipelineCacheData", vkGetPipelineCacheData)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkMergePipelineCaches", vkMergePipelineCaches)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateGraphicsPipelines", vkCreateGraphicsPipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateComputePipelines", vkCreateComputePipelines)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipeline", vkDestroyPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreatePipelineLayout", vkCreatePipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipelineLayout", vkDestroyPipelineLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateSampler", vkCreateSampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroySampler", vkDestroySampler)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateDescriptorSetLayout", vkCreateDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDescriptorSetLayout", vkDestroyDescriptorSetLayout)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateDescriptorPool", vkCreateDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDescriptorPool", vkDestroyDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetDescriptorPool", vkResetDescriptorPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateDescriptorSets", vkAllocateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeDescriptorSets", vkFreeDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkUpdateDescriptorSets", vkUpdateDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateFramebuffer", vkCreateFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyFramebuffer", vkDestroyFramebuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateRenderPass", vkCreateRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyRenderPass", vkDestroyRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetRenderAreaGranularity", vkGetRenderAreaGranularity)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateCommandPool", vkCreateCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyCommandPool", vkDestroyCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetCommandPool", vkResetCommandPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateCommandBuffers", vkAllocateCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeCommandBuffers", vkFreeCommandBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBeginCommandBuffer", vkBeginCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkEndCommandBuffer", vkEndCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetCommandBuffer", vkResetCommandBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindPipeline", vkCmdBindPipeline)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetViewport", vkCmdSetViewport)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetScissor", vkCmdSetScissor)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetLineWidth", vkCmdSetLineWidth)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetDepthBias", vkCmdSetDepthBias)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetBlendConstants", vkCmdSetBlendConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetDepthBounds", vkCmdSetDepthBounds)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilCompareMask", vkCmdSetStencilCompareMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilWriteMask", vkCmdSetStencilWriteMask)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilReference", vkCmdSetStencilReference)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindDescriptorSets", vkCmdBindDescriptorSets)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindIndexBuffer", vkCmdBindIndexBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindVertexBuffers", vkCmdBindVertexBuffers)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDraw", vkCmdDraw)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndexed", vkCmdDrawIndexed)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndirect", vkCmdDrawIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndexedIndirect", vkCmdDrawIndexedIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDispatch", vkCmdDispatch)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDispatchIndirect", vkCmdDispatchIndirect)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyBuffer", vkCmdCopyBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyImage", vkCmdCopyImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBlitImage", vkCmdBlitImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyBufferToImage", vkCmdCopyBufferToImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyImageToBuffer", vkCmdCopyImageToBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdUpdateBuffer", vkCmdUpdateBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdFillBuffer", vkCmdFillBuffer)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearColorImage", vkCmdClearColorImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearDepthStencilImage", vkCmdClearDepthStencilImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearAttachments", vkCmdClearAttachments)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResolveImage", vkCmdResolveImage)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetEvent", vkCmdSetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResetEvent", vkCmdResetEvent)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdWaitEvents", vkCmdWaitEvents)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdPipelineBarrier", vkCmdPipelineBarrier)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBeginQuery", vkCmdBeginQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdEndQuery", vkCmdEndQuery)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResetQueryPool", vkCmdResetQueryPool)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdWriteTimestamp", vkCmdWriteTimestamp)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyQueryPoolResults", vkCmdCopyQueryPoolResults))
    {
#if 0
       /* Don't return false here. Would cause MESA Intel Ivy Bridge drivers to not work at all. */
       return VK_FALSE;
#endif
    }
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdPushConstants", vkCmdPushConstants)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBeginRenderPass", vkCmdBeginRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdNextSubpass", vkCmdNextSubpass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdEndRenderPass", vkCmdEndRenderPass)) return VK_FALSE;
    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdExecuteCommands", vkCmdExecuteCommands)) return VK_FALSE;
    return VK_TRUE;
}</pre>
<h2>./include/libretro.h</h2>
<pre>#ifndef LIBRETRO_H
#define LIBRETRO_H

#include &lt;stdint.h&gt;
#include &lt;stdbool.h&gt;   // &lt;&lt;-- needed for 'bool'

struct retro_game_geometry {
    unsigned width;
    unsigned height;
    unsigned max_width;
    unsigned max_height;
    float aspect_ratio;
};

typedef bool (*retro_environment_t)(unsigned cmd, void *data);

#endif</pre>

./make

## Using in RetroArch
Copy `libgameboy_perfect_core.so` into RetroArch cores folder and load a ROM (extensions: `.gb`, `.gbc`, `.gba`). The core will detect mode heuristically.

## Next steps
- Replace `cpu_stub` with a full LR35902 CPU and ARM7TDMI for GBA to get full emulation.
- Integrate APU for audio.

./makefile

CC ?= gcc
CFLAGS ?= -O2 -fPIC -Wall -Wextra -I./src
LDFLAGS ?= -shared
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
TARGET := libgameboy_perfect_core.so

all: $(TARGET)

$(TARGET): $(OBJ)
	$(CC) $(LDFLAGS) -o $@ $^

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -f $(OBJ) $(TARGET)

.PHONY: all clean

./project_source_html.sh

#!/bin/bash
# project_source_html.sh
# Generates a static HTML mirror of a local Git repo for readable file contents.

# CONFIGURATION
REPO_DIR="."   # path to your local repo
OUTPUT_FILE="./index.html"          # output HTML file
TITLE="gameboy-perfect-core Mirror"

# Check if repo exists
if [ ! -d "$REPO_DIR" ]; then
    echo "Error: Repo directory $REPO_DIR does not exist."
    exit 1
fi

# Start HTML
cat <<EOT > "$OUTPUT_FILE"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$TITLE</title>
<style>
body { font-family: monospace; background: #f4f4f4; padding: 1rem; }
h2 { margin-top: 2rem; font-size: 1rem; }
pre { background: #2d2d2d; color: #f8f8f2; padding: 0.5rem; overflow-x: auto; white-space: pre-wrap; border-radius: 4px; margin-bottom: 2rem; }
</style>
</head>
<body>
<h1>$TITLE</h1>
EOT

# Loop through all files in the repo
cd "$REPO_DIR"
# Find all regular files (exclude .git)
find . -type f ! -path "*/.git/*" | sort | while read -r file; do
    # Escape HTML characters
    content=$(sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g;' "$file")
    echo "<h2>$file</h2>" >> "$OUTPUT_FILE"
    echo "<pre>$content</pre>" >> "$OUTPUT_FILE"
done

# End HTML
cat <<EOT >> "$OUTPUT_FILE"
</body>
</html>
EOT

echo "Static HTML mirror generated: $OUTPUT_FILE"

./readme.md

# gameboy-perfect-core

Unified C libretro core scaffold supporting GB / GBC / GBA modes with a cycle-driven timing engine and pixel-perfect framebuffer output.

## Build (Linux)

./short_errors.txt

/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:1:7: error: expected identifier or ‘(’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:100: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:113: error: universal character \u2019 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:129: error: unknown type name ‘has’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2018 is not valid in an identifier
    2 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:2:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:3:9: error: stray ‘#’ in program
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2018 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:5:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:6:9: error: stray ‘#’ in program
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2018 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:8:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:86: error: expected ‘)’ before ‘->’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:116: error: expected ‘)’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:149: error: expected ‘)’ before ‘(’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:9:168: error: expected identifier or ‘(’ before ‘return’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:10:7: error: expected identifier or ‘(’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:100: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:113: error: universal character \u2019 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:129: error: unknown type name ‘has’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2018 is not valid in an identifier
   11 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:11:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:12:9: error: stray ‘#’ in program
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2018 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:14:96: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:60: error: expected ‘)’ before ‘->’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:90: error: expected ‘)’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:123: error: expected ‘)’ before ‘(’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:15:142: error: expected identifier or ‘(’ before ‘return’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:16:7: error: expected identifier or ‘(’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:100: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:113: error: universal character \u2019 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:129: error: unknown type name ‘has’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2018 is not valid in an identifier
   18 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:15:31: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:18:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:19:9: error: stray ‘#’ in program
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2018 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:21:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:22:9: error: stray ‘#’ in program
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2018 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:24:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:59: error: expected ‘)’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:92: error: expected ‘)’ before ‘(’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:25:111: error: expected identifier or ‘(’ before ‘return’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:26:7: error: expected identifier or ‘(’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:74: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:100: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:113: error: universal character \u2019 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:129: error: unknown type name ‘has’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘member’
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:136: error: unknown type name ‘member’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2018 is not valid in an identifier
   28 | /home/ubuntu/Desktop/gameboy-perfect-core/src/common/cpu.c:16:33: error: \u2018gb_cpu_t\u2019 {aka \u2018struct gb_cpu_s\u2019} has no member named \u2018freg\u2019
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:28:149: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:29:9: error: stray ‘#’ in program
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2018 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:31:95: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:32:9: error: stray ‘#’ in program
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2018 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:34:97: error: universal character \u2019 is not valid in an identifier
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:59: error: expected ‘)’ before ‘|’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:92: error: expected ‘)’ before ‘(’ token
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:35:111: error: expected identifier or ‘(’ before ‘return’
/home/ubuntu/Desktop/gameboy-perfect-core/src/common/apu.h:36:7: error: expected identifier or ‘(’ before ‘|’ token

./src/common/apu.c

#include "apu.h"
#include <math.h>
#include <string.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

// --- Helpers for tone generation ---
static inline float square_wave(double phase) {
    return (fmod(phase, 1.0) < 0.5) ? 1.0f : -1.0f;
}

static inline float noise_sample(uint16_t *lfsr) {
    // 15-bit LFSR used in Game Boy noise channel
    uint16_t bit = (*lfsr ^ (*lfsr >> 1)) & 1;
    *lfsr = (*lfsr >> 1) | (bit << 14);
    return ((*lfsr & 1) ? 1.0f : -1.0f);
}

// --- Initialization ---
void gb_apu_init(gb_apu_t *apu) {
    memset(apu, 0, sizeof(gb_apu_t));
    apu->volume = 0.3f;
    apu->noise_lfsr = 0x7FFF;
    apu->cycles_per_sample = 4194304 / GB_APU_SAMPLE_RATE; // ~95 cycles/sample
}

// --- Reset ---
void gb_apu_reset(gb_apu_t *apu) {
    gb_apu_init(apu);
}

// --- Step the APU by CPU cycles ---
void gb_apu_step(gb_apu_t *apu, int cycles) {
    apu->cycle_counter += cycles;
    if (apu->cycle_counter < apu->cycles_per_sample)
        return;

    apu->cycle_counter -= apu->cycles_per_sample;

    // --- Generate simple tone for each channel ---
    float mix = 0.0f;

    if (apu->ch1_enabled) {
        apu->ch1_phase += 440.0 / GB_APU_SAMPLE_RATE;
        mix += square_wave(apu->ch1_phase);
    }

    if (apu->ch2_enabled) {
        apu->ch2_phase += 660.0 / GB_APU_SAMPLE_RATE;
        mix += square_wave(apu->ch2_phase);
    }

    if (apu->ch3_enabled) {
        apu->ch3_phase += 880.0 / GB_APU_SAMPLE_RATE;
        mix += sinf(2.0f * M_PI * fmod(apu->ch3_phase, 1.0));
    }

    if (apu->ch4_enabled) {
        mix += noise_sample(&apu->noise_lfsr);
    }

    // Normalize mix
    mix *= 0.25f * apu->volume;

    // Output simple stereo panning (left/right equal)
    apu->left = mix;
    apu->right = mix;
}

// --- Retrieve current audio samples ---
float gb_apu_sample_left(gb_apu_t *apu) {
    return apu->left;
}

float gb_apu_sample_right(gb_apu_t *apu) {
    return apu->right;
}

./src/common/apu.h

#ifndef GB_APU_H
#define GB_APU_H

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

#define GB_APU_SAMPLE_RATE 44100

typedef struct {
    // Channel enable flags
    bool ch1_enabled;
    bool ch2_enabled;
    bool ch3_enabled;
    bool ch4_enabled;

    // Sound registers
    uint8_t ch1_regs[5];
    uint8_t ch2_regs[5];
    uint8_t ch3_regs[5];
    uint8_t ch4_regs[5];

    // Internal counters and phase accumulators
    double ch1_phase;
    double ch2_phase;
    double ch3_phase;
    double ch4_phase;

    // Noise generator state
    uint16_t noise_lfsr;

    // Master volume control
    float volume;

    // Frame sequencer counter
    uint32_t frame_seq;
    uint32_t cycles_per_sample;
    uint32_t cycle_counter;

    // Output mix buffer (mono or stereo)
    float left;
    float right;

} gb_apu_t;

// --- Public API ---
void gb_apu_init(gb_apu_t *apu);
void gb_apu_reset(gb_apu_t *apu);
void gb_apu_step(gb_apu_t *apu, int cycles);
float gb_apu_sample_left(gb_apu_t *apu);
float gb_apu_sample_right(gb_apu_t *apu);

#ifdef __cplusplus
}
#endif

#endif /* GB_APU_H */

./src/common/audio.c

#include "audio.h"

void audio_init(void) {}
void audio_sample(int16_t left, int16_t right) {}
void audio_update(void) {}

./src/common/audio.h

#ifndef AUDIO_H
#define AUDIO_H

#include <stdint.h>

void audio_init(void);
void audio_sample(int16_t left, int16_t right);
void audio_update(void);

#endif // AUDIO_H

./src/common/core_common.h

#ifndef CORE_COMMON_H
#define CORE_COMMON_H

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

// Modes
typedef enum {
    MODE_UNSET = 0,
    MODE_GB,
    MODE_GBC,
    MODE_GBA
} core_mode_t;

// Pixel type (8-bit grayscale for GB/GBC, 32-bit ARGB for GBA)
typedef uint32_t pixel_t;

// Screen dimensions
#define GB_WIDTH 160
#define GB_HEIGHT 144
#define GBA_WIDTH 240
#define GBA_HEIGHT 160

#endif // CORE_COMMON_H

./src/common/core_state.c

#include "core_state.h"
#include <string.h>

void gb_core_init(core_state_t* state, const uint8_t* rom_data, size_t rom_size) {
    memset(state, 0, sizeof(core_state_t));

    state->rom = rom_data;
    state->rom_size = rom_size;
    state->mmu = (gb_mmu_t*)malloc(sizeof(gb_mmu_t));
    if (!state->mmu) return;

    gb_mmu_reset(state->mmu);
    gb_cpu_init(&state->cpu);
    gb_ppu_init(&state->ppu);
    gb_apu_init(&state->apu);

    state->running = true;
}

void gb_core_reset(core_state_t* state) {
    gb_cpu_reset(&state->cpu);
    gb_ppu_reset(&state->ppu);
    gb_apu_reset(&state->apu);
    gb_mmu_reset(state->mmu);
}

void gb_core_step(core_state_t* state, int cycles) {
    gb_cpu_step(&state->cpu, state->mmu, cycles);
    gb_ppu_step(&state->ppu, cycles);
    gb_apu_step(&state->apu, cycles);
}

void gb_core_destroy(core_state_t* state) {
    if (state->mmu) {
        free(state->mmu);
        state->mmu = NULL;
    }
    state->running = false;
}

./src/common/core_state.h

#ifndef GB_CORE_STATE_H
#define GB_CORE_STATE_H

#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "mmu.h"
#include "cpu.h"
#include "ppu.h"
#include "apu.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct core_state_s {
    gb_cpu_t cpu;
    gb_ppu_t ppu;
    gb_apu_t apu;
    gb_mmu_t *mmu;        // dynamically allocated MMU
    const uint8_t *rom;   // pointer to loaded ROM data
    size_t rom_size;
    bool running;
} core_state_t;

void gb_core_init(core_state_t* state, const uint8_t* rom_data, size_t rom_size);
void gb_core_reset(core_state_t* state);
void gb_core_step(core_state_t* state, int cycles);
void gb_core_destroy(core_state_t* state);

#ifdef __cplusplus
}
#endif

#endif /* GB_CORE_STATE_H */

./src/common/cpu.c

#include "cpu.h"
#include "mmu.h"
#include "ppu.h"
#include "apu.h"
#include "core_state.h"
#include <stdint.h>
#include <string.h>

// CPU Flags
#define FLAG_Z 0x80
#define FLAG_N 0x40
#define FLAG_H 0x20
#define FLAG_C 0x10

#define SET_FLAG(cpu,f) ((cpu)->freg|=(f))
#define CLEAR_FLAG(cpu,f) ((cpu)->freg&=~(f))
#define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))

// Register helpers
static inline uint16_t get_bc(gb_cpu_t *cpu){return (cpu->b<<8)|cpu->c;}
static inline void set_bc(gb_cpu_t *cpu,uint16_t val){cpu->b=val>>8; cpu->c=val&0xFF;}
static inline uint16_t get_de(gb_cpu_t *cpu){return (cpu->d<<8)|cpu->e;}
static inline void set_de(gb_cpu_t *cpu,uint16_t val){cpu->d=val>>8; cpu->e=val&0xFF;}
static inline uint16_t get_hl(gb_cpu_t *cpu){return (cpu->h<<8)|cpu->l;}
static inline void set_hl(gb_cpu_t *cpu,uint16_t val){cpu->h=val>>8; cpu->l=val&0xFF;}

// Stack helpers
static inline void push_word(gb_cpu_t *cpu, mmu_t *mmu, uint16_t val){
    gb_mmu_write_byte(mmu,--cpu->sp,(val>>8)&0xFF);
    gb_mmu_write_byte(mmu,--cpu->sp,val&0xFF);
}
static inline uint16_t pop_word(gb_cpu_t *cpu, mmu_t *mmu){
    uint16_t val = gb_mmu_read_byte(mmu,cpu->sp++);
    val |= gb_mmu_read_byte(mmu,cpu->sp++)<<8;
    return val;
}

// Forward CB executor
static int gb_cpu_execute_cb(uint8_t cb_opcode, gb_cpu_t *cpu, core_state_t *state);

// Reset CPU
void gb_cpu_reset(gb_cpu_t *cpu){
    if(!cpu) return;
    memset(cpu,0,sizeof(gb_cpu_t));
    cpu->sp=0xFFFE;
    cpu->pc=0x0100;
    cpu->ime_enabled=0;
}

// Step CPU
void gb_cpu_step(gb_cpu_t *cpu, core_state_t *state){
    if(!cpu||!state||!state->mmu) return;

    uint8_t opcode = gb_mmu_read_byte(state->mmu,cpu->pc++);
    int cycles=0;

    if(opcode==0xCB){
        uint8_t cb_opcode=gb_mmu_read_byte(state->mmu,cpu->pc++);
        cycles=gb_cpu_execute_cb(cb_opcode,cpu,state);
    }else{
        switch(opcode){
            case 0x00: cycles=4; break; // NOP
            case 0x01: cpu->c=gb_mmu_read_byte(state->mmu,cpu->pc++);
                     cpu->b=gb_mmu_read_byte(state->mmu,cpu->pc++); cycles=12; break; // LD BC,nn
            case 0x02: gb_mmu_write_byte(state->mmu,get_bc(cpu),cpu->a); cycles=8; break; // LD (BC),A
            case 0x03: set_bc(cpu,get_bc(cpu)+1); cycles=8; break; // INC BC
            case 0x04: cpu->b++; UPDATE_FLAG(cpu,FLAG_Z,cpu->b==0);
                     CLEAR_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->b&0x0F)==0); cycles=4; break; // INC B
            case 0x05: cpu->b--; UPDATE_FLAG(cpu,FLAG_Z,cpu->b==0);
                     SET_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->b&0x0F)==0x0F); cycles=4; break; // DEC B
            case 0x06: cpu->b=gb_mmu_read_byte(state->mmu,cpu->pc++); cycles=8; break; // LD B,n
            case 0x07:{ uint8_t c=cpu->a>>7; cpu->a=(cpu->a<<1)|c; UPDATE_FLAG(cpu,FLAG_C,c); CLEAR_FLAG(cpu,FLAG_N|FLAG_H|FLAG_Z); cycles=4;}break; // RLCA
            case 0x08:{ uint16_t addr=gb_mmu_read_byte(state->mmu,cpu->pc++);
                        addr|=gb_mmu_read_byte(state->mmu,cpu->pc++)<<8;
                        gb_mmu_write_byte(state->mmu,addr,cpu->sp&0xFF);
                        gb_mmu_write_byte(state->mmu,addr+1,cpu->sp>>8);
                        cycles=20;}break; // LD (nn),SP
            case 0x09:{ uint16_t hl=get_hl(cpu); uint16_t bc=get_bc(cpu); uint32_t res=hl+bc;
                        CLEAR_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(hl&0x0FFF)+(bc&0x0FFF)>0x0FFF);
                        UPDATE_FLAG(cpu,FLAG_C,res>0xFFFF); set_hl(cpu,res&0xFFFF); cycles=8;}break; // ADD HL,BC
            case 0x0A: cpu->a=gb_mmu_read_byte(state->mmu,get_bc(cpu)); cycles=8; break; // LD A,(BC)
            case 0x0B: set_bc(cpu,get_bc(cpu)-1); cycles=8; break; // DEC BC
            case 0x0C: cpu->c++; UPDATE_FLAG(cpu,FLAG_Z,cpu->c==0); CLEAR_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->c&0x0F)==0); cycles=4; break; // INC C
            case 0x0D: cpu->c--; UPDATE_FLAG(cpu,FLAG_Z,cpu->c==0); SET_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->c&0x0F)==0x0F); cycles=4; break; // DEC C
            case 0x0E: cpu->c=gb_mmu_read_byte(state->mmu,cpu->pc++); cycles=8; break; // LD C,n
            case 0x0F:{ uint8_t c=cpu->a&1; cpu->a=(cpu->a>>1)|(c<<7); UPDATE_FLAG(cpu,FLAG_C,c); CLEAR_FLAG(cpu,FLAG_Z|FLAG_N|FLAG_H); cycles=4;}break; // RRCA
            case 0x10: cpu->halted=1; cpu->pc++; cycles=4; break; // STOP
            case 0x76: cpu->halted=1; cycles=4; break; // HALT
            case 0xF3: cpu->ime_enabled=0; cycles=4; break; // DI
            case 0xFB: cpu->ime_enabled=1; cycles=4; break; // EI
            default: cycles=4; break; // TODO: fill remaining opcodes
        }
    }

    gb_ppu_step(&state->ppu,cycles);
    gb_apu_step(&state->apu,cycles);
}

// CB-prefixed opcodes
static int gb_cpu_execute_cb(uint8_t cb_opcode, gb_cpu_t *cpu, core_state_t *state){
    switch(cb_opcode){
        case 0x00: cpu->b=(cpu->b<<1)|(cpu->b>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->b==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->b&0x80)!=0); return 8;
        case 0x01: cpu->c=(cpu->c<<1)|(cpu->c>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->c==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->c&0x80)!=0); return 8;
        case 0x02: cpu->d=(cpu->d<<1)|(cpu->d>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->d==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->d&0x80)!=0); return 8;
        case 0x03: cpu->e=(cpu->e<<1)|(cpu->e>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->e==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->e&0x80)!=0); return 8;
        case 0x04: cpu->h=(cpu->h<<1)|(cpu->h>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->h==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->h&0x80)!=0); return 8;
        case 0x05: cpu->l=(cpu->l<<1)|(cpu->l>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->l==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->l&0x80)!=0); return 8;
        case 0x06:{ uint16_t hl=get_hl(cpu); uint8_t val=gb_mmu_read_byte(state->mmu,hl); val=(val<<1)|(val>>7); gb_mmu_write_byte(state->mmu,hl,val); UPDATE_FLAG(cpu,FLAG_Z,val==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(val&0x80)!=0); return 16;}
        case 0x07: cpu->a=(cpu->a<<1)|(cpu->a>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->a==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->a&0x80)!=0); return 8;
        default: return 8; // TODO: implement all remaining CB opcodes (rotates, shifts, swaps, BIT/RES/SET)
    }
}

./src/common/cpu.h

#ifndef GB_CPU_H
#define GB_CPU_H

#include <stdint.h>
#include <stdbool.h>
#include "mmu.h"

#ifdef __cplusplus
extern "C" {
#endif

#define FLAG_Z 0x80
#define FLAG_N 0x40
#define FLAG_H 0x20
#define FLAG_C 0x10

typedef struct gb_cpu_s {
    uint8_t a, f;   // Accumulator & flags register
    uint8_t b, c;
    uint8_t d, e;
    uint8_t h, l;
    uint16_t sp;    // Stack pointer
    uint16_t pc;    // Program counter
    bool ime;       // Interrupt Master Enable
    bool halted;
    bool stopped;
} gb_cpu_t;

void gb_cpu_init(gb_cpu_t* cpu);
void gb_cpu_reset(gb_cpu_t* cpu);
void gb_cpu_step(gb_cpu_t* cpu, gb_mmu_t* mmu, int cycles);

// Flag helper macros
#define SET_FLAG(cpu, f)    ((cpu)->f |= (f))
#define CLEAR_FLAG(cpu, f)  ((cpu)->f &= ~(f))
#define IS_FLAG(cpu, f)     (((cpu)->f & (f)) != 0)
#define UPDATE_FLAG(cpu,f,cond) ((cond)?SET_FLAG(cpu,f):CLEAR_FLAG(cpu,f))

#ifdef __cplusplus
}
#endif

#endif /* GB_CPU_H */

./src/common/gba_cpu.c

#include "gba_cpu.h"

// Initialize CPU
void gba_cpu_init(gba_cpu_t *cpu, gba_mmu_t *mmu) {
    cpu->mmu = mmu;
    gba_cpu_reset(cpu);
}

// Reset CPU
void gba_cpu_reset(gba_cpu_t *cpu) {
    for (int i = 0; i < 16; i++)
        cpu->regs[i] = 0;
    cpu->regs[15] = 0x08000000; // PC starts at ROM base
    cpu->cpsr = 0x0000001F;     // Supervisor mode
}

// Step CPU (placeholder: advance PC)
void gba_cpu_step(gba_cpu_t *cpu) {
    // Fetch instruction (placeholder, 32-bit ARM instruction)
    uint32_t pc = cpu->regs[15];
    uint32_t instr = cpu->mmu->rom[pc - 0x08000000];

    // Decode & execute (placeholder)
    cpu->regs[15] += 4; // Advance PC by 4 bytes
}

./src/common/gba_cpu.h

#ifndef GBA_CPU_H
#define GBA_CPU_H

#include <stdint.h>
#include "gba_mmu.h"

typedef struct {
    uint32_t regs[16]; // R0-R15
    uint32_t cpsr;     // Current Program Status Register
    gba_mmu_t *mmu;    // Pointer to MMU
} gba_cpu_t;

void gba_cpu_init(gba_cpu_t *cpu, gba_mmu_t *mmu);
void gba_cpu_reset(gba_cpu_t *cpu);
void gba_cpu_step(gba_cpu_t *cpu);

#endif // GBA_CPU_H

./src/common/gba_cpu_step.c

#include "cpu.h"
#include "mmu.h"
#include "ppu.h"
#include "apu.h"
#include "core_state.h"

// Flag manipulation macros
#define FLAG_Z 0x80
#define FLAG_N 0x40
#define FLAG_H 0x20
#define FLAG_C 0x10

#define SET_FLAG(cpu, f)   ((cpu)->freg |= (f))
#define CLEAR_FLAG(cpu, f) ((cpu)->freg &= ~(f))
#define UPDATE_FLAG(cpu, f, cond) ((cond) ? SET_FLAG(cpu,f) : CLEAR_FLAG(cpu,f))

static inline uint16_t get_bc(gb_cpu_t *cpu) { return (cpu->b<<8)|cpu->c; }
static inline void set_bc(gb_cpu_t *cpu, uint16_t val) { cpu->b = val>>8; cpu->c = val&0xFF; }

static inline uint16_t get_de(gb_cpu_t *cpu) { return (cpu->d<<8)|cpu->e; }
static inline void set_de(gb_cpu_t *cpu, uint16_t val) { cpu->d = val>>8; cpu->e = val&0xFF; }

static inline uint16_t get_hl(gb_cpu_t *cpu) { return (cpu->h<<8)|cpu->l; }
static inline void set_hl(gb_cpu_t *cpu, uint16_t val) { cpu->h = val>>8; cpu->l = val&0xFF; }

static inline void push_word(gb_cpu_t *cpu, mmu_t *mmu, uint16_t val) {
    gb_mmu_write_byte(mmu, --cpu->sp, val>>8);
    gb_mmu_write_byte(mmu, --cpu->sp, val&0xFF);
}

static inline uint16_t pop_word(gb_cpu_t *cpu, mmu_t *mmu) {
    uint16_t val = gb_mmu_read_byte(mmu, cpu->sp++);
    val |= gb_mmu_read_byte(mmu, cpu->sp++)<<8;
    return val;
}

// Forward CB execution
static int gb_cpu_execute_cb(uint8_t cb_opcode, gb_cpu_t *cpu, core_state_t *state);

void gb_cpu_step(gb_cpu_t *cpu, core_state_t *state) {
    if (!cpu || !state || !state->mmu) return;

    uint8_t opcode = gb_mmu_read_byte(state->mmu, cpu->pc++);
    int cycles = 0;

    if (opcode == 0xCB) {
        uint8_t cb_opcode = gb_mmu_read_byte(state->mmu, cpu->pc++);
        cycles = gb_cpu_execute_cb(cb_opcode, cpu, state);
    } else {
        switch(opcode) {
            case 0x00: cycles=4; break; // NOP
            case 0x01: cpu->c=gb_mmu_read_byte(state->mmu,cpu->pc++);
                     cpu->b=gb_mmu_read_byte(state->mmu,cpu->pc++);
                     cycles=12; break; // LD BC,nn
            case 0x02: gb_mmu_write_byte(state->mmu,get_bc(cpu),cpu->a); cycles=8; break; // LD (BC),A
            case 0x03: set_bc(cpu,get_bc(cpu)+1); cycles=8; break; // INC BC
            case 0x04: cpu->b++; UPDATE_FLAG(cpu,FLAG_Z,cpu->b==0);
                     CLEAR_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->b&0x0F)==0);
                     cycles=4; break; // INC B
            case 0x05: cpu->b--; UPDATE_FLAG(cpu,FLAG_Z,cpu->b==0);
                     SET_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->b&0x0F)==0x0F);
                     cycles=4; break; // DEC B
            case 0x06: cpu->b=gb_mmu_read_byte(state->mmu,cpu->pc++); cycles=8; break; // LD B,n
            case 0x07: {
                uint8_t c = cpu->a>>7;
                cpu->a = (cpu->a<<1)|c;
                UPDATE_FLAG(cpu,FLAG_C,c);
                CLEAR_FLAG(cpu,FLAG_N|FLAG_H|FLAG_Z);
                cycles=4;
                break; // RLCA
            }
            case 0x08: {
                uint16_t addr = gb_mmu_read_byte(state->mmu,cpu->pc++);
                addr |= gb_mmu_read_byte(state->mmu,cpu->pc++)<<8;
                gb_mmu_write_byte(state->mmu,addr,cpu->sp&0xFF);
                gb_mmu_write_byte(state->mmu,addr+1,cpu->sp>>8);
                cycles=20; break; // LD (nn),SP
            }
            case 0x09: {
                uint16_t hl=get_hl(cpu);
                uint16_t bc=get_bc(cpu);
                uint32_t res=hl+bc;
                CLEAR_FLAG(cpu,FLAG_N);
                UPDATE_FLAG(cpu,FLAG_H,(hl&0x0FFF)+(bc&0x0FFF)>0x0FFF);
                UPDATE_FLAG(cpu,FLAG_C,res>0xFFFF);
                set_hl(cpu,res&0xFFFF); cycles=8; break; // ADD HL,BC
            }
            case 0x0A: cpu->a=gb_mmu_read_byte(state->mmu,get_bc(cpu)); cycles=8; break; // LD A,(BC)
            case 0x0B: set_bc(cpu,get_bc(cpu)-1); cycles=8; break; // DEC BC
            case 0x0C: cpu->c++; UPDATE_FLAG(cpu,FLAG_Z,cpu->c==0);
                     CLEAR_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->c&0x0F)==0); cycles=4; break; // INC C
            case 0x0D: cpu->c--; UPDATE_FLAG(cpu,FLAG_Z,cpu->c==0);
                     SET_FLAG(cpu,FLAG_N); UPDATE_FLAG(cpu,FLAG_H,(cpu->c&0x0F)==0x0F); cycles=4; break; // DEC C
            case 0x0E: cpu->c=gb_mmu_read_byte(state->mmu,cpu->pc++); cycles=8; break; // LD C,n
            case 0x0F: {
                uint8_t c=cpu->a&1; cpu->a=(cpu->a>>1)|(c<<7);
                UPDATE_FLAG(cpu,FLAG_C,c); CLEAR_FLAG(cpu,FLAG_Z|FLAG_N|FLAG_H); cycles=4; break; // RRCA
            }
            case 0x10: cpu->halted=1; cpu->pc++; cycles=4; break; // STOP
            case 0x76: cpu->halted=1; cycles=4; break; // HALT
            case 0xF3: cpu->ime_enabled=0; cycles=4; break; // DI
            case 0xFB: cpu->ime_enabled=1; cycles=4; break; // EI

            // TODO: Implement 0x20?0xFF (jumps, calls, loads, arithmetic, logic, RST, DAA, CPL, SCF, CCF)
            default: cycles=4; break; // fallback
        }
    }

    gb_ppu_step(&state->ppu, cycles);
    gb_apu_step(&state->apu, cycles);
}

// CB-prefixed instruction executor
static int gb_cpu_execute_cb(uint8_t cb_opcode, gb_cpu_t *cpu, core_state_t *state) {
    // Full 0xCB00?0xCBFF table goes here with shifts, rotates, swaps, BIT/RES/SET
    // Ensure correct cycles and flags
    // Example:
    switch(cb_opcode) {
        case 0x11: cpu->c = (cpu->c<<1)|(cpu->c>>7); UPDATE_FLAG(cpu,FLAG_Z,cpu->c==0); CLEAR_FLAG(cpu,FLAG_N|FLAG_H); UPDATE_FLAG(cpu,FLAG_C,(cpu->c&0x80)!=0); return 8;
        // ... all other 0xCB opcodes
        default: return 8;
    }
}

./src/common/gba_mmu.c

#include "gba_mmu.h"
#include <string.h>
#include <stdio.h>

void gba_mmu_init(gba_mmu_t *mmu) {
    gba_mmu_reset(mmu);
}

void gba_mmu_reset(gba_mmu_t *mmu) {
    memset(mmu->rom, 0, GBA_ROM_SIZE);
    memset(mmu->ram, 0, GBA_RAM_SIZE);
}

int gba_mmu_load_rom(gba_mmu_t *mmu, const void *data, size_t size) {
    if (size > GBA_ROM_SIZE) return -1;
    memcpy(mmu->rom, data, size);
    return 0;
}

./src/common/gba_mmu.h

#ifndef GBA_MMU_H
#define GBA_MMU_H

#include <stdint.h>
#include <stddef.h>

#define GBA_ROM_SIZE 0x02000000 // 32 MB max ROM
#define GBA_RAM_SIZE 0x00040000 // 256 KB internal RAM

typedef struct {
    uint8_t rom[GBA_ROM_SIZE];
    uint8_t ram[GBA_RAM_SIZE];
} gba_mmu_t;

void gba_mmu_init(gba_mmu_t *mmu);
void gba_mmu_reset(gba_mmu_t *mmu);
int gba_mmu_load_rom(gba_mmu_t *mmu, const void *data, size_t size);

#endif // GBA_MMU_H

./src/common/libretro.c

#include <libretro.h>
#include <stdlib.h>
#include <string.h>
#include "core_state.h"

// Core state
static core_state_t* state = NULL;

// Libretro callbacks
static retro_video_refresh_t video_cb;
static retro_audio_sample_t audio_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;

// Video buffer
static uint16_t video_buffer[160 * 144];

// Audio buffer (placeholder)
#define AUDIO_BUFFER_SIZE 2048
static int16_t audio_buffer[AUDIO_BUFFER_SIZE];
static size_t audio_index = 0;

// --- Libretro API functions ---

void retro_init(void) {
    state = gb_core_create();
}

void retro_deinit(void) {
    if (state) {
        gb_core_destroy(state);
        state = NULL;
    }
}

unsigned retro_api_version(void) {
    return RETRO_API_VERSION;
}

void retro_set_environment(retro_environment_t cb) {
    (void)cb;
}

void retro_set_video_refresh(retro_video_refresh_t cb) {
    video_cb = cb;
}

void retro_set_audio_sample(retro_audio_sample_t cb) {
    audio_cb = cb;
}

void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) {
    (void)cb; // not used, simple implementation
}

void retro_set_input_poll(retro_input_poll_t cb) {
    input_poll_cb = cb;
}

void retro_set_input_state(retro_input_state_t cb) {
    input_state_cb = cb;
}

void retro_reset(void) {
    if (state) {
        gb_cpu_reset(&state->cpu);
        gb_ppu_reset(&state->ppu);
        gb_apu_reset(&state->apu);
    }
}

// Load a ROM
bool retro_load_game(const struct retro_game_info *info) {
    if (!info || !info->data || !info->size) return false;

    gb_core_init(state, (const uint8_t*)info->data, info->size);
    return true;
}

void retro_unload_game(void) {
    // Free ROM data
    if (state && state->rom) {
        free(state->rom);
        state->rom = NULL;
        state->rom_size = 0;
    }
}

// Main run loop
void retro_run(void) {
    if (!state) return;

    input_poll_cb();

    // Step CPU, PPU, APU until a frame is ready
    do {
        int cycles = gb_cpu_step(&state->cpu, state);
        gb_ppu_step(&state->ppu, cycles);
        gb_apu_step(&state->apu, cycles);
    } while (!gb_core_frame_ready(state));

    // Video callback
    video_cb(state->ppu.framebuffer, 160, 144, 160 * sizeof(uint16_t));

    // Audio callback placeholder
    audio_cb(0, 0);
}

size_t retro_serialize_size(void) {
    return 0; // Not implemented
}

bool retro_serialize(void *data, size_t size) {
    return false;
}

bool retro_unserialize(const void *data, size_t size) {
    return false;
}

void retro_cheat_reset(void) {}
void retro_cheat_set(unsigned index, bool enabled, const char *code) {}
void retro_get_system_info(struct retro_system_info *info) {
    memset(info, 0, sizeof(*info));
    info->library_name = "GameBoy Perfect Core";
    info->library_version = "1.0";
    info->valid_extensions = "gb|gbc";
    info->need_fullpath = false;
    info->block_extract = false;
}

void retro_get_system_av_info(struct retro_system_av_info *info) {
    info->timing.fps = 59.73;
    info->timing.sample_rate = 44100.0;
    info->geometry.base_width = 160;
    info->geometry.base_height = 144;
    info->geometry.max_width = 160;
    info->geometry.max_height = 144;
    info->geometry.aspect_ratio = 160.0 / 144.0;
}

./src/common/mmu.c

#include "mmu.h"
#include <string.h>

// Initialize all MMU memory regions
void gb_mmu_reset(gb_mmu_t *mmu) {
    if (!mmu) return;

    memset(mmu->rom, 0, ROM_SIZE_MAX);
    memset(mmu->vram, 0, VRAM_SIZE);
    memset(mmu->eram, 0, EXTRAM_SIZE);
    memset(mmu->wram, 0, WRAM_SIZE);
    memset(mmu->oam, 0, OAM_SIZE);
    memset(mmu->io, 0, IO_SIZE);
    memset(mmu->hram, 0, HRAM_SIZE);
    mmu->ie = 0;
}

// Read a byte from the MMU
uint8_t gb_mmu_read_byte(gb_mmu_t *mmu, uint16_t addr) {
    if (!mmu) return 0xFF;

    if (addr <= 0x7FFF) {              // ROM
        return mmu->rom[addr];
    } else if (addr >= 0x8000 && addr <= 0x9FFF) { // VRAM
        return mmu->vram[addr - 0x8000];
    } else if (addr >= 0xA000 && addr <= 0xBFFF) { // External RAM
        return mmu->eram[addr - 0xA000];
    } else if (addr >= 0xC000 && addr <= 0xDFFF) { // Work RAM
        return mmu->wram[addr - 0xC000];
    } else if (addr >= 0xE000 && addr <= 0xFDFF) { // Echo RAM
        return mmu->wram[addr - 0xE000];
    } else if (addr >= 0xFE00 && addr <= 0xFE9F) { // OAM
        return mmu->oam[addr - 0xFE00];
    } else if (addr >= 0xFF00 && addr <= 0xFF7F) { // I/O registers
        return mmu->io[addr - 0xFF00];
    } else if (addr >= 0xFF80 && addr <= 0xFFFE) { // High RAM
        return mmu->hram[addr - 0xFF80];
    } else if (addr == 0xFFFF) {       // Interrupt Enable register
        return mmu->ie;
    }

    return 0xFF; // Default fallback
}

// Write a byte to the MMU
void gb_mmu_write_byte(gb_mmu_t *mmu, uint16_t addr, uint8_t val) {
    if (!mmu) return;

    if (addr <= 0x7FFF) {              // ROM is read-only
        return;
    } else if (addr >= 0x8000 && addr <= 0x9FFF) { // VRAM
        mmu->vram[addr - 0x8000] = val;
    } else if (addr >= 0xA000 && addr <= 0xBFFF) { // External RAM
        mmu->eram[addr - 0xA000] = val;
    } else if (addr >= 0xC000 && addr <= 0xDFFF) { // Work RAM
        mmu->wram[addr - 0xC000] = val;
    } else if (addr >= 0xE000 && addr <= 0xFDFF) { // Echo RAM
        mmu->wram[addr - 0xE000] = val;
    } else if (addr >= 0xFE00 && addr <= 0xFE9F) { // OAM
        mmu->oam[addr - 0xFE00] = val;
    } else if (addr >= 0xFF00 && addr <= 0xFF7F) { // I/O registers
        mmu->io[addr - 0xFF00] = val;
    } else if (addr >= 0xFF80 && addr <= 0xFFFE) { // High RAM
        mmu->hram[addr - 0xFF80] = val;
    } else if (addr == 0xFFFF) {       // Interrupt Enable register
        mmu->ie = val;
    }
}

// Read a 16-bit word from memory
uint16_t gb_mmu_read_word(gb_mmu_t *mmu, uint16_t addr) {
    uint8_t lo = gb_mmu_read_byte(mmu, addr);
    uint8_t hi = gb_mmu_read_byte(mmu, addr + 1);
    return (hi << 8) | lo;
}

// Write a 16-bit word to memory
void gb_mmu_write_word(gb_mmu_t *mmu, uint16_t addr, uint16_t val) {
    gb_mmu_write_byte(mmu, addr, val & 0xFF);
    gb_mmu_write_byte(mmu, addr + 1, (val >> 8) & 0xFF);
}

./src/common/mmu.h

#ifndef GB_MMU_H
#define GB_MMU_H

#include <stdint.h>
#include "core_state.h"

// Sizes for various memory regions
#define ROM_SIZE_MAX   0x8000  // 32KB for basic Gameboy ROM banking
#define VRAM_SIZE      0x2000  // 8KB
#define EXTRAM_SIZE    0x2000  // External cartridge RAM
#define WRAM_SIZE      0x2000  // Work RAM (internal)
#define OAM_SIZE       0xA0    // Sprite attribute table
#define IO_SIZE        0x80    // I/O registers
#define HRAM_SIZE      0x7F    // High RAM

typedef struct gb_mmu_s {
    uint8_t rom[ROM_SIZE_MAX];
    uint8_t vram[VRAM_SIZE];
    uint8_t eram[EXTRAM_SIZE];
    uint8_t wram[WRAM_SIZE];
    uint8_t oam[OAM_SIZE];
    uint8_t io[IO_SIZE];
    uint8_t hram[HRAM_SIZE];
    uint8_t ie;          // Interrupt Enable register
} gb_mmu_t;

// Initialize MMU
void gb_mmu_reset(gb_mmu_t *mmu);

// Read a byte from memory (address in 0x0000-0xFFFF)
uint8_t gb_mmu_read_byte(gb_mmu_t *mmu, uint16_t addr);

// Write a byte to memory (address in 0x0000-0xFFFF)
void gb_mmu_write_byte(gb_mmu_t *mmu, uint16_t addr, uint8_t val);

// Read a word (16-bit) from memory
uint16_t gb_mmu_read_word(gb_mmu_t *mmu, uint16_t addr);

// Write a word (16-bit) to memory
void gb_mmu_write_word(gb_mmu_t *mmu, uint16_t addr, uint16_t val);

#endif // GB_MMU_H

./src/common/ppu.c

#include "ppu.h"
#include "core_state.h"
#include <string.h>
#include <stdint.h>

#define SCREEN_WIDTH 160
#define SCREEN_HEIGHT 144
#define CYCLES_PER_SCANLINE 456
#define TOTAL_SCANLINES 154

// Reset PPU state
void gb_ppu_reset(gb_ppu_t *ppu) {
    if (!ppu) return;
    memset(ppu, 0, sizeof(gb_ppu_t));
}

// Step the PPU for a number of CPU cycles
void gb_ppu_step(gb_ppu_t *ppu, int cycles) {
    if (!ppu) return;

    ppu->cycle += cycles;

    while (ppu->cycle >= CYCLES_PER_SCANLINE) {
        ppu->cycle -= CYCLES_PER_SCANLINE;
        ppu->line++;

        if (ppu->line < SCREEN_HEIGHT) {
            // Render this scanline to framebuffer
            // For simplicity, fill with some dummy data for now
            for (int x = 0; x < SCREEN_WIDTH; x++) {
                ppu->framebuffer[ppu->line * SCREEN_WIDTH + x] = 0; // Replace 0 with actual pixel rendering logic
            }
        }

        if (ppu->line == SCREEN_HEIGHT) {
            ppu->frame_ready = 1; // Frame is ready to be drawn
        }

        if (ppu->line >= TOTAL_SCANLINES) {
            ppu->line = 0; // Restart vertical scanlines
        }
    }
}

// Query if a frame is ready
int gb_ppu_frame_ready(gb_ppu_t *ppu) {
    if (!ppu) return 0;
    if (ppu->frame_ready) {
        ppu->frame_ready = 0; // Reset flag
        return 1;
    }
    return 0;
}

./src/common/ppu.h

#ifndef GB_PPU_H
#define GB_PPU_H

#include <stdint.h>

#define SCREEN_WIDTH 160
#define SCREEN_HEIGHT 144

typedef struct gb_ppu_s {
    uint16_t framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT]; // Pixel data for screen
    int cycle;        // Current cycle within scanline
    int line;         // Current vertical scanline (0-153)
    int frame_ready;  // Flag indicating a frame is ready
} gb_ppu_t;

// Reset the PPU state
void gb_ppu_reset(gb_ppu_t *ppu);

// Step the PPU by a number of CPU cycles
void gb_ppu_step(gb_ppu_t *ppu, int cycles);

// Query if a frame is ready to be drawn
int gb_ppu_frame_ready(gb_ppu_t *ppu);

#endif // GB_PPU_H

./src/common/timing.c

#include "timing.h"
#include "core_state.h"

// Timing-specific function
uint64_t cycles_per_frame_for_mode(core_mode_t m) {
    switch (m) {
        case MODE_GBA: return 16777216ULL / 60ULL; // ~279620 cycles/frame
        default: return 4194304ULL / 60ULL;       // ~69905 cycles/frame
    }
}

./src/common/timing.h

#ifndef TIMING_H
#define TIMING_H

#include <stdint.h>
#include "core_common.h"

uint64_t cycles_per_frame_for_mode(core_mode_t m);

#endif // TIMING_H

./src/gba/core_state.c

#include "cpu.h"
#include "core_state.h"
#include <stdlib.h>
#include <string.h>

bool gba_core_init(gba_core_t *core) {
    if (!core) return false;
    core->mode = MODE_GBA;
    core->rom = NULL;
    core->rom_size = 0;
    core->cycles = 0;
    core->rom_loaded = false;
    memset(core->ram, 0, sizeof(core->ram));
    return true;
}

void gba_core_reset(gba_core_t *core) {
    if (!core) return;
    core->cycles = 0;
    memset(core->ram, 0, sizeof(core->ram));
}

bool gba_core_load_rom(gba_core_t *core, const uint8_t *data, size_t size) {
    if (!core || !data || size == 0 || size > GBA_ROM_MAX_SIZE) return false;

    if (core->rom) free(core->rom);
    core->rom = (uint8_t *)malloc(size);
    if (!core->rom) return false;

    memcpy(core->rom, data, size);
    core->rom_size = size;
    core->rom_loaded = true;
    return true;
}

void gba_core_unload_rom(gba_core_t *core) {
    if (!core) return;
    if (core->rom) {
        free(core->rom);
        core->rom = NULL;
    }
    core->rom_size = 0;
    core->rom_loaded = false;
    memset(core->ram, 0, sizeof(core->ram));
    core->cycles = 0;
}

./src/gba/core_state.h

#ifndef GBA_CORE_STATE_H
#define GBA_CORE_STATE_H

#include <stdint.h>
#include <stdbool.h>
#include "core_common.h"

// GBA memory layout
#define GBA_RAM_SIZE       0x00040000
#define GBA_ROM_MAX_SIZE   0x02000000

typedef struct {
    core_mode_t mode;      // CORE_GBA
    uint8_t *rom;
    size_t rom_size;
    uint8_t ram[GBA_RAM_SIZE];
    uint64_t cycles;
    bool rom_loaded;
} gba_core_t;

// Core management
bool gba_core_init(gba_core_t *core);
void gba_core_reset(gba_core_t *core);
bool gba_core_load_rom(gba_core_t *core, const uint8_t *data, size_t size);
void gba_core_unload_rom(gba_core_t *core);

#endif // GBA_CORE_STATE_H

./src/gba/cpu.c

#include "cpu.h"

// Initialize CPU and connect to MMU
void gba_cpu_init(gba_cpu_t *cpu, gba_mmu_t *mmu) {
    if (!cpu || !mmu) return;
    for (int i = 0; i < 16; i++) cpu->regs[i] = 0;
    cpu->cpsr = 0x00000000;
    cpu->mmu = mmu;
}

// Fetch 32-bit instruction from memory
uint32_t gba_cpu_fetch32(gba_cpu_t *cpu, uint32_t addr) {
    if (!cpu || !cpu->mmu) return 0xFFFFFFFF;
    uint32_t val = 0;
    val |= cpu->mmu->rom[addr - 0x08000000];
    val |= cpu->mmu->rom[addr - 0x08000000 + 1] << 8;
    val |= cpu->mmu->rom[addr - 0x08000000 + 2] << 16;
    val |= cpu->mmu->rom[addr - 0x08000000 + 3] << 24;
    return val;
}

// Minimal CPU step (placeholder)
void gba_cpu_step(gba_cpu_t *cpu) {
    // TODO: implement ARM7TDMI instruction decoding
    cpu->regs[15] += 4; // increment PC
}

./src/gba/cpu.h

#ifndef GBA_CPU_H
#define GBA_CPU_H

#include <stdint.h>
#include "gba_mmu.h"

typedef struct gba_cpu_t {
    uint32_t regs[16];       // R0-R15
    uint32_t cpsr;           // Current Program Status Register
    gba_mmu_t *mmu;          // pointer to MMU
} gba_cpu_t;

void gba_cpu_init(gba_cpu_t *cpu, gba_mmu_t *mmu);
uint32_t gba_cpu_fetch32(gba_cpu_t *cpu, uint32_t addr);
void gba_cpu_step(gba_cpu_t *cpu);  // execute one instruction (placeholder)

#endif // GBA_CPU_H

./src/gba/cpu_stub.c

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gba/cpu_stub.h

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gba/gba_apu.c

#include "gba_apu.h"
#include <string.h>

void gba_apu_init(gba_apu_t *apu) {
    apu->buffer_pos = 0;
    memset(apu->buffer, 0, sizeof(apu->buffer));
}

void gba_apu_reset(gba_apu_t *apu) {
    apu->buffer_pos = 0;
    memset(apu->buffer, 0, sizeof(apu->buffer));
}

void gba_apu_step(gba_apu_t *apu, int cycles) {
    // Skeleton: just advance buffer position
    apu->buffer_pos = (apu->buffer_pos + cycles) % 4096;
}

./src/gba/gba_apu.h

#ifndef GBA_APU_H
#define GBA_APU_H

#include <stdint.h>

typedef struct {
    // Simple audio buffer
    int16_t buffer[4096];
    size_t buffer_pos;
} gba_apu_t;

// Initialize APU
void gba_apu_init(gba_apu_t *apu);

// Reset
void gba_apu_reset(gba_apu_t *apu);

// Step audio cycles
void gba_apu_step(gba_apu_t *apu, int cycles);

#endif // GBA_APU_H

./src/gba/gba_core.c

#include "cpu.h"
#include "gba_mmu.h"
#include "gba_ppu.h"

typedef struct gba_core_t {
    gba_mmu_t mmu;
    gba_cpu_t cpu;
    gba_ppu_t ppu;
} gba_core_t;

void gba_core_init(gba_core_t *core, uint8_t *rom, uint32_t rom_size) {
    gba_mmu_init(&core->mmu, rom, rom_size);
    gba_cpu_init(&core->cpu, &core->mmu);
    gba_ppu_init(&core->ppu, &core->mmu);
}

void gba_core_step(gba_core_t *core) {
    gba_cpu_step(&core->cpu);
    gba_ppu_step(&core->ppu);
}

./src/gba/gba_cpu.c

#include "gba_cpu.h"
#include <string.h>

void gba_cpu_init(gba_cpu_t *cpu, uint8_t *memory) {
    cpu->memory = memory;
    memset(cpu->regs, 0, sizeof(cpu->regs));
    cpu->cpsr = 0;
}

void gba_cpu_reset(gba_cpu_t *cpu) {
    memset(cpu->regs, 0, sizeof(cpu->regs));
    cpu->cpsr = 0;
    cpu->regs[15] = 0x08000000; // typical entry for GBA ROM
}

void gba_cpu_step(gba_cpu_t *cpu, int cycles) {
    // Skeleton: Just increment PC
    for (int i = 0; i < cycles; i++) {
        cpu->regs[15] += 4; // move PC forward
    }
}

./src/gba/gba_cpu.h

#ifndef GBA_CPU_H
#define GBA_CPU_H

#include <stdint.h>
#include <stddef.h>

typedef struct {
    uint32_t regs[16]; // R0-R15
    uint32_t cpsr;     // Current Program Status Register
    uint8_t *memory;   // pointer to MMU memory
} gba_cpu_t;

// Initialize CPU
void gba_cpu_init(gba_cpu_t *cpu, uint8_t *memory);

// Reset CPU
void gba_cpu_reset(gba_cpu_t *cpu);

// Execute N cycles
void gba_cpu_step(gba_cpu_t *cpu, int cycles);

#endif // GBA_CPU_H

./src/gba/gba_mmu.c

#include "gba_mmu.h"
#include <string.h>

void gba_mmu_init(gba_mmu_t *mmu) {
    memset(mmu->mem, 0, sizeof(mmu->mem));
}

uint8_t gba_mmu_read8(gba_mmu_t *mmu, uint32_t addr) {
    return mmu->mem[addr % GBA_MEM_SIZE];
}

void gba_mmu_write8(gba_mmu_t *mmu, uint32_t addr, uint8_t value) {
    mmu->mem[addr % GBA_MEM_SIZE] = value;
}

./src/gba/gba_mmu.h

#ifndef GBA_MMU_H
#define GBA_MMU_H

#include <stdint.h>
#include <stddef.h>

#define GBA_MEM_SIZE 0x02000000 // 32MB address space

typedef struct {
    uint8_t mem[GBA_MEM_SIZE];
} gba_mmu_t;

// Initialize MMU
void gba_mmu_init(gba_mmu_t *mmu);

// Read/write helpers
uint8_t gba_mmu_read8(gba_mmu_t *mmu, uint32_t addr);
void gba_mmu_write8(gba_mmu_t *mmu, uint32_t addr, uint8_t value);

#endif // GBA_MMU_H

./src/gba/gba_ppu.c

#include "gba_ppu.h"
#include <string.h>

void gba_ppu_init(gba_ppu_t *ppu, void *mmu) {
    (void)mmu; // unused in skeleton
    memset(ppu->framebuffer, 0, sizeof(ppu->framebuffer));
}

void gba_ppu_reset(gba_ppu_t *ppu) {
    memset(ppu->framebuffer, 0, sizeof(ppu->framebuffer));
}

// Simple PPU step; fills framebuffer with dummy gradient for now
void gba_ppu_step(gba_ppu_t *ppu) {
    for(int y = 0; y < GBA_HEIGHT; y++) {
        for(int x = 0; x < GBA_WIDTH; x++) {
            uint8_t r = (x * 255) / GBA_WIDTH;
            uint8_t g = (y * 255) / GBA_HEIGHT;
            uint8_t b = ((x + y) * 255) / (GBA_WIDTH + GBA_HEIGHT);
            ppu->framebuffer[y][x] = (0xFF << 24) | (r << 16) | (g << 8) | b;
        }
    }
}

./src/gba/gba_ppu.h

#ifndef GBA_PPU_H
#define GBA_PPU_H

#include <stdint.h>
#include <stddef.h>

#define GBA_WIDTH 240
#define GBA_HEIGHT 160

typedef struct {
    uint32_t framebuffer[GBA_HEIGHT][GBA_WIDTH];
    // Add other PPU state as needed (BG, OBJ, layers)
} gba_ppu_t;

// Initialize PPU with pointer to MMU (if needed)
void gba_ppu_init(gba_ppu_t *ppu, void *mmu);

// Reset PPU state
void gba_ppu_reset(gba_ppu_t *ppu);

// Step PPU for a single frame / scanline
void gba_ppu_step(gba_ppu_t *ppu);

#endif // GBA_PPU_H

./src/gba/mmu.c

#include "mmu.h"
#include <string.h>

bool gba_mmu_init(gba_mmu_t *mmu, uint8_t *bios, uint8_t *rom, uint32_t rom_size) {
    if (!mmu || !bios || !rom || rom_size == 0) return false;

    mmu->bios = bios;
    mmu->rom = rom;
    mmu->rom_size = rom_size;

    memset(mmu->wram, 0, sizeof(mmu->wram));
    memset(mmu->ewram, 0, sizeof(mmu->ewram));
    memset(mmu->io_regs, 0, sizeof(mmu->io_regs));

    return true;
}

void gba_mmu_reset(gba_mmu_t *mmu) {
    if (!mmu) return;
    memset(mmu->wram, 0, sizeof(mmu->wram));
    memset(mmu->ewram, 0, sizeof(mmu->ewram));
    memset(mmu->io_regs, 0, sizeof(mmu->io_regs));
}

uint8_t gba_mmu_read8(gba_mmu_t *mmu, uint32_t addr) {
    if (!mmu) return 0xFF;

    if (addr < 0x400000) return mmu->bios[addr];        // BIOS
    if (addr >= 0x2000000 && addr < 0x2000000 + GBA_RAM_SIZE) return mmu->wram[addr - 0x2000000];
    if (addr >= 0x3000000 && addr < 0x3000000 + GBA_EWRAM_SIZE) return mmu->ewram[addr - 0x3000000];
    if (addr >= 0x4000000 && addr < 0x4000000 + GBA_IO_SIZE) return mmu->io_regs[addr - 0x4000000];
    if (addr >= 0x8000000 && addr < 0x8000000 + mmu->rom_size) return mmu->rom[addr - 0x8000000];

    return 0xFF; // unmapped
}

uint16_t gba_mmu_read16(gba_mmu_t *mmu, uint32_t addr) {
    uint8_t lo = gba_mmu_read8(mmu, addr);
    uint8_t hi = gba_mmu_read8(mmu, addr + 1);
    return lo | (hi << 8);
}

uint32_t gba_mmu_read32(gba_mmu_t *mmu, uint32_t addr) {
    uint16_t lo = gba_mmu_read16(mmu, addr);
    uint16_t hi = gba_mmu_read16(mmu, addr + 2);
    return lo | (hi << 16);
}

void gba_mmu_write8(gba_mmu_t *mmu, uint32_t addr, uint8_t value) {
    if (!mmu) return;

    if (addr >= 0x2000000 && addr < 0x2000000 + GBA_RAM_SIZE) mmu->wram[addr - 0x2000000] = value;
    else if (addr >= 0x3000000 && addr < 0x3000000 + GBA_EWRAM_SIZE) mmu->ewram[addr - 0x3000000] = value;
    else if (addr >= 0x4000000 && addr < 0x4000000 + GBA_IO_SIZE) mmu->io_regs[addr - 0x4000000] = value;
}

void gba_mmu_write16(gba_mmu_t *mmu, uint32_t addr, uint16_t value) {
    gba_mmu_write8(mmu, addr, value & 0xFF);
    gba_mmu_write8(mmu, addr + 1, value >> 8);
}

void gba_mmu_write32(gba_mmu_t *mmu, uint32_t addr, uint32_t value) {
    gba_mmu_write16(mmu, addr, value & 0xFFFF);
    gba_mmu_write16(mmu, addr + 2, value >> 16);
}

./src/gba/mmu.h

#ifndef GBA_MMU_H
#define GBA_MMU_H

#include <stdint.h>
#include <stdbool.h>
#include "cpu.h"
#include "core_common.h"

// Memory sizes
#define GBA_RAM_SIZE     0x40000     // 256KB internal working RAM
#define GBA_EWRAM_SIZE   0x40000     // External WRAM (256KB)
#define GBA_IO_SIZE      0x400       // IO registers

typedef struct {
    uint8_t wram[GBA_RAM_SIZE];
    uint8_t ewram[GBA_EWRAM_SIZE];
    uint8_t io_regs[GBA_IO_SIZE];
    uint8_t *bios;          // Pointer to 16KB BIOS
    uint8_t *rom;           // Pointer to cartridge ROM
    uint32_t rom_size;
} gba_mmu_t;

// MMU lifecycle
bool gba_mmu_init(gba_mmu_t *mmu, uint8_t *bios, uint8_t *rom, uint32_t rom_size);
void gba_mmu_reset(gba_mmu_t *mmu);

// Memory access
uint8_t  gba_mmu_read8(gba_mmu_t *mmu, uint32_t addr);
uint16_t gba_mmu_read16(gba_mmu_t *mmu, uint32_t addr);
uint32_t gba_mmu_read32(gba_mmu_t *mmu, uint32_t addr);

void gba_mmu_write8(gba_mmu_t *mmu, uint32_t addr, uint8_t value);
void gba_mmu_write16(gba_mmu_t *mmu, uint32_t addr, uint16_t value);
void gba_mmu_write32(gba_mmu_t *mmu, uint32_t addr, uint32_t value);

#endif // GBA_MMU_H

./src/gba/ppu.c

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gba/ppu.h

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gb/apu.h

#ifndef GB_APU_H
#define GB_APU_H

typedef struct gb_apu_s {
    // Example APU state
    unsigned char nr10, nr11, nr12, nr13, nr14;
} gb_apu_t;

void gb_apu_reset( gb_apu_t *apu );

#endif // GB_APU_H

./src/gb/cpu.c

#include "cpu.h"
#include "../common/core_state.h"
#include "mmu.h"
#include "ppu.h"
#include "gb_apu.h"
#include <stdbool.h>
#include <stdint.h>

// Reset CPU registers and flags
void gb_cpu_reset(gb_cpu_t *cpu) {
    cpu->reg.af = 0x01B0;
    cpu->reg.bc = 0x0013;
    cpu->reg.de = 0x00D8;
    cpu->reg.hl = 0x014D;
    cpu->reg.sp = 0xFFFE;
    cpu->reg.pc = 0x0100;
    cpu->ime = true;
    cpu->halted = false;
}

// Fetch next byte from memory
static uint8_t fetch_byte(core_state_t *state) {
    uint8_t val = gb_mmu_read_byte(&state->mmu, state->cpu.reg.pc);
    state->cpu.reg.pc++;
    return val;
}

// Fetch next word (2 bytes) from memory
static uint16_t fetch_word(core_state_t *state) {
    uint8_t low = fetch_byte(state);
    uint8_t high = fetch_byte(state);
    return (high << 8) | low;
}

// Step CPU one instruction
void gb_cpu_step(core_state_t *state) {
    uint8_t opcode = fetch_byte(state);

    switch (opcode) {
        case 0x00: /* NOP */
            break;

        case 0xAF: /* XOR A */
            state->cpu.reg.af ^= state->cpu.reg.af;
            // Clear flags after XOR A
            state->cpu.reg.f = 0x80;
            break;

        default:
            // Unimplemented opcode
            // For now, just ignore or log
            break;
    }

    // Advance PPU and APU cycles
    gb_ppu_tick(&state->ppu);
    gb_apu_tick(&state->apu);
}

./src/gb/cpu.h

#ifndef GB_CPU_H
#define GB_CPU_H

#include <stdint.h>
#include <stdbool.h>

// Forward declaration so struct name is known
typedef struct core_state_s core_state_t;

// CPU register structure
typedef struct {
    union {
        struct { uint8_t f; uint8_t a; };
        uint16_t af;
    };
    union {
        struct { uint8_t c; uint8_t b; };
        uint16_t bc;
    };
    union {
        struct { uint8_t e; uint8_t d; };
        uint16_t de;
    };
    union {
        struct { uint8_t l; uint8_t h; };
        uint16_t hl;
    };
    uint16_t sp;
    uint16_t pc;
} gb_registers_t;

// CPU state structure
typedef struct {
    gb_registers_t reg;
    bool ime;
    bool halted;
} gb_cpu_t;

void gb_cpu_reset(gb_cpu_t *cpu);
void gb_cpu_step(core_state_t *state);

#endif // GB_CPU_H

./src/gb/cpu_stub.c

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gb/cpu_stub.h

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gb/gb_apu.c

#include "gb_apu.h"
#include <string.h>
#include <stdbool.h>

void gb_apu_init(gb_apu_t *apu) {
    if (!apu) return;
    memset(apu, 0, sizeof(gb_apu_t));
    apu->sample_rate = 44100;
    apu->enabled = true;
    apu->cycles = 0;
}

void gb_apu_reset(gb_apu_t *apu) {
    if (!apu) return;
    apu->sample_rate = 44100;
    apu->enabled = true;
    apu->cycles = 0;
}

// Tick once per CPU cycle
void gb_apu_tick(gb_apu_t *apu) {
    if (!apu || !apu->enabled) return;
    apu->cycles++;
    // In future, generate samples or handle sound registers here.
}

// Advance by N CPU cycles
void gb_apu_step(gb_apu_t *apu, int cycles) {
    if (!apu || !apu->enabled) return;
    apu->cycles += cycles;
}

./src/gb/gb_apu.h

#ifndef GB_APU_H
#define GB_APU_H

#include <stdint.h>
#include <stdbool.h>

// Simple Game Boy APU (Audio Processing Unit) state
typedef struct {
    bool enabled;          // Whether the APU is active
    int sample_rate;       // Sample output rate (Hz)
    uint32_t cycles;       // Internal cycle counter
} gb_apu_t;

// Initialize or reset APU
void gb_apu_init(gb_apu_t *apu);
void gb_apu_reset(gb_apu_t *apu);

// Run APU for one tick (called every CPU cycle)
void gb_apu_tick(gb_apu_t *apu);

// Step APU by a number of cycles (used by CPU)
void gb_apu_step(gb_apu_t *apu, int cycles);

#endif // GB_APU_H

./src/gb/gb_cart.c

#include "gb_cart.h"
#include <string.h>

void gb_cart_init(gb_cart_t *cart) {
    if (!cart) return;
    memset(cart, 0, sizeof(gb_cart_t));
}

bool gb_cart_load(gb_cart_t *cart, const uint8_t *data, size_t size) {
    if (!cart || !data || size == 0) return false;
    size_t copy_size = size < sizeof(cart->rom) ? size : sizeof(cart->rom);
    memcpy(cart->rom, data, copy_size);
    cart->loaded = true;
    return true;
}

void gb_cart_unload(gb_cart_t *cart) {
    if (!cart) return;
    memset(cart, 0, sizeof(gb_cart_t));
}

./src/gb/gb_cart.h

#ifndef GB_CART_H
#define GB_CART_H

#include <stdint.h>
#include <stdbool.h>

typedef struct gb_cart_s {
    uint8_t rom[0x8000];  // simplified fixed ROM area
    uint8_t ram[0x2000];  // simplified cartridge RAM
    bool loaded;
} gb_cart_t;

void gb_cart_init(gb_cart_t *cart);
bool gb_cart_load(gb_cart_t *cart, const uint8_t *data, size_t size);
void gb_cart_unload(gb_cart_t *cart);

#endif // GB_CART_H

./src/gb/gb_input.c

#include "gb_input.h"
#include <string.h>

void gb_input_init(gb_input_t *input) {
    if (!input) return;
    memset(input, 0, sizeof(gb_input_t));
}

void gb_input_reset(gb_input_t *input) {
    if (!input) return;
    memset(input, 0, sizeof(gb_input_t));
}

void gb_input_press(gb_input_t *input, int button) {
    if (!input || button < 0 || button >= 8) return;
    input->buttons[button] = true;
}

void gb_input_release(gb_input_t *input, int button) {
    if (!input || button < 0 || button >= 8) return;
    input->buttons[button] = false;
}

bool gb_input_is_pressed(gb_input_t *input, int button) {
    if (!input || button < 0 || button >= 8) return false;
    return input->buttons[button];
}

./src/gb/gb_input.h

#ifndef GB_INPUT_H
#define GB_INPUT_H

#include <stdint.h>
#include <stdbool.h>

typedef struct gb_input_s {
    bool buttons[8]; // A, B, Select, Start, Right, Left, Up, Down
} gb_input_t;

enum {
    GB_BUTTON_A = 0,
    GB_BUTTON_B,
    GB_BUTTON_SELECT,
    GB_BUTTON_START,
    GB_BUTTON_RIGHT,
    GB_BUTTON_LEFT,
    GB_BUTTON_UP,
    GB_BUTTON_DOWN
};

void gb_input_init(gb_input_t *input);
void gb_input_reset(gb_input_t *input);
void gb_input_press(gb_input_t *input, int button);
void gb_input_release(gb_input_t *input, int button);
bool gb_input_is_pressed(gb_input_t *input, int button);

#endif // GB_INPUT_H

./src/gb/gb_mem.c

#include "gb_mem.h"
#include <string.h>

void gb_mem_init(gb_mem_t *mem) {
    if (!mem) return;
    memset(mem, 0, sizeof(gb_mem_t));
}

void gb_mem_reset(gb_mem_t *mem) {
    if (!mem) return;
    memset(mem, 0, sizeof(gb_mem_t));
}

uint8_t gb_mem_read(gb_mem_t *mem, uint16_t addr) {
    (void)mem;
    (void)addr;
    return 0xFF; // placeholder value
}

void gb_mem_write(gb_mem_t *mem, uint16_t addr, uint8_t value) {
    (void)mem;
    (void)addr;
    (void)value;
}

./src/gb/gb_mem.h

#ifndef GB_MEM_H
#define GB_MEM_H

#include <stdint.h>
#include <stdbool.h>

typedef struct gb_mem_s {
    uint8_t wram[0x2000];  // Work RAM
    uint8_t hram[0x7F];    // High RAM
    uint8_t io[0x80];      // IO Registers
} gb_mem_t;

void gb_mem_init(gb_mem_t *mem);
void gb_mem_reset(gb_mem_t *mem);
uint8_t gb_mem_read(gb_mem_t *mem, uint16_t addr);
void gb_mem_write(gb_mem_t *mem, uint16_t addr, uint8_t value);

#endif // GB_MEM_H

./src/gb/gb_ppu.c

#include "gb_ppu.h"
#include <string.h> // for memset

void gb_ppu_init(gb_ppu_t *ppu) {
    if (!ppu) return;
    memset(ppu, 0, sizeof(gb_ppu_t));
}

void gb_ppu_reset(gb_ppu_t *ppu) {
    if (!ppu) return;
    memset(ppu, 0, sizeof(gb_ppu_t));
}

void gb_ppu_tick(gb_ppu_t *ppu, int cycles) {
    (void)ppu;
    (void)cycles;
    // Stub: placeholder for timing and rendering logic
}

void gb_ppu_render_scanline(gb_ppu_t *ppu) {
    (void)ppu;
    // Stub: would draw one line of pixels to framebuffer
}

./src/gb/gb_ppu.h

#ifndef GB_PPU_H
#define GB_PPU_H

#include <stdint.h>
#include <stdbool.h>

// LCD dimensions
#define GB_LCD_WIDTH 160
#define GB_LCD_HEIGHT 144

// Game Boy PPU (Picture Processing Unit) state
typedef struct gb_ppu_s {
    uint8_t lcdc;  // LCD Control
    uint8_t stat;  // LCD Status
    uint8_t scy;   // Scroll Y
    uint8_t scx;   // Scroll X
    uint8_t ly;    // LCD Y coordinate
    uint8_t lyc;   // LY Compare
    uint8_t bgp;   // BG Palette
    uint8_t obp0;  // Object Palette 0
    uint8_t obp1;  // Object Palette 1
    uint8_t wy;    // Window Y position
    uint8_t wx;    // Window X position
    uint8_t vram[0x2000]; // VRAM
    uint8_t oam[0xA0];    // Object Attribute Memory
} gb_ppu_t;

// Functions
void gb_ppu_init(gb_ppu_t *ppu);
void gb_ppu_reset(gb_ppu_t *ppu);
void gb_ppu_tick(gb_ppu_t *ppu, int cycles);
void gb_ppu_render_scanline(gb_ppu_t *ppu);

#endif // GB_PPU_H

./src/gb/.goutputstream-5NBAE3

#ifndef GB_APU_H
#define GB_APU_H

#include <stdint.h>
#include <stdbool.h>

// Max audio buffer size per frame
#define GB_AUDIO_BUFFER_SIZE 2048

// GB audio channels
typedef struct {
    bool enabled;
    uint8_t volume;
    uint16_t frequency;
    uint16_t length;
    uint8_t duty;
    uint8_t envelope;
    int phase;
} gb_apu_channel_t;

typedef struct {
    gb_apu_channel_t square1;
    gb_apu_channel_t square2;
    gb_apu_channel_t wave;
    gb_apu_channel_t noise;

    int16_t buffer[GB_AUDIO_BUFFER_SIZE];
    size_t buffer_pos;
} gb_apu_t;

void gb_apu_init(gb_apu_t *apu);
void gb_apu_reset(gb_apu_t *apu);
void gb_apu_step(gb_apu_t *apu, int cycles);
void gb_apu_mix(gb_apu_t *apu, int16_t *out_buffer, size_t samples);

#endif // GB_APU_H

./src/gb/mmu.c

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gb/mmu.h

#ifndef GB_MMU_H
#define GB_MMU_H

#include <stdint.h>

typedef struct {
    uint8_t memory[0x10000]; // 64KB Game Boy memory map
} gb_mmu_t;

void gb_mmu_reset(gb_mmu_t *mmu);
uint8_t gb_mmu_read_byte(gb_mmu_t *mmu, uint16_t addr);
void gb_mmu_write_byte(gb_mmu_t *mmu, uint16_t addr, uint8_t value);

#endif // GB_MMU_H

./src/gb/ppu.c

#ifndef MMU_H
#define MMU_H

#include <stdint.h>
#include <stddef.h>
#include "core_common.h"

void mmu_init(core_mode_t mode, const uint8_t *rom, size_t rom_size);
uint8_t mmu_read8(uint32_t addr);
void mmu_write8(uint32_t addr, uint8_t val);

// For convenience in CPU stubs
const uint8_t* mmu_get_rom_ptr(void);
size_t mmu_get_rom_size(void);

#endif // MMU_H

./src/gb/ppu.h

#ifndef GB_PPU_H
#define GB_PPU_H

#include <stdint.h>

typedef struct {
    uint8_t vram[0x2000];
    uint8_t oam[0xA0];
    int scanline;
} gb_ppu_t;

void gb_ppu_reset(gb_ppu_t *ppu);
void gb_ppu_tick(gb_ppu_t *ppu);

#endif // GB_PPU_H

./src/gb/timing.c

#ifndef CORE_COMMON_H
#define CORE_COMMON_H

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

// Modes
typedef enum {
    MODE_UNSET = 0,
    MODE_GB,
    MODE_GBC,
    MODE_GBA
} core_mode_t;

// Pixel type (8-bit grayscale for GB/GBC, 32-bit ARGB for GBA)
typedef uint32_t pixel_t;

// Screen dimensions
#define GB_WIDTH 160
#define GB_HEIGHT 144
#define GBA_WIDTH 240
#define GBA_HEIGHT 160

#endif // CORE_COMMON_H

./src/gb/timing.h

#ifndef CORE_COMMON_H
#define CORE_COMMON_H

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

// Modes
typedef enum {
    MODE_UNSET = 0,
    MODE_GB,
    MODE_GBC,
    MODE_GBA
} core_mode_t;

// Pixel type (8-bit grayscale for GB/GBC, 32-bit ARGB for GBA)
typedef uint32_t pixel_t;

// Screen dimensions
#define GB_WIDTH 160
#define GB_HEIGHT 144
#define GBA_WIDTH 240
#define GBA_HEIGHT 160

#endif // CORE_COMMON_H